fixed list paddings
fixed android styles group chat contacts management refactored contact group contacts, deletion, implemented group chat settings reworked contacts screens, implemented “add contacts” screen and “edit contacts” screen group chat ui refresh
After Width: | Height: | Size: 469 B |
After Width: | Height: | Size: 462 B |
After Width: | Height: | Size: 466 B |
After Width: | Height: | Size: 1007 B |
After Width: | Height: | Size: 351 B |
After Width: | Height: | Size: 337 B |
After Width: | Height: | Size: 323 B |
After Width: | Height: | Size: 639 B |
After Width: | Height: | Size: 531 B |
After Width: | Height: | Size: 562 B |
After Width: | Height: | Size: 568 B |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 721 B |
After Width: | Height: | Size: 747 B |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 902 B |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 2.3 KiB |
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "icon_arrow_right_red.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
BIN
ios/StatusIm/Images.xcassets/icon_arrow_right_red.imageset/icon_arrow_right_red.png
vendored
Normal file
After Width: | Height: | Size: 531 B |
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "icon_close_blue.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
After Width: | Height: | Size: 562 B |
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "icon_close_red.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
After Width: | Height: | Size: 568 B |
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "icon_speaker_blue.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
BIN
ios/StatusIm/Images.xcassets/icon_speaker_blue.imageset/icon_speaker_blue.png
vendored
Normal file
After Width: | Height: | Size: 1.2 KiB |
|
@ -25,8 +25,14 @@
|
|||
[status-im.transactions.screen :refer [confirm]]
|
||||
[status-im.chats-list.screen :refer [chats-list]]
|
||||
[status-im.new-group.screen-public :refer [new-public-group]]
|
||||
[status-im.new-group.screen-private :refer [new-group contact-group]]
|
||||
[status-im.new-group.views.contact-list :refer [contact-group-list]]
|
||||
[status-im.new-group.screen-private :refer [new-group
|
||||
edit-group]]
|
||||
[status-im.new-group.views.chat-group-settings :refer [chat-group-settings]]
|
||||
[status-im.new-group.views.contact-list :refer [edit-group-contact-list
|
||||
edit-chat-group-contact-list]]
|
||||
[status-im.new-group.views.contact-toggle-list :refer [contact-toggle-list
|
||||
add-contacts-toggle-list
|
||||
add-participants-toggle-list]]
|
||||
[status-im.new-group.views.reorder-groups :refer [reorder-groups]]
|
||||
[status-im.participants.views.add :refer [new-participants]]
|
||||
[status-im.participants.views.remove :refer [remove-participants]]
|
||||
|
@ -108,11 +114,16 @@
|
|||
:remove-participants remove-participants
|
||||
:chat-list main-tabs
|
||||
:new-group new-group
|
||||
:edit-group edit-group
|
||||
:chat-group-settings chat-group-settings
|
||||
:add-contacts-toggle-list add-contacts-toggle-list
|
||||
:add-participants-toggle-list add-participants-toggle-list
|
||||
:edit-group-contact-list edit-group-contact-list
|
||||
:edit-chat-group-contact-list edit-chat-group-contact-list
|
||||
:new-public-group new-public-group
|
||||
:contact-group contact-group
|
||||
:contact-group-list contact-group-list
|
||||
:group-settings group-settings
|
||||
:contact-list main-tabs
|
||||
:contact-toggle-list contact-toggle-list
|
||||
:contact-list-search-results contacts-search-results
|
||||
:group-contacts contact-list
|
||||
:reorder-groups reorder-groups
|
||||
|
|
|
@ -49,8 +49,8 @@
|
|||
:font-size 14}
|
||||
:info-container {:margin-left 16}
|
||||
:contact-inner-container {:height 56}
|
||||
:contacts-list-container {:padding-top 8
|
||||
:padding-bottom 8}
|
||||
:contact-list-spacing {:background-color styles/color-white
|
||||
:height 8}
|
||||
:separator {:height 0}
|
||||
:icon-check {:border-radius 2
|
||||
:width 17
|
||||
|
@ -76,13 +76,17 @@
|
|||
:members-text {:font-size 14}
|
||||
:members-text-count {:font-size 14}
|
||||
:add-text {:margin-left 16
|
||||
:letter-spacing 0.5
|
||||
:font-size 14}
|
||||
:delete-group-text {:letter-spacing 0.5
|
||||
:font-size 14}
|
||||
:delete-group-prompt-text {:font-size 14}
|
||||
:line-height 24
|
||||
:font-size 16}
|
||||
:contact-container {:height 56}
|
||||
:delete-group-container {:padding-left 72}}
|
||||
:settings-group-text {:letter-spacing 0.5
|
||||
:font-size 16}
|
||||
:delete-group-prompt-text {:font-size 12}
|
||||
:settings-group-item {:padding-left 16
|
||||
:height 56
|
||||
:flex-direction :row
|
||||
:align-items :center}
|
||||
:settings-group-container {:margin-top 23}}
|
||||
:reorder-groups {:order-item-container {:height 56
|
||||
:background-color styles/color-white}
|
||||
:order-item-icon {:padding-right 16}
|
||||
|
@ -144,6 +148,5 @@
|
|||
:discover {:uppercase-subtitles? false}
|
||||
:public-group-icon-container {:margin-top 4}
|
||||
:private-group-icon-container {:margin-top 6}
|
||||
:group-chat-focus-line-color styles/color-light-blue
|
||||
:group-chat-focus-line-height 2
|
||||
:public-group-chat-hash-style {:top 10 :left 4}})
|
||||
|
|
|
@ -55,7 +55,7 @@
|
|||
[action-button-item
|
||||
{:title (label :t/new-group-chat)
|
||||
:buttonColor :#1abc9c
|
||||
:onPress #(dispatch [:navigate-to :new-group])}
|
||||
:onPress #(dispatch [:open-contact-toggle-list :chat-group])}
|
||||
[icon :private_group_big st/group-icon]]
|
||||
[action-button-item
|
||||
{:title (label :t/new-public-group-chat)
|
||||
|
|
|
@ -24,29 +24,20 @@
|
|||
:show (when show-search? :contact-list)
|
||||
:text "")))
|
||||
|
||||
(defmethod nav/preload-data! :contact-group
|
||||
[db [_ _ group]]
|
||||
(defmethod nav/preload-data! :edit-group
|
||||
[db [_ _ group group-type]]
|
||||
(if group
|
||||
(-> db
|
||||
(assoc :contact-group group
|
||||
:selected-contacts (into #{} (map :identity (:contacts group)))
|
||||
:new-chat-name (:name group))
|
||||
(update :toolbar-search assoc
|
||||
:show :contact-list
|
||||
:text ""))
|
||||
(assoc db :contact-group-id (:group-id group)
|
||||
:group-type group-type
|
||||
:new-chat-name (:name group))
|
||||
db))
|
||||
|
||||
(defmethod nav/preload-data! :new-group
|
||||
[db _]
|
||||
(-> db
|
||||
(assoc :new-group #{})
|
||||
(assoc :new-chat-name nil)))
|
||||
|
||||
(defmethod nav/preload-data! :contact-list
|
||||
[db [_ _ click-handler]]
|
||||
(-> db
|
||||
(assoc-in [:toolbar-search :show] nil)
|
||||
(assoc-in [:contact-list-ui-props :edit?] false)
|
||||
(assoc-in [:contacts-ui-props :edit?] false)
|
||||
(assoc :contacts-click-handler click-handler)))
|
||||
|
||||
(defmethod nav/preload-data! :reorder-groups
|
||||
|
@ -342,7 +333,7 @@
|
|||
|
||||
(register-handler :remove-contact-from-group
|
||||
(u/side-effect!
|
||||
(fn [{:keys [contact-groups]} [_ {:keys [whisper-identity]} {:keys [group-id]}]]
|
||||
(fn [{:keys [contact-groups]} [_ whisper-identity group-id]]
|
||||
(let [group' (update (contact-groups group-id) :contacts (remove-contact-from-group whisper-identity))]
|
||||
(dispatch [:update-group group'])))))
|
||||
|
||||
|
@ -369,11 +360,12 @@
|
|||
:cancel-text (label :t/cancel)}))))
|
||||
|
||||
(register-handler
|
||||
:open-contact-group-list
|
||||
(after #(dispatch [:navigate-to :contact-group-list]))
|
||||
(fn [db _]
|
||||
:open-contact-toggle-list
|
||||
(after #(dispatch [:navigate-to :contact-toggle-list]))
|
||||
(fn [db [_ group-type]]
|
||||
(->
|
||||
(assoc db :contact-group nil
|
||||
:group-type group-type
|
||||
:selected-contacts #{}
|
||||
:new-chat-name "")
|
||||
(assoc-in [:toolbar-search :show] nil)
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
(def toolbar-options
|
||||
[{:text (label :t/new-contact) :value #(dispatch [:navigate-to :new-contact])}
|
||||
{:text (label :t/edit) :value #(dispatch [:set-in [:contacts-ui-props :edit?] true])}
|
||||
{:text (label :t/new-group) :value #(dispatch [:open-contact-group-list])}
|
||||
{:text (label :t/new-group) :value #(dispatch [:open-contact-toggle-list :contact-group])}
|
||||
{:text (label :t/reorder-groups) :value #(dispatch [:navigate-to :reorder-groups])}])
|
||||
|
||||
(defn toolbar-actions []
|
||||
|
@ -52,7 +52,8 @@
|
|||
:title (label :t/edit-contacts)}])
|
||||
|
||||
(defn options-btn [group]
|
||||
(let [options [{:value #(dispatch [:navigate-to :contact-group group]) :text (label :t/edit-group)}]]
|
||||
(let [options [{:value #(dispatch [:navigate-to :edit-group group :contact-group])
|
||||
:text (label :t/edit-group)}]]
|
||||
[view st/more-btn
|
||||
[context-menu
|
||||
[icon :options_gray]
|
||||
|
@ -89,6 +90,7 @@
|
|||
(when (and subtitle shadows?)
|
||||
[group-top-view])
|
||||
[view st/contacts-list
|
||||
[view st/contact-list-spacing]
|
||||
(doall
|
||||
(map (fn [contact]
|
||||
^{:key contact}
|
||||
|
@ -101,7 +103,9 @@
|
|||
[{:value #(dispatch [:hide-contact contact])
|
||||
:text (label :t/delete-contact)
|
||||
:style st/delete-contact-text}
|
||||
{:value #(dispatch [:remove-contact-from-group contact group])
|
||||
{:value #(dispatch [:remove-contact-from-group
|
||||
(:whisper-identity contact)
|
||||
(:group-id group)])
|
||||
:text (label :t/remove-from-group)}])}]
|
||||
(when-not (= contact (last contacts))
|
||||
[view st/contact-item-separator-wrapper
|
||||
|
@ -112,7 +116,10 @@
|
|||
[view st/contact-item-separator-wrapper
|
||||
[view st/contact-item-separator]]
|
||||
[view st/show-all
|
||||
[touchable-highlight (when-not edit? {:on-press #(dispatch [:navigate-to :group-contacts group])})
|
||||
[touchable-highlight {:on-press #(do
|
||||
(when edit?
|
||||
(dispatch [:set-in [:contact-list-ui-props :edit?] true]))
|
||||
(dispatch [:navigate-to :group-contacts group]))}
|
||||
[view
|
||||
[text {:style st/show-all-text
|
||||
:uppercase? (get-in platform-specific [:uppercase?])
|
||||
|
|
|
@ -26,8 +26,7 @@
|
|||
{:flex 1}))
|
||||
|
||||
(def contacts-list
|
||||
(merge (get-in p/platform-specific [:component-styles :contacts :contacts-list-container])
|
||||
{:background-color color-white}))
|
||||
{:background-color color-white})
|
||||
|
||||
(def empty-contact-groups
|
||||
(merge contact-groups
|
||||
|
@ -123,13 +122,8 @@
|
|||
(assoc option-inner-image
|
||||
:tint-color color-gray))
|
||||
|
||||
(def spacing-top
|
||||
{:background-color color-white
|
||||
:height 8})
|
||||
|
||||
(def spacing-bottom
|
||||
{:background-color color-white
|
||||
:height 8})
|
||||
(def contact-list-spacing
|
||||
(get-in p/platform-specific [:component-styles :contacts :contact-list-spacing]))
|
||||
|
||||
(def contact-inner-container
|
||||
(merge (get-in p/platform-specific [:component-styles :contacts :contact-inner-container])
|
||||
|
|
|
@ -40,6 +40,16 @@
|
|||
(get-in @db [:contact-groups group-id :contacts]))))]
|
||||
(reaction (filter-group-contacts @group-contacts @contacts)))))
|
||||
|
||||
(defn filter-not-group-contacts [group-contacts contacts]
|
||||
(remove #(group-contacts (:whisper-identity %)) contacts))
|
||||
|
||||
(register-sub :all-not-added-group-contacts
|
||||
(fn [db [_ group-id]]
|
||||
(let [contacts (subscribe [:all-added-contacts])
|
||||
group-contacts (reaction (into #{} (map #(:identity %)
|
||||
(get-in @db [:contact-groups group-id :contacts]))))]
|
||||
(reaction (filter-not-group-contacts @group-contacts @contacts)))))
|
||||
|
||||
(register-sub :all-added-group-contacts-with-limit
|
||||
(fn [db [_ group-id limit]]
|
||||
(let [contacts (subscribe [:all-added-group-contacts group-id])]
|
||||
|
@ -77,16 +87,30 @@
|
|||
text (str/lower-case text)]
|
||||
(not= (str/index-of name text) nil)))
|
||||
|
||||
(defn search-filter-reaction [contacts]
|
||||
(let [text (subscribe [:get-in [:toolbar-search :text]])]
|
||||
(reaction
|
||||
(if @text
|
||||
(filter #(search-filter @text %) @contacts)
|
||||
@contacts))))
|
||||
|
||||
(register-sub :all-added-group-contacts-filtered
|
||||
(fn [_ [_ group-id]]
|
||||
(let [contacts (if group-id
|
||||
(subscribe [:all-added-group-contacts group-id])
|
||||
(subscribe [:all-added-contacts]))
|
||||
text (subscribe [:get-in [:toolbar-search :text]])]
|
||||
(reaction
|
||||
(if @text
|
||||
(filter #(search-filter @text %) @contacts)
|
||||
@contacts)))))
|
||||
(subscribe [:all-added-contacts]))]
|
||||
(search-filter-reaction contacts))))
|
||||
|
||||
(register-sub :all-group-not-added-contacts-filtered
|
||||
(fn [db _]
|
||||
(let [contact-group-id (:contact-group-id @db)
|
||||
contacts (subscribe [:all-not-added-group-contacts contact-group-id])]
|
||||
(search-filter-reaction contacts))))
|
||||
|
||||
(register-sub :contacts-filtered
|
||||
(fn [db [_ subscription-id]]
|
||||
(let [contacts (subscribe [subscription-id])]
|
||||
(search-filter-reaction contacts))))
|
||||
|
||||
(register-sub :contacts-with-letters
|
||||
(fn [db _]
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
(defn new-group-chat-view []
|
||||
[view
|
||||
[touchable-highlight
|
||||
{:on-press #(dispatch [:navigate-to :new-group])}
|
||||
{:on-press #(dispatch [:open-contact-toggle-list :chat-group])}
|
||||
[view st/contact-container
|
||||
[view st/option-inner-container
|
||||
[view st/option-inner
|
||||
|
@ -53,7 +53,9 @@
|
|||
:extend-options (when group
|
||||
[{:value #(dispatch [:hide-contact row])
|
||||
:text (label :t/delete-contact)}
|
||||
{:value #(dispatch [:remove-contact-from-group row group])
|
||||
{:value #(dispatch [:remove-contact-from-group
|
||||
(:whisper-identity row)
|
||||
(:group-id group)])
|
||||
:text (label :t/remove-from-group)}])
|
||||
:on-click (when (and (not edit?) click-handler)
|
||||
#(click-handler row action params))}])))
|
||||
|
@ -70,6 +72,22 @@
|
|||
:number-of-lines 1}
|
||||
label]]]]])
|
||||
|
||||
(defn modal-view [action click-handler]
|
||||
[view
|
||||
[contact-list-entry {:click-handler #(do
|
||||
(dispatch [:send-to-webview-bridge
|
||||
{:event (name :webview-send-transaction)}])
|
||||
(dispatch [:navigate-back]))
|
||||
:icon :icon_enter_address
|
||||
:icon-style st/enter-address-icon
|
||||
:label (label :t/enter-address)}]
|
||||
[contact-list-entry {:click-handler #(click-handler :qr-scan action)
|
||||
:icon :icon_scan_q_r
|
||||
:icon-style st/scan-qr-icon
|
||||
:label (label (if (= :request action)
|
||||
:t/show-qr
|
||||
:t/scan-qr))}]])
|
||||
|
||||
(defview contact-list-toolbar-edit [group]
|
||||
[toolbar {:nav-action (act/back #(dispatch [:set-in [:contact-list-ui-props :edit?] false]))
|
||||
:actions [{:image :blank}]
|
||||
|
@ -96,8 +114,8 @@
|
|||
|
||||
(defn render-separator [_ row-id _]
|
||||
(list-item ^{:key row-id}
|
||||
[view st/contact-item-separator-wrapper
|
||||
[view st/contact-item-separator]]))
|
||||
[view st/contact-item-separator-wrapper
|
||||
[view st/contact-item-separator]]))
|
||||
|
||||
(defview contacts-list-view [group modal click-handler action edit?]
|
||||
[contacts [:all-added-group-contacts-filtered (:group-id group)]
|
||||
|
@ -112,9 +130,10 @@
|
|||
:keyboardShouldPersistTaps true
|
||||
:renderHeader #(list-item
|
||||
[view
|
||||
(when show-new-group-chat?
|
||||
[new-group-chat-view])])
|
||||
:renderFooter #(list-item [view st/spacing-bottom])
|
||||
(if show-new-group-chat?
|
||||
[new-group-chat-view]
|
||||
[view st/contact-list-spacing])])
|
||||
:renderFooter #(list-item [view st/contact-list-spacing])
|
||||
:renderSeparator render-separator
|
||||
:style st/contacts-list}])))
|
||||
|
||||
|
@ -123,7 +142,8 @@
|
|||
modal [:get :modal]
|
||||
edit? [:get-in [:contact-list-ui-props :edit?]]
|
||||
click-handler [:get :contacts-click-handler]
|
||||
group [:get :contacts-group]]
|
||||
group [:get :contacts-group]
|
||||
type [:get :group-type]]
|
||||
[drawer-view
|
||||
[view {:flex 1}
|
||||
[view
|
||||
|
@ -133,18 +153,5 @@
|
|||
[contact-list-toolbar group])]
|
||||
;; todo add stub
|
||||
(when modal
|
||||
[view
|
||||
[contact-list-entry {:click-handler #(do
|
||||
(dispatch [:send-to-webview-bridge
|
||||
{:event (name :webview-send-transaction)}])
|
||||
(dispatch [:navigate-back]))
|
||||
:icon :icon_enter_address
|
||||
:icon-style st/enter-address-icon
|
||||
:label (label :t/enter-address)}]
|
||||
[contact-list-entry {:click-handler #(click-handler :qr-scan action)
|
||||
:icon :icon_scan_q_r
|
||||
:icon-style st/scan-qr-icon
|
||||
:label (label (if (= :request action)
|
||||
:t/show-qr
|
||||
:t/scan-qr))}]])
|
||||
[modal-view action click-handler])
|
||||
[contacts-list-view group modal click-handler action edit?]]])
|
||||
|
|
|
@ -18,6 +18,15 @@
|
|||
[groups]
|
||||
(mapv save groups))
|
||||
|
||||
(defn save-property
|
||||
[group-id property-name value]
|
||||
(data-store/save-property group-id property-name value))
|
||||
|
||||
(defn delete
|
||||
[group-id]
|
||||
(data-store/delete group-id))
|
||||
|
||||
(defn add-contacts
|
||||
[group-id identities]
|
||||
(data-store/add-contacts group-id identities))
|
||||
|
||||
|
|
|
@ -16,6 +16,14 @@
|
|||
[group update?]
|
||||
(realm/save @realm/account-realm :contact-group group update?))
|
||||
|
||||
(defn save-property
|
||||
[group-id property-name value]
|
||||
(realm/write @realm/account-realm
|
||||
(fn []
|
||||
(-> @realm/account-realm
|
||||
(realm/get-one-by-field :contact-group :group-id group-id)
|
||||
(aset (name property-name) value)))))
|
||||
|
||||
(defn exists?
|
||||
[group-id]
|
||||
(realm/exists? @realm/account-realm :contact-group {:group-id group-id}))
|
||||
|
@ -23,4 +31,23 @@
|
|||
(defn delete
|
||||
[group-id]
|
||||
(when-let [group (realm/get-one-by-field @realm/account-realm :contact-group :group-id group-id)]
|
||||
(realm/delete @realm/account-realm group)))
|
||||
(realm/delete @realm/account-realm group)))
|
||||
|
||||
(defn get-contacts
|
||||
[group-id]
|
||||
(-> @realm/account-realm
|
||||
(realm/get-one-by-field :contact-group :group-id group-id)
|
||||
(aget "contacts")))
|
||||
|
||||
(defn- save-contacts
|
||||
[identities contacts]
|
||||
(doseq [contact-identity identities]
|
||||
(if-let [contact (.find contacts (fn [object _ _]
|
||||
(= contact-identity (aget object "identity"))))]
|
||||
(.push contacts (clj->js {:identity contact-identity})))))
|
||||
|
||||
(defn add-contacts
|
||||
[group-id identities]
|
||||
(let [contacts (get-contacts group-id)]
|
||||
(realm/write @realm/account-realm
|
||||
#(save-contacts identities contacts))))
|
|
@ -37,10 +37,11 @@
|
|||
(select-keys [:name :color]))]
|
||||
(assoc db :new-chat-name name
|
||||
:new-chat-color color
|
||||
:group-type :chat-group
|
||||
:group-settings {})))
|
||||
|
||||
(register-handler :show-group-settings
|
||||
(after (fn [_ _] (dispatch [:navigate-to :group-settings])))
|
||||
(after (fn [_ _] (dispatch [:navigate-to :chat-group-settings])))
|
||||
prepare-chat-settings)
|
||||
|
||||
(register-handler :set-chat-name
|
||||
|
|
|
@ -22,8 +22,14 @@
|
|||
[status-im.accounts.screen :refer [accounts]]
|
||||
[status-im.transactions.screen :refer [confirm]]
|
||||
[status-im.chats-list.screen :refer [chats-list]]
|
||||
[status-im.new-group.screen-private :refer [new-group contact-group]]
|
||||
[status-im.new-group.views.contact-list :refer [contact-group-list]]
|
||||
[status-im.new-group.screen-private :refer [new-group
|
||||
edit-group]]
|
||||
[status-im.new-group.views.chat-group-settings :refer [chat-group-settings]]
|
||||
[status-im.new-group.views.contact-list :refer [edit-group-contact-list
|
||||
edit-chat-group-contact-list]]
|
||||
[status-im.new-group.views.contact-toggle-list :refer [contact-toggle-list
|
||||
add-contacts-toggle-list
|
||||
add-participants-toggle-list]]
|
||||
[status-im.new-group.views.reorder-groups :refer [reorder-groups]]
|
||||
[status-im.new-group.screen-public :refer [new-public-group]]
|
||||
[status-im.participants.views.add :refer [new-participants]]
|
||||
|
@ -89,14 +95,19 @@
|
|||
:remove-participants remove-participants
|
||||
:chat-list main-tabs
|
||||
:new-group new-group
|
||||
:edit-group edit-group
|
||||
:chat-group-settings chat-group-settings
|
||||
:edit-group-contact-list edit-group-contact-list
|
||||
:edit-chat-group-contact-list edit-chat-group-contact-list
|
||||
:add-contacts-toggle-list add-contacts-toggle-list
|
||||
:add-participants-toggle-list add-participants-toggle-list
|
||||
:reorder-groups reorder-groups
|
||||
:new-public-group new-public-group
|
||||
:group-settings group-settings
|
||||
:contact-list main-tabs
|
||||
:contact-toggle-list contact-toggle-list
|
||||
:contact-list-search-results contacts-search-results
|
||||
:group-contacts contact-list
|
||||
:reorder-groups reorder-groups
|
||||
:contact-group contact-group
|
||||
:contact-group-list contact-group-list
|
||||
:new-contact new-contact
|
||||
:qr-scanner qr-scanner
|
||||
:chat chat
|
||||
|
|
|
@ -89,13 +89,22 @@
|
|||
:letter-spacing -0.2
|
||||
:font-size 17
|
||||
:line-height 20}
|
||||
:delete-group-text {:letter-spacing -0.2
|
||||
:font-size 17
|
||||
:line-height 20}
|
||||
:delete-group-prompt-text {:font-size 13
|
||||
:letter-spacing -0.1}
|
||||
:contact-container {:height 63}
|
||||
:delete-group-container {:padding-left 68}}
|
||||
:settings-group-text {:color styles/color-light-blue
|
||||
:letter-spacing -0.2
|
||||
:font-size 17
|
||||
:line-height 20}
|
||||
:settings-group-item {:padding-left 16
|
||||
:height 64
|
||||
:flex-direction :row
|
||||
:align-items :center}
|
||||
:settings-group-container {:margin-top 25}
|
||||
:settings-icon-container {:background-color "#628fe333"
|
||||
:border-radius 50}
|
||||
:delete-group-prompt-text {:font-size 14
|
||||
:letter-spacing -0.2}
|
||||
:delete-icon-container {:background-color "#d84b4b33"
|
||||
:border-radius 50}}
|
||||
:reorder-groups {:order-item-separator {:margin-left 16
|
||||
:opacity 0.5}
|
||||
:order-item-container {:height 63}
|
||||
|
@ -163,7 +172,6 @@
|
|||
:discover {:uppercase-subtitles? true}
|
||||
:public-group-icon-container {:margin-top 2}
|
||||
:private-group-icon-container {:margin-top 2}
|
||||
:group-chat-focus-line-color styles/color-gray5
|
||||
:group-chat-focus-line-height 1
|
||||
:public-group-chat-hash-style {:top 6 :left 3}})
|
||||
|
||||
|
|
|
@ -13,6 +13,24 @@
|
|||
[taoensso.timbre :as log]
|
||||
[status-im.navigation.handlers :as nav]))
|
||||
|
||||
(defn clear-toolbar-search [db]
|
||||
(-> db
|
||||
(assoc-in [:toolbar-search :show] nil)
|
||||
(assoc-in [:toolbar-search :text] "")))
|
||||
|
||||
(defmethod nav/preload-data! :add-contacts-toggle-list
|
||||
[db _]
|
||||
(->
|
||||
(assoc db :selected-contacts #{})
|
||||
(clear-toolbar-search)))
|
||||
|
||||
|
||||
(defmethod nav/preload-data! :add-participants-toggle-list
|
||||
[db _]
|
||||
(->
|
||||
(assoc db :selected-participants #{})
|
||||
(clear-toolbar-search)))
|
||||
|
||||
(defn deselect-contact
|
||||
[db [_ id]]
|
||||
(update db :selected-contacts disj id))
|
||||
|
@ -199,20 +217,6 @@
|
|||
((after create-group!))
|
||||
((after show-contact-list!))))
|
||||
|
||||
(defn prepare-group-after-edit
|
||||
[{:keys [selected-contacts] :as db} [_ group group-name]]
|
||||
(let [contacts (mapv #(hash-map :identity %) selected-contacts)
|
||||
group' (assoc group :name group-name
|
||||
:contacts contacts)]
|
||||
(assoc db :new-group group')))
|
||||
|
||||
(register-handler
|
||||
:update-group-after-edit
|
||||
(-> prepare-group-after-edit
|
||||
((enrich update-group))
|
||||
((after update-group!))
|
||||
((after show-contact-list!))))
|
||||
|
||||
(register-handler
|
||||
:update-group
|
||||
(-> (fn [db [_ new-group]]
|
||||
|
@ -289,3 +293,52 @@
|
|||
(map-indexed vector (reverse groups-order)))]
|
||||
(dispatch [:update-groups new-groups])
|
||||
(dispatch [:navigate-to-clean :contact-list])))))
|
||||
|
||||
(defn save-property!
|
||||
[contact-group-id property-name value]
|
||||
(groups/save-property contact-group-id property-name value))
|
||||
|
||||
(defn save-group-property!
|
||||
[db-name property-name]
|
||||
(fn [{:keys [contact-group-id] :as db} _]
|
||||
(let [property (db-name db)]
|
||||
(save-property! contact-group-id property-name property))))
|
||||
|
||||
(defn update-group-property
|
||||
[db-name property-name]
|
||||
(fn [{:keys [contact-group-id] :as db} _]
|
||||
(let [property (db-name db)]
|
||||
(assoc-in db [:contact-groups contact-group-id property-name] property))))
|
||||
|
||||
(register-handler :set-group-name
|
||||
(after (save-group-property! :new-chat-name :name))
|
||||
(update-group-property :new-chat-name :name))
|
||||
|
||||
(defn add-selected-contacts-to-group
|
||||
[{:keys [selected-contacts contact-groups contact-group-id] :as db} _]
|
||||
(let [new-identities (mapv #(hash-map :identity %) selected-contacts)]
|
||||
(update db [:contact-groups contact-group-id :contacts] concat new-identities)))
|
||||
|
||||
(defn add-selected-contacts-to-group!
|
||||
[{:keys [contact-group-id selected-contacts]} _]
|
||||
(groups/add-contacts contact-group-id selected-contacts))
|
||||
|
||||
(register-handler
|
||||
:add-selected-contacts-to-group
|
||||
(-> add-selected-contacts-to-group
|
||||
((after add-selected-contacts-to-group!))))
|
||||
|
||||
(defn delete-group []
|
||||
(fn [{:keys [contact-group-id] :as db} _]
|
||||
(assoc-in db [:contact-groups contact-group-id :pending?] true)))
|
||||
|
||||
(defn delete-group! []
|
||||
(fn [{:keys [contact-group-id]} _]
|
||||
(save-property! contact-group-id :pending? true)))
|
||||
|
||||
(register-handler :delete-group
|
||||
(after (delete-group!))
|
||||
(delete-group))
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -1,147 +1,100 @@
|
|||
(ns status-im.new-group.screen-private
|
||||
(:require-macros [status-im.utils.views :refer [defview]])
|
||||
(:require [re-frame.core :refer [subscribe dispatch]]
|
||||
[status-im.resources :as res]
|
||||
(:require [re-frame.core :refer [dispatch]]
|
||||
[status-im.contacts.views.contact :refer [contact-view]]
|
||||
[status-im.contacts.styles :as cst]
|
||||
[status-im.components.react :refer [view
|
||||
text
|
||||
image
|
||||
icon
|
||||
touchable-highlight
|
||||
scroll-view
|
||||
list-view
|
||||
list-item]]
|
||||
[status-im.components.text-field.view :refer [text-field]]
|
||||
[status-im.components.confirm-button :refer [confirm-button]]
|
||||
[status-im.components.styles :refer [color-blue color-gray5]]
|
||||
[status-im.components.status-bar :refer [status-bar]]
|
||||
[status-im.components.toolbar-new.view :refer [toolbar]]
|
||||
[status-im.utils.platform :refer [platform-specific]]
|
||||
[status-im.utils.listview :refer [to-datasource]]
|
||||
[status-im.new-group.views.contact :refer [new-group-contact]]
|
||||
[status-im.new-group.styles :as st]
|
||||
[status-im.new-group.views.group :refer [group-toolbar
|
||||
group-chat-settings-btns
|
||||
group-name-view
|
||||
add-btn
|
||||
more-btn
|
||||
delete-btn
|
||||
separator]]
|
||||
[status-im.new-group.validations :as v]
|
||||
[status-im.i18n :refer [label]]
|
||||
[cljs.spec :as s]))
|
||||
|
||||
(defview new-chat-group-toolbar []
|
||||
[new-chat-name [:get :new-chat-name]]
|
||||
(let [create-btn-enabled? (s/valid? ::v/name new-chat-name)]
|
||||
[view
|
||||
[status-bar]
|
||||
[toolbar
|
||||
{:title (label :t/new-group-chat)
|
||||
:actions [{:image {:source res/v ;; {:uri "icon_search"}
|
||||
:style (st/toolbar-icon create-btn-enabled?)}
|
||||
:handler (when create-btn-enabled?
|
||||
#(dispatch [:create-new-group-chat new-chat-name]))}]}]]))
|
||||
(def contacts-limit 3)
|
||||
|
||||
(defview group-name-input []
|
||||
[new-chat-name [:get :new-chat-name]]
|
||||
(defview group-contacts-view [group]
|
||||
[contacts [:all-added-group-contacts-with-limit (:group-id group) contacts-limit]
|
||||
contacts-count [:all-added-group-contacts-count (:group-id group)]]
|
||||
[view
|
||||
[text-field
|
||||
{:error (when
|
||||
(not (s/valid? ::v/not-illegal-name new-chat-name))
|
||||
(label :t/illegal-group-chat-name))
|
||||
:error-color color-blue
|
||||
:wrapper-style st/group-chat-name-wrapper
|
||||
:line-color color-gray5
|
||||
:focus-line-color st/group-chat-focus-line-color
|
||||
:focus-line-height st/group-chat-focus-line-height
|
||||
:label-hidden? true
|
||||
:input-style st/group-chat-name-input
|
||||
:auto-focus true
|
||||
:on-change-text #(dispatch [:set :new-chat-name %])
|
||||
:value new-chat-name}]])
|
||||
(when (pos? contacts-count)
|
||||
[separator])
|
||||
[view
|
||||
(doall
|
||||
(map (fn [row]
|
||||
^{:key row}
|
||||
[view
|
||||
[contact-view
|
||||
{:contact row
|
||||
:extend-options [{:value #(dispatch [:remove-contact-from-group
|
||||
(:whisper-identity row)
|
||||
(:group-id group)])
|
||||
:text (label :t/remove-from-group)}]
|
||||
:extended? true}]
|
||||
(when-not (= row (last contacts))
|
||||
[separator])])
|
||||
contacts))]
|
||||
(when (< contacts-limit contacts-count)
|
||||
[more-btn contacts-limit contacts-count #(dispatch [:navigate-to :edit-group-contact-list])])])
|
||||
|
||||
(defview new-group []
|
||||
[contacts [:all-added-contacts]]
|
||||
[view st/new-group-container
|
||||
[new-chat-group-toolbar]
|
||||
[view st/chat-name-container
|
||||
[text {:style st/members-text
|
||||
:font :medium}
|
||||
(label :t/group-chat-name)]
|
||||
[group-name-input]
|
||||
[text {:style st/members-text
|
||||
:font :medium}
|
||||
(label :t/members-title)]
|
||||
#_[touchable-highlight {:on-press (fn [])}
|
||||
[view st/add-container
|
||||
[icon :add_gray st/add-icon]
|
||||
[text {:style st/add-text} (label :t/add-members)]]]
|
||||
[list-view
|
||||
{:dataSource (to-datasource contacts)
|
||||
:renderRow (fn [row _ _]
|
||||
(list-item [new-group-contact row]))}]]])
|
||||
(defn save []
|
||||
(dispatch [:set-group-name]))
|
||||
|
||||
(defview new-contacts-group-toolbar [edit?]
|
||||
[view
|
||||
[status-bar]
|
||||
[toolbar
|
||||
{:title (label (if edit? :t/edit-group :t/new-group))
|
||||
:actions [{:image :blank}]}]])
|
||||
|
||||
(defn chat-name-view [contacts-count]
|
||||
[view st/chat-name-container
|
||||
[text {:style st/group-name-text}
|
||||
(label :t/group-name)]
|
||||
[group-name-input]
|
||||
[view st/members-container
|
||||
[text {:style st/members-text
|
||||
:font :medium}
|
||||
(label :t/group-members)]
|
||||
[text {:style st/members-text-count
|
||||
:font :medium}
|
||||
contacts-count]]
|
||||
[touchable-highlight {:on-press #(dispatch [:navigate-forget :contact-group-list])}
|
||||
[view st/add-container
|
||||
[view st/add-icon-container
|
||||
[icon :add_blue st/add-icon]]
|
||||
[text {:style st/add-text
|
||||
:font :medium
|
||||
:uppercase? (get-in platform-specific [:uppercase?])}
|
||||
(label :t/add-members)]]]])
|
||||
|
||||
(defn delete-btn [on-press]
|
||||
[touchable-highlight {:on-press on-press}
|
||||
[view st/delete-group-container
|
||||
[text {:style st/delete-group-text
|
||||
:font :medium
|
||||
:uppercase? (get-in platform-specific [:uppercase?])}
|
||||
(label :t/delete-group)]
|
||||
[text {:style st/delete-group-prompt-text} (label :t/delete-group-prompt)]]])
|
||||
(defview edit-group []
|
||||
[group-name [:get :new-chat-name]
|
||||
group [:get-contact-group]
|
||||
type [:get :group-type]]
|
||||
(let [save-btn-enabled? (and (s/valid? ::v/name group-name)
|
||||
(not= group-name (:name group)))]
|
||||
[view st/group-container
|
||||
[group-toolbar type true]
|
||||
[group-name-view]
|
||||
[add-btn #(dispatch [:navigate-to :add-contacts-toggle-list])]
|
||||
[group-contacts-view group]
|
||||
[view st/separator]
|
||||
[delete-btn #(do
|
||||
(dispatch [:delete-group])
|
||||
(dispatch [:navigate-to-clean :contact-list]))]
|
||||
[view {:flex 1}]
|
||||
(when save-btn-enabled?
|
||||
[confirm-button (label :t/save) save])]))
|
||||
|
||||
(defn render-separator [_ row-id _]
|
||||
(list-item ^{:key row-id}
|
||||
[view cst/contact-item-separator-wrapper
|
||||
[view cst/contact-item-separator]]))
|
||||
[separator]))
|
||||
|
||||
;;TODO: should be refactored into one common function for group chats and contact groups
|
||||
(defview contact-group []
|
||||
(defn render-row [row _ _]
|
||||
(list-item
|
||||
^{:key row}
|
||||
[contact-view {:contact row
|
||||
:on-click #()}]))
|
||||
|
||||
(defview new-group []
|
||||
[contacts [:selected-group-contacts]
|
||||
group-name [:get :new-chat-name]
|
||||
group [:get :contact-group]]
|
||||
group-type [:get :group-type]]
|
||||
(let [save-btn-enabled? (and (s/valid? ::v/name group-name) (pos? (count contacts)))]
|
||||
[view st/new-group-container
|
||||
[new-contacts-group-toolbar (boolean group)]
|
||||
[chat-name-view (count contacts)]
|
||||
[list-view
|
||||
{:dataSource (to-datasource contacts)
|
||||
:renderRow (fn [row _ _]
|
||||
(list-item
|
||||
^{:key row}
|
||||
[contact-view
|
||||
{:contact row
|
||||
:extend-options [{:value #(dispatch [:deselect-contact (:whisper-identity row)])
|
||||
:text (label :t/remove-from-group)}]
|
||||
:extended? true}]))
|
||||
:renderSeparator render-separator}]
|
||||
(when group
|
||||
[delete-btn #(do
|
||||
(dispatch [:update-group (assoc group :pending? true)])
|
||||
(dispatch [:navigate-to-clean :contact-list]))])
|
||||
[view st/group-container
|
||||
[group-toolbar group-type false]
|
||||
[group-name-view]
|
||||
[view {:flex 1}
|
||||
[list-view {:dataSource (to-datasource contacts)
|
||||
:enableEmptySections true
|
||||
:renderRow render-row
|
||||
:bounces false
|
||||
:keyboardShouldPersistTaps true
|
||||
:renderSeparator render-separator}]]
|
||||
(when save-btn-enabled?
|
||||
[confirm-button (label :t/save) (if group
|
||||
#(dispatch [:update-group-after-edit group group-name])
|
||||
#(dispatch [:create-new-group group-name]))])]))
|
||||
[confirm-button (label :t/save)
|
||||
(if (= group-type :contact-group)
|
||||
#(dispatch [:create-new-group group-name])
|
||||
#(dispatch [:create-new-group-chat group-name]))])]))
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
[status-im.components.status-bar :refer [status-bar]]
|
||||
[status-im.components.toolbar.view :refer [toolbar]]
|
||||
[status-im.utils.listview :refer [to-datasource]]
|
||||
[status-im.new-group.views.contact :refer [new-group-contact]]
|
||||
[status-im.new-group.styles :as st]
|
||||
[status-im.new-group.validations :as v]
|
||||
[status-im.i18n :refer [label]]
|
||||
|
@ -56,7 +55,7 @@
|
|||
[text {:style st/topic-hash} "#"]])
|
||||
|
||||
(defn new-public-group []
|
||||
[view st/new-group-container
|
||||
[view st/group-container
|
||||
[new-group-toolbar]
|
||||
[view st/chat-name-container
|
||||
[text {:style st/members-text
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
:height 18
|
||||
:opacity (if enabled? 1 0.3)})
|
||||
|
||||
(def new-group-container
|
||||
(def group-container
|
||||
{:flex 1
|
||||
:flex-direction :column
|
||||
:background-color color-white})
|
||||
|
@ -40,8 +40,12 @@
|
|||
{:margin-top 21
|
||||
:margin-left 16})
|
||||
|
||||
(def add-button-container
|
||||
{:margin-left 16})
|
||||
|
||||
(def group-chat-name-input
|
||||
{:font-size 17
|
||||
:padding-bottom 0
|
||||
:letter-spacing -0.2
|
||||
:color text1-color})
|
||||
|
||||
|
@ -57,9 +61,6 @@
|
|||
:position :absolute}
|
||||
(get-in platform-specific [:public-group-chat-hash-style])))
|
||||
|
||||
(def group-chat-focus-line-color
|
||||
(get-in platform-specific [:group-chat-focus-line-color]))
|
||||
|
||||
(def group-chat-focus-line-height
|
||||
(get-in platform-specific [:group-chat-focus-line-height]))
|
||||
|
||||
|
@ -93,27 +94,36 @@
|
|||
:height 64
|
||||
:margin-top 12})
|
||||
|
||||
(def add-icon-container
|
||||
{:width 40
|
||||
:align-items :center
|
||||
:justify-content :center})
|
||||
(def settings-icon-container
|
||||
(merge (ps-new-group :settings-icon-container)
|
||||
{:width 40
|
||||
:height 40
|
||||
:align-items :center
|
||||
:justify-content :center}))
|
||||
|
||||
(def add-icon
|
||||
{:align-items :center
|
||||
:width 24
|
||||
:height 24})
|
||||
|
||||
(def add-text
|
||||
(merge (ps-new-group :add-text)
|
||||
(def add-group-text
|
||||
(merge (ps-new-group :settings-group-text)
|
||||
{:color color-light-blue}))
|
||||
|
||||
(def settings-group-text
|
||||
(merge (ps-new-group :settings-group-text)))
|
||||
|
||||
(def settings-group-text-container
|
||||
{:padding-left 16})
|
||||
|
||||
(def delete-group-text
|
||||
(merge (ps-new-group :delete-group-text)
|
||||
(merge (ps-new-group :settings-group-text)
|
||||
{:color color-light-red}))
|
||||
|
||||
(def delete-group-prompt-text
|
||||
(merge (ps-new-group :delete-group-prompt-text)
|
||||
{:color color-gray4}))
|
||||
{:color color-gray4
|
||||
:padding-top 5}))
|
||||
|
||||
(def contact-container
|
||||
(merge (ps-new-group :contact-container)
|
||||
|
@ -139,10 +149,18 @@
|
|||
{:width 12
|
||||
:height 12})
|
||||
|
||||
(def delete-group-container
|
||||
(merge (ps-new-group :delete-group-container)
|
||||
{:height 64
|
||||
:padding-top 12}))
|
||||
(def settings-group-container
|
||||
(ps-new-group :settings-group-container))
|
||||
|
||||
(def settings-group-item
|
||||
(ps-new-group :settings-group-item))
|
||||
|
||||
(def delete-icon-container
|
||||
(merge (ps-new-group :delete-icon-container)
|
||||
{:width 40
|
||||
:height 40
|
||||
:align-items :center
|
||||
:justify-content :center}))
|
||||
|
||||
(def order-item-container
|
||||
{:background-color color-white})
|
||||
|
@ -178,7 +196,7 @@
|
|||
|
||||
(def toolbar-title-with-count-text-count
|
||||
(merge toolbar-title-with-count-text
|
||||
{:color "#628fe3"}))
|
||||
{:color color-light-blue}))
|
||||
|
||||
(def toolbar-title-with-count
|
||||
{:flex-direction :row})
|
||||
|
@ -186,6 +204,11 @@
|
|||
(def toolbar-title-with-count-container
|
||||
{:padding-left 6})
|
||||
|
||||
(def separator
|
||||
{:background-color color-gray5
|
||||
:height 1
|
||||
:opacity 0.5})
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -6,10 +6,20 @@
|
|||
(register-sub :is-contact-selected?
|
||||
(u/contains-sub :selected-contacts))
|
||||
|
||||
(defn filter-selected-contacts [selected-contacts contacts]
|
||||
(remove #(true? (:pending? (contacts %))) selected-contacts))
|
||||
|
||||
(register-sub :selected-contacts-count
|
||||
(fn [_ _]
|
||||
(let [contacts (subscribe [:get :selected-contacts])]
|
||||
(reaction (count @contacts)))))
|
||||
(let [selected-contacts (subscribe [:get :selected-contacts])
|
||||
contacts (subscribe [:get :contacts])]
|
||||
;TODO temporary, contact should be deleted from group after contact deletion from contacts
|
||||
(reaction (count (filter-selected-contacts @selected-contacts @contacts))))))
|
||||
|
||||
(register-sub :selected-participants-count
|
||||
(fn [_ _]
|
||||
(let [selected-participants (subscribe [:get :selected-participants])]
|
||||
(reaction (count @selected-participants)))))
|
||||
|
||||
(defn filter-contacts [selected-contacts added-contacts]
|
||||
(filter #(selected-contacts (:whisper-identity %)) added-contacts))
|
||||
|
@ -19,3 +29,9 @@
|
|||
(let [selected-contacts (subscribe [:get :selected-contacts])
|
||||
added-contacts (subscribe [:all-added-contacts])]
|
||||
(reaction (filter-contacts @selected-contacts @added-contacts)))))
|
||||
|
||||
(register-sub :get-contact-group
|
||||
(fn [db _]
|
||||
(let [contact-groups (reaction (:contact-groups @db))
|
||||
contact-group-id (reaction (:contact-group-id @db))]
|
||||
(reaction (@contact-groups @contact-group-id)))))
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
(ns status-im.new-group.views.chat-group-settings
|
||||
(:require-macros [status-im.utils.views :refer [defview]])
|
||||
(:require [re-frame.core :refer [dispatch]]
|
||||
[status-im.contacts.views.contact :refer [contact-view]]
|
||||
[status-im.components.react :refer [view
|
||||
scroll-view
|
||||
icon
|
||||
touchable-highlight]]
|
||||
[status-im.components.confirm-button :refer [confirm-button]]
|
||||
[status-im.new-group.styles :as st]
|
||||
[status-im.new-group.views.group :refer [group-toolbar
|
||||
group-chat-settings-btns
|
||||
group-name-view
|
||||
add-btn
|
||||
more-btn
|
||||
delete-btn
|
||||
separator]]
|
||||
[status-im.new-group.validations :as v]
|
||||
[status-im.i18n :refer [label]]
|
||||
[cljs.spec :as s]))
|
||||
|
||||
(def contacts-limit 3)
|
||||
|
||||
(defn save-chat-name []
|
||||
(dispatch [:set-chat-name]))
|
||||
|
||||
(defview chat-group-contacts-view [admin?]
|
||||
[contacts [:current-chat-contacts]]
|
||||
(let [limited-contacts (take contacts-limit contacts)
|
||||
contacts-count (count contacts)]
|
||||
[view
|
||||
(when (and admin? (pos? contacts-count))
|
||||
[separator])
|
||||
[view
|
||||
(doall
|
||||
(map (fn [row]
|
||||
^{:key row}
|
||||
[view
|
||||
[contact-view
|
||||
{:contact row
|
||||
:on-click #()
|
||||
:extend-options [{:value #(do
|
||||
(dispatch [:set :selected-participants #{(:whisper-identity row)}])
|
||||
(dispatch [:remove-participants]))
|
||||
:text (label :t/remove)}]
|
||||
:extended? admin?}]
|
||||
(when-not (= row (last limited-contacts))
|
||||
[separator])])
|
||||
limited-contacts))]
|
||||
(when (< contacts-limit contacts-count)
|
||||
[more-btn contacts-limit contacts-count #(dispatch [:navigate-to :edit-chat-group-contact-list])])]))
|
||||
|
||||
(defview chat-group-members []
|
||||
[current-pk [:get :current-public-key]
|
||||
group-admin [:chat :group-admin]]
|
||||
(let [admin? (= current-pk group-admin)]
|
||||
[view
|
||||
(when admin?
|
||||
[add-btn #(dispatch [:navigate-to :add-participants-toggle-list])])
|
||||
[chat-group-contacts-view admin?]]))
|
||||
|
||||
(defview chat-group-settings []
|
||||
[new-chat-name [:get :new-chat-name]
|
||||
chat-name [:chat :name]
|
||||
type [:get :group-type]]
|
||||
(let [save-btn-enabled? (and (s/valid? ::v/name new-chat-name)
|
||||
(not= new-chat-name chat-name))]
|
||||
[view st/group-container
|
||||
[view {:flex 1}
|
||||
[group-toolbar type true]
|
||||
[scroll-view {:keyboardShouldPersistTaps true}
|
||||
[group-name-view]
|
||||
[chat-group-members]
|
||||
[view st/separator]
|
||||
[group-chat-settings-btns]]]
|
||||
(when save-btn-enabled?
|
||||
[confirm-button (label :t/save) save-chat-name])]))
|
|
@ -1,27 +0,0 @@
|
|||
(ns status-im.new-group.views.contact
|
||||
(:require-macros [status-im.utils.views :refer [defview]])
|
||||
(:require [re-frame.core :refer [subscribe dispatch dispatch-sync]]
|
||||
[status-im.components.react :refer [view icon touchable-highlight]]
|
||||
[status-im.contacts.views.contact-inner :refer [contact-inner-view]]
|
||||
[status-im.new-group.styles :as st]
|
||||
[status-im.contacts.styles :as cst]
|
||||
[status-im.components.styles :refer [color-light-blue color-gray5]]
|
||||
[status-im.utils.platform :refer [platform-specific]]))
|
||||
|
||||
(defn on-toggle [checked? whisper-identity]
|
||||
(let [action (if checked? :deselect-contact :select-contact)]
|
||||
(dispatch [action whisper-identity])))
|
||||
|
||||
;;TODO: maybe it's better to have only one global component contact-view (with the types: default, extended and toggle)
|
||||
(defview new-group-contact [{:keys [whisper-identity] :as contact}]
|
||||
[checked [:is-contact-selected? whisper-identity]]
|
||||
[touchable-highlight {:on-press #(on-toggle checked whisper-identity)}
|
||||
[view
|
||||
[view (merge st/contact-container (when checked {:style st/selected-contact}))
|
||||
[contact-inner-view (merge {:contact contact}
|
||||
(when checked {:style st/selected-contact}))]
|
||||
[view st/toggle-container
|
||||
[view (merge st/icon-check-container
|
||||
{:background-color (if checked color-light-blue color-gray5)})
|
||||
(when checked
|
||||
[icon :check_on st/check-icon])]]]]])
|
|
@ -1,6 +1,7 @@
|
|||
(ns status-im.new-group.views.contact-list
|
||||
(:require-macros [status-im.utils.views :refer [defview]])
|
||||
(:require [re-frame.core :refer [dispatch]]
|
||||
[status-im.contacts.views.contact :refer [contact-view]]
|
||||
[status-im.components.react :refer [view
|
||||
text
|
||||
list-view
|
||||
|
@ -9,50 +10,92 @@
|
|||
[status-im.components.status-bar :refer [status-bar]]
|
||||
[status-im.components.toolbar-new.view :refer [toolbar-with-search]]
|
||||
[status-im.utils.listview :refer [to-datasource]]
|
||||
[status-im.new-group.views.contact :refer [new-group-contact]]
|
||||
[status-im.new-group.views.group :refer [separator]]
|
||||
[status-im.new-group.styles :as st]
|
||||
[status-im.contacts.styles :as cst]
|
||||
[status-im.i18n :refer [label]]))
|
||||
[status-im.i18n :refer [label]]
|
||||
[status-im.components.toolbar-new.actions :as act]))
|
||||
|
||||
(defn title-with-count [title count-value]
|
||||
[view st/toolbar-title-with-count
|
||||
[text {:style st/toolbar-title-with-count-text
|
||||
:font :toolbar-title}
|
||||
title]
|
||||
(when (pos? count-value)
|
||||
[view st/toolbar-title-with-count-container
|
||||
[text {:style st/toolbar-title-with-count-text-count
|
||||
:font :toolbar-title}
|
||||
count-value]])])
|
||||
|
||||
(defn contact-list-toolbar [contacts-count show-search? search-text]
|
||||
(defview contact-list-toolbar [title]
|
||||
[show-search [:get-in [:toolbar-search :show]]
|
||||
search-text [:get-in [:toolbar-search :text]]]
|
||||
(toolbar-with-search
|
||||
{:show-search? (= show-search? :contact-group-list)
|
||||
{:show-search? (= show-search :contact-list)
|
||||
:search-text search-text
|
||||
:search-key :contact-group-list
|
||||
:custom-title (title-with-count (label :t/new-group) contacts-count)
|
||||
:search-key :contact-list
|
||||
:title title
|
||||
:search-placeholder (label :t/search-contacts)}))
|
||||
|
||||
(defn render-separator [_ row-id _]
|
||||
(list-item ^{:key row-id}
|
||||
[view cst/contact-item-separator-wrapper
|
||||
[view cst/contact-item-separator]]))
|
||||
[separator]))
|
||||
|
||||
(defview contact-group-list []
|
||||
[contacts [:all-added-group-contacts-filtered]
|
||||
selected-contacts-count [:selected-contacts-count]
|
||||
show-search [:get-in [:toolbar-search :show]]
|
||||
search-text [:get-in [:toolbar-search :text]]]
|
||||
[view st/new-group-container
|
||||
(defn render-spacing []
|
||||
#(list-item [view cst/contact-list-spacing]))
|
||||
|
||||
(defn render-row [group]
|
||||
(fn [row _ _]
|
||||
(list-item
|
||||
^{:key row}
|
||||
[contact-view {:contact row
|
||||
:extended? true
|
||||
:extend-options (when group
|
||||
[{:value #(dispatch [:remove-contact-from-group
|
||||
(:whisper-identity row)
|
||||
(:group-id group)])
|
||||
:text (label :t/remove-from-group)}])
|
||||
:on-click nil}])))
|
||||
|
||||
(defview contacts-list-view [group]
|
||||
[contacts [:all-added-group-contacts-filtered (:group-id group)]]
|
||||
[view {:flex 1}
|
||||
[list-view {:dataSource (to-datasource contacts)
|
||||
:enableEmptySections true
|
||||
:renderRow (render-row group)
|
||||
:bounces false
|
||||
:keyboardShouldPersistTaps true
|
||||
:renderSeparator render-separator
|
||||
:renderFooter (render-spacing)
|
||||
:renderHeader (render-spacing)}]])
|
||||
|
||||
(defview edit-group-contact-list []
|
||||
[group [:get-contact-group]
|
||||
type [:get :group-type]]
|
||||
[view st/group-container
|
||||
[status-bar]
|
||||
[contact-list-toolbar selected-contacts-count show-search search-text]
|
||||
[view {:flex 1}
|
||||
[list-view
|
||||
{:dataSource (to-datasource contacts)
|
||||
:renderRow (fn [row _ _]
|
||||
(list-item ^{:key row} [new-group-contact row]))
|
||||
:renderSeparator render-separator
|
||||
:style cst/contacts-list
|
||||
:keyboardShouldPersistTaps true}]]
|
||||
(when (pos? selected-contacts-count)
|
||||
[confirm-button (label :t/next) #(dispatch [:navigation-replace :contact-group])])])
|
||||
[contact-list-toolbar (:name group)]
|
||||
[contacts-list-view group]])
|
||||
|
||||
(defn render-chat-row [admin?]
|
||||
(fn [row _ _]
|
||||
(list-item
|
||||
^{:key row}
|
||||
[contact-view {:contact row
|
||||
:extended? admin?
|
||||
:extend-options [{:value #(do
|
||||
(dispatch [:set :selected-participants #{(:whisper-identity row)}])
|
||||
(dispatch [:remove-participants]))
|
||||
:text (label :t/remove)}]
|
||||
:on-click #()}])))
|
||||
|
||||
(defview chat-contacts-list-view []
|
||||
[contacts [:contacts-filtered :current-chat-contacts]
|
||||
current-pk [:get :current-public-key]
|
||||
group-admin [:chat :group-admin]]
|
||||
(let [admin? (= current-pk group-admin)]
|
||||
[view {:flex 1}
|
||||
[list-view {:dataSource (to-datasource contacts)
|
||||
:enableEmptySections true
|
||||
:renderRow (render-chat-row admin?)
|
||||
:bounces false
|
||||
:keyboardShouldPersistTaps true
|
||||
:renderSeparator render-separator
|
||||
:renderFooter (render-spacing)
|
||||
:renderHeader (render-spacing)}]]))
|
||||
|
||||
(defview edit-chat-group-contact-list []
|
||||
[chat-name [:chat :name]]
|
||||
[view st/group-container
|
||||
[status-bar]
|
||||
[contact-list-toolbar chat-name]
|
||||
[chat-contacts-list-view]])
|
|
@ -0,0 +1,117 @@
|
|||
(ns status-im.new-group.views.contact-toggle-list
|
||||
(:require-macros [status-im.utils.views :refer [defview]])
|
||||
(:require [re-frame.core :refer [dispatch]]
|
||||
[status-im.contacts.views.contact :refer [contact-view]]
|
||||
[status-im.components.react :refer [view
|
||||
text
|
||||
list-view
|
||||
list-item]]
|
||||
[status-im.components.confirm-button :refer [confirm-button]]
|
||||
[status-im.components.status-bar :refer [status-bar]]
|
||||
[status-im.components.toolbar-new.view :refer [toolbar-with-search]]
|
||||
[status-im.utils.listview :refer [to-datasource]]
|
||||
[status-im.new-group.views.toggle-contact :refer [group-toggle-contact
|
||||
group-toggle-participant]]
|
||||
[status-im.new-group.views.group :refer [separator]]
|
||||
[status-im.new-group.styles :as st]
|
||||
[status-im.contacts.styles :as cst]
|
||||
[status-im.i18n :refer [label]]
|
||||
[status-im.components.toolbar-new.actions :as act]))
|
||||
|
||||
(defn title-with-count [title count-value]
|
||||
[view st/toolbar-title-with-count
|
||||
[text {:style st/toolbar-title-with-count-text
|
||||
:font :toolbar-title}
|
||||
title]
|
||||
(when (pos? count-value)
|
||||
[view st/toolbar-title-with-count-container
|
||||
[text {:style st/toolbar-title-with-count-text-count
|
||||
:font :toolbar-title}
|
||||
count-value]])])
|
||||
|
||||
(defview toggle-list-toolbar [title contacts-count]
|
||||
[show-search [:get-in [:toolbar-search :show]]
|
||||
search-text [:get-in [:toolbar-search :text]]]
|
||||
(toolbar-with-search
|
||||
{:show-search? (= show-search :contact-group-list)
|
||||
:search-text search-text
|
||||
:search-key :contact-group-list
|
||||
:custom-title (title-with-count title contacts-count)
|
||||
:search-placeholder (label :t/search-contacts)}))
|
||||
|
||||
(defn render-separator [_ row-id _]
|
||||
(list-item ^{:key row-id}
|
||||
[separator]))
|
||||
|
||||
(defn render-spacing []
|
||||
#(list-item [view cst/contact-list-spacing]))
|
||||
|
||||
(defview contact-toggle-list []
|
||||
[contacts [:all-added-group-contacts-filtered]
|
||||
selected-contacts-count [:selected-contacts-count]
|
||||
group-type [:get :group-type]]
|
||||
[view st/group-container
|
||||
[status-bar]
|
||||
[toggle-list-toolbar
|
||||
(label (if (= group-type :contact-group)
|
||||
:t/new-group
|
||||
:t/new-group-chat))
|
||||
selected-contacts-count]
|
||||
[view {:flex 1}
|
||||
[list-view
|
||||
{:dataSource (to-datasource contacts)
|
||||
:renderRow (fn [row _ _]
|
||||
(list-item ^{:key row} [group-toggle-contact row]))
|
||||
:renderSeparator render-separator
|
||||
:renderFooter (render-spacing)
|
||||
:renderHeader (render-spacing)
|
||||
:style cst/contacts-list
|
||||
:keyboardShouldPersistTaps true}]]
|
||||
(when (pos? selected-contacts-count)
|
||||
[confirm-button (label :t/next) #(dispatch [:navigate-to :new-group])])])
|
||||
|
||||
(defview add-contacts-toggle-list []
|
||||
[contacts [:all-group-not-added-contacts-filtered]
|
||||
group [:get-contact-group]
|
||||
selected-contacts-count [:selected-contacts-count]]
|
||||
[view st/group-container
|
||||
[status-bar]
|
||||
[toggle-list-toolbar (:name group) selected-contacts-count]
|
||||
[view {:flex 1}
|
||||
[list-view
|
||||
{:dataSource (to-datasource contacts)
|
||||
:renderRow (fn [row _ _]
|
||||
(list-item ^{:key row} [group-toggle-contact row]))
|
||||
:renderSeparator render-separator
|
||||
:renderFooter (render-spacing)
|
||||
:renderHeader (render-spacing)
|
||||
:style cst/contacts-list
|
||||
:keyboardShouldPersistTaps true}]]
|
||||
(when (pos? selected-contacts-count)
|
||||
[confirm-button (label :t/save) #(do
|
||||
(dispatch [:add-selected-contacts-to-group])
|
||||
(dispatch [:navigate-back]))])])
|
||||
|
||||
(defview add-participants-toggle-list []
|
||||
[contacts [:contacts-filtered :all-new-contacts]
|
||||
chat-name [:chat :name]
|
||||
selected-contacts-count [:selected-participants-count]]
|
||||
[view st/group-container
|
||||
[status-bar]
|
||||
[toggle-list-toolbar chat-name selected-contacts-count]
|
||||
[view {:flex 1}
|
||||
[list-view
|
||||
{:dataSource (to-datasource contacts)
|
||||
:renderRow (fn [row _ _]
|
||||
(list-item ^{:key row} [group-toggle-participant row]))
|
||||
:renderSeparator render-separator
|
||||
:renderFooter (render-spacing)
|
||||
:renderHeader (render-spacing)
|
||||
:style cst/contacts-list
|
||||
:keyboardShouldPersistTaps true}]]
|
||||
(when (pos? selected-contacts-count)
|
||||
[confirm-button (label :t/save) #(do
|
||||
(dispatch [:add-new-participants])
|
||||
(dispatch [:navigate-back]))])])
|
||||
|
||||
|
|
@ -0,0 +1,111 @@
|
|||
(ns status-im.new-group.views.group
|
||||
(:require-macros [status-im.utils.views :refer [defview]])
|
||||
(:require [re-frame.core :refer [dispatch]]
|
||||
[status-im.contacts.styles :as cst]
|
||||
[status-im.components.react :refer [view
|
||||
text
|
||||
icon
|
||||
touchable-highlight]]
|
||||
[status-im.components.text-field.view :refer [text-field]]
|
||||
[status-im.components.styles :refer [color-blue color-gray5 color-light-blue]]
|
||||
[status-im.components.status-bar :refer [status-bar]]
|
||||
[status-im.components.toolbar-new.view :refer [toolbar]]
|
||||
[status-im.utils.platform :refer [platform-specific]]
|
||||
[status-im.new-group.styles :as st]
|
||||
[status-im.i18n :refer [label]]))
|
||||
|
||||
(defn separator []
|
||||
[view cst/contact-item-separator-wrapper
|
||||
[view cst/contact-item-separator]])
|
||||
|
||||
(defview group-name-input []
|
||||
[new-group-name [:get :new-chat-name]]
|
||||
[view
|
||||
[text-field
|
||||
{:wrapper-style st/group-chat-name-wrapper
|
||||
:line-color color-gray5
|
||||
:focus-line-color color-light-blue
|
||||
:focus-line-height st/group-chat-focus-line-height
|
||||
:label-hidden? true
|
||||
:input-style st/group-chat-name-input
|
||||
:auto-focus true
|
||||
:on-change-text #(dispatch [:set :new-chat-name %])
|
||||
:value new-group-name}]])
|
||||
|
||||
(defn group-toolbar [group-type edit?]
|
||||
[view
|
||||
[status-bar]
|
||||
[toolbar
|
||||
{:title (label
|
||||
(if (= group-type :contact-group)
|
||||
(if edit? :t/edit-group :t/new-group)
|
||||
(if edit? :t/chat-settings :t/new-group-chat)))
|
||||
:actions [{:image :blank}]}]])
|
||||
|
||||
(defn group-name-view []
|
||||
[view st/chat-name-container
|
||||
[text {:style st/group-name-text}
|
||||
(label :t/name)]
|
||||
[group-name-input]])
|
||||
|
||||
(defn add-btn [on-press]
|
||||
[view st/add-button-container
|
||||
[touchable-highlight {:on-press on-press}
|
||||
[view st/add-container
|
||||
[view st/settings-icon-container
|
||||
[icon :add_blue st/add-icon]]
|
||||
[view st/settings-group-text-container
|
||||
[text {:style st/add-group-text}
|
||||
(label :t/add-members)]]]]])
|
||||
|
||||
(defn delete-btn [on-press]
|
||||
[view st/settings-group-container
|
||||
[touchable-highlight {:on-press on-press}
|
||||
[view st/settings-group-item
|
||||
[view st/delete-icon-container
|
||||
[icon :close_red st/add-icon]]
|
||||
[view st/settings-group-text-container
|
||||
[text {:style st/delete-group-text}
|
||||
(label :t/delete-group)]
|
||||
[text {:style st/delete-group-prompt-text}
|
||||
(label :t/delete-group-prompt)]]]]])
|
||||
|
||||
(defn group-chat-settings-btns []
|
||||
[view st/settings-group-container
|
||||
[view {:opacity 0.4}
|
||||
[touchable-highlight {:on-press #()}
|
||||
[view st/settings-group-item
|
||||
[view st/settings-icon-container
|
||||
[icon :speaker_blue st/add-icon]]
|
||||
[view st/settings-group-text-container
|
||||
[text {:style st/settings-group-text}
|
||||
(label :t/mute-notifications)]]]]]
|
||||
[separator]
|
||||
[touchable-highlight {:on-press #(dispatch [:clear-history])}
|
||||
[view st/settings-group-item
|
||||
[view st/settings-icon-container
|
||||
[icon :close_blue st/add-icon]]
|
||||
[view st/settings-group-text-container
|
||||
[text {:style st/settings-group-text}
|
||||
(label :t/clear-history)]]]]
|
||||
[separator]
|
||||
[touchable-highlight {:on-press #(dispatch [:leave-group-chat])}
|
||||
[view st/settings-group-item
|
||||
[view st/delete-icon-container
|
||||
[icon :arrow_right_red st/add-icon]]
|
||||
[view st/settings-group-text-container
|
||||
[text {:style st/delete-group-text}
|
||||
(label :t/leave-chat)]]]]])
|
||||
|
||||
(defn more-btn [contacts-limit contacts-count on-press]
|
||||
[view
|
||||
[view cst/contact-item-separator-wrapper
|
||||
[view cst/contact-item-separator]]
|
||||
[view cst/show-all
|
||||
[touchable-highlight {:on-press on-press}
|
||||
[view
|
||||
[text {:style cst/show-all-text
|
||||
:uppercase? (get-in platform-specific [:uppercase?])
|
||||
:font (get-in platform-specific [:component-styles :contacts :show-all-text-font])}
|
||||
(str (- contacts-count contacts-limit) " " (label :t/more))]]]]])
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
(ns status-im.new-group.views.toggle-contact
|
||||
(:require-macros [status-im.utils.views :refer [defview]])
|
||||
(:require [re-frame.core :refer [subscribe dispatch dispatch-sync]]
|
||||
[status-im.components.react :refer [view icon touchable-highlight]]
|
||||
[status-im.contacts.views.contact-inner :refer [contact-inner-view]]
|
||||
[status-im.new-group.styles :as st]
|
||||
[status-im.contacts.styles :as cst]
|
||||
[status-im.components.styles :refer [color-light-blue color-gray5]]
|
||||
[status-im.utils.platform :refer [platform-specific]]))
|
||||
|
||||
(defn on-toggle [checked? whisper-identity]
|
||||
(let [action (if checked? :deselect-contact :select-contact)]
|
||||
(dispatch [action whisper-identity])))
|
||||
|
||||
(defn on-toggle-participant [checked? whisper-identity]
|
||||
(let [action (if checked? :deselect-participant :select-participant)]
|
||||
(dispatch [action whisper-identity])))
|
||||
|
||||
;;TODO: maybe it's better to have only one global component contact-view (with the types: default, extended and toggle)
|
||||
(defview toogle-contact-view [{:keys [whisper-identity] :as contact} selected-key on-toggle-handler]
|
||||
[checked [selected-key whisper-identity]]
|
||||
[touchable-highlight {:on-press #(on-toggle-handler checked whisper-identity)}
|
||||
[view
|
||||
[view (merge st/contact-container (when checked {:style st/selected-contact}))
|
||||
[contact-inner-view (merge {:contact contact}
|
||||
(when checked {:style st/selected-contact}))]
|
||||
[view st/toggle-container
|
||||
[view (merge st/icon-check-container
|
||||
{:background-color (if checked color-light-blue color-gray5)})
|
||||
(when checked
|
||||
[icon :check_on st/check-icon])]]]]])
|
||||
|
||||
(defn group-toggle-contact [{:keys [whisper-identity] :as contact}]
|
||||
[toogle-contact-view contact :is-contact-selected? on-toggle])
|
||||
|
||||
(defn group-toggle-participant [{:keys [whisper-identity] :as contact}]
|
||||
[toogle-contact-view contact :is-participant-selected? on-toggle-participant])
|
||||
|
|
@ -161,10 +161,12 @@
|
|||
:save "Save"
|
||||
:change-color "Change color"
|
||||
:clear-history "Clear history"
|
||||
:mute-notifications "Mute notifications"
|
||||
:leave-chat "Leave chat"
|
||||
:delete-and-leave "Delete and leave"
|
||||
:chat-settings "Chat settings"
|
||||
:edit "Edit"
|
||||
:add-members "Add Members"
|
||||
:add-members "Add members"
|
||||
:blue "Blue"
|
||||
:purple "Purple"
|
||||
:green "Green"
|
||||
|
@ -195,7 +197,7 @@
|
|||
:group-name "Group name"
|
||||
:edit-group "Edit group"
|
||||
:delete-group "Delete group"
|
||||
:delete-group-prompt "This will not affect group members"
|
||||
:delete-group-prompt "This will not affect contacts"
|
||||
:group-members "Group members"
|
||||
:contact-s {:one "contact"
|
||||
:other "contacts"}
|
||||
|
|