Reorder community chats and categories using drag and drop (#12854)

This commit is contained in:
Parvesh Monu 2021-12-24 21:04:44 +05:30 committed by GitHub
parent 5402c217df
commit 94fde74b88
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 276 additions and 155 deletions

View File

@ -164,3 +164,7 @@ used for some abi encoding primitives
## "rn-emoji-keyboard": "https://github.com/status-im/rn-emoji-keyboard" ## "rn-emoji-keyboard": "https://github.com/status-im/rn-emoji-keyboard"
Used for taking emoji input, for custom emoji thumbnails for community channels Used for taking emoji input, for custom emoji thumbnails for community channels
## "react-native-draggable-flatlist": "https://github.com/computerjazz/react-native-draggable-flatlist"
A drag-and-drop-enabled FlatList component for React Native

View File

@ -39,6 +39,7 @@
"react-native-dark-mode": "^0.2.2", "react-native-dark-mode": "^0.2.2",
"react-native-device-info": "^7.4.0", "react-native-device-info": "^7.4.0",
"react-native-dialogs": "^1.0.4", "react-native-dialogs": "^1.0.4",
"react-native-draggable-flatlist": "^3.0.3",
"react-native-fast-image": "8.5.11", "react-native-fast-image": "8.5.11",
"react-native-fetch-polyfill": "^1.1.2", "react-native-fetch-polyfill": "^1.1.2",
"react-native-fs": "^2.14.1", "react-native-fs": "^2.14.1",

Binary file not shown.

After

Width:  |  Height:  |  Size: 196 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 250 B

View File

@ -206,6 +206,9 @@
(def rn-emoji-keyboard (def rn-emoji-keyboard
#js {:EmojiKeyboard #js {}}) #js {:EmojiKeyboard #js {}})
(def react-native-draggable-flatlist
#js {:default #js {}})
;; Update i18n_resources.cljs ;; Update i18n_resources.cljs
(defn mock [module] (defn mock [module]
(case module (case module
@ -239,6 +242,7 @@
"@react-native-community/push-notification-ios" push-notification-ios "@react-native-community/push-notification-ios" push-notification-ios
"react-native-camera-kit" react-native-camera-kit "react-native-camera-kit" react-native-camera-kit
"rn-emoji-keyboard" rn-emoji-keyboard "rn-emoji-keyboard" rn-emoji-keyboard
"react-native-draggable-flatlist" react-native-draggable-flatlist
"./fleets.js" default-fleets "./fleets.js" default-fleets
"./chats.js" default-chats "./chats.js" default-chats
"../translations/ar.json" (js/JSON.parse (slurp "./translations/ar.json")) "../translations/ar.json" (js/JSON.parse (slurp "./translations/ar.json"))

View File

@ -55,13 +55,13 @@
:small :base :small :base
:large)) :large))
(defn container [{:keys [size]} & children] (defn container [{:keys [size container-style]} & children]
(into [rn/view {:style (merge (:tiny spacing/padding-horizontal) (into [rn/view {:style (merge (:tiny spacing/padding-horizontal)
{:min-height (size->container-size size) {:min-height (size->container-size size)
:padding-vertical 8 :padding-vertical 8
:flex-direction :row :flex-direction :row
:align-items :center :align-items :center
:justify-content :space-between})}] :justify-content :space-between} container-style)}]
children)) children))
(defn icon-column (defn icon-column
@ -197,7 +197,7 @@
left-side-alignment icon-color icon-bg-color left-side-alignment icon-color icon-bg-color
title subtitle subtitle-secondary active on-press on-long-press chevron size text-size title subtitle subtitle-secondary active on-press on-long-press chevron size text-size
accessory-text accessibility-label title-accessibility-label accessory-style accessory-text accessibility-label title-accessibility-label accessory-style
haptic-feedback haptic-type error animated animated-accessory? title-text-weight] haptic-feedback haptic-type error animated animated-accessory? title-text-weight container-style]
:or {subtitle-max-lines 1 :or {subtitle-max-lines 1
theme :main theme :main
haptic-feedback true haptic-feedback true
@ -233,7 +233,7 @@
{:on-long-press (fn [] {:on-long-press (fn []
(optional-haptic) (optional-haptic)
(on-long-press))})) (on-long-press))}))
[container {:size size} [container {:size size :container-style container-style}
[left-side {:icon-color icon-color [left-side {:icon-color icon-color
:text-color (if on-press :text-color (if on-press
text-color text-color

View File

@ -5,7 +5,10 @@
["react-native" :as rn] ["react-native" :as rn]
["@react-native-community/hooks" :as hooks] ["@react-native-community/hooks" :as hooks]
["react-native-navigation" :refer (Navigation)] ["react-native-navigation" :refer (Navigation)]
["rn-emoji-keyboard" :refer (EmojiKeyboard)])) ["rn-emoji-keyboard" :refer (EmojiKeyboard)]
["react-native-draggable-flatlist" :default DraggableFlatList]))
(def rn-draggable-flatlist (reagent/adapt-react-class DraggableFlatList))
(def emoji-keyboard (reagent/adapt-react-class EmojiKeyboard)) (def emoji-keyboard (reagent/adapt-react-class EmojiKeyboard))
@ -107,7 +110,13 @@
(defn- wrap-render-fn [f render-data] (defn- wrap-render-fn [f render-data]
(fn [data] (fn [data]
(reagent/as-element [f (.-item ^js data) (.-index ^js data) (.-separators ^js data) render-data]))) (reagent/as-element [f (.-item ^js data) (.-index ^js data)
(.-separators ^js data) render-data
(.-isActive ^js data) (.-drag ^js data)])))
(defn- wrap-on-drag-end-fn [f]
(fn [data]
(f (.-from ^js data) (.-to ^js data) (.-data ^js data))))
(defn- wrap-key-fn [f] (defn- wrap-key-fn [f]
(fn [data index] (fn [data index]
@ -115,19 +124,23 @@
(f data index))) (f data index)))
(defn base-list-props (defn base-list-props
[{:keys [key-fn render-fn empty-component header footer separator data render-data] :as props}] [{:keys [key-fn render-fn empty-component header footer separator data render-data on-drag-end-fn] :as props}]
(merge {:data (to-array data)} (merge {:data (to-array data)}
(when key-fn {:keyExtractor (wrap-key-fn key-fn)}) (when key-fn {:keyExtractor (wrap-key-fn key-fn)})
(when render-fn {:renderItem (wrap-render-fn render-fn render-data)}) (when render-fn {:renderItem (wrap-render-fn render-fn render-data)})
(when separator {:ItemSeparatorComponent (fn [] (reagent/as-element separator))}) (when separator {:ItemSeparatorComponent (fn [] (reagent/as-element separator))})
(when empty-component {:ListEmptyComponent (fn [] (reagent/as-element empty-component))}) (when empty-component {:ListEmptyComponent (fn [] (reagent/as-element empty-component))})
(when header {:ListHeaderComponent (reagent/as-element header)}) (when header {:ListHeaderComponent (reagent/as-element header)})
(when footer {:ListFooterComponent (reagent/as-element footer)}) (when footer {:ListFooterComponent (reagent/as-element footer)})
(dissoc props :data :header :footer :empty-component :separator :render-fn :key-fn))) (when on-drag-end-fn {:onDragEnd (wrap-on-drag-end-fn on-drag-end-fn)})
(dissoc props :data :header :footer :empty-component :separator :render-fn :key-fn :on-drag-end-fn)))
(defn flat-list [props] (defn flat-list [props]
[rn-flat-list (base-list-props props)]) [rn-flat-list (base-list-props props)])
(defn draggable-flat-list [props]
[rn-draggable-flatlist (base-list-props props)])
(defn animated-flat-list [props] (defn animated-flat-list [props]
[animated-flat-list-class (base-list-props props)]) [animated-flat-list-class (base-list-props props)])
;; Hooks ;; Hooks

View File

@ -288,7 +288,7 @@
(fx/defn edit-channel (fx/defn edit-channel
{:events [::edit-channel-confirmation-pressed]} {:events [::edit-channel-confirmation-pressed]}
[{:keys [db] :as cofx}] [{:keys [db] :as cofx}]
(let [{:keys [name description color community-id emoji edit-channel-id category-id]} (let [{:keys [name description color community-id emoji edit-channel-id category-id position]}
(get db :communities/create-channel)] (get db :communities/create-channel)]
{::json-rpc/call [{:method "wakuext_editCommunityChat" {::json-rpc/call [{:method "wakuext_editCommunityChat"
:params [community-id :params [community-id
@ -298,6 +298,7 @@
:color color :color color
:emoji emoji} :emoji emoji}
:category_id category-id :category_id category-id
:position position
:permissions {:access constants/community-channel-access-no-membership}}] :permissions {:access constants/community-channel-access-no-membership}}]
:js-response true :js-response true
:on-success #(re-frame/dispatch [::community-channel-edited %]) :on-success #(re-frame/dispatch [::community-channel-edited %])
@ -345,7 +346,7 @@
(fx/defn edit-channel-pressed (fx/defn edit-channel-pressed
{:events [::edit-channel-pressed]} {:events [::edit-channel-pressed]}
[{:keys [db] :as cofx} community-id chat-name description color emoji chat-id category-id] [{:keys [db] :as cofx} community-id chat-name description color emoji chat-id category-id position]
(let [{:keys [color emoji]} (if (string/blank? emoji) (let [{:keys [color emoji]} (if (string/blank? emoji)
(rand-nth emoji-thumbnail-styles/emoji-picker-default-thumbnails) (rand-nth emoji-thumbnail-styles/emoji-picker-default-thumbnails)
{:color color :emoji emoji})] {:color color :emoji emoji})]
@ -356,7 +357,8 @@
:community-id community-id :community-id community-id
:emoji emoji :emoji emoji
:edit-channel-id chat-id :edit-channel-id chat-id
:category-id category-id})} :category-id category-id
:position position})}
(navigation/open-modal :edit-community-channel nil)))) (navigation/open-modal :edit-community-channel nil))))
(fx/defn community-created (fx/defn community-created
@ -564,6 +566,15 @@
:on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %]) :on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])
:on-error #(log/error "failed to remove chat from community" %)}]})) :on-error #(log/error "failed to remove chat from community" %)}]}))
(fx/defn delete-community-chat
{:events [:delete-community-chat]}
[_ community-id chat-id]
{::json-rpc/call [{:method "wakuext_deleteCommunityChat"
:params [community-id chat-id]
:js-response true
:on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])
:on-error #(log/error "failed to delete community chat" %)}]})
(fx/defn delete-category (fx/defn delete-category
{:events [:delete-community-category]} {:events [:delete-community-category]}
[_ community-id category-id] [_ community-id category-id]
@ -592,6 +603,18 @@
(navigation/navigate-back) (navigation/navigate-back)
(remove-chat-from-category community-id id categoryID)))) (remove-chat-from-category community-id id categoryID))))
(fx/defn reorder-category-chat
{:events [::reorder-community-category-chat]}
[_ community-id category-id chat-id new-position]
{::json-rpc/call [{:method "wakuext_reorderCommunityChat"
:params [{:communityId community-id
:categoryId category-id
:chatId chat-id
:position new-position}]
:js-response true
:on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])
:on-error #(log/error "failed to reorder community category chat" %)}]})
(fx/defn reorder-category (fx/defn reorder-category
{:events [::reorder-community-category]} {:events [::reorder-community-category]}
[_ community-id category-id new-position] [_ community-id category-id new-position]

View File

@ -165,6 +165,7 @@
"wakuext_reorderCommunityChat" {} "wakuext_reorderCommunityChat" {}
"wakuext_editCommunityCategory" {} "wakuext_editCommunityCategory" {}
"wakuext_deleteCommunityCategory" {} "wakuext_deleteCommunityCategory" {}
"wakuext_deleteCommunityChat" {}
"wakuext_ensVerified" {} "wakuext_ensVerified" {}
"wakuext_dismissActivityCenterNotifications" {} "wakuext_dismissActivityCenterNotifications" {}
"wakuext_acceptActivityCenterNotifications" {} "wakuext_acceptActivityCenterNotifications" {}

View File

@ -876,6 +876,22 @@
(assoc :color colors/blue)) (assoc :color colors/blue))
chats))))) chats)))))
(re-frame/reg-sub
:chats/sorted-categories-by-community-id
(fn [[_ community-id]]
[(re-frame/subscribe [:chats/by-community-id community-id])
(re-frame/subscribe [:communities/community-chats community-id])])
(fn [[chats comm-chats] [_ community-id]]
(let [chat-cat (into {} (map (fn [{:keys [id categoryID position]}]
{(str community-id id) {:categoryID categoryID
:position position}})
(vals comm-chats)))]
(group-by :categoryID (sort-by :position
(map #(cond-> (merge % (chat-cat (:chat-id %)))
(= community-id constants/status-community-id)
(assoc :color colors/blue))
chats))))))
(re-frame/reg-sub (re-frame/reg-sub
:chats/category-by-chat-id :chats/category-by-chat-id
(fn [[_ community-id _]] (fn [[_ community-id _]]
@ -902,7 +918,9 @@
:<- [:communities] :<- [:communities]
(fn [communities [_ id]] (fn [communities [_ id]]
(->> (get-in communities [id :categories]) (->> (get-in communities [id :categories])
(sort-by #(:position (get % 1)))))) (map #(assoc (get % 1) :community-id id))
(sort-by :position)
(into []))))
(re-frame/reg-sub (re-frame/reg-sub
:chats/current-chat-ui-props :chats/current-chat-ui-props

View File

@ -12,6 +12,7 @@
(fn [] (fn []
(let [current-chat (<sub [:chat-by-id chat-id]) (let [current-chat (<sub [:chat-by-id chat-id])
{:keys [chat-name color description community-id emoji]} current-chat {:keys [chat-name color description community-id emoji]} current-chat
{:keys [position]} (<sub [:chats/community-chat-by-id community-id chat-id])
category (<sub [:chats/category-by-chat-id community-id chat-id]) category (<sub [:chats/category-by-chat-id community-id chat-id])
{:keys [admin]} (<sub [:communities/community community-id]) {:keys [admin]} (<sub [:communities/community community-id])
pinned-messages (<sub [:chats/pinned chat-id])] pinned-messages (<sub [:chats/pinned chat-id])]
@ -27,7 +28,8 @@
color color
emoji emoji
chat-id chat-id
(:id category)])}]) (:id category)
position])}])
:extended-header (profile-header/extended-header :extended-header (profile-header/extended-header
{:title chat-name {:title chat-name
:color color :color color

View File

@ -22,7 +22,6 @@
[re-frame.core :as re-frame] [re-frame.core :as re-frame]
[status-im.ui.screens.chat.sheets :as sheets] [status-im.ui.screens.chat.sheets :as sheets]
[status-im.ui.components.accordion :as accordion] [status-im.ui.components.accordion :as accordion]
[clojure.string :as string]
[status-im.ui.screens.communities.styles :as styles])) [status-im.ui.screens.communities.styles :as styles]))
(def request-cooldown-ms (* 60 1000)) (def request-cooldown-ms (* 60 1000))
@ -139,12 +138,6 @@
:title (i18n/label :t/edit-chats) :title (i18n/label :t/edit-chats)
:accessibility-label :community-edit-chats :accessibility-label :community-edit-chats
:icon :main-icons/edit :icon :main-icons/edit
:on-press #(hide-sheet-and-dispatch [:open-modal :community-edit-chats {:community-id id}])}]
[quo/list-item
{:theme :accent
:title (i18n/label :t/reorder-categories)
:accessibility-label :community-reorder-categories
:icon :main-icons/channel-category
:on-press #(hide-sheet-and-dispatch :on-press #(hide-sheet-and-dispatch
[:open-modal :community-reorder-categories {:community-id id}])}]])])) [:open-modal :community-reorder-categories {:community-id id}])}]])]))
@ -168,46 +161,28 @@
{:content (fn [] {:content (fn []
[sheets/actions home-item])}])}]) [sheets/actions home-item])}])}])
(defn categories-accordion [community-id chats categories edit data] (defn categories-accordion [community-id chats categories data]
[:<> [:<>
(for [{:keys [name id state]} (vals categories)] (for [{:keys [name id state]} categories]
^{:key (str "cat" name id)} ^{:key (str "cat" name id)}
[:<> [:<>
[accordion/section [accordion/section
{:on-open #(>evt [::communities/store-category-state community-id id true]) {:on-open #(>evt [::communities/store-category-state community-id id true])
:on-close #(>evt [::communities/store-category-state community-id id false]) :on-close #(>evt [::communities/store-category-state community-id id false])
:default state :default state
:opened edit
:disabled edit
:title [rn/view styles/category-item :title [rn/view styles/category-item
(if edit [icons/icon :main-icons/channel-category {:color colors/gray}]
[rn/touchable-opacity {:on-press #(>evt [:delete-community-category community-id id])}
[icons/icon :main-icons/delete-circle {:no-color true}]]
[icons/icon :main-icons/channel-category {:color colors/gray}])
[rn/text {:style {:font-size 17 :margin-left 10 :color colors/black}} name]] [rn/text {:style {:font-size 17 :margin-left 10 :color colors/black}} name]]
:content [rn/view :content [:<>
(for [chat (get chats id)] (for [chat (get chats id)]
(if edit ^{:key (str "chat" chat id)}
^{:key (str "chat" chat id)} [community-chat-item chat nil nil data])]}]
[rn/view styles/category-item
[rn/touchable-opacity {:on-press #(>evt [:remove-chat-from-community-category
community-id
(string/replace (:chat-id chat) community-id "")
(:categoryID chat)])}
[icons/icon :main-icons/delete-circle {:no-color true}]]
[rn/view {:flex 1}
[inner-item/home-list-item
(assoc chat :public? true)]]]
^{:key (str "chat" chat id)}
[community-chat-item chat nil nil data]))]}]
[quo/separator]])]) [quo/separator]])])
(defn community-chat-list [community-id categories edit from-chat] (defn community-chat-list [community-id categories from-chat]
(let [chats (<sub [:chats/categories-by-community-id community-id])] (let [chats (<sub [:chats/sorted-categories-by-community-id community-id])]
(if (and (empty? categories) (empty? chats)) (if (and (empty? categories) (empty? chats))
(if edit [blank-page (i18n/label :t/welcome-community-blank-message)]
[blank-page (i18n/label :t/welcome-community-blank-message-edit-chats)]
[blank-page (i18n/label :t/welcome-community-blank-message)])
[list/flat-list [list/flat-list
{:key-fn :chat-id {:key-fn :chat-id
:content-container-style {:padding-bottom 8} :content-container-style {:padding-bottom 8}
@ -215,7 +190,7 @@
:data (get chats "") :data (get chats "")
:render-data {:from-chat from-chat} :render-data {:from-chat from-chat}
:render-fn community-chat-item :render-fn community-chat-item
:header [categories-accordion community-id chats categories edit {:from-chat from-chat}] :header [categories-accordion community-id chats categories {:from-chat from-chat}]
:footer [rn/view {:height 68}]}]))) :footer [rn/view {:height 68}]}])))
(defn channel-preview-item [{:keys [id name]}] (defn channel-preview-item [{:keys [id name]}]
@ -267,23 +242,6 @@
[components.react/small-loading-indicator] [components.react/small-loading-indicator]
(i18n/label :t/fetch-community))]]])) (i18n/label :t/fetch-community))]]]))
(defn community-edit []
(let [{:keys [community-id]} (<sub [:get-screen-params])]
(fn []
(let [{:keys [id name images members permissions color]} (<sub [:communities/community community-id])
categories (<sub [:communities/sorted-categories community-id])]
[:<>
[topbar/topbar
{:modal? true
:content [toolbar-content
id
name
color
images
(not= (:access permissions) constants/community-no-membership-access)
(count members)]}]
[community-chat-list id categories true false]]))))
(defn community [] (defn community []
(let [{:keys [community-id from-chat]} (<sub [:get-screen-params])] (let [{:keys [community-id from-chat]} (<sub [:get-screen-params])]
(fn [] (fn []

View File

@ -1,60 +1,176 @@
(ns status-im.ui.screens.communities.reorder-categories (ns status-im.ui.screens.communities.reorder-categories
(:require [quo.core :as quo] (:require [quo.core :as quo]
[clojure.walk :as walk]
[quo.react-native :as rn] [quo.react-native :as rn]
[reagent.core :as reagent]
[clojure.string :as string]
[clojure.set :as clojure.set] [clojure.set :as clojure.set]
[status-im.i18n.i18n :as i18n] [status-im.i18n.i18n :as i18n]
[status-im.utils.utils :as utils]
[status-im.constants :as constants] [status-im.constants :as constants]
[quo.design-system.colors :as colors] [quo.design-system.colors :as colors]
[status-im.ui.components.react :as react] [status-im.utils.platform :as platform]
[status-im.ui.components.topbar :as topbar] [status-im.ui.components.topbar :as topbar]
[status-im.communities.core :as communities] [status-im.communities.core :as communities]
[status-im.utils.handlers :refer [>evt <sub]] [status-im.utils.handlers :refer [>evt <sub]]
[status-im.ui.components.icons.icons :as icons] [status-im.ui.components.icons.icons :as icons]
[status-im.ui.screens.communities.styles :as styles] [status-im.ui.screens.communities.styles :as styles]
[status-im.ui.screens.communities.community :as community])) [status-im.ui.screens.communities.community :as community]
[status-im.ui.screens.home.views.inner-item :as inner-item]))
(defn category-change-positon [community-id key up? position] (def collapse-chats? (reagent/atom false))
(let [new-position (if up? (dec position) (inc position))] (def data (reagent/atom []))
(>evt [::communities/reorder-community-category community-id key new-position])))
(defn category-item-button [community-id up? disabled? key position] (defn show-delete-chat-confirmation [community-id chat-id]
(let [[margin-right icon] (if up? (utils/show-confirmation
[10 :main-icons/dropdown-up] {:title (i18n/label :t/delete-confirmation)
[25 :main-icons/dropdown])] :content (i18n/label :t/delete-chat-confirmation)
[react/touchable-opacity {:disabled disabled? :confirm-button-text (i18n/label :t/delete)
:on-press #(category-change-positon :on-accept #(>evt [:delete-community-chat community-id chat-id])}))
community-id key up? position)}
[rn/view {:style (styles/reorder-categories-button margin-right)}
[icons/icon icon {:color colors/black}]]]))
(defn category-item [community-id count {:keys [key name position]}] (defn show-delete-catgory-confirmation [community-id category-id]
(let [up-disabled? (= position 0) (utils/show-confirmation
down-disabled? (= position (dec count))] {:title (i18n/label :t/delete-confirmation)
:content (i18n/label :t/delete-category-confirmation)
:confirm-button-text (i18n/label :t/delete)
:on-accept #(>evt [:delete-community-category community-id category-id])}))
(defn chat-item
[{:keys [id community-id] :as home-item} is-active? drag]
(let [chat-id (string/replace id community-id "")
background-color (if is-active? colors/gray-lighter colors/white)
home-item (clojure.set/rename-keys home-item {:id :chat-id})]
[rn/view {:accessibility-label :chat-item
:style (merge styles/category-item
{:background-color background-color})}
[rn/touchable-opacity
{:accessibility-label :delete-community-chat
:on-press #(show-delete-chat-confirmation community-id chat-id)}
[icons/icon :main-icons/delete-circle {:no-color true}]]
[rn/view {:flex 1}
[inner-item/home-list-item (assoc home-item :edit? true) {:active-opacity 1}]]
[rn/touchable-opacity {:on-long-press drag
:delay-long-press 100
:accessibility-label :chat-drag-handle
:style {:padding 20}}
[icons/icon :main-icons/reorder-handle {:no-color true :width 18 :height 12}]]]))
(defn category-item
[{:keys [id name community-id]} is-active? drag]
(let [background-color (if is-active? colors/gray-lighter colors/white)
category-none? (string/blank? id)]
[:<> [:<>
[rn/view {:style styles/reorder-categories-item} [quo/separator]
[icons/icon :main-icons/channel-category {:color colors/gray}] [rn/view {:accessibility-label :category-item
[rn/text {:style (styles/reorder-categories-text)} name] :style (merge styles/category-item
[category-item-button community-id true up-disabled? key position] {:background-color background-color})}
[category-item-button community-id false down-disabled? key position]] (if category-none?
[quo/separator]])) [icons/icon :main-icons/channel-category {:color colors/gray}]
[rn/touchable-opacity
{:accessibility-label :delete-category-button
:on-press #(show-delete-catgory-confirmation community-id id)}
[icons/icon :main-icons/delete-circle {:no-color true}]])
[rn/view {:flex 1}
[rn/text {:style {:font-size 17 :margin-left 10 :color colors/black}} name]]
(when (and (not category-none?) @collapse-chats?)
[rn/touchable-opacity {:accessibility-label :category-drag-handle
:on-long-press drag
:delay-long-press 100
:style {:padding 20}}
[icons/icon :main-icons/reorder-handle {:no-color true :width 18 :height 12}]])]]))
(defn categories-view [community-id categories count] (defn render-fn
[rn/view {:accessibility-label :reorder-categories-list} [{:keys [chat-type] :as item} _ _ _ is-active? drag]
(for [category-vector categories] (if (= chat-type constants/community-chat-type)
(let [category (clojure.set/rename-keys (get category-vector 1) {:id :key})] [chat-item item is-active? drag]
[category-item community-id count category]))]) [category-item item is-active? drag]))
(defn calculate-chat-new-position-and-category
[to second-call? old-category going-up?]
(let [{:keys [id chat-type categoryID position]} (get @data to)
[new-category new-position]
(if going-up?
(if (= chat-type constants/community-chat-type)
[categoryID (if second-call? (inc position) position)]
(if second-call? [id 0]
(calculate-chat-new-position-and-category (dec to) true old-category true)))
(if (= chat-type constants/community-chat-type)
(if (= categoryID old-category)
[categoryID position]
[categoryID (inc position)]) [id 0]))]
[new-category new-position]))
(defn update-local-atom [data-js]
(reset! data data-js)
(reagent/flush))
(defn on-drag-end-chat [from to data-js]
(let [{:keys [id community-id categoryID position]} (get @data from)
[new-category new-position] (calculate-chat-new-position-and-category
to false categoryID (> from to))
chat-id (string/replace id community-id "")]
(when-not (and (= new-position position) (= new-category categoryID))
(update-local-atom data-js)
(>evt [::communities/reorder-community-category-chat
community-id new-category chat-id new-position]))))
(defn on-drag-end-category [from to data-js]
(let [{:keys [id community-id position]} (get @data from)]
(when (and (< to (count @data)) (not= position to) (not= id ""))
(update-local-atom data-js)
(>evt [::communities/reorder-community-category community-id id to]))))
(defn on-drag-end-fn [from to data-js]
(if @collapse-chats?
(on-drag-end-category from to data-js)
(when-not (= to 0) (on-drag-end-chat from to data-js))))
(defn reset-data [categories chats]
(reset! data (if @collapse-chats? categories ;; If chats are collapsed then only show categories
(walk/postwalk-replace ;; else, categories and chats
{:chat-id :id}
(reduce (fn [acc category]
(-> acc
(conj category)
(into (get chats (:id category))))) [] categories)))))
(defn draggable-list []
[rn/draggable-flat-list
{:key-fn :id
:data @data
:render-fn render-fn
:autoscroll-threshold (if platform/android? 150 250)
:autoscroll-speed (if platform/android? 10 150) ;; TODO - Use same speed for both ios and android
:container-style {:margin-bottom 108} ;; after bumping react native version to > 0.64
:on-drag-end-fn on-drag-end-fn}])
(defn view [] (defn view []
(let [{:keys [community-id]} (<sub [:get-screen-params]) (let [{:keys [community-id]} (<sub [:get-screen-params])
{:keys [id name images members permissions color]} {:keys [id name images members permissions color]}
(<sub [:communities/community community-id]) (<sub [:communities/community community-id])
categories (<sub [:communities/sorted-categories community-id])] sorted-categories (<sub [:communities/sorted-categories community-id])
categories (if @collapse-chats? sorted-categories
(conj sorted-categories
{:id ""
:position (count sorted-categories)
:name (i18n/label :t/none)
:community-id community-id}))
chats (<sub [:chats/sorted-categories-by-community-id community-id])]
(reset-data categories chats)
[:<> [:<>
[topbar/topbar [topbar/topbar
{:modal? true {:modal? true
:content [community/toolbar-content id name color images :content [community/toolbar-content id name color images
(not= (:access permissions) constants/community-no-membership-access) (not= (:access permissions) constants/community-no-membership-access)
(count members)]}] (count members)]}]
(if (empty? categories) (if (and (empty? sorted-categories) (empty? chats))
[community/blank-page (i18n/label :t/welcome-community-blank-message-categories)] [community/blank-page (i18n/label :t/welcome-community-blank-message-edit-chats)]
[categories-view community-id categories (count categories)])])) [:<>
[quo/list-item {:size :small
:title (i18n/label :t/rearrange-categories)
:active @collapse-chats?
:accessory :switch
:container-style {:padding-left 10}
:on-press #(reset! collapse-chats? (not @collapse-chats?))}]
[quo/separator]
[draggable-list]])]))

View File

@ -25,6 +25,7 @@
(let [{:keys [community-id chat]} (<sub [:get-screen-params])] (let [{:keys [community-id chat]} (<sub [:get-screen-params])]
(fn [] (fn []
(let [categories (<sub [:communities/sorted-categories community-id]) (let [categories (<sub [:communities/sorted-categories community-id])
chats (<sub [:chats/sorted-categories-by-community-id community-id])
comm-chat (<sub [:chats/community-chat-by-id community-id (:chat-id chat)]) comm-chat (<sub [:chats/community-chat-by-id community-id (:chat-id chat)])
_ (reset! selected-item (:categoryID comm-chat))] _ (reset! selected-item (:categoryID comm-chat))]
[:<> [:<>
@ -44,7 +45,7 @@
:create-community-category :create-community-category
{:community-id community-id}]) {:community-id community-id}])
:title (i18n/label :t/create-category)}] :title (i18n/label :t/create-category)}]
:data (conj (vec (vals categories)) {:name (i18n/label :t/none) :id ""}) :data (conj categories {:name (i18n/label :t/none) :id ""})
:render-fn render-fn}]] :render-fn render-fn}]]
[toolbar/toolbar [toolbar/toolbar
{:show-border? true {:show-border? true
@ -54,6 +55,7 @@
[::communities/change-category-confirmation-pressed [::communities/change-category-confirmation-pressed
community-id community-id
@selected-item @selected-item
comm-chat] (assoc comm-chat :position
(count (get chats @selected-item)))] ;; Add as last item in new category
3000)} 3000)}
(i18n/label :t/done)]}]])))) (i18n/label :t/done)]}]]))))

View File

@ -1,34 +1,8 @@
(ns status-im.ui.screens.communities.styles (ns status-im.ui.screens.communities.styles)
(:require [quo.design-system.colors :as colors]))
(def category-item (def category-item
{:flex 1 {:flex 1
:flex-direction :row :flex-direction :row
:align-items :center :align-items :center
:height 52 :height 52
:margin-left 18}) :padding-left 18})
(def reorder-categories-item
{:accessibility-label :reorder-categories-item
:flex-direction :row
:height 60
:align-items :center
:margin-left 18})
(defn reorder-categories-text []
{:font-size 17
:margin-left 10
:color (colors/get-color :text-01)
:flex 1})
(defn reorder-categories-button [margin-right]
{:accessibility-label :reorder-categories-button
:width 30
:height 30
:border-radius 15
:margin 10
:margin-right margin-right
:border-width 1
:justify-content :center
:align-items :center
:border-color colors/black})

View File

@ -149,13 +149,16 @@
:else :else
[icons/icon :main-icons/tiny-new-contact (icon-style)])) [icons/icon :main-icons/tiny-new-contact (icon-style)]))
(defn chat-item-title [chat-id muted group-chat chat-name] (defn chat-item-title [chat-id muted group-chat chat-name edit?]
[quo/text {:weight :medium [quo/text {:weight :medium
:color (when muted :secondary) :color (when muted :secondary)
:accessibility-label :chat-name-text :accessibility-label :chat-name-text
:ellipsize-mode :tail :ellipsize-mode :tail
:number-of-lines 1 :number-of-lines 1
:style {:position :absolute :left 92 :top 10 :right 90}} :style {:position :absolute
:left 92
:top 10
:right (if edit? 50 90)}}
(if group-chat (if group-chat
(utils/truncate-str chat-name 30) (utils/truncate-str chat-name 30)
;; This looks a bit odd, but I would like only to subscribe ;; This looks a bit odd, but I would like only to subscribe
@ -164,7 +167,7 @@
(first @(re-frame/subscribe [:contacts/contact-two-names-by-identity chat-id])))]) (first @(re-frame/subscribe [:contacts/contact-two-names-by-identity chat-id])))])
(defn home-list-item [home-item opts] (defn home-list-item [home-item opts]
(let [{:keys [chat-id chat-name color group-chat public? timestamp last-message muted emoji highlight]} home-item (let [{:keys [chat-id chat-name color group-chat public? timestamp last-message muted emoji highlight edit?]} home-item
background-color (when highlight (colors/get-color :interactive-02))] background-color (when highlight (colors/get-color :interactive-02))]
[react/touchable-opacity (merge {:style {:height 64 :background-color background-color}} opts) [react/touchable-opacity (merge {:style {:height 64 :background-color background-color}} opts)
[:<> [:<>
@ -178,13 +181,15 @@
:default-chat-icon-text (if (string/blank? emoji) :default-chat-icon-text (if (string/blank? emoji)
(chat-icon.styles/default-chat-icon-text 40) (chat-icon.styles/default-chat-icon-text 40)
(chat-icon.styles/emoji-chat-icon-text 40))}] (chat-icon.styles/emoji-chat-icon-text 40))}]
[chat-item-title chat-id muted group-chat chat-name] [chat-item-title chat-id muted group-chat chat-name edit?]
[react/text {:style styles/datetime-text (when-not edit?
:number-of-lines 1 [:<>
:accessibility-label :last-message-time-text} [react/text {:style styles/datetime-text
;;TODO (perf) move to event :number-of-lines 1
(memo-timestamp (if (pos? (:whisper-timestamp last-message)) :accessibility-label :last-message-time-text}
(:whisper-timestamp last-message) ;;TODO (perf) move to event
timestamp))] (memo-timestamp (if (pos? (:whisper-timestamp last-message))
[message-content-text (select-keys last-message [:content :content-type :community-id]) true] (:whisper-timestamp last-message)
[unviewed-indicator home-item]]])) timestamp))]
[unviewed-indicator home-item]])
[message-content-text (select-keys last-message [:content :content-type :community-id]) true]]]))

View File

@ -288,11 +288,6 @@
;;TODO custom ;;TODO custom
:options {:topBar {:visible false}} :options {:topBar {:visible false}}
:component select-category/view} :component select-category/view}
{:name :community-edit-chats
;;TODO custom
:insets {:bottom true}
:options {:topBar {:visible false}}
:component community/community-edit}
{:name :community-reorder-categories {:name :community-reorder-categories
:insets {:top false} :insets {:top false}
:options {:topBar {:visible false}} :options {:topBar {:visible false}}

View File

@ -184,7 +184,7 @@
"membership-request-pending": "Membership request pending", "membership-request-pending": "Membership request pending",
"create-community": "Create a community", "create-community": "Create a community",
"create-category": "Create category", "create-category": "Create category",
"reorder-categories": "Reorder categories", "rearrange-categories": "Rearrange Categories",
"edited": "Edited", "edited": "Edited",
"edit-community": "Edit community", "edit-community": "Edit community",
"editing-message": "Editing message", "editing-message": "Editing message",
@ -412,6 +412,7 @@
"delete-bootnode-title": "Delete bootnode", "delete-bootnode-title": "Delete bootnode",
"delete-chat": "Delete chat", "delete-chat": "Delete chat",
"delete-chat-confirmation": "Are you sure you want to delete this chat?", "delete-chat-confirmation": "Are you sure you want to delete this chat?",
"delete-category-confirmation": "Are you sure you want to delete this category?",
"delete-confirmation": "Delete?", "delete-confirmation": "Delete?",
"delete-mailserver": "Delete Status node", "delete-mailserver": "Delete Status node",
"delete-mailserver-are-you-sure": "Are you sure you want to delete this Status node?", "delete-mailserver-are-you-sure": "Are you sure you want to delete this Status node?",
@ -1344,7 +1345,6 @@
"welcome-blank-message": "Your chats will appear here. To start new chats press the ⊕ button", "welcome-blank-message": "Your chats will appear here. To start new chats press the ⊕ button",
"welcome-community-blank-message": "Your channels will appear here. To create a new channel, click on the ⊕ button and select \"Create a channel\"", "welcome-community-blank-message": "Your channels will appear here. To create a new channel, click on the ⊕ button and select \"Create a channel\"",
"welcome-community-blank-message-edit-chats": "Your channels will appear here. To create a new channel, go back to the community screen, click on the ⊕ button and select \"Create a channel\"", "welcome-community-blank-message-edit-chats": "Your channels will appear here. To create a new channel, go back to the community screen, click on the ⊕ button and select \"Create a channel\"",
"welcome-community-blank-message-categories": "Your categories will appear here. To create a new category, go back to the community screen, click on the ⊕ button and select \"Create category\"",
"welcome-blank-community-message": "Your communities will appear here.", "welcome-blank-community-message": "Your communities will appear here.",
"fetch-community": "Fetch community", "fetch-community": "Fetch community",
"fetching-community": "Fetching community...", "fetching-community": "Fetching community...",

View File

@ -6618,6 +6618,11 @@ react-native-dialogs@^1.0.4:
resolved "https://registry.yarnpkg.com/react-native-dialogs/-/react-native-dialogs-1.1.0.tgz#8f7ee7f9d96574fc878fb7c1be101611fb4af517" resolved "https://registry.yarnpkg.com/react-native-dialogs/-/react-native-dialogs-1.1.0.tgz#8f7ee7f9d96574fc878fb7c1be101611fb4af517"
integrity sha512-clnxO0nMyML/6+G5dja3Yt34gPxegLY2OHTwb8BwYTEvQ2UhRKR49Uq91XqU0q6g7Ur9DiYxC0tqV3rcZWUrjQ== integrity sha512-clnxO0nMyML/6+G5dja3Yt34gPxegLY2OHTwb8BwYTEvQ2UhRKR49Uq91XqU0q6g7Ur9DiYxC0tqV3rcZWUrjQ==
react-native-draggable-flatlist@^3.0.3:
version "3.0.3"
resolved "https://registry.yarnpkg.com/react-native-draggable-flatlist/-/react-native-draggable-flatlist-3.0.3.tgz#e85503585253be01ad251f78d5b341ac22f9d952"
integrity sha512-bDro6aqQMvvTm/CuHre9dAjSBKosAfZRLDx3nmrjOz799kxcn0bq+uCB6yF6m+g1Xd/gVPl7E3Ss4uX+oPUlHg==
react-native-fast-image@8.5.11: react-native-fast-image@8.5.11:
version "8.5.11" version "8.5.11"
resolved "https://registry.yarnpkg.com/react-native-fast-image/-/react-native-fast-image-8.5.11.tgz#e3dc969d0e4e8df026646bf18194465aa55cbc2b" resolved "https://registry.yarnpkg.com/react-native-fast-image/-/react-native-fast-image-8.5.11.tgz#e3dc969d0e4e8df026646bf18194465aa55cbc2b"