Compare commits

...
Author SHA1 Message Date
Omar Basem d433285acb selectable-input 2023-05-04 10:26:51 +04:00
Omar Basem eb16f4b6c4 revert podfile.lock 2023-05-04 09:17:53 +04:00
Omar Basem 9268060aa9 review 2023-05-04 09:16:53 +04:00
Omar Basem 7ab9e7abd0 review 2023-05-04 09:16:52 +04:00
Omar Basem 2430bde3d5 review 2023-05-04 09:16:52 +04:00
Omar Basem 739556f2b4 review 2023-05-04 09:16:52 +04:00
Omar Basem f4ac7a4c51 lint 2023-05-04 09:16:51 +04:00
Omar Basem 36fac66eac feat: mentions new design
review

lint

review

udpates

updates

updates

udpates

updates

updates

lint

updates

composer shell button

updates

updates

updates

updates

updates

updates

updates

updates

updates

updates

updates

updates

updates
2023-05-04 09:16:51 +04:00
Alexander 4774b0f5e5 Fix for mention text overlaying message text when mention is added during message editing (Android) (#15778) 2023-05-03 18:26:37 +02:00
Siddarth Kumar 6aa38de7c7 set checked for communities disclaimer explicitly (#15804) 2023-05-03 21:24:19 +05:30
Omar Basem a973976123 New composer - add audio comp (#15790)
* feat: composer - add audio comp
2023-05-03 09:54:23 +04:00
Ajay Sivan 03aac0e4ce fix: quo2 title-input component selection style fix for android (#15717) 2023-05-02 17:01:09 +05:30
Siddarth Kumar fac368521b (fix) modify disclaimer component for on tap UX (#15757) 2023-05-02 15:55:49 +05:30
Omar Basem 51b9253734 revert podfile.lock (#15791)
* revert podfile.lock
2023-05-02 09:27:47 +04:00
Omar Basem 08e6b8164e feat: composer - edit message (#15772)
* feat: new composer - edit message
2023-05-01 20:39:07 +04:00
Parvesh Monu 9a8354f783 Improve dissmiss all overlays (#15773) 2023-04-28 20:52:34 +05:30
Churikova Tetiana 6c0c742676 e2e: align with new communities / cleanup 2023-04-28 13:56:31 +02:00
flexsurfer e0ed2a250b clean old code, remove public chat, implement drawers for home screens (#15766) 2023-04-28 13:42:38 +02:00
jakub 2f988fcd47 nix: disable sandboxing for xcodewrapper
Otherwise we see weird errors like this:
```
/nix/store/g0jijpgcb4q54zbvz5p8yvxcnb6lshnk-stdenv-darwin/setup: line 1391: /nix/store/sja8sqq4y5s9ijkb97i3pi2jrhsy40cz-xcode-wrapper-14.3/bin/xcodebuild: Operation not permitted
We require xcodebuild version: 14.3
error: builder for '/nix/store/d1dji0ywl851wgj9vv58ibpm32gq3wsm-xcode-wrapper-14.3.drv' failed with exit code 1;
       last 2 log lines:
       > /nix/store/g0jijpgcb4q54zbvz5p8yvxcnb6lshnk-stdenv-darwin/setup: line 1391: /nix/store/sja8sqq4y5s9ijkb97i3pi2jrhsy40cz-xcode-wrapper-14.3/bin/xcodebuild: Operation not permitted
       > We require xcodebuild version: 14.3
```
Related to: https://github.com/NixOS/nixpkgs/pull/228696

Signed-off-by: Jakub Sokołowski <jakub@status.im>
2023-04-28 11:24:16 +02:00
frank ee71117111 remove unused code relate to old text-input component (#15765)
* remove unused code relate to old text-input component

* removed tow lines
2023-04-28 09:37:13 +08:00
107 changed files with 1101 additions and 3209 deletions
@@ -8,6 +8,9 @@ assert stdenv.isDarwin;
stdenv.mkDerivation {
name = "xcode-wrapper-${version}${if allowHigher then "-plus" else ""}";
# Fix 'xcodebuild: Operation not permitted' when 'sandbox=relaxed' is used.
# https://github.com/NixOS/nixpkgs/pull/228696
__noChroot = stdenv.isDarwin;
buildCommand = ''
mkdir -p $out/bin
cd $out/bin
Binary file not shown.

After

Width:  |  Height:  |  Size: 528 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 769 B

@@ -1,5 +1,6 @@
(ns quo2.components.inputs.title-input.style
(:require [quo2.foundations.colors :as colors]))
(:require [quo2.foundations.colors :as colors]
[react-native.platform :as platform]))
(defn get-focused-placeholder-color
[blur? override-theme]
@@ -28,9 +29,11 @@
(defn get-selection-color
[customization-color blur? override-theme]
(if blur?
(colors/theme-colors colors/neutral-100 colors/white override-theme)
(colors/custom-color customization-color (if (or (= :dark override-theme) (colors/dark?)) 60 50))))
(colors/alpha (if blur?
(colors/theme-colors colors/neutral-100 colors/white override-theme)
(colors/custom-color customization-color
(if (or (= :dark override-theme) colors/dark?) 60 50)))
(if platform/ios? 1 0.2)))
(def text-input-container {:flex 1})
@@ -154,12 +154,12 @@
ready-to-send? (reagent/atom false)
ready-to-lock? (reagent/atom false)
ready-to-delete? (reagent/atom false)
reviewing-audio? (reagent/atom false)
reviewing-audio? (reagent/atom (some? audio-file))
playing-audio? (reagent/atom false)
recording-length-ms (reagent/atom 0)
audio-current-time-ms (reagent/atom 0)
seeking-audio? (reagent/atom false)
force-show-controls? (reagent/atom false)
force-show-controls? (reagent/atom (some? audio-file))
clear-timeout (atom nil)
record-button-at-initial-position? (atom true)
record-button-is-animating? (atom false)
@@ -169,7 +169,7 @@
touch-active? (atom false)
recording-timer (atom nil)
playing-timer (atom nil)
output-file (atom nil)
output-file (atom audio-file)
reached-max-duration? (atom false)
touch-timestamp (atom nil)
disabled? (atom false)
@@ -512,10 +512,7 @@
(on-init reset-recorder))
(when audio-file
(let [filename (last (string/split audio-file "/"))]
(reload-player filename)
(reset! output-file audio-file)
(reset! reviewing-audio? true)
(reset! force-show-controls? true)))))
(reload-player filename)))))
[rn/view
{:style style/bar-container
:pointer-events :box-none}
@@ -5,15 +5,17 @@
[react-native.core :as rn]))
(defn view
[{:keys [checked? blur? on-change accessibility-label container-style]} label]
[rn/view
{:style (merge container-style (style/container blur?))}
[selectors/checkbox
{:accessibility-label accessibility-label
:blur? blur?
:checked? checked?
:on-change on-change}]
[text/text
{:size :paragraph-2
:style style/text}
label]])
[{:keys [checked? blur? accessibility-label container-style on-change]} label]
[rn/touchable-opacity
{:on-press on-change
:accessibility-label "disclaimer-touchable-opacity"}
[rn/view {:style (merge container-style (style/container blur?))}
[selectors/checkbox
{:accessibility-label accessibility-label
:blur? blur?
:checked? checked?
:on-change on-change}]
[text/text
{:size :paragraph-2
:style style/text}
label]]])
-4
View File
@@ -41,10 +41,6 @@
[comp]
(.catch (.dismissOverlay Navigation comp) #()))
(defn dissmiss-all-overlays
[]
(.catch (.dismissAllOverlays Navigation) #()))
(defn reg-app-launched-listener
[handler]
(.registerAppLaunchedListener ^js (.events ^js Navigation) handler))
-102
View File
@@ -1,102 +0,0 @@
(ns status-im.add-new.core
(:require [clojure.string :as string]
[re-frame.core :as re-frame]
[status-im.add-new.db :as db]
[status-im2.contexts.chat.events :as chat]
[status-im2.contexts.contacts.events :as contact]
[status-im.ethereum.core :as ethereum]
[status-im.ethereum.ens :as ens]
[status-im.ethereum.stateofus :as stateofus]
[utils.i18n :as i18n]
[status-im.router.core :as router]
[status-im.utils.db :as utils.db]
[utils.re-frame :as rf]
[status-im.utils.random :as random]
[status-im.utils.utils :as utils]
[status-im2.navigation.events :as navigation]))
(re-frame/reg-fx
:resolve-public-key
(fn [{:keys [chain-id contact-identity cb]}]
(let [ens-name (stateofus/ens-name-parse contact-identity)]
(ens/pubkey chain-id ens-name cb))))
;;NOTE we want to handle only last resolve
(def resolve-last-id (atom nil))
(rf/defn new-chat-set-new-identity
{:events [:new-chat/set-new-identity]}
[{db :db} new-identity-raw new-ens-name id]
(let [ens-error (and (= new-identity-raw "0x") (not (string/blank? new-ens-name)))]
(when (or (not id) (= id @resolve-last-id))
(if ens-error
{:db (assoc-in db [:contacts/new-identity :state] :error)}
(let [new-identity (utils/safe-trim new-identity-raw)
is-public-key? (and (string? new-identity)
(utils.db/valid-public-key? new-identity))
is-ens? (and (not is-public-key?)
(ens/valid-eth-name-prefix? new-identity))
error (db/validate-pub-key db new-identity)]
(reset! resolve-last-id nil)
(merge {:db (assoc db
:contacts/new-identity
{:public-key new-identity
:state (cond is-ens?
:searching
(and (string/blank? new-identity) (not new-ens-name))
:empty
error
:error
:else
:valid)
:error error
:ens-name (stateofus/ens-name-parse new-ens-name)})}
(when is-ens?
(reset! resolve-last-id (random/id))
{:resolve-public-key
{:chain-id (ethereum/chain-id db)
:contact-identity new-identity
:cb #(re-frame/dispatch [:new-chat/set-new-identity
%
new-identity
@resolve-last-id])}})))))))
(rf/defn clear-new-identity
{:events [::clear-new-identity ::new-chat-focus]}
[{:keys [db]}]
{:db (dissoc db :contacts/new-identity)})
(rf/defn qr-code-handled
{:events [::qr-code-handled]}
[{:keys [db] :as cofx} {:keys [type public-key chat-id data ens-name]}
{:keys [new-contact? nickname] :as opts}]
(let [public-key? (and (string? data)
(string/starts-with? data "0x"))
chat-key (cond
(= type :private-chat) chat-id
(= type :contact) public-key
(and (= type :undefined)
public-key?)
data)
validation-result (db/validate-pub-key db chat-key)]
(if-not validation-result
(if new-contact?
(rf/merge cofx
(contact/send-contact-request chat-key)
(navigation/navigate-to :contacts-list {}))
(chat/start-chat cofx chat-key ens-name))
{:utils/show-popup {:title (i18n/label :t/unable-to-read-this-code)
:content (case validation-result
:invalid
(i18n/label :t/use-valid-contact-code)
:yourself
(i18n/label :t/can-not-add-yourself))
:on-dismiss #(re-frame/dispatch [:pop-to-root :shell-stack])}})))
(rf/defn qr-code-scanned
{:events [:contact/qr-code-scanned]}
[{:keys [db]} data opts]
{::router/handle-uri {:chain (ethereum/chain-keyword db)
:chats (get db :chats)
:uri data
:cb #(re-frame/dispatch [::qr-code-handled % opts])}})
-30
View File
@@ -1,30 +0,0 @@
(ns status-im.add-new.db
(:require [cljs.spec.alpha :as spec]
[status-im.ethereum.ens :as ens]
[utils.validators :as validators]))
(defn own-public-key?
[{:keys [multiaccount]} public-key]
(= (:public-key multiaccount) public-key))
(defn validate-pub-key
[db public-key]
(cond
(or (not (validators/valid-public-key? public-key))
(= public-key ens/default-key))
:invalid
(own-public-key? db public-key)
:yourself))
(spec/def ::name (spec/and string? not-empty))
(spec/def ::topic
(spec/and string?
not-empty
(partial re-matches #"[a-z0-9\-]+")))
(defn valid-topic?
[topic]
(and topic
(spec/valid? ::topic topic)
(not (validators/valid-public-key? topic))))
-4
View File
@@ -1,7 +1,6 @@
(ns status-im.bottom-sheet.sheets
(:require [utils.re-frame :as rf]
[status-im.ui.screens.about-app.views :as about-app]
[status-im.ui.screens.home.sheet.views :as home.sheet]
[status-im.ui.screens.keycard.views :as keycard]
[status-im.ui.screens.mobile-network-settings.view :as mobile-network-settings]
[status-im.ui.screens.multiaccounts.key-storage.views :as key-storage]
@@ -27,9 +26,6 @@
(= view :mobile-network-offline)
(merge mobile-network-settings/offline-sheet)
(= view :add-new)
(merge home.sheet/add-new)
(= view :keycard.login/more)
(merge keycard/more-sheet)
-35
View File
@@ -1,35 +0,0 @@
(ns status-im.chat.models
(:require [utils.i18n :as i18n]
[re-frame.core :as re-frame]
[utils.re-frame :as rf]
[taoensso.timbre :as log]
[status-im.add-new.db :as new-public-chat.db]
[status-im.data-store.chats :as chats-store]))
;; OLD
(rf/defn handle-public-chat-created
{:events [::public-chat-created]}
[{:keys [db]} chat-id response]
{:db (-> db
(assoc-in [:chats chat-id] (chats-store/<-rpc (first (:chats response))))
(update :chats-home-list conj chat-id))
:dispatch [:chat/navigate-to-chat chat-id]})
(rf/defn create-public-chat-go
[_ chat-id]
{:json-rpc/call [{:method "wakuext_createPublicChat"
:params [{:id chat-id}]
:on-success #(re-frame/dispatch [::public-chat-created chat-id %])
:on-error #(log/error "failed to create public chat" chat-id %)}]})
(rf/defn start-public-chat
"Starts a new public chat"
{:events [:chat.ui/start-public-chat]}
[cofx topic]
(if (new-public-chat.db/valid-topic? topic)
(create-public-chat-go
cofx
topic)
{:utils/show-popup {:title (i18n/label :t/cant-open-public-chat)
:content (i18n/label :t/invalid-public-chat-topic)}}))
+46 -35
View File
@@ -6,12 +6,12 @@
[status-im.chat.models.mentions :as mentions]
[status-im.chat.models.message :as chat.message]
[status-im.chat.models.message-content :as message-content]
[status-im2.config :as config]
[status-im2.constants :as constants]
[utils.re-frame :as rf]
[utils.i18n :as i18n]
[status-im.utils.utils :as utils]
[taoensso.timbre :as log]
[status-im.ui.screens.chat.components.input :as input]))
[taoensso.timbre :as log]))
(defn text->emoji
"Replaces emojis in a specified `text`"
@@ -51,6 +51,18 @@
(let [current-chat-id (or chat-id (:current-chat-id db))]
{:db (assoc-in db [:chat/inputs current-chat-id :input-maximized?] maximized?)}))
(rf/defn set-input-focused
{:events [:chat.ui/set-input-focused]}
[{db :db} focused? chat-id]
(let [current-chat-id (or chat-id (:current-chat-id db))]
{:db (assoc-in db [:chat/inputs current-chat-id :focused?] focused?)}))
(rf/defn set-input-audio
{:events [:chat.ui/set-input-audio]}
[{db :db} audio chat-id]
(let [current-chat-id (or chat-id (:current-chat-id db))]
{:db (assoc-in db [:chat/inputs current-chat-id :audio] audio)}))
(rf/defn select-mention
{:events [:chat.ui/select-mention]}
[{:keys [db] :as cofx} text-input-ref {:keys [primary-name searched-text match public-key] :as user}]
@@ -92,15 +104,15 @@
[{:keys [db] :as cofx} message]
(let [current-chat-id (:current-chat-id db)
text (get-in message [:content :text])]
(rf/merge cofx
{:db (-> db
(assoc-in [:chat/inputs current-chat-id :metadata :editing-message]
message)
(assoc-in [:chat/inputs current-chat-id :metadata :responding-to-message] nil)
(update-in [:chat/inputs current-chat-id :metadata]
dissoc
:sending-image))}
(input/set-input-text text current-chat-id))))
{:db (-> db
(assoc-in [:chat/inputs current-chat-id :metadata :editing-message]
message)
(assoc-in [:chat/inputs current-chat-id :metadata :responding-to-message] nil)
(update-in [:chat/inputs current-chat-id :metadata]
dissoc
:sending-image))
:dispatch (when-not config/new-composer-enabled?
[:mention/to-input-field text current-chat-id])}))
(rf/defn show-contact-request-input
"Sets reference to previous chat message and focuses on input"
@@ -175,7 +187,8 @@
[{:keys [db] :as cofx}]
(let [current-chat-id (:current-chat-id db)]
(rf/merge cofx
{:set-text-input-value [current-chat-id ""]}
(when-not config/new-composer-enabled?
{:set-text-input-value [current-chat-id ""]})
(clean-input current-chat-id)
(mentions/clear-mentions))))
@@ -219,22 +232,21 @@
(rf/defn send-edited-message
[{:keys [db] :as cofx} text {:keys [message-id quoted-message chat-id]}]
(let [pinned-message (get-in db [:pin-messages chat-id message-id])]
(rf/merge
cofx
{:json-rpc/call [{:method "wakuext_editMessage"
:params [{:id message-id
:text text
:content-type (if (message-content/emoji-only-content?
{:text text :response-to quoted-message})
constants/content-type-emoji
constants/content-type-text)}]
:js-response true
:on-error #(log/error "failed to edit message " %)
:on-success (fn [result]
(re-frame/dispatch [:sanitize-messages-and-process-response
result]))}]}
(cancel-message-edit))))
(rf/merge
cofx
{:json-rpc/call [{:method "wakuext_editMessage"
:params [{:id message-id
:text text
:content-type (if (message-content/emoji-only-content?
{:text text :response-to quoted-message})
constants/content-type-emoji
constants/content-type-text)}]
:js-response true
:on-error #(log/error "failed to edit message " %)
:on-success (fn [result]
(re-frame/dispatch [:sanitize-messages-and-process-response
result]))}]}
(cancel-message-edit)))
(rf/defn send-current-message
"Sends message from current chat input"
@@ -270,13 +282,12 @@
{:events [:contacts/send-contact-request]}
[{:keys [db] :as cofx} public-key message]
(rf/merge cofx
{:chat.ui/clear-inputs nil
:chat.ui/clear-inputs-old nil
:json-rpc/call [{:method "wakuext_sendContactRequest"
:js-response true
:params [{:id public-key :message message}]
:on-error #(log/warn "failed to send a contact request" %)
:on-success #(re-frame/dispatch [:transport/message-sent %])}]}
{:chat.ui/clear-inputs nil
:json-rpc/call [{:method "wakuext_sendContactRequest"
:js-response true
:params [{:id public-key :message message}]
:on-error #(log/warn "failed to send a contact request" %)
:on-success #(re-frame/dispatch [:transport/message-sent %])}]}
(mentions/clear-mentions)
(clean-input (:current-chat-id db))))
+28 -11
View File
@@ -3,6 +3,7 @@
[quo.react :as react]
[quo.react-native :as rn]
[re-frame.core :as re-frame]
[status-im2.config :as config]
[utils.re-frame :as rf]
[taoensso.timbre :as log]
[native-module.core :as native-module]))
@@ -80,6 +81,19 @@
(log/error "[mentions] on-error"
{:context context
:error error}))
(rf/defn to-input-field
{:events [:mention/to-input-field]}
[_ text chat-id]
(let [params [chat-id text]
method "wakuext_chatMentionToInputField"]
(log/debug "[mentions] to-input-field" {:params params})
{:json-rpc/call [{:method method
:params params
:on-success #(rf/dispatch [:mention/on-to-input-field-success %])
:on-error #(rf/dispatch [:mention/on-error
{:method method
:params params} %])}]}))
(rf/defn on-to-input-field-success
{:events [:mention/on-to-input-field-success]}
[{:keys [db]} result]
@@ -154,17 +168,20 @@
cursor (+ at-sign-idx (count primary-name) 2)]
(rf/merge
cofx
{:db (-> db
(assoc-in [:chats/mention-suggestions chat-id] nil))
:set-text-input-value [chat-id new-text text-input-ref]
:dispatch [:chat.ui/set-chat-input-text new-text chat-id]}
;; NOTE(rasom): Some keyboards do not react on selection property passed to
;; text input (specifically Samsung keyboard with predictive text set on).
;; In this case, if the user continues typing after the programmatic change,
;; the new text is added to the last known cursor position before
;; programmatic change. By calling `reset-text-input-cursor` we force the
;; keyboard's cursor position to be changed before the next input.
(reset-text-input-cursor text-input-ref cursor)
(let [common {:db (-> db
(assoc-in [:chats/mention-suggestions chat-id] nil))
:dispatch [:chat.ui/set-chat-input-text new-text chat-id]}
extra (if (not config/new-composer-enabled?)
;; NOTE(rasom): Some keyboards do not react on selection property passed to
;; text input (specifically Samsung keyboard with predictive text set on).
;; In this case, if the user continues typing after the programmatic change,
;; the new text is added to the last known cursor position before
;; programmatic change. By calling `reset-text-input-cursor` we force the
;; keyboard's cursor position to be changed before the next input.
{:set-text-input-value [chat-id new-text text-input-ref]
:reset-text-input-cursor (reset-text-input-cursor text-input-ref cursor)}
{})]
(merge common extra))
(recheck-at-idxs public-key))))
(rf/defn clear-suggestions
+1 -1
View File
@@ -505,7 +505,7 @@
(handle-response response-js)))
(rf/defn open-create-community
{:events [::open-create-community]}
{:events [:legacy-only-for-e2e/open-create-community]}
[{:keys [db] :as cofx}]
(rf/merge cofx
{:db (assoc db :communities/create {:membership constants/community-no-membership-access})}
+1 -6
View File
@@ -9,8 +9,7 @@
(defn rpc->type
[{:keys [chat-type name] :as chat}]
(cond
(or (= constants/public-chat-type chat-type)
(= constants/profile-chat-type chat-type)
(or (= constants/profile-chat-type chat-type)
(= constants/timeline-chat-type chat-type))
(assoc chat
:chat-name (str "#" name)
@@ -39,10 +38,6 @@
(defn- unmarshal-members
[{:keys [members chat-type] :as chat}]
(cond
(= constants/public-chat-type chat-type) (assoc chat
:contacts #{}
:admins #{}
:members-joined #{})
(= constants/private-group-chat-type chat-type) (merge chat
(reduce members-reducer
{:admins #{}
-1
View File
@@ -7,7 +7,6 @@
status-im.bootnodes.core
status-im.browser.core
status-im.browser.permissions
status-im.chat.models
status-im.chat.models.images
status-im.chat.models.input
status-im.chat.models.loading
-15
View File
@@ -2,21 +2,6 @@
(:require [re-frame.core :as re-frame]
[status-im.utils.http :as http]))
(re-frame/reg-fx
:http-get
(fn [{:keys [url response-validator on-success on-error timeout-ms]}]
(let [opts {:valid-response? response-validator
:timeout-ms timeout-ms}]
(http/get url on-success on-error opts))))
(re-frame/reg-fx
:http-get-n
(fn [calls]
(doseq [{:keys [url response-validator on-success on-error timeout-ms]} calls]
(let [opts {:valid-response? response-validator
:timeout-ms timeout-ms}]
(http/get url on-success on-error opts)))))
(re-frame/reg-fx
:http-post
(fn [{:keys [url data response-validator on-success on-error timeout-ms opts]}]
+1 -1
View File
@@ -125,7 +125,7 @@
(rf-test/wait-for ; wait for login
[::transport/messenger-started]
(assert-messenger-started)
(rf/dispatch-sync [:status-im.communities.core/open-create-community])
(rf/dispatch-sync [:legacy-only-for-e2e/open-create-community])
(doseq [[k v] (dissoc community :membership)]
(rf/dispatch-sync [:status-im.communities.core/create-field k v]))
(rf/dispatch [:status-im.communities.core/create-confirmation-pressed])
@@ -16,7 +16,6 @@
(rf/merge cofx
{:set-root :progress
:chat.ui/clear-inputs nil
:chat.ui/clear-inputs-old nil
:shell/reset-bottom-tabs nil
:hide-popover nil
::logout nil
+6 -15
View File
@@ -1,7 +1,5 @@
(ns status-im.qr-scanner.core
(:require [re-frame.core :as re-frame]
[status-im.add-new.db :as new-chat.db]
[status-im.chat.models :as chat]
[status-im.ethereum.core :as ethereum]
[status-im.group-chats.core :as group-chats]
[utils.i18n :as i18n]
@@ -43,25 +41,24 @@
{:browser/show-browser-selection url}
(navigation/navigate-back)))
(defn own-public-key?
[{:keys [multiaccount]} public-key]
(= (:public-key multiaccount) public-key))
(rf/defn handle-private-chat
[{:keys [db] :as cofx} {:keys [chat-id]}]
(if-not (new-chat.db/own-public-key? db chat-id)
(if-not (own-public-key? db chat-id)
{:dispatch [:chat.ui/start-chat chat-id]}
{:utils/show-popup {:title (i18n/label :t/unable-to-read-this-code)
:content (i18n/label :t/can-not-add-yourself)}}))
(rf/defn handle-public-chat
[cofx {:keys [topic]}]
(when (seq topic)
(chat/start-public-chat cofx topic)))
(rf/defn handle-group-chat
[cofx params]
(group-chats/create-from-link cofx params))
(rf/defn handle-view-profile
[{:keys [db] :as cofx} {:keys [public-key ens-name]}]
(let [own (new-chat.db/own-public-key? db public-key)]
(let [own (own-public-key? db public-key)]
(cond
(and public-key own)
(rf/merge cofx
@@ -85,11 +82,6 @@
(navigation/change-tab :wallet-stack)
(navigation/pop-to-root :shell-stack)))
(rf/defn handle-wallet-connect
{:events [::handle-wallet-connect-uri]}
[cofx data]
{:dispatch [:wallet-connect/pair data]})
(rf/defn handle-local-pairing
{:events [::handle-local-pairing-uri]}
[_ data]
@@ -99,7 +91,6 @@
{:events [::match-scanned-value]}
[cofx {:keys [type] :as data}]
(case type
:public-chat (handle-public-chat cofx data)
:group-chat (handle-group-chat cofx data)
:private-chat (handle-private-chat cofx data)
:contact (handle-view-profile cofx data)
@@ -65,11 +65,3 @@
k
(get ui k))
k)))
(def reactions-old
{:love (js/require "../resources/images/reactions/love.png")
:angry (js/require "../resources/images/reactions/angry.png")
:sad (js/require "../resources/images/reactions/sad.png")
:laugh (js/require "../resources/images/reactions/laugh.png")
:thumbs-up (js/require "../resources/images/reactions/thumbs-up.png")
:thumbs-down (js/require "../resources/images/reactions/thumbs-down.png")})
+1 -16
View File
@@ -2,7 +2,6 @@
(:require [bidi.bidi :as bidi]
[clojure.string :as string]
[re-frame.core :as re-frame]
[status-im.add-new.db :as public-chat.db]
[status-im2.contexts.chat.events :as chat.events]
[status-im2.constants :as constants]
[status-im.ethereum.core :as ethereum]
@@ -21,8 +20,6 @@
(def uri-schemes ["status-im://" "status-im:"])
(def wallet-connect-scheme "wc:")
(def web-prefixes ["https://" "http://" "https://www." "http://wwww."])
(def web2-domain "join.status.im")
@@ -48,9 +45,7 @@
(def routes
[""
{handled-schemes {["" :chat-id] :public-chat
"chat" {["/public/" :chat-id] :public-chat}
"b/" browser-extractor
{handled-schemes {"b/" browser-extractor
"browser/" browser-extractor
["p/" :chat-id] :private-chat
["cr/" :community-id] :community-requests
@@ -107,14 +102,6 @@
(callback {:type :contact
:error :not-found}))))
(defn match-public-chat
[{:keys [chat-id]}]
(if (public-chat.db/valid-topic? chat-id)
{:type :public-chat
:topic chat-id}
{:type :public-chat
:error :invalid-topic}))
(defn match-group-chat
[chats {:strs [a a1 a2]}]
(let [[admin-pk encoded-chat-name chat-id] [a a1 a2]
@@ -225,8 +212,6 @@
(let [{:keys [handler route-params query-params]} (match-uri uri)]
(log/info "[router] uri " uri " matched " handler " with " route-params)
(cond
(= handler :public-chat)
(cb (match-public-chat route-params))
(= handler :browser)
(cb (match-browser uri route-params))
-6
View File
@@ -18,9 +18,6 @@
:query-params (when (= 3 (count expected)) (last expected))
:uri uri})
"status-im://status"
[:public-chat {:chat-id "status"}]
"status-im://u/statuse2e"
[:user {:user-id "statuse2e"}]
@@ -36,9 +33,6 @@
(str "https://join.status.im/g/args?a=" public-key "&a1=" chat-name-url "&a2=" chat-id)
[:group-chat {:params "arg"} {"a" public-key "a1" chat-name "a2" chat-id}]
"https://join.status.im/status"
[:public-chat {:chat-id "status"}]
"https://join.status.im/u/statuse2e"
[:user {:user-id "statuse2e"}]
@@ -1,362 +0,0 @@
(ns status-im.ui.screens.add-new.new-chat.views
(:require
[clojure.string :as string]
[quo.core :as quo]
[quo.design-system.colors :as colors]
[quo.platform :as platform]
[quo.react-native :as rn]
[re-frame.core :as re-frame]
[reagent.core :as reagent]
[status-im.ethereum.ens :as ens]
[utils.i18n :as i18n]
[status-im.multiaccounts.core :as multiaccounts]
[status-im.qr-scanner.core :as qr-scanner]
[status-im.ui.components.animation :as animation]
[status-im.ui.components.chat-icon.screen :as chat-icon]
[status-im.ui.components.icons.icons :as icons]
[status-im.ui.components.invite.views :as invite]
[status-im.ui.components.keyboard-avoid-presentation :as kb-presentation]
[status-im.ui.components.list.views :as list]
[status-im.ui.components.react :as react]
[status-im.ui.components.topbar :as topbar]
[status-im.ui.screens.chat.photos :as photos]
[utils.validators :as validators]
[status-im.utils.gfycat.core :as gfycat]
[status-im.utils.identicon :as identicon]
[status-im.utils.utils :as utils]
[utils.debounce :as debounce])
(:require-macros [status-im.utils.views :as views]))
(defn- render-row
[row]
[quo/list-item
{:title (:primary-name row)
:icon [chat-icon/contact-icon-contacts-tab
(multiaccounts/displayed-photo row)]
:on-press #(re-frame/dispatch [:chat.ui/start-chat
(:public-key row)])}])
(defn- icon-wrapper
[color icon]
[react/view
{:style {:width 32
:height 32
:border-radius 25
:align-items :center
:justify-content :center
:background-color color}}
icon])
(defn- input-icon
[state new-contact? entered-nickname blocked?]
(let [icon (if new-contact? :main-icons/add :main-icons/arrow-right)]
(cond
(= state :searching)
[icon-wrapper colors/gray
[react/activity-indicator {:color colors/white-persist}]]
(and (= state :valid) (not blocked?))
[react/touchable-highlight
{:on-press #(debounce/dispatch-and-chill [:contact.ui/contact-code-submitted new-contact?
entered-nickname]
3000)}
[icon-wrapper colors/blue
[icons/icon icon {:color colors/white-persist}]]]
:else
[icon-wrapper colors/gray
[icons/icon icon {:color colors/white-persist}]])))
(defn get-validation-label
[value]
(case value
:invalid
(i18n/label :t/profile-not-found)
:yourself
(i18n/label :t/can-not-add-yourself)))
(defn search-contacts
[filter-text {:keys [name alias nickname]}]
(or
(string/includes? (string/lower-case (str name)) filter-text)
(string/includes? (string/lower-case (str alias)) filter-text)
(when nickname
(string/includes? (string/lower-case (str nickname)) filter-text))))
(defn filter-contacts
[filter-text contacts]
(let [lower-filter-text (string/lower-case filter-text)]
(if filter-text
(filter (partial search-contacts lower-filter-text) contacts)
contacts)))
(defn is-public-key?
[k]
(and
(string? k)
(string/starts-with? k "0x")))
(defn is-valid-username?
[username]
(let [is-chat-key? (and (is-public-key? username)
(= (count username) 132))
is-ens? (ens/valid-eth-name-prefix? username)]
(or is-chat-key? is-ens?)))
(defn translate-anim
[translate-y-value translate-y-anim-value]
(animation/start
(animation/timing translate-y-anim-value
{:toValue translate-y-value
:duration 200
:useNativeDriver true})))
(views/defview new-chat
[]
(views/letsubs [contacts [:contacts/active]
{:keys [state ens-name public-key error]} [:contacts/new-identity]
search-value (reagent/atom "")
account @(re-frame/subscribe [:multiaccount])
on-share #(re-frame/dispatch
[:show-popover
{:view :share-chat-key
:address (account :public-key)
:ens-name (account :preferred-name)}])
my-profile-button-anim-y (animation/create-value 0)
keyboard-show-listener (atom nil)
keyboard-hide-listener (atom nil)
on-keyboard-show (fn []
;; 42 is the bottom position so we
;; translate it by 32 pts to leave 10 as
;; margin
(translate-anim 32
my-profile-button-anim-y))
on-keyboard-hide (fn []
(translate-anim 0
my-profile-button-anim-y))
keyboard-show-event (if platform/android?
"keyboardDidShow"
"keyboardWillShow")
keyboard-hide-event (if platform/android?
"keyboardDidHide"
"keyboardWillHide")]
{:component-did-mount
(fn [_]
(reset! keyboard-show-listener (.addListener react/keyboard keyboard-show-event on-keyboard-show))
(reset! keyboard-hide-listener (.addListener react/keyboard
keyboard-hide-event
on-keyboard-hide)))
:component-will-unmount
(fn []
(some-> ^js @keyboard-show-listener
.remove)
(some-> ^js @keyboard-hide-listener
.remove))}
[kb-presentation/keyboard-avoiding-view {:style {:flex 1}}
[react/view {:style {:flex 1}}
[topbar/topbar
{:title (i18n/label :t/new-chat)
:modal? true
:right-accessories
[{:icon :qr
:accessibility-label :scan-contact-code-button
:on-press #(re-frame/dispatch [::qr-scanner/scan-code
{:title (i18n/label :t/new-chat)
:handler :contact/qr-code-scanned}])}]}]
[react/view
{:flex-direction :row
:padding 16}
[react/view {:flex 1}
[quo/text-input
{:on-change-text
#(do
(reset! search-value %)
(re-frame/dispatch [:set-in [:contacts/new-identity :state] :empty])
(debounce/debounce-and-dispatch [:contacts/set-new-identity %] 600))
:on-submit-editing
#(when (= state :valid)
(debounce/dispatch-and-chill [:contact.ui/contact-code-submitted false nil] 3000))
:placeholder (i18n/label :t/enter-contact-code)
:show-cancel false
:accessibility-label :enter-contact-code-input
:auto-capitalize :none
:return-key-type :go
:monospace true
:auto-correct false}]]]
[react/scroll-view
{:style {:flex 1}
:keyboard-dismiss-mode :on-drag
:keyboard-should-persist-taps :handled}
[react/view
(when (and
(= (count contacts) 0)
(= @search-value ""))
{:flex 1})
(if (and
(= (count contacts) 0)
(= @search-value ""))
[react/view
{:flex 1
:align-items :center
:padding-horizontal 58
:padding-top 160}
[quo/text
{:size :base
:align :center
:color :secondary}
(i18n/label :t/you-dont-have-contacts-invite-friends)]
[invite/button]]
[list/flat-list
{:data (filter-contacts @search-value contacts)
:key-fn :address
:render-fn render-row}])]
(when-not (= @search-value "")
[react/view
[quo/text
{:style {:margin-horizontal 16
:margin-vertical 14}
:size :base
:align :left
:color :secondary}
(i18n/label :t/non-contacts)]
(when (and (= state :searching)
(is-valid-username? @search-value))
[rn/activity-indicator
{:color colors/gray
:size (if platform/android? :large :small)}])
(if (= state :valid)
[quo/list-item
(merge
{:title (or ens-name (gfycat/generate-gfy public-key))
:subtitle (if ens-name
(gfycat/generate-gfy public-key)
(utils/get-shortened-address public-key))
:icon [chat-icon/contact-icon-contacts-tab
(identicon/identicon public-key)]
:on-press #(do
(debounce/dispatch-and-chill [:contact.ui/contact-code-submitted false] 3000)
(re-frame/dispatch [:search/home-filter-changed nil]))}
(when ens-name {:subtitle-secondary public-key}))]
[quo/text
{:style {:margin-horizontal 16}
:size :base
:align :center
:color :secondary}
(if (is-valid-username? @search-value)
(when (= state :error)
(get-validation-label error))
(i18n/label :t/invalid-username-or-key))])])]
(when-not (and
(= (count contacts) 0)
(= @search-value ""))
[react/animated-view
{:style {:height 36
:width 124
:position :absolute
:bottom 42
:transform [{:translateY my-profile-button-anim-y}]
:align-self :center}}
[react/touchable-opacity
{:style {:padding-horizontal 2
:height 36
:width 124
:background-color colors/blue
:border-radius 18
:elevation 4
:shadow-offset {:width 0 :height 4}
:shadow-color "rgba(0, 34, 51, 0.16)"
:shadow-radius 4
:shadow-opacity 1}
:on-press on-share}
[react/view
{:style {:flex 1
:flex-direction :row
:align-items :center}}
[photos/photo
(multiaccounts/displayed-photo account)
{:size 32
:accessibility-label :current-account-photo}]
[quo/text
{:size :base
:weight :medium
:color :inverse
:style {:margin-left 6}}
(i18n/label :t/my-profile)]]]])]]))
(defn- nickname-input
[entered-nickname]
[quo/text-input
{:on-change-text #(reset! entered-nickname %)
:auto-capitalize :none
:max-length 32
:auto-focus false
:accessibility-label :nickname-input
:placeholder (i18n/label :t/add-nickname)
:return-key-type :done
:auto-correct false}])
(defn new-contact
[]
(let [entered-nickname (reagent/atom "")]
(fn []
(let [{:keys [state ens-name public-key error]} @(re-frame/subscribe [:contacts/new-identity])
blocked? (and
(validators/valid-public-key? (or public-key ""))
@(re-frame/subscribe [:contacts/contact-blocked?
public-key]))]
[react/view {:style {:flex 1}}
[topbar/topbar
{:title (i18n/label :t/new-contact)
:modal? true
:right-accessories
[{:icon :qr
:accessibility-label :scan-contact-code-button
:on-press #(re-frame/dispatch [::qr-scanner/scan-code
{:title (i18n/label :t/new-contact)
:handler :contact/qr-code-scanned
:new-contact? true
:nickname @entered-nickname}])}]}]
[react/view
{:flex-direction :row
:padding 16}
[react/view
{:flex 1
:padding-right 16}
[quo/text-input
{:on-change-text
#(do
(re-frame/dispatch [:set-in [:contacts/new-identity :state] :searching])
(debounce/debounce-and-dispatch [:contacts/set-new-identity %] 600))
:on-submit-editing
#(when (= state :valid)
(debounce/dispatch-and-chill [:contact.ui/contact-code-submitted true @entered-nickname]
3000))
:placeholder (i18n/label :t/enter-contact-code)
:show-cancel false
:accessibility-label :enter-contact-code-input
:auto-capitalize :none
:return-key-type :go}]]
[react/view
{:justify-content :center
:align-items :center}
[input-icon state true @entered-nickname blocked?]]]
[react/view {:min-height 30 :justify-content :flex-end :margin-bottom 16}
[quo/text
{:style {:margin-horizontal 16}
:size :small
:align :center
:color :secondary}
(cond (= state :error)
(get-validation-label error)
(= state :valid)
(str (when ens-name (str ens-name " • "))
(utils/get-shortened-address public-key))
:else "")]]
[react/text {:style {:margin-horizontal 16 :color colors/gray}}
(i18n/label :t/nickname-description)]
[react/view {:padding 16}
[nickname-input entered-nickname]
[react/text
{:style {:align-self :flex-end
:margin-top 16
:color colors/gray}}
(str (count @entered-nickname) " / 32")]]]))))
@@ -1,50 +0,0 @@
(ns status-im.ui.screens.add-new.new-public-chat.view
(:require [quo.core :as quo]
[quo.design-system.colors :as colors]
[re-frame.core :as re-frame]
[status-im.add-new.db :as db]
[status-im.react-native.resources :as resources]
[status-im.ui.components.icons.icons :as icons]
[status-im.ui.components.react :as react]
[utils.i18n :as i18n])
(:require-macros [status-im.utils.views :as views]))
(defn- start-chat
[topic]
(re-frame/dispatch [:chat.ui/start-public-chat topic])
(re-frame/dispatch [:set :public-group-topic nil]))
(defn- hash-icon
[]
[icons/icon :main-icons/channel {:color colors/gray}])
(defn- chat-name-input
[topic error]
[quo/text-input
{:on-change-text #(re-frame/dispatch [:set :public-group-topic %])
:on-submit-editing #(when (db/valid-topic? topic) (start-chat topic))
:auto-capitalize :none
:auto-focus false
:accessibility-label :chat-name-input
:before {:component [hash-icon]}
;; Set default-value as otherwise it will
;; be erased in global `onWillBlur` handler
:default-value topic
:placeholder "chat-name"
:return-key-type :go
:auto-correct false
:error error}])
(views/defview new-public-chat
[]
(views/letsubs [topic [:public-group-topic]
error [:public-chat.new/topic-error-message]]
[react/scroll-view {:style {:flex 1}}
[react/view {:padding-horizontal 16}
[react/view {:align-items :center :padding-vertical 8}
[react/image
{:source (:new-chat-header resources/ui)
:style {:width 160 :height 160}}]]
[react/text {:style {:text-align :center :margin-bottom 16 :line-height 22}}
(i18n/label :t/public-chat-description)]
[chat-name-input topic error]]]))
@@ -41,8 +41,7 @@
(defn browser-options
[url account empty-tab name]
(fn []
(let [topic (http/topic-from-url url)
bookmarks @(re-frame/subscribe [:bookmarks/active])
(let [bookmarks @(re-frame/subscribe [:bookmarks/active])
permissions @(re-frame/subscribe [:dapps/permissions])
fav? (get bookmarks url)
connected? (some #{constants/dapp-permission-web3}
@@ -85,15 +84,6 @@
(js/setTimeout
#(browser/share-link url)
200))}]
[quo/list-item
{:icon [chat-icon/custom-icon-view-list
topic
(rand-nth colors/chat-colors)]
:accessibility-label :open-chat
:title (str "#" topic)
:subtitle (i18n/label :t/open-chat)
:on-press #(hide-sheet-and-dispatch [:chat.ui/start-public-chat topic])
:chevron true}]
[components/separator]])
(if connected?
[quo/list-item
@@ -1,157 +0,0 @@
(ns status-im.ui.screens.chat.components.accessory
(:require [cljs-bean.core :as bean]
[quo.animated :as animated]
[quo.design-system.colors :as colors]
[quo.platform :as platform]
[quo.react :as react]
[quo.react-native :as rn]
[reagent.core :as reagent]
[status-im.ui.components.tabbar.core :as tabbar]
[status-im.ui.screens.chat.components.hooks :refer [use-keyboard-dimension]]
[react-native.safe-area :as safe-area]))
(def duration 250)
(defn create-pan-responder
[y pan-active]
(when-not platform/android?
(js->clj
(.-panHandlers
^js
(.create
^js rn/pan-responder
#js
{:onPanResponderGrant (fn []
(animated/set-value pan-active 1))
:onPanResponderMove (fn [_ ^js state]
(animated/set-value y (.-moveY state)))
:onPanResponderRelease (fn []
(animated/set-value pan-active 0)
(js/setTimeout
#(animated/set-value y 0)
100))
:onPanResponderTerminate (fn []
(animated/set-value pan-active 0)
(js/setTimeout
#(animated/set-value y 0)
100))})))))
(def ios-view
(reagent/adapt-react-class
(react/memo
(fn [props]
(let [{on-update-inset :onUpdateInset
y :y
pan-state :panState
on-close :onClose
has-panel :hasPanel
children :children}
(bean/bean props)
{keyboard-height :height
keyboard-max-height :max-height
keyboard-end-position :end-position}
(use-keyboard-dimension)
bottom (safe-area/get-bottom)
{on-layout :on-layout
bar-height :height}
(rn/use-layout)
visible (or has-panel (pos? keyboard-height))
anim-visible (animated/use-value visible)
kb-on-screen (if platform/android? 0 (* -1 (- keyboard-height bottom (tabbar/get-height))))
panel-on-screen (* -1 (- keyboard-max-height bottom (tabbar/get-height)))
max-delta (min 0 (if has-panel panel-on-screen kb-on-screen))
panel-height (* -1 max-delta)
end-position (- keyboard-end-position (when has-panel keyboard-max-height))
delay (+ (/ (- keyboard-max-height panel-height)
(/ keyboard-max-height duration))
16)
drag-diff (animated/clamp (animated/sub y end-position) 0 keyboard-max-height)
animated-y (react/use-memo
(fn []
(animated/mix
(animated/with-timing-transition anim-visible
{:duration (- duration delay)
:easing (:keyboard animated/easings)})
0
panel-on-screen))
[panel-on-screen])
delta-y (animated/clamp (animated/add drag-diff animated-y) max-delta 0)
on-update (fn []
(when on-update-inset
(on-update-inset (+ bar-height panel-height))))
children (react/get-children children)]
(react/effect! on-update [panel-height bar-height])
(animated/code!
(fn []
(when has-panel
;; TODO: Check also velocity
(animated/cond* (animated/and* (animated/greater-or-eq drag-diff (* 0.6 panel-height))
(animated/not* pan-state))
[(animated/call* [] on-close)])))
[delta-y pan-state has-panel on-close])
(animated/code!
(fn []
(animated/delay
(animated/set anim-visible (if visible 1 0))
(if visible delay 0)))
[visible keyboard-max-height delay])
(reagent/as-element
[animated/view
{:style {:position :absolute
:left 0
:right 0
:background-color (:ui-background @colors/theme)
:bottom max-delta
:transform [{:translateY delta-y}]}}
[rn/view {:on-layout on-layout}
(first children)]
[rn/view
{:style {:flex 1
:height (when (pos? panel-height) panel-height)}}
(second children)]]))))))
(def android-view
(reagent/adapt-react-class
(react/memo
(fn [props]
(let [{on-update-inset :onUpdateInset
on-close :onClose
has-panel :hasPanel
children :children}
(bean/bean props)
{keyboard-max-height :max-height} (use-keyboard-dimension)
bottom (safe-area/get-bottom)
{on-layout :on-layout
bar-height :height}
(rn/use-layout)
visible has-panel
panel-on-screen (* -1 (- keyboard-max-height bottom (tabbar/get-height)))
max-delta (min 0 (if has-panel panel-on-screen 0))
panel-height (* -1 max-delta)
on-update (fn []
(when on-update-inset
(on-update-inset (+ bar-height panel-height))))
children (react/get-children children)]
(react/effect! on-update [panel-height bar-height])
(rn/use-back-handler
(fn []
(when visible
(on-close))
visible))
(reagent/as-element
[animated/view
{:style {:position :absolute
:left 0
:right 0
:bottom 0
:background-color (:ui-background @colors/theme)}}
[rn/view {:on-layout on-layout}
(first children)]
[rn/view
{:style {:flex 1
:height (when (pos? panel-height) panel-height)}}
(second children)]]))))))
(def view (if platform/android? android-view ios-view))
@@ -1,98 +0,0 @@
(ns status-im.ui.screens.chat.components.contact-request
(:require [clojure.string :as string]
[quo.core :as quo]
[quo.design-system.colors :as quo.colors]
[quo.react :as quo.react]
[quo.react-native :as rn]
[re-frame.core :as re-frame]
[status-im.ethereum.stateofus :as stateofus]
[utils.i18n :as i18n]
[status-im.ui.screens.chat.components.style :as styles])
(:require-macros [status-im.utils.views :refer [defview letsubs]]))
(def ^:private contact-request-symbol "↪ ")
(defn input-focus
[text-input-ref]
(some-> ^js (quo.react/current-ref text-input-ref)
.focus))
(defn format-author
[contact-name]
(let [author (if (or (= (aget contact-name 0) "@")
;; in case of replies
(= (aget contact-name 1) "@"))
(or (stateofus/username contact-name)
(subs contact-name 0 81))
contact-name)]
(i18n/label :contact-requesting-to {:author author})))
(defn format-contact-request-author
[from username current-public-key]
(or (and (= from current-public-key)
(str contact-request-symbol (i18n/label :t/You)))
(str contact-request-symbol (format-author username))))
(defn get-quoted-text-with-mentions
[parsed-text]
(string/join
(mapv (fn [{:keys [type literal children]}]
(cond
(= type "paragraph")
(get-quoted-text-with-mentions children)
(= type "mention")
@(re-frame/subscribe [:messages/resolve-mention literal])
(seq children)
(get-quoted-text-with-mentions children)
:else
literal))
parsed-text)))
(defn contact-request-message
[their-public-key]
(let [{:keys [input-text]} @(re-frame/subscribe [:chats/current-chat-input])]
[rn/view {:style {:flex-direction :row}}
[rn/view {:style (styles/contact-request-content)}
[quo/button
{:type :secondary
:weight :medium
:number-of-lines 1
:style {:line-height 18}
:on-press #(re-frame/dispatch [:chat.ui/cancel-contact-request])}
(i18n/label :t/cancel)]
[quo/button
{:type :secondary
:disabled (string/blank? input-text)
:weight :medium
:after :main-icons/send
:on-press #(re-frame/dispatch [:contacts/send-contact-request their-public-key input-text])
:style {:line-height 18}}
(i18n/label :t/send-request)]]]))
(defn focus-input-on-contact-request
[contact-request had-contact-request text-input-ref]
;;when we show contact-request we focus input
(when-not (= contact-request @had-contact-request)
(reset! had-contact-request contact-request)
(when contact-request
(js/setTimeout #(input-focus text-input-ref) 250))))
(defn contact-request-message-wrapper
[contact-request]
[rn/view
{:style {:padding-horizontal 15
:border-top-width 1
:border-top-color (:ui-01 @quo.colors/theme)
:padding-vertical 8}}
[contact-request-message contact-request]])
(defview contact-request-message-auto-focus-wrapper
[text-input-ref]
(letsubs [had-reply (atom nil)
contact-request @(re-frame/subscribe [:chats/sending-contact-request])]
{:component-did-mount #(focus-input-on-contact-request contact-request had-reply text-input-ref)}
(when contact-request
[contact-request-message-wrapper contact-request])))
@@ -1,59 +0,0 @@
(ns status-im.ui.screens.chat.components.edit
(:require [quo.components.animated.pressable :as pressable]
[quo.core :as quo]
[quo.design-system.colors :as quo.colors]
[quo.react :as quo.react]
[quo.react-native :as rn]
[re-frame.core :as re-frame]
[utils.i18n :as i18n]
[status-im.ui.components.icons.icons :as icons]
[status-im.ui.screens.chat.components.style :as styles]))
(defn input-focus
[text-input-ref]
(some-> ^js (quo.react/current-ref text-input-ref)
.focus))
(defn edit-message
[]
[rn/view {:style {:flex-direction :row}}
[rn/view {}
[icons/icon :tiny-icons/tiny-edit {:container-style {:margin-top 5}}]]
[rn/view {:style (styles/reply-content)}
[quo/text
{:weight :medium
:number-of-lines 1}
(i18n/label :t/editing-message)]]
[rn/view
[pressable/pressable
{:on-press #(re-frame/dispatch [:chat.ui/cancel-message-edit])
:accessibility-label :cancel-message-reply}
[icons/icon :main-icons/close-circle
{:container-style (styles/close-button)
:color (:icon-02 @quo.colors/theme)}]]]])
(defn focus-input-on-edit
[edit had-edit text-input-ref]
;;when we show edit we focus input
(when-not (= edit @had-edit)
(reset! had-edit edit)
(when edit
(js/setTimeout #(input-focus text-input-ref) 250))))
(defn edit-message-wrapper
[edit]
[rn/view
{:style {:padding-horizontal 15
:border-top-width 1
:border-top-color (:ui-01 @quo.colors/theme)
:padding-vertical 8}}
[edit-message edit]])
(defn edit-message-auto-focus-wrapper
[text-input-ref]
(let [had-edit (atom nil)]
(fn []
(let [edit @(re-frame/subscribe [:chats/edit-message])]
(focus-input-on-edit edit had-edit text-input-ref)
(when edit
[edit-message-wrapper])))))
@@ -1,50 +0,0 @@
(ns status-im.ui.screens.chat.components.hooks
(:require [quo.platform :as platform]
[quo.react :as react]
[quo.react-native :refer [use-window-dimensions] :as rn]
[react-native.safe-area :as safe-area]))
(def ^:private keyboard-change-event (if platform/android? "keyboardDidShow" "keyboardWillChangeFrame"))
(def default-kb-height (if platform/ios? 258 272))
(def min-duration 100)
(defn use-keyboard-dimension
[]
(let [{:keys [height]} (use-window-dimensions)
bottom (safe-area/get-bottom)
keyboard-listener (atom nil)
keyboard (react/state
{:height 0
:duration min-duration
:end-position height
:max-height (+ (if platform/ios? bottom 0) default-kb-height)})]
(react/effect!
(fn []
(letfn
[(dimensions-change [evt]
(swap! keyboard assoc :end-position (-> ^js evt .-window .-height)))
(keyboard-dimensions [evt]
(let [duration (.-duration ^js evt)
easing (.-easing ^js evt)
screen-y (-> ^js evt .-endCoordinates .-screenY)
new-height (- height screen-y)]
(when-not (= new-height (:height @keyboard))
(when (and duration easing platform/ios?)
(rn/configure-next
#js
{:duration (max min-duration duration)
:update #js
{:duration (max min-duration duration)
:type (-> ^js rn/layout-animation .-Types (aget easing))}})))
(reset! keyboard {:height new-height
:end-position screen-y
:duration (max min-duration duration)
:max-height (max new-height (:max-height @keyboard))})))]
(.addEventListener rn/dimensions "change" dimensions-change)
(reset! keyboard-listener (.addListener rn/keyboard keyboard-change-event keyboard-dimensions))
(fn []
(.removeEventListener rn/dimensions "change" dimensions-change)
(some-> ^js @keyboard-listener
.remove)))))
@keyboard))
@@ -1,408 +0,0 @@
(ns status-im.ui.screens.chat.components.input
(:require [clojure.string :as string]
[quo.components.animated.pressable :as pressable]
[quo.components.list.item :as list-item]
[quo.components.text :as text]
[quo.design-system.colors :as colors]
[quo.platform :as platform]
[quo.react :as quo.react]
[quo.react-native :as rn]
[re-frame.core :as re-frame]
[reagent.core :as reagent]
[status-im2.constants :as chat.constants]
[utils.i18n :as i18n]
[status-im.ui.components.icons.icons :as icons]
[status-im.ui.components.list.views :as list]
[status-im.ui.screens.chat.components.reply :as reply]
[status-im.ui.screens.chat.components.style :as styles]
[status-im.ui.screens.chat.photos :as photos]
[utils.re-frame :as rf]
[status-im.utils.utils :as utils.utils]))
(defn input-focus
[text-input-ref]
(some-> ^js (quo.react/current-ref text-input-ref)
.focus))
(def panel->icons
{:extensions :main-icons/commands
:images :main-icons/photo})
(defn touchable-icon
[{:keys [panel active set-active accessibility-label]}]
[pressable/pressable
{:type :scale
:accessibility-label accessibility-label
:on-press #(set-active (when-not (= active panel) panel))}
[rn/view {:style (styles/touchable-icon)}
[icons/icon
(panel->icons panel)
(styles/icon (= active panel))]]])
(defn touchable-stickers-icon
[{:keys [panel active set-active accessibility-label input-focus]}]
[pressable/pressable
{:type :scale
:accessibility-label accessibility-label
:on-press #(if (= active panel)
(input-focus)
(set-active panel))}
[rn/view {:style (styles/in-input-touchable-icon)}
(if (= active panel)
[icons/icon :main-icons/keyboard (styles/icon false)]
[icons/icon :main-icons/stickers (styles/icon false)])]])
;; TODO(Ferossgp): Move this into audio panel.
;; Instead of not changing panel we can show a placeholder with no permission
(defn- request-record-audio-permission
[set-active panel]
(re-frame/dispatch
[:request-permissions
{:permissions [:record-audio]
:on-allowed
#(set-active panel)
:on-denied
#(utils.utils/set-timeout
(fn []
(utils.utils/show-popup
(i18n/label :t/audio-recorder-error)
(i18n/label :t/audio-recorder-permissions-error)))
50)}]))
(defn touchable-audio-icon
[{:keys [panel active set-active accessibility-label input-focus]}]
[pressable/pressable
{:type :scale
:accessibility-label accessibility-label
:on-press #(if (= active panel)
(input-focus)
(request-record-audio-permission set-active panel))}
[rn/view {:style (styles/in-input-touchable-icon)}
(if (= active panel)
[icons/icon :main-icons/keyboard (styles/icon false)]
[icons/icon :main-icons/speech (styles/icon false)])]])
(defn send-button
[on-send contact-request]
[rn/touchable-opacity {:on-press-in on-send}
[rn/view {:style (styles/send-message-button)}
(when-not contact-request
[icons/icon :main-icons/arrow-up
{:container-style (styles/send-message-container contact-request)
:accessibility-label :send-message-button
:color (styles/send-icon-color)}])]])
(defn on-selection-change
[timeout-id last-text-change args]
(let [selection (.-selection ^js (.-nativeEvent ^js args))
start (.-start selection)
end (.-end selection)]
;; NOTE(rasom): on iOS we do not dispatch this event immediately
;; because it is needed only in case if selection is changed without
;; typing. Timeout might be canceled on `on-change`.
(when platform/ios?
(reset!
timeout-id
(utils.utils/set-timeout
#(re-frame/dispatch [:mention/on-selection-change
{:start start
:end end}])
50)))
;; NOTE(rasom): on Android we dispatch event only in case if there
;; was no text changes during last 50ms. `on-selection-change` is
;; dispatched after `on-change`, that's why there is no another way
;; to know whether selection was changed without typing.
(when (and platform/android?
(or (not @last-text-change)
(< 50 (- (js/Date.now) @last-text-change))))
(re-frame/dispatch [:mention/on-selection-change
{:start start
:end end}]))))
(defonce input-texts (atom {}))
(defonce mentions-enabled (reagent/atom {}))
(defonce chat-input-key (reagent/atom 1))
(re-frame/reg-fx
:chat.ui/clear-inputs-old
(fn []
(reset! input-texts {})
(reset! mentions-enabled {})
(reset! chat-input-key 1)))
(defn force-text-input-update!
"force-text-input-update! forces the
input to re-render, necessary when we are setting value"
[]
(swap! chat-input-key inc))
(defn show-send
[{:keys [actions-ref send-ref sticker-ref]}]
(when actions-ref
(quo.react/set-native-props actions-ref #js {:width 0 :left -88}))
(quo.react/set-native-props send-ref #js {:width nil :right nil})
(when sticker-ref
(quo.react/set-native-props sticker-ref #js {:width 0 :right -100})))
(defn hide-send
[{:keys [actions-ref send-ref sticker-ref]}]
(when actions-ref
(quo.react/set-native-props actions-ref #js {:width nil :left nil}))
(quo.react/set-native-props send-ref #js {:width 0 :right -100})
(when sticker-ref
(quo.react/set-native-props sticker-ref #js {:width nil :right nil})))
(defn reset-input
[refs chat-id]
(some-> ^js (quo.react/current-ref (:text-input-ref refs))
.clear)
(swap! mentions-enabled update :render not)
(swap! input-texts dissoc chat-id))
(defn clear-input
[chat-id refs]
(hide-send refs)
(if (get @mentions-enabled chat-id)
(do
(swap! mentions-enabled dissoc chat-id)
;;we need this timeout, because if we clear text input and first index was a mention object with
;;blue color,
;;after clearing text will be typed with this blue color, so we render white text first and then
;;clear it
(js/setTimeout #(reset-input refs chat-id) 50))
(reset-input refs chat-id)))
(defn on-text-change
[val chat-id]
(swap! input-texts assoc chat-id val)
;;we still store it in app-db for mentions, we don't have reactions in views
(re-frame/dispatch [:chat.ui/set-chat-input-text val]))
(defn on-change
[last-text-change timeout-id refs chat-id sending-image args]
(let [text (.-text ^js (.-nativeEvent ^js args))
prev-text (get @input-texts chat-id)]
(when (and (seq prev-text) (empty? text) (not sending-image))
(hide-send refs))
(when (and (empty? prev-text) (seq text))
(show-send refs))
(when (and (not (get @mentions-enabled chat-id)) (string/index-of text "@"))
(swap! mentions-enabled assoc chat-id true))
;; NOTE(rasom): on iOS `on-selection-change` is canceled in case if it
;; happens during typing because it is not needed for mention
;; suggestions calculation
(when (and platform/ios? @timeout-id)
(utils.utils/clear-timeout @timeout-id))
(when platform/android?
(reset! last-text-change (js/Date.now)))
(on-text-change text chat-id)))
(rf/defn set-input-text
"Set input text for current-chat. Takes db and input text and cofx
as arguments and returns new fx. Always clear all validation messages."
{:events [:chat.ui.input/set-chat-input-text]}
[{:keys [db]} text chat-id]
(let [params [chat-id text]
method "wakuext_chatMentionToInputField"]
{:json-rpc/call [{:method method
:params params
:on-success #(rf/dispatch [:mention/on-to-input-field-success %])
:on-error #(rf/dispatch [:mention/on-error
{:method method
:params params} %])}]}))
(defn on-text-input
[chat-id args]
(let [native-event (.-nativeEvent ^js args)
text (.-text ^js native-event)]
(when (and (not (get @mentions-enabled chat-id)) (string/index-of text "@"))
(swap! mentions-enabled assoc chat-id true))))
(defn text-input
[{:keys [set-active-panel refs chat-id sending-image]}]
(let [cooldown-enabled? @(re-frame/subscribe [:chats/current-chat-cooldown-enabled?])
timeout-id (atom nil)
last-text-change (atom nil)
mentions-enabled (get @mentions-enabled chat-id)
contact-request @(re-frame/subscribe [:chats/sending-contact-request])]
[rn/text-input
{:style (styles/text-input contact-request)
:ref (:text-input-ref refs)
:max-font-size-multiplier 1
:accessibility-label :chat-message-input
:text-align-vertical :center
:multiline true
:editable (not cooldown-enabled?)
:blur-on-submit false
:auto-focus false
:on-focus #(set-active-panel nil)
:max-length chat.constants/max-text-size
:placeholder-text-color (:text-02 @colors/theme)
:placeholder (if cooldown-enabled?
(i18n/label :cooldown/text-input-disabled)
(i18n/label :t/type-a-message))
:underline-color-android :transparent
:auto-capitalize :sentences
:on-selection-change (partial on-selection-change
timeout-id
last-text-change)
:on-change
(partial on-change last-text-change timeout-id refs chat-id sending-image)
:on-text-input (partial on-text-input chat-id)}
(if mentions-enabled
(for [[idx [type text]] (map-indexed
(fn [idx item]
[idx item])
@(re-frame/subscribe [:chat/input-with-mentions]))]
^{:key (str idx "_" type "_" text)}
[rn/text (when (= type :mention) {:style {:color "#0DA4C9"}})
text])
(get @input-texts chat-id))]))
(defn mention-item
[[public-key {:keys [alias name nickname] :as user}] _ _ text-input-ref]
(let [ens-name? (not= alias name)]
[list-item/list-item
(cond->
{:icon [photos/member-photo public-key]
:size :small
:text-size :small
:title
[text/text
{:weight :medium
:ellipsize-mode :tail
:number-of-lines 1
:size :small}
(if nickname
nickname
name)
(when nickname
[text/text
{:weight :regular
:color :secondary
:ellipsize-mode :tail
:size :small}
" "
(when ens-name?
"@")
name])]
:title-text-weight :medium
:on-press
(fn []
(re-frame/dispatch [:chat.ui/select-mention text-input-ref user]))}
ens-name?
(assoc :subtitle alias))]))
(def chat-toolbar-height (reagent/atom nil))
(defn autocomplete-mentions
[text-input-ref bottom]
(let [suggestions @(re-frame/subscribe [:chat/mention-suggestions])]
(when (seq suggestions)
(let [height (+ 16 (* 52 (min 4.5 (count suggestions))))]
[rn/view
{:style (styles/autocomplete-container bottom)
:accessibility-label :suggestions-list}
[rn/view
{:style {:height height}}
[list/flat-list
{:keyboard-should-persist-taps :always
:footer [rn/view {:style {:height 8}}]
:header [rn/view {:style {:height 8}}]
:data suggestions
:key-fn first
:render-data text-input-ref
:render-fn mention-item}]]]))))
(defn on-chat-toolbar-layout
[^js ev]
(reset! chat-toolbar-height (-> ev .-nativeEvent .-layout .-height)))
(defn send-image
[]
(let [sending-image @(re-frame/subscribe [:chats/sending-image])]
(when (seq sending-image)
[reply/send-image sending-image])))
(defn actions
[extensions image show-send actions-ref active-panel set-active-panel contact-request]
[rn/view
{:style (styles/actions-wrapper (and (not contact-request) show-send))
:ref actions-ref}
(when extensions
[touchable-icon
{:panel :extensions
:accessibility-label :show-extensions-icon
:active active-panel
:set-active set-active-panel}])
(when image
[touchable-icon
{:panel :images
:accessibility-label :show-photo-icon
:active active-panel
:set-active set-active-panel}])])
(defn chat-toolbar
[{:keys [chat-id]}]
(let [actions-ref (quo.react/create-ref)
send-ref (quo.react/create-ref)
sticker-ref (quo.react/create-ref)
toolbar-options (re-frame/subscribe [:chats/chat-toolbar])
show-send (seq (get @input-texts chat-id))]
(fn [{:keys [active-panel set-active-panel text-input-ref chat-id]}]
(let [;we want to control components on native level, so instead of RN state we set native props
;via reference
;we don't react on input text in this view, @input-texts below is a regular atom
refs {:actions-ref actions-ref
:send-ref send-ref
:sticker-ref sticker-ref
:text-input-ref text-input-ref}
{:keys [send stickers image extensions audio
sending-image]} @toolbar-options
show-send (or show-send sending-image)
contact-request @(re-frame/subscribe [:chats/sending-contact-request])]
[rn/view
{:style (styles/toolbar)
:on-layout on-chat-toolbar-layout}
;; EXTENSIONS and IMAGE buttons
[actions extensions image show-send actions-ref active-panel set-active-panel contact-request]
[rn/view {:style (styles/input-container contact-request)}
[send-image]
[rn/view {:style styles/input-row}
[text-input
{:chat-id chat-id
:sending-image sending-image
:refs refs
:set-active-panel set-active-panel}]
;; SEND button
[rn/view {:ref send-ref :style (when-not show-send {:width 0 :right -100})}
(when send
[send-button
#(do (clear-input chat-id refs)
(re-frame/dispatch [:chat.ui/send-current-message]))
contact-request])]
;; STICKERS and AUDIO buttons
(when-not @(re-frame/subscribe [:chats/edit-message])
[rn/view
{:style (merge {:flex-direction :row} (when show-send {:width 0 :right -100}))
:ref sticker-ref}
(when stickers
[touchable-stickers-icon
{:panel :stickers
:accessibility-label :show-stickers-icon
:active active-panel
:input-focus #(input-focus text-input-ref)
:set-active set-active-panel}])
(when audio
[touchable-audio-icon
{:panel :audio
:accessibility-label :show-audio-message-icon
:active active-panel
:input-focus #(input-focus text-input-ref)
:set-active set-active-panel}])])]]]))))
@@ -1,121 +0,0 @@
(ns status-im.ui.screens.chat.components.reply
(:require [clojure.string :as string]
[quo.components.animated.pressable :as pressable]
[quo.core :as quo]
[quo.design-system.colors :as quo.colors]
[quo.react :as quo.react]
[quo.react-native :as rn]
[re-frame.core :as re-frame]
[status-im.ethereum.stateofus :as stateofus]
[utils.i18n :as i18n]
[status-im.ui.components.icons.icons :as icons]
[status-im.ui.screens.chat.components.style :as styles]))
(def ^:private reply-symbol "↪ ")
(defn input-focus
[text-input-ref]
(some-> ^js (quo.react/current-ref text-input-ref)
.focus))
(defn format-author
[contact-name]
(let [author (if (or (= (aget contact-name 0) "@")
;; in case of replies
(= (aget contact-name 1) "@"))
(or (stateofus/username contact-name)
(subs contact-name 0 81))
contact-name)]
(i18n/label :replying-to {:author author})))
(defn format-reply-author
[from username current-public-key]
(or (and (= from current-public-key)
(str reply-symbol (i18n/label :t/You)))
(str reply-symbol (format-author username))))
(defn get-quoted-text-with-mentions
[parsed-text]
(string/join
(mapv (fn [{:keys [type literal children]}]
(cond
(= type "paragraph")
(get-quoted-text-with-mentions children)
(= type "mention")
@(re-frame/subscribe [:messages/resolve-mention literal])
(seq children)
(get-quoted-text-with-mentions children)
:else
literal))
parsed-text)))
(defn reply-message
[{:keys [from]}]
(let [contact-name @(re-frame/subscribe [:contacts/contact-name-by-identity from])
current-public-key @(re-frame/subscribe [:multiaccount/public-key])]
[rn/view {:style {:flex-direction :row}}
[rn/view {:style (styles/reply-content)}
[quo/text
{:weight :medium
:number-of-lines 1
:style {:line-height 18}}
(format-reply-author from contact-name current-public-key)]]
[rn/view
[pressable/pressable
{:on-press #(re-frame/dispatch [:chat.ui/cancel-message-reply])
:accessibility-label :cancel-message-reply}
[icons/icon :main-icons/close-circle
{:container-style (styles/close-button)
:color (:icon-02 @quo.colors/theme)}]]]]))
(defn send-image
[images]
[rn/view {:style (styles/reply-container-image)}
[rn/scroll-view
{:horizontal true
:style (styles/reply-content)}
(for [{:keys [uri]} (vals images)]
^{:key uri}
[rn/image
{:source {:uri uri}
:style {:width 56
:height 56
:border-radius 4
:margin-right 4}}])]
[rn/view
[pressable/pressable
{:on-press #(re-frame/dispatch [:chat.ui/cancel-sending-image])
:accessibility-label :cancel-send-image}
[icons/icon :main-icons/close-circle
{:container-style (styles/close-button)
:color quo.colors/white}]]]])
(defn focus-input-on-reply
[reply had-reply text-input-ref]
;;when we show reply we focus input
(when-not (= reply @had-reply)
(reset! had-reply reply)
(when reply
;; A setTimeout of 0 is necessary to ensure the statement is enqueued and will get executed ASAP.
(js/setTimeout #(input-focus text-input-ref) 0))))
(defn reply-message-wrapper
[reply]
[rn/view
{:style {:padding-horizontal 15
:border-top-width 1
:border-top-color (:ui-01 @quo.colors/theme)
:padding-vertical 8}}
[reply-message reply]])
(defn reply-message-auto-focus-wrapper
[text-input-ref]
(let [had-reply (atom nil)]
(fn []
(let [reply @(re-frame/subscribe [:chats/reply-message])]
(focus-input-on-reply reply had-reply text-input-ref)
(when reply
[reply-message-wrapper reply])))))
@@ -1,152 +0,0 @@
(ns status-im.ui.screens.chat.components.style
(:require [quo.design-system.colors :as colors]
[quo.design-system.typography :as typography]
[quo.platform :as platform]))
(defn toolbar
[]
{:min-height 52
:padding-vertical 8
:border-top-width 1
:border-top-color (:ui-01 @colors/theme)
:align-items :flex-end
:flex-direction :row})
(defn input-container
[contact-request]
{:background-color (:ui-01 @colors/theme)
:flex 1
:height (when contact-request 44)
:border-top-left-radius (if contact-request 8 16)
:border-top-right-radius (if contact-request 8 16)
:border-bottom-right-radius (if contact-request 8 4)
:border-bottom-left-radius (if contact-request 8 16)
:margin-horizontal 8})
(def input-row
{:flex-direction :row
:overflow :hidden
:align-items :flex-end})
(defn text-input-wrapper
[]
(merge {:flex-direction :row
:align-items :flex-start
:flex 1
:min-height 34
:max-height 144}
(when platform/ios?
{:padding-top 2})))
(defn text-input
[contact-request]
(merge typography/font-regular
typography/base
{:flex 1
:min-height 34
:max-height 144
:margin 0
:flex-shrink 1
:color (:text-01 @colors/theme)
:padding-horizontal 12}
(if platform/android?
{:padding-vertical 2}
{:padding-top (if contact-request 10 2)
:padding-bottom (if contact-request 5 6)})))
(defn actions-wrapper
[show-send]
(merge (when show-send
{:width 0 :left -88})
{:flex-direction :row
:padding-left 4
:min-height 34}))
(defn touchable-icon
[]
{:padding-horizontal 10
:padding-vertical 5
:justify-content :center
:align-items :center})
(defn in-input-touchable-icon
[]
{:padding-horizontal 6
:padding-vertical 5
:justify-content :center
:align-items :center})
(defn icon
[active]
{:color (if active
(:icon-04 @colors/theme)
(:icon-02 @colors/theme))})
(defn reply-container-image
[]
{:border-top-left-radius 14
:border-top-right-radius 14
:border-bottom-right-radius 4
:border-bottom-left-radius 14
:margin 2
:flex-direction :row
:background-color (:ui-03 @colors/theme)})
(defn reply-container
[]
{:flex-direction :row})
(defn reply-content
[]
{:padding-vertical 6
:padding-horizontal 10
:flex 1})
(defn quoted-message
[pin?]
(merge {:flex-direction :row
:align-items :center
:width "45%"}
(when-not pin?
{:position :absolute
:left 34
:top 3})))
(defn contact-request-content
[]
{:flex 1
:flex-direction :row
:justify-content :space-between})
(defn close-button
[]
{:margin-top 3})
(defn send-message-button
[]
{:margin-vertical 4
:margin-horizontal 5})
(defn send-message-container
[contact-request]
{:background-color (:interactive-01 @colors/theme)
:width 26
:height (if contact-request 44 26)
:border-radius (if contact-request 22 13)
:justify-content :center
:align-items :center})
(defn send-icon-color
[]
colors/white)
(defn autocomplete-container
[bottom]
{:position :absolute
:left 0
:right 0
:bottom bottom
:background-color (colors/get-color :ui-background)
:border-top-width 1
:border-top-color (colors/get-color :ui-01)
:z-index 3})
+1 -43
View File
@@ -4,10 +4,8 @@
[status-im2.constants :as constants]
[utils.i18n :as i18n]
[status-im.ui.components.chat-icon.screen :as chat-icon]
[status-im.ui.components.list-selection :as list-selection]
[status-im.ui.components.react :as react]
[status-im.ui.screens.chat.styles.message.sheets :as sheets.styles]
[status-im.utils.universal-links.utils :as universal-links]))
[status-im.ui.screens.chat.styles.message.sheets :as sheets.styles]))
(defn hide-sheet-and-dispatch
[event]
@@ -42,41 +40,6 @@
:icon :main-icons/delete
:on-press #(re-frame/dispatch [:chat.ui/show-remove-confirmation chat-id])}]]))
(defn public-chat-accents
[chat-id]
(let [link (universal-links/generate-link :public-chat :external chat-id)
message (i18n/label :t/share-public-chat-text {:link link})]
[react/view
[quo/list-item
{:theme :accent
:title (i18n/label :t/share-chat)
:accessibility-label :share-chat-button
:icon :main-icons/share
:on-press (fn []
(re-frame/dispatch [:bottom-sheet/hide-old])
;; https://github.com/facebook/react-native/pull/26839
(js/setTimeout
#(list-selection/open-share {:message message})
250))}]
[quo/list-item
{:theme :accent
:title (i18n/label :t/mark-all-read)
:accessibility-label :mark-all-read-button
:icon :main-icons/check
:on-press #(hide-sheet-and-dispatch [:chat.ui/mark-all-read-pressed chat-id])}]
[quo/list-item
{:theme :accent
:title (i18n/label :t/clear-history)
:accessibility-label :clear-history-button
:icon :main-icons/close
:on-press #(re-frame/dispatch [:chat.ui/show-clear-history-confirmation chat-id])}]
[quo/list-item
{:theme :negative
:title (i18n/label :t/delete-chat)
:accessibility-label :delete-chat-button
:icon :main-icons/delete
:on-press #(re-frame/dispatch [:chat.ui/show-remove-confirmation chat-id])}]]))
(defn community-chat-accents
[]
(fn [{:keys [chat-id group-chat chat-name color emoji]}]
@@ -150,11 +113,6 @@
[{:keys [chat-type chat-id]
:as current-chat}]
(cond
(#{constants/public-chat-type
constants/profile-chat-type
constants/timeline-chat-type}
chat-type)
[public-chat-accents chat-id]
(= chat-type constants/community-chat-type)
[community-chat-accents current-chat]
@@ -19,10 +19,10 @@
[status-im.ui.components.topbar :as topbar]
[status-im.ui.screens.chat.photos :as photos]
[status-im.ui.screens.chat.sheets :as sheets]
[status-im.ui.screens.home.views.inner-item :as inner-item]
[status-im.utils.core :as utils]
[utils.datetime :as datetime]
[utils.re-frame :as rf]))
[utils.re-frame :as rf]
[status-im.ui.screens.home.views.inner-item :as inner-item]))
(def request-cooldown-ms (* 24 60 60 1000))
@@ -1,183 +0,0 @@
(ns status-im.ui.screens.communities.views
(:require [quo.core :as quo]
[quo.design-system.colors :as quo.colors]
[status-im.communities.core :as communities]
[status-im2.constants :as constants]
[utils.i18n :as i18n]
[status-im.ui.components.badge :as badge]
[status-im.ui.components.copyable-text :as copyable-text]
[status-im.ui.components.list.views :as list]
[status-im.ui.components.react :as react]
[status-im.ui.components.toolbar :as toolbar]
[status-im.ui.components.topbar :as topbar]
[status-im.ui.screens.communities.community :as community]
[status-im.ui.screens.communities.icon :as communities.icon]
[status-im.utils.core :as utils]
[utils.re-frame :as rf]))
(defn hide-sheet-and-dispatch
[event]
(rf/dispatch [:bottom-sheet/hide-old])
(rf/dispatch event))
(defn community-unviewed-count
[id]
(let [{:keys [unviewed-messages-count unviewed-mentions-count]} (rf/sub [:communities/unviewed-counts
id])]
(cond
(pos? unviewed-mentions-count)
[badge/message-counter unviewed-mentions-count]
(pos? unviewed-messages-count)
[react/view
{:style {:background-color quo.colors/blue
:border-radius 6
:margin-right 5
:margin-top 2
:width 12
:height 12}
:accessibility-label :unviewed-messages-public}])))
(defn community-home-list-item
[{:keys [id name last?] :as community}]
[react/touchable-opacity
{:style (merge {:height 64}
(when last?
{:border-bottom-color (quo.colors/get-color :ui-01)
:border-bottom-width 1}))
:on-press (fn []
(rf/dispatch [:communities/load-category-states id])
(rf/dispatch [:dismiss-keyboard])
(rf/dispatch [:navigate-to :community-overview id]))
:on-long-press #(rf/dispatch [:bottom-sheet/show-sheet-old
{:content (fn []
[community/community-actions community])}])}
[:<>
[react/view {:top 12 :left 16 :position :absolute}
[communities.icon/community-icon community]]
[react/view
{:style {:margin-left 72
:flex-direction :row
:flex 1}
:accessibility-label :chat-name-text}
[react/view
{:flex-direction :row
:flex 1
:padding-right 16
:align-items :center}
[quo/text
{:weight :medium
:accessibility-label :chat-name-text
:font-size 17
:ellipsize-mode :tail
:number-of-lines 1}
name]]
[react/view
{:flex-direction :row
:flex 1
:margin-right 15
:justify-content :flex-end
:align-items :center}
[community-unviewed-count id]]]]])
(defn community-list-item
[{:keys [id permissions members name description] :as community}]
(let [members-count (count members)
show-members-count? (not= (:access permissions) constants/community-no-membership-access)]
[quo/list-item
{:icon [communities.icon/community-icon community]
:title [react/view
{:flex-direction :row
:flex 1
:padding-right 16
:align-items :center}
[quo/text
{:weight :medium
:accessibility-label :community-name-text
:ellipsize-mode :tail
:number-of-lines 1}
(utils/truncate-str name 30)]]
:title-accessibility-label :community-name-text
:subtitle [react/view
[quo/text {:number-of-lines 1}
description]
[quo/text
{:number-of-lines 1
:color :secondary}
(if show-members-count?
(i18n/label-pluralize members-count
:t/community-members
{:count members-count})
(i18n/label :t/open-membership))]]
:on-press #(do
(rf/dispatch [:dismiss-keyboard])
(rf/dispatch [:navigate-to :community-overview id]))}]))
(defn communities-actions
[]
[:<>
[quo/list-item
{:theme :accent
:title (i18n/label :t/import-community)
:accessibility-label :community-import-community
:icon :main-icons/objects
:on-press #(hide-sheet-and-dispatch [:navigate-to :community-import])}]
[quo/list-item
{:theme :accent
:title (i18n/label :t/create-community)
:accessibility-label :community-create-community
:icon :main-icons/add
:on-press #(hide-sheet-and-dispatch [::communities/open-create-community])}]])
(defn communities-list
[communities]
[list/section-list
{:content-container-style {:padding-vertical 8}
:key-fn :id
:keyboard-should-persist-taps :always
:sticky-section-headers-enabled false
:sections communities
:render-section-header-fn quo/list-index
:render-fn community-list-item}])
(defn communities
[]
(let [communities (rf/sub [:communities/section-list])]
[:<>
[topbar/topbar
{:title (i18n/label :t/communities)
:right-accessories
[{:icon :main-icons/more
:accessibility-label :chat-menu-button
:on-press
#(rf/dispatch [:bottom-sheet/show-sheet-old
{:content (fn []
[communities-actions])
:height 256}])}]}]
[communities-list communities]
[toolbar/toolbar
{:show-border? true
:center [quo/button
{:on-press #(rf/dispatch [::communities/open-create-community])
:type :secondary}
(i18n/label :t/create-community)]}]]))
(defn export-community
[]
(let [{:keys [community-key]} (rf/sub [:popover/popover])]
[react/view
{:style {:padding-top 16
:padding-horizontal 16}}
[quo/text
{:size :x-large
:align :center}
(i18n/label :t/community-private-key)]
[copyable-text/copyable-text-view
{:container-style {:padding-vertical 12}
:copied-text community-key}
[quo/text
{:number-of-lines 1
:ellipsize-mode :middle
:accessibility-label :chat-key
:monospace true}
community-key]]]))
@@ -11,8 +11,7 @@
:title (i18n/label :t/faq)
:accessibility-label :faq-button
:on-press
#(.openURL ^js react/linking
constants/faq)
#(.openURL ^js react/linking constants/faq)
:chevron true}
{:size :small
:title (i18n/label :t/glossary)
@@ -25,13 +24,6 @@
:accessibility-label :submit-bug-button
:on-press
#(re-frame/dispatch [:open-modal :bug-report])
:chevron true}
{:size :small
:title (i18n/label :t/request-feature)
:accessibility-label :request-a-feature-button
:on-press
#(re-frame/dispatch [:chat.ui/start-public-chat
"support"])
:chevron true}])
(defn help-center
@@ -1,7 +0,0 @@
(ns status-im.ui.screens.home.sheet.styles)
(def add-new-view-wrapper
{:style {:flex-direction :row
:padding-left 16
:padding-right 8
:justify-content :space-between
:align-items :center}})
@@ -1,62 +0,0 @@
(ns status-im.ui.screens.home.sheet.views
(:require [quo.core :as quo]
[utils.re-frame :as rf]
[utils.i18n :as i18n]
[status-im.qr-scanner.core :as qr-scanner]
[status-im.ui.components.invite.views :as invite]
[status-im.ui.components.react :as rn]
[status-im2.config :as config]
[status-im.ui.screens.home.sheet.styles :as style]))
(defn- hide-sheet-and-dispatch
[event]
(rf/dispatch [:bottom-sheet/hide-old])
(rf/dispatch event))
(defn add-new-view
[]
[rn/view
[rn/view style/add-new-view-wrapper
[quo/text
{:size :large
:weight :bold}
(i18n/label :t/open-home)]
[quo/button
{:type :icon
:theme :icon
:accessibility-label :universal-qr-scanner
:on-press #(hide-sheet-and-dispatch
[::qr-scanner/scan-code
{:handler ::qr-scanner/on-scan-success}])}
:main-icons/qr]]
[quo/list-item
{:theme :accent
:title (i18n/label :t/start-new-chat)
:accessibility-label :start-1-1-chat-button
:icon :main-icons/one-on-one-chat
:on-press #(hide-sheet-and-dispatch [:open-modal :new-chat])}]
(when config/group-chat-enabled?
[quo/list-item
{:theme :accent
:title (i18n/label :t/start-group-chat)
:accessibility-label :start-group-chat-button
:icon :main-icons/group-chat
:on-press #(hide-sheet-and-dispatch [:contact.ui/start-group-chat-pressed])}])
[quo/list-item
{:theme :accent
:title (i18n/label :t/new-public-group-chat)
:accessibility-label :join-public-chat-button
:icon :main-icons/public-chat
:on-press #(hide-sheet-and-dispatch [:open-modal :new-public-chat])}]
[quo/list-item
{:theme :accent
:title (i18n/label :t/communities-alpha)
:accessibility-label :communities-button
:icon :main-icons/communities
:on-press #(hide-sheet-and-dispatch [:navigate-to :communities])}]
[invite/list-item
{:accessibility-label :chats-menu-invite-friends-button}]])
;; Deprecated
(def add-new
{:content add-new-view})
-375
View File
@@ -1,375 +0,0 @@
(ns status-im.ui.screens.home.views
(:require
[quo.core :as quo]
[quo.design-system.colors :as colors]
[quo2.components.buttons.button :as quo2.button]
[quo2.components.markdown.text :as quo2.text]
[quo2.foundations.colors :as quo2.colors]
[re-frame.core :as re-frame]
[reagent.core :as reagent]
[status-im.add-new.db :as db]
[utils.i18n :as i18n]
[status-im.qr-scanner.core :as qr-scanner]
[status-im.react-native.resources :as resources]
[status-im.ui.components.chat-icon.screen :as chat-icon.screen]
[status-im.ui.components.chat-icon.styles :as chat-icon.styles]
[status-im.ui.components.connectivity.view :as connectivity]
[status-im.ui.components.icons.icons :as icons]
[status-im.ui.components.invite.views :as invite]
[status-im.ui.components.list.views :as list]
[status-im.ui.components.plus-button :as components.plus-button]
[status-im.ui.components.react :as react]
[status-im.ui.components.search-input.view :as search-input]
[status-im.ui.components.topbar :as topbar]
[status-im.ui.screens.chat.sheets :as sheets]
[status-im.ui.screens.communities.views :as communities.views]
[status-im.ui.screens.home.styles :as styles]
[status-im.ui.screens.home.views.inner-item :as inner-item]
[status-im.utils.utils :as utils]
[utils.debounce :as debounce])
(:require-macros [status-im.utils.views :as views]))
(defn home-tooltip-view
[]
[react/view (styles/chat-tooltip)
[react/view
{:style {:width 66
:position :absolute
:top -6
:background-color colors/white
:align-items :center}}
[react/image
{:source (resources/get-image :empty-chats-header)
:style {:width 50 :height 50}}]]
[react/touchable-highlight
{:style {:position :absolute
:right 0
:top 0
:width 44
:height 44
:align-items :center
:justify-content :center}
:on-press #(re-frame/dispatch [:multiaccounts.ui/hide-home-tooltip])
:accessibility-label :hide-home-button}
[icons/icon :main-icons/close-circle {:color colors/gray}]]
[react/i18n-text {:style styles/no-chats-text :key :chat-and-transact}]
[react/view
{:align-items :center
:margin-top 8
:margin-bottom 12}
[invite/button]]])
(defn welcome-blank-page
[]
[react/view {:style {:flex 1 :flex-direction :row :align-items :center :justify-content :center}}
[react/i18n-text {:style styles/welcome-blank-text :key :welcome-blank-message}]])
(defonce search-active? (reagent/atom false))
(defn search-input-wrapper
[search-filter chats-empty]
[react/view
{:padding-horizontal 16
:padding-vertical 10}
[search-input/search-input
{:search-active? search-active?
:placeholder (i18n/label :t/search)
:border-radius 10
:search-filter search-filter
:before true
:on-cancel #(re-frame/dispatch [:search/home-filter-changed nil])
:on-blur (fn []
(when chats-empty
(re-frame/dispatch [:search/home-filter-changed nil]))
(re-frame/dispatch [:contacts/clear-new-identity]))
:on-focus (fn [search-filter]
(when-not search-filter
(re-frame/dispatch [:search/home-filter-changed ""])
(re-frame/dispatch [:contacts/clear-new-identity])))
:on-change (fn [text]
(re-frame/dispatch [:search/home-filter-changed text])
(re-frame/dispatch [:set-in [:contacts/new-identity :state] :searching])
(debounce/debounce-and-dispatch [:contacts/set-new-identity text] 300))}]])
(defn search-input-wrapper-old
[search-filter chats-empty]
[react/view
{:padding-horizontal 16
:padding-vertical 10}
[search-input/search-input-old
{:search-active? search-active?
:search-filter search-filter
:on-cancel #(re-frame/dispatch [:search/home-filter-changed nil])
:on-blur (fn []
(when chats-empty
(re-frame/dispatch [:search/home-filter-changed nil]))
(re-frame/dispatch [:contacts/clear-new-identity]))
:on-focus (fn [search-filter]
(when-not search-filter
(re-frame/dispatch [:search/home-filter-changed ""])
(re-frame/dispatch [:contacts/clear-new-identity])))
:on-change (fn [text]
(re-frame/dispatch [:search/home-filter-changed text])
(re-frame/dispatch [:set-in [:contacts/new-identity :state] :searching])
(debounce/debounce-and-dispatch [:new-chat/set-new-identity text] 300))}]])
(defn start-suggestion
[search-value]
(let [{:keys [state ens-name public-key compressed-key]}
@(re-frame/subscribe [:contacts/new-identity])
valid-private? (= state :valid)
valid-public? (db/valid-topic? search-value)]
(when (or valid-public? valid-private?)
[react/view
[quo/list-header (i18n/label :t/search-no-chat-found)]
(when valid-private?
[quo/list-item
{:theme :accent
:icon :main-icons/private-chat
:title (or ens-name
(utils/get-shortened-address
(or compressed-key public-key)))
:subtitle (i18n/label :t/join-new-private-chat)
:on-press (fn []
(debounce/dispatch-and-chill [:contact.ui/contact-code-submitted false] 3000)
(re-frame/dispatch [:search/home-filter-changed nil]))}])
(when valid-public?
[quo/list-item
{:theme :accent
:icon :main-icons/public-chat
:title (str "#" search-value)
:subtitle (i18n/label :t/join-new-public-chat)
:on-press (fn []
(re-frame/dispatch [:chat.ui/start-public-chat search-value])
(re-frame/dispatch [:set :public-group-topic nil])
(re-frame/dispatch [:search/home-filter-changed nil]))}])])))
(defn render-fn
[{:keys [chat-id] :as home-item}]
;; We use `chat-id` to distinguish communities from chats
(if chat-id
[inner-item/home-list-item
home-item
{:on-press (fn []
(re-frame/dispatch [:dismiss-keyboard])
(re-frame/dispatch [:chat/navigate-to-chat chat-id])
(re-frame/dispatch [:search/home-filter-changed nil]))
:on-long-press #(re-frame/dispatch [:bottom-sheet/show-sheet-old
{:content (fn []
[sheets/actions home-item])}])}]
[communities.views/community-home-list-item home-item]))
(defn render-fn-old
[{:keys [chat-id] :as home-item}]
;; We use `chat-id` to distinguish communities from chats
(if chat-id
[inner-item/home-list-item-old
home-item
{:on-press (fn []
(re-frame/dispatch [:dismiss-keyboard])
(re-frame/dispatch [:chat/navigate-to-chat chat-id])
(re-frame/dispatch [:search/home-filter-changed nil]))
:on-long-press #(re-frame/dispatch [:bottom-sheet/show-sheet-old
{:content (fn []
[sheets/actions home-item])}])}]
[communities.views/community-home-list-item home-item]))
(defn chat-list-key-fn
[item]
(or (:chat-id item) (:id item)))
(defn get-item-layout
[_ index]
#js {:length 64 :offset (* 64 index) :index index})
(views/defview communities-and-chats
[]
(views/letsubs [{:keys [items search-filter]} [:home-items]
hide-home-tooltip? [:hide-home-tooltip?]]
(if (and (empty? items)
(empty? search-filter)
hide-home-tooltip?
(not @search-active?))
[welcome-blank-page]
[list/flat-list
{:key-fn chat-list-key-fn
:getItemLayout get-item-layout
:on-end-reached #(re-frame/dispatch [:chat/show-more-chats])
:keyboard-should-persist-taps :always
:data items
:render-fn render-fn
:header [:<>
(when (or (seq items) @search-active? (seq search-filter))
[search-input-wrapper search-filter (empty? items)])
(when (and (empty? items)
(or @search-active? (seq search-filter)))
[start-suggestion search-filter])]
:footer (if (and (not hide-home-tooltip?) (not @search-active?))
[home-tooltip-view]
[react/view {:height 68}])}])))
(views/defview communities-and-chats-old
[]
(views/letsubs [{:keys [items search-filter]} [:home-items]
hide-home-tooltip? [:hide-home-tooltip?]]
(if (and (empty? items)
(empty? search-filter)
hide-home-tooltip?
(not @search-active?))
[welcome-blank-page]
[list/flat-list
{:key-fn chat-list-key-fn
:getItemLayout get-item-layout
:on-end-reached #(re-frame/dispatch [:chat/show-more-chats])
:keyboard-should-persist-taps :always
:data items
:render-fn render-fn-old
:header [:<>
(when (or (seq items) @search-active? (seq search-filter))
[search-input-wrapper-old search-filter (empty? items)])
(when (and (empty? items)
(or @search-active? (seq search-filter)))
[start-suggestion search-filter])]
:footer (if (and (not hide-home-tooltip?) (not @search-active?))
[home-tooltip-view]
[react/view {:height 68}])}])))
(views/defview chats-list
[]
(views/letsubs [loading? [:chats/loading?]]
[:<>
[connectivity/loading-indicator]
(if loading?
[react/view {:flex 1 :align-items :center :justify-content :center}
[react/activity-indicator {:animating true}]]
[communities-and-chats])]))
(views/defview chats-list-old
[]
(views/letsubs [loading? [:chats/loading?]]
[:<>
[connectivity/loading-indicator]
(if loading?
[react/view {:flex 1 :align-items :center :justify-content :center}
[react/activity-indicator {:animating true}]]
[communities-and-chats-old])]))
(views/defview plus-button
[]
(views/letsubs [logging-in? [:multiaccounts/login]]
[components.plus-button/plus-button-old
{:on-press (when-not logging-in?
(fn []
(re-frame/dispatch [:group-chat/clear-contacts])
(re-frame/dispatch [:bottom-sheet/show-sheet-old :start-a-new-chat {}])))
:loading logging-in?
:accessibility-label :new-chat-button}]))
(views/defview plus-button-old
[]
(views/letsubs [logging-in? [:multiaccounts/login]]
[components.plus-button/plus-button-old
{:on-press (when-not logging-in?
(fn []
(re-frame/dispatch [:group-chat/clear-contacts])
(re-frame/dispatch [:bottom-sheet/show-sheet-old :start-a-new-chat {}])))
:loading logging-in?
:accessibility-label :new-chat-button}]))
(views/defview notifications-button
[]
(views/letsubs [notif-count [:activity-center/unread-count]]
[react/view
[quo2.button/button
{:type :grey
:size 32
:width 32
:style {:margin-left 12}
:accessibility-label :notifications-button
:on-press #(re-frame/dispatch [:activity-center/open])}
[icons/icon :main-icons/notification2
{:color (quo2.colors/theme-colors quo2.colors/neutral-100 quo2.colors/white)}]]
(when (pos? notif-count)
[react/view
{:style (merge (styles/counter-public-container) {:top 5 :right 5})
:pointer-events :none}
[react/view
{:style styles/counter-public
:accessibility-label :notifications-unread-badge}]])]))
(defn qr-button
[]
[quo2.button/button
{:type :grey
:accessibility-label "qr-button"
:size 32
:width 32
:style {:margin-left 12}
:on-press #(do
(re-frame/dispatch [::qr-scanner/scan-code
{:handler ::qr-scanner/on-scan-success}]))}
[icons/icon :main-icons/qr2
{:color (quo2.colors/theme-colors quo2.colors/neutral-100 quo2.colors/white)}]])
(defn scan-button
[]
[quo2.button/button
{:type :grey
:size 32
:width 32
:accessibility-label "scan-button"
:on-press #(do
(re-frame/dispatch [::qr-scanner/scan-code
{:handler ::qr-scanner/on-scan-success}]))}
[icons/icon :main-icons/scan2
{:color (quo2.colors/theme-colors quo2.colors/neutral-100 quo2.colors/white)}]])
(views/defview profile-button
[]
(views/letsubs [{:keys [public-key preferred-name emoji]} [:multiaccount]]
[react/view
[chat-icon.screen/emoji-chat-icon-view public-key false preferred-name emoji
{:size 28
:chat-icon chat-icon.styles/chat-icon-chat-list}]]))
(defn home
[]
[react/keyboard-avoiding-view
{:style {:flex 1
:background-color (quo2.colors/theme-colors quo2.colors/neutral-5
quo2.colors/neutral-95)}
:ignore-offset true}
[topbar/topbar
{:navigation :none
:use-insets true
:background (quo2.colors/theme-colors quo2.colors/neutral-5 quo2.colors/neutral-95)
:left-component [react/view {:flex-direction :row :margin-left 16}
[profile-button]]
:right-component [react/view {:flex-direction :row :margin-right 16}
[scan-button]
[qr-button]
[notifications-button]]
:border-bottom false}]
[react/view
{:flex-direction :row
:justify-content :space-between
:align-items :center
:margin-horizontal 16
:margin-top 15
:margin-bottom 8}
[quo2.text/text {:size :heading-1 :weight :semi-bold} (i18n/label :t/messages)]
[plus-button]]
[chats-list]])
(defn home-old
[]
[react/keyboard-avoiding-view
{:style {:flex 1}
:ignore-offset true}
[topbar/topbar
{:title (i18n/label :t/chat)
:navigation :none
:right-component [react/view {:flex-direction :row :margin-right 16}
[connectivity/connectivity-button]]}]
[chats-list-old]
[plus-button-old]])
@@ -7,7 +7,6 @@
[status-im.ui.components.animation :as anim]
[status-im.ui.components.react :as react]
[status-im.ui.screens.biometric.views :as biometric]
[status-im.ui.screens.communities.views :as communities]
[status-im.ui.screens.keycard.frozen-card.view :as frozen-card]
[status-im.ui.screens.keycard.views :as keycard.views]
[status-im.ui.screens.multiaccounts.key-storage.views :as multiaccounts.key-storage]
@@ -167,9 +166,6 @@
(= :blocked-card view)
[keycard.views/blocked-card-popover]
(= :export-community view)
[communities/export-community]
(= :seed-key-uid-mismatch view)
[multiaccounts.key-storage/seed-key-uid-mismatch-popover]
+6 -31
View File
@@ -4,8 +4,6 @@
[utils.i18n :as i18n]
[status-im.ui.components.icons.icons :as icons]
[status-im.ui.screens.about-app.views :as about-app]
[status-im.ui.screens.add-new.new-chat.views :as new-chat]
[status-im.ui.screens.add-new.new-public-chat.view :as new-public-chat]
[status-im.ui.screens.advanced-settings.views :as advanced-settings]
[status-im.ui.screens.appearance.views :as appearance]
[status-im.ui.screens.backup-settings.view :as backup-settings]
@@ -30,7 +28,6 @@
[status-im.ui.screens.communities.reorder-categories :as reorder-categories]
[status-im.ui.screens.communities.requests-to-join :as requests-to-join]
[status-im.ui.screens.communities.select-category :as select-category]
[status-im.ui.screens.communities.views :as communities]
[status-im.ui.screens.contacts-list.views :as contacts-list]
[status-im.ui.screens.currency-settings.views :as currency-settings]
[status-im.ui.screens.dapps-permissions.views :as dapps-permissions]
@@ -277,13 +274,10 @@
:options {:insets {:top? true}}
;;TODO custom subtitle
:component group-chat/new-group}
{:name :communities
;;TODO custom
:options {:insets {:top? true}}
:component communities/communities}
{:name :community-import
:options {:topBar {:title {:text (i18n/label :t/import-community-title)}}
:insets {:top? true}}
:insets {:top? true
:bottom? true}}
:component communities.import/view}
{:name :community-edit
:options {:topBar {:title {:text (i18n/label :t/community-edit-title)}}
@@ -291,11 +285,13 @@
:component community.edit/edit}
{:name :community-create
:options {:topBar {:title {:text (i18n/label :t/new-community-title)}}
:insets {:top? true}}
:insets {:top? true
:bottom? true}}
:component communities.create/view}
{:name :community-membership
:options {:topBar {:title {:text (i18n/label :t/membership-title)}}
:insets {:top? true}}
:insets {:top? true
:bottom? true}}
:component membership/membership}
;;WALLET
@@ -576,20 +572,6 @@
;;MODALS
;[Chat] New Chat
{:name :new-chat
:on-focus [:contacts/new-chat-focus]
;;TODO accessories
:options {:insets {:top? true}}
:component new-chat/new-chat}
;[Chat] New Public chat
{:name :new-public-chat
:options {:topBar {:title {:text (i18n/label :t/new-public-group-chat)}}
:insets {:bottom? true
:top? true}}
:component new-public-chat/new-public-chat}
;[Chat] Link preview settings
{:name :link-preview-settings
:options {:topBar {:title {:text (i18n/label :t/chat-link-previews)}}
@@ -610,13 +592,6 @@
:options {:insets {:top? true}}
:component new-chat-aio/contact-selection-list}
;[Chat] New Public chat
{:name :new-public-chat
:options {:topBar {:title {:text (i18n/label :t/new-public-group-chat)}}
:insets {:bottom? true
:top? true}}
:component new-public-chat/new-public-chat}
;[Group chat] Add participants
{:name :add-participants-toggle-list
:on-focus [:group/add-participants-toggle-list]
+7 -13
View File
@@ -2,8 +2,6 @@
(:require [clojure.string :as string]
[goog.string :as gstring]
[re-frame.core :as re-frame]
[status-im.add-new.db :as new-chat.db]
[status-im.chat.models :as chat]
[status-im2.constants :as constants]
[status-im.ethereum.core :as ethereum]
[status-im.group-chats.core :as group-chats]
@@ -26,8 +24,7 @@
:internal "status-im:/"})
(def links
{:public-chat "%s/%s"
:private-chat "%s/p/%s"
{:private-chat "%s/p/%s"
:community-requests "%s/cr/%s"
:community "%s/c/%s"
:group-chat "%s/g/%s"
@@ -60,11 +57,15 @@
(log/info "universal-links: handling group" params)
(group-chats/create-from-link cofx params))
(defn own-public-key?
[{:keys [multiaccount]} public-key]
(= (:public-key multiaccount) public-key))
(rf/defn handle-private-chat
[{:keys [db] :as cofx} {:keys [chat-id]}]
(log/info "universal-links: handling private chat" chat-id)
(when chat-id
(if-not (new-chat.db/own-public-key? db chat-id)
(if-not (own-public-key? db chat-id)
{:dispatch [:chat.ui/start-chat chat-id]}
{:utils/show-popup {:title (i18n/label :t/unable-to-read-this-code)
:content (i18n/label :t/can-not-add-yourself)}})))
@@ -98,17 +99,11 @@
(log/info "universal-links: handling community chat" chat-id)
{:dispatch [:chat/navigate-to-chat chat-id]})
(rf/defn handle-public-chat
[cofx {:keys [topic]}]
(log/info "universal-links: handling public chat" topic)
(when (seq topic)
(chat/start-public-chat cofx topic)))
(rf/defn handle-view-profile
[{:keys [db] :as cofx} {:keys [public-key ens-name]}]
(log/info "universal-links: handling view profile" public-key)
(cond
(and public-key (new-chat.db/own-public-key? db public-key))
(and public-key (own-public-key? db public-key))
(rf/merge cofx
{:pop-to-root-fx :shell-stack}
(navigation/navigate-to :my-profile nil))
@@ -153,7 +148,6 @@
[cofx url {:keys [type] :as data}]
(case type
:group-chat (handle-group-chat cofx data)
:public-chat (handle-public-chat cofx data)
:private-chat (handle-private-chat cofx data)
:community-requests (handle-community-requests cofx data)
:community (handle-community cofx data)
@@ -8,8 +8,7 @@
:internal "status-im:/"})
(def links
{:public-chat "%s/%s"
:private-chat "%s/p/%s"
{:private-chat "%s/p/%s"
:user "%s/u/%s"
:browse "%s/b/%s"})
@@ -433,15 +433,6 @@
(notification-actions item inside-chat?)
(destructive-actions item)]])
(defn public-chat-actions
[{:keys [chat-id] :as item} inside-chat?]
[quo/action-drawer
[[(group-details-entry chat-id)
(when inside-chat?
(add-members-entry))]
(notification-actions item inside-chat?)
(destructive-actions item)]])
(defn private-group-chat-actions
[item inside-chat?]
[quo/action-drawer
@@ -470,8 +461,6 @@
(case chat-type
constants/one-to-one-chat-type
[one-to-one-actions item inside-chat?]
constants/public-chat-type
[public-chat-actions item inside-chat?]
constants/private-group-chat-type
[private-group-chat-actions item inside-chat?]))
+8
View File
@@ -45,3 +45,11 @@
(update-in [:db :toasts] assoc :hide-toasts-timer-set true)
(assoc :dispatch-later [{:ms 500 :dispatch [:toasts/hide-with-check]}]))
effect))))
(rf/defn close-all-toasts
{:events [:toasts/close-all-toasts]}
[{:keys [db]}]
{:dispatch-n (reduce (fn [acc toast]
(conj acc [:toasts/close (key toast)]))
[]
(get-in db [:toasts :toasts]))})
+1 -1
View File
@@ -159,4 +159,4 @@
(def default-kdf-iterations 3200)
(def ^:const new-composer-enabled? false)
(def ^:const new-composer-enabled? true)
@@ -0,0 +1,20 @@
(ns status-im2.contexts.chat.actions.view
(:require [quo2.core :as quo]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(defn new-chat
[]
[quo/action-drawer
[[{:icon :i/new-message
:accessibility-label :start-a-new-chat
:label (i18n/label :t/new-chat)
:on-press (fn []
(rf/dispatch [:group-chat/clear-contacts])
(rf/dispatch [:open-modal :start-a-new-chat]))}
{:icon :i/add-user
:accessibility-label :add-a-contact
:label (i18n/label :t/add-a-contact)
:sub-label (i18n/label :t/enter-a-chat-key)
:add-divider? true
:on-press #(rf/dispatch [:open-modal :new-contact])}]]])
@@ -18,4 +18,17 @@
{:position :absolute
:right 0
:z-index z-index
:background-color (colors/theme-colors colors/white colors/neutral-95)}))
:background-color (colors/theme-colors colors/white colors/neutral-95)
:padding-vertical 3
:padding-left 2}))
(defn record-audio-container
[]
{:align-items :center
:background-color :transparent
:flex-direction :row
:position :absolute
:left -20
:right -20
:bottom 0
:height constants/composer-default-height})
@@ -14,8 +14,7 @@
[status-im2.contexts.chat.bottom-sheet-composer.actions.style :as style]))
(defn send-message
[{:keys [input-ref]}
{:keys [text-value focused? maximized?]}
[{:keys [text-value focused? maximized?]}
{:keys [height saved-height last-height opacity background-y container-opacity]}
window-height]
(reanimated/animate height constants/input-height)
@@ -33,13 +32,10 @@
(rf/dispatch [:chat.ui/set-chat-input-text nil])
(reset! maximized? false)
(reset! text-value "")
(when @input-ref
(.clear ^js @input-ref))
(messages.list/scroll-to-bottom))
(defn send-button
[props
{:keys [text-value] :as state}
[{:keys [text-value] :as state}
animations
window-height
images?]
@@ -64,17 +60,62 @@
{:icon true
:size 32
:accessibility-label :send-message-button
:on-press #(send-message props state animations window-height)}
:on-press #(send-message state animations window-height)}
:i/arrow-up]])]))])
(defn audio-button
[]
[quo/button
{:on-press #(js/alert "to be added")
:icon true
:type :outline
:size 32}
:i/audio])
[{:keys [record-permission? record-reset-fn]}
{:keys [recording? gesture-enabled?]}
{:keys [container-opacity]}]
(let [audio (rf/sub [:chats/sending-audio])]
[rn/view
{:style (style/record-audio-container)
:pointer-events :box-none}
[quo/record-audio
{:record-audio-permission-granted record-permission?
:on-init (fn [reset-fn]
(reset! record-reset-fn reset-fn))
:on-start-recording (fn []
(reset! recording? true)
(reset! gesture-enabled? false)
(reanimated/animate container-opacity 1))
:audio-file audio
:on-reviewing-audio (fn [file]
(rf/dispatch [:chat.ui/set-input-audio file]))
:on-send (fn [{:keys [file-path duration]}]
(reset! recording? false)
(reset! gesture-enabled? true)
(rf/dispatch [:chat/send-audio file-path duration])
(reanimated/animate container-opacity
constants/empty-opacity)
(rf/dispatch [:chat.ui/set-input-audio nil]))
:on-cancel (fn []
(when @recording?
(reset! recording? false)
(reset! gesture-enabled? true)
(reanimated/animate container-opacity
constants/empty-opacity)
(rf/dispatch [:chat.ui/set-input-audio nil])))
:on-check-audio-permissions (fn []
(permissions/permission-granted?
:record-audio
#(reset! record-permission? %)
#(reset! record-permission? false)))
:on-request-record-audio-permission (fn []
(rf/dispatch
[:request-permissions
{:permissions [:record-audio]
:on-allowed
#(reset! record-permission? true)
:on-denied
#(js/setTimeout
(fn []
(alert/show-popup
(i18n/label :t/audio-recorder-error)
(i18n/label
:t/audio-recorder-permissions-error)))
50)}]))}]]))
(defn camera-button
[]
@@ -133,12 +174,14 @@
:i/format])
(defn view
[props state animations window-height insets images?]
[props state animations window-height insets images? audio]
[rn/view {:style style/actions-container}
[rn/view {:style {:flex-direction :row}}
[rn/view
{:style {:flex-direction :row
:display (if @(:recording? state) :none :flex)}}
[camera-button]
[image-button props animations insets]
[reaction-button]
[format-button]]
[send-button props state animations window-height images?]
[audio-button]])
[send-button state animations window-height images?]
[audio-button props state animations audio]])
@@ -19,6 +19,10 @@
(def ^:const reply-container-height 32)
(def ^:const edit-container-height 32)
(def ^:const mentions-max-height 240)
(def ^:const extra-content-offset (if platform/ios? 6 0))
(def ^:const content-change-threshold 10)
@@ -0,0 +1,23 @@
(ns status-im2.contexts.chat.bottom-sheet-composer.edit.style)
(def container
{:flex-direction :row
:height 24})
(def content-container
{:flex 1
:flex-direction :row})
(def icon-container
{:position :absolute
:left 0
:bottom -4
:width 16
:height 16})
(def text-container
{:position :absolute
:left 24
:top 3
:flex-direction :row
:align-items :center})
@@ -0,0 +1,49 @@
(ns status-im2.contexts.chat.bottom-sheet-composer.edit.view
(:require
[react-native.reanimated :as reanimated]
[status-im2.contexts.chat.bottom-sheet-composer.constants :as constants]
[utils.i18n :as i18n]
[quo2.core :as quo]
[quo2.foundations.colors :as colors]
[re-frame.core :as rf]
[react-native.core :as rn]
[status-im2.contexts.chat.bottom-sheet-composer.edit.style :as style]))
(defn edit-message
[cancel]
[rn/view
{:style style/container
:accessibility-label :edit-message}
[rn/view {:style style/content-container}
[quo/icon
:i/connector-dotted
{:size 16
:color (colors/theme-colors colors/neutral-40 colors/neutral-60)
:container-style style/icon-container}]
[rn/view {:style style/text-container}
[quo/text
{:weight :medium
:size :paragraph-2}
(i18n/label :t/editing-message)]]]
[quo/button
{:width 24
:size 24
:accessibility-label :edit-cancel-button
:on-press (fn []
(cancel)
(rf/dispatch [:chat.ui/cancel-message-edit]))
:type :outline}
[quo/icon :i/close
{:size 16
:color (colors/theme-colors colors/neutral-100 colors/neutral-40)}]]])
(defn- f-view
[edit cancel]
(let [height (reanimated/use-shared-value (if edit constants/edit-container-height 0))]
(rn/use-effect #(reanimated/animate height (if edit constants/edit-container-height 0)) [edit])
[reanimated/view {:style (reanimated/apply-animations-to-style {:height height} {})}
(when edit [edit-message cancel])]))
(defn view
[edit cancel]
[:f> f-view edit cancel])
@@ -65,12 +65,36 @@
(when-not reply?
(reset! replying? false)))
(defn edit-effect
[{:keys [text-value saved-cursor-position]}
{:keys [editing? input-ref]}
edit]
(let [edit-text (get-in edit [:content :text])]
(when (and (not @editing?) edit @input-ref)
(.focus ^js @input-ref)
(reset! editing? true)
(reset! text-value edit-text)
(reset! saved-cursor-position (count edit-text)))
(when-not edit-text
(reset! editing? false))))
(defn audio-effect
[{:keys [recording? gesture-enabled?]}
{:keys [container-opacity]}
audio]
(when (and audio (not @recording?))
(reset! recording? true)
(reset! gesture-enabled? false)
(reanimated/animate container-opacity 1)))
(defn empty-effect
[{:keys [text-value maximized? focused?]}
{:keys [container-opacity]}
images?
reply?]
(when (and (empty? @text-value) (not images?) (not reply?) (not @maximized?) (not @focused?))
reply?
audio]
(when
(and (empty? @text-value) (not images?) (not reply?) (not @maximized?) (not @focused?) (not audio))
(reanimated/animate-delay container-opacity constants/empty-opacity 200)))
(defn component-will-unmount
@@ -80,7 +104,8 @@
(.remove ^js @keyboard-frame-listener))
(defn initialize
[props state animations {:keys [max-height] :as dimensions} chat-input keyboard-height images? reply?]
[props state animations {:keys [max-height] :as dimensions} chat-input keyboard-height images? reply?
edit audio]
(rn/use-effect
(fn []
(maximized-effect state animations dimensions chat-input)
@@ -89,7 +114,9 @@
(kb-default-height-effect state)
(background-effect state animations dimensions chat-input)
(images-or-reply-effect animations props images? reply?)
(empty-effect state animations images? reply?)
(edit-effect state props edit)
(audio-effect state animations audio)
(empty-effect state animations images? reply? audio)
(kb/add-kb-listeners props state animations dimensions keyboard-height)
#(component-will-unmount props))
[max-height]))
@@ -1,11 +1,12 @@
(ns status-im2.contexts.chat.bottom-sheet-composer.handlers
(:require [react-native.reanimated :as reanimated]
[reagent.core :as reagent]
[oops.core :as oops]
[status-im2.contexts.chat.bottom-sheet-composer.constants :as constants]
[status-im2.contexts.chat.bottom-sheet-composer.keyboard :as kb]
[status-im2.contexts.chat.bottom-sheet-composer.utils :as utils]
[utils.re-frame :as rf]))
(:require
[react-native.reanimated :as reanimated]
[reagent.core :as reagent]
[oops.core :as oops]
[status-im2.contexts.chat.bottom-sheet-composer.constants :as constants]
[status-im2.contexts.chat.bottom-sheet-composer.keyboard :as kb]
[status-im2.contexts.chat.bottom-sheet-composer.utils :as utils]
[utils.re-frame :as rf]))
(defn focus
[{:keys [input-ref] :as props}
@@ -14,6 +15,7 @@
:as animations}
{:keys [max-height] :as dimensions}]
(reset! focused? true)
(rf/dispatch [:chat.ui/set-input-focused true])
(reanimated/animate height (reanimated/get-shared-value last-height))
(reanimated/set-shared-value saved-height (reanimated/get-shared-value last-height))
(reanimated/animate container-opacity 1)
@@ -39,12 +41,13 @@
(let [min-height (utils/get-min-height lines)
reopen-height (utils/calc-reopen-height text-value min-height content-height saved-height)]
(reset! focused? false)
(rf/dispatch [:chat.ui/set-input-focused false])
(reanimated/set-shared-value last-height reopen-height)
(reanimated/animate height min-height)
(reanimated/set-shared-value saved-height min-height)
(reanimated/animate opacity 0)
(js/setTimeout #(reanimated/set-shared-value background-y (- window-height)) 300)
(when (utils/empty-input? @text-value images reply)
(when (utils/empty-input? @text-value images reply nil)
(reanimated/animate container-opacity constants/empty-opacity))
(reanimated/animate gradient-opacity 0)
(reset! lock-selection? true)
@@ -68,7 +71,8 @@
(reanimated/animate height new-height)
(reanimated/set-shared-value saved-height new-height))
(when (= new-height max-height)
(reset! maximized? true))
(reset! maximized? true)
(rf/dispatch [:chat.ui/set-input-maximized true]))
(if (utils/show-background? saved-height max-height new-height)
(do
(reanimated/set-shared-value background-y 0)
@@ -80,10 +84,12 @@
(defn scroll
[event
{:keys [scroll-y]}
{:keys [gradient-z-index focused?]}
{:keys [gradient-opacity]}
{:keys [lines max-lines]}]
(let [y (oops/oget event "nativeEvent.contentOffset.y")]
(reset! scroll-y y)
(when (utils/show-top-gradient? y lines max-lines gradient-opacity focused?)
(reset! gradient-z-index 1)
(js/setTimeout #(reanimated/animate gradient-opacity 1) 0))
@@ -93,17 +99,22 @@
(defn change-text
[text
{:keys [input-ref]}
{:keys [text-value cursor-position]}]
{:keys [input-ref record-reset-fn]}
{:keys [text-value cursor-position recording?]}]
(reset! text-value text)
(reagent/next-tick #(when @input-ref
(.setNativeProps ^js @input-ref
(clj->js {:selection {:start @cursor-position
:end @cursor-position}}))))
(rf/dispatch [:chat.ui/set-chat-input-text text]))
(when @recording?
(@record-reset-fn)
(reset! recording? false))
(rf/dispatch [:chat.ui/set-chat-input-text text])
(rf/dispatch [:mention/on-change-text text]))
(defn selection-change
[event {:keys [lock-selection? cursor-position]}]
(println "selectionc ahnge")
(when-not @lock-selection?
(reset! cursor-position (oops/oget event "nativeEvent.selection.end"))))
@@ -0,0 +1,30 @@
(ns status-im2.contexts.chat.bottom-sheet-composer.mentions.style
(:require [quo2.foundations.colors :as colors]
[react-native.platform :as platform]
[react-native.reanimated :as reanimated]
[status-im2.contexts.chat.bottom-sheet-composer.constants :as constants]))
(defn shadow
[]
(if platform/ios?
{:shadow-radius (colors/theme-colors 30 50)
:shadow-opacity (colors/theme-colors 0.1 0.7)
:shadow-color colors/neutral-100
:shadow-offset {:width 0 :height (colors/theme-colors 8 12)}}
{:elevation 10}))
(defn container
[opacity bottom]
(reanimated/apply-animations-to-style
{:opacity opacity}
(merge
{:position :absolute
:bottom bottom
:left 8
:right 8
:border-radius 16
:z-index 4
:max-height constants/mentions-max-height
:background-color (colors/theme-colors colors/white colors/neutral-95)}
(shadow))))
@@ -0,0 +1,67 @@
(ns status-im2.contexts.chat.bottom-sheet-composer.mentions.view
(:require
[react-native.hooks :as hooks]
[react-native.platform :as platform]
[react-native.safe-area :as safe-area]
[reagent.core :as reagent]
[status-im2.contexts.chat.bottom-sheet-composer.utils :as utils]
[utils.re-frame :as rf]
[react-native.core :as rn]
[react-native.reanimated :as reanimated]
[status-im2.common.contact-list-item.view :as contact-list-item]
[status-im2.contexts.chat.bottom-sheet-composer.mentions.style :as style]))
(defn update-cursor
[user {:keys [cursor-position input-ref]}]
(when platform/android?
(let [new-cursor-pos (+ (count (:primary-name user)) @cursor-position)]
(reset! cursor-position new-cursor-pos)
(reagent/next-tick #(when @input-ref
(.setNativeProps ^js @input-ref
(clj->js {:selection {:start new-cursor-pos
:end
new-cursor-pos}})))))))
(defn mention-item
[user _ _ render-data]
[contact-list-item/contact-list-item
{:on-press (fn []
(rf/dispatch [:chat.ui/select-mention nil user])
(update-cursor user render-data))}
user])
(defn- f-view
[suggestions-atom props state animations max-height cursor-pos]
(let [{:keys [keyboard-height]} (hooks/use-keyboard)
suggestions (rf/sub [:chat/mention-suggestions])
opacity (reanimated/use-shared-value (if (seq suggestions) 1 0))
size (count suggestions)
data {:keyboard-height keyboard-height
:insets (safe-area/get-insets)
:curr-height (reanimated/get-shared-value (:height animations))
:window-height (rf/sub [:dimensions/window-height])
:reply (rf/sub [:chats/reply-message])
:edit (rf/sub [:chats/edit-message])}
mentions-pos (utils/calc-suggestions-position cursor-pos max-height size state data)]
(rn/use-effect
(fn []
(if (seq suggestions)
(reset! suggestions-atom suggestions)
(js/setTimeout #(reset! suggestions-atom suggestions) 300))
(reanimated/animate opacity (if (seq suggestions) 1 0)))
[(seq suggestions)])
[reanimated/view
{:style (style/container opacity mentions-pos)}
[rn/flat-list
{:keyboard-should-persist-taps :always
:data (vals @suggestions-atom)
:key-fn :key
:render-fn mention-item
:render-data {:cursor-position (:cursor-position state)
:input-ref (:input-ref props)}
:accessibility-label :mentions-list}]]))
(defn view
[props state animations max-height cursor-pos]
(let [suggestions-atom (reagent/atom {})]
[:f> f-view suggestions-atom props state animations max-height cursor-pos]))
@@ -126,11 +126,14 @@
(get-quoted-text-with-mentions (or parsed-text (:parsed-text content))))]])]
(when (and in-chat-input? (not recording-audio?))
[quo/button
{:icon true
:type :outline
:size 24
:on-press #(rf/dispatch [:chat.ui/cancel-message-reply])}
:i/close])
{:width 24
:size 24
:accessibility-label :reply-cancel-button
:on-press #(rf/dispatch [:chat.ui/cancel-message-reply])
:type :outline}
[quo/icon :i/close
{:size 16
:color (colors/theme-colors colors/neutral-100 colors/neutral-40)}]])
(when (and in-chat-input? recording-audio?)
[linear-gradient/linear-gradient
{:colors [(colors/theme-colors colors/white-opa-0 colors/neutral-90-opa-0)
@@ -140,13 +143,13 @@
:style style/gradient}])]))
(defn- f-view
[]
[recording?]
(let [reply (rf/sub [:chats/reply-message])
height (reanimated/use-shared-value (if reply constants/reply-container-height 0))]
(rn/use-effect #(reanimated/animate height (if reply constants/reply-container-height 0)) [reply])
[reanimated/view {:style (reanimated/apply-animations-to-style {:height height} {})}
(when reply [reply-message reply true false false])]))
(when reply [reply-message reply true false recording?])]))
(defn view
[]
[:f> f-view])
[{:keys [recording?]}]
[:f> f-view @recording?])
@@ -0,0 +1,42 @@
(ns status-im2.contexts.chat.bottom-sheet-composer.selectable-input.view
(:require [utils.i18n :as i18n]))
(declare first-level-menu-items second-level-menu-items)
(defn calculate-input-text
[{:keys [full-text selection-start selection-end]} content]
(let [head (subs full-text 0 selection-start)
tail (subs full-text selection-end)]
(str head content tail)))
(defn reset-to-first-level-menu
[first-level menu-items]
(reset! first-level true)
(reset! menu-items first-level-menu-items))
(defn append-markdown-char
[{:keys [first-level menu-items content selection-start selection-end text-input-handle
selection-event]
:as params} wrap-chars]
(let [content (str wrap-chars content wrap-chars)
new-text (calculate-input-text params content)
len-wrap-chars (count wrap-chars)
selection-start (+ selection-start len-wrap-chars)
selection-end (+ selection-end len-wrap-chars)]
;don't update selection directly here, process it within on-selection-change instead
;so that we can avoid java.lang.IndexOutOfBoundsException: setSpan..
(reset! selection-event {:start selection-start
:end selection-end
:text-input-handle text-input-handle})
;(update-input-text params new-text)
(reset-to-first-level-menu first-level menu-items)))
(def second-level-menus
{:bold #(append-markdown-char % "**")
:italic #(append-markdown-char % "*")
:strikethrough #(append-markdown-char % "~~")})
(def second-level-menu-items (map i18n/label (keys second-level-menus)))
@@ -6,18 +6,18 @@
[status-im2.contexts.chat.bottom-sheet-composer.constants :as constants]))
(defn shadow
[elevation?]
[focused?]
(if platform/ios?
{:shadow-radius 20
:shadow-opacity (colors/theme-colors 0.1 0.7)
:shadow-color colors/neutral-100
:shadow-offset {:width 0 :height (colors/theme-colors -4 -8)}}
{:elevation (if elevation? 10 0)}))
{:elevation (if @focused? 10 0)}))
(defn sheet-container
[insets opacity elevation?]
[insets {:keys [focused?]} {:keys [container-opacity]}]
(reanimated/apply-animations-to-style
{:opacity opacity}
{:opacity container-opacity}
(merge
{:border-top-left-radius 20
:border-top-right-radius 20
@@ -29,7 +29,7 @@
:background-color (colors/theme-colors colors/white colors/neutral-95)
:z-index 3
:padding-bottom (:bottom insets)}
(shadow elevation?))))
(shadow focused?))))
(def bar-container
{:height constants/bar-container-height
@@ -55,18 +55,19 @@
:overflow :hidden}))
(defn input
[maximized? saved-keyboard-height]
[{:keys [saved-emoji-kb-extra-height]}
{:keys [focused? recording?]}]
(merge typography/paragraph-1
{:min-height constants/input-height
:color (colors/theme-colors :black :white)
:text-align-vertical :top
:flex 1
:z-index 1
:position (if saved-keyboard-height :relative :absolute)
:position (if @saved-emoji-kb-extra-height :relative :absolute)
:top 0
:left 0
:right (when (or maximized? platform/ios?) 0)}))
:right (when (or focused? platform/ios?) 0)
:display (if @recording? :none :flex)}))
(defn background
[opacity background-y window-height]
(reanimated/apply-animations-to-style
@@ -1,9 +1,11 @@
(ns status-im2.contexts.chat.bottom-sheet-composer.utils
(:require
[clojure.string :as string]
[oops.core :as oops]
[react-native.platform :as platform]
[react-native.reanimated :as reanimated]
[status-im2.contexts.chat.bottom-sheet-composer.constants :as constants]))
[status-im2.contexts.chat.bottom-sheet-composer.constants :as constants]
[utils.re-frame :as rf]))
(defn bounded-val
[val min-val max-val]
@@ -60,7 +62,7 @@
(if platform/ios? lines (dec lines))))
(defn calc-max-height
[window-height kb-height insets images? reply?]
[window-height kb-height insets images? reply? edit?]
(let [margin-top (if platform/ios? (:top insets) (+ 10 (:top insets)))
max-height (- window-height
margin-top
@@ -68,13 +70,74 @@
constants/bar-container-height
constants/actions-container-height)
max-height (if images? (- max-height constants/images-container-height) max-height)
max-height (if reply? (- max-height constants/reply-container-height) max-height)]
max-height (if reply? (- max-height constants/reply-container-height) max-height)
max-height (if edit? (- max-height constants/edit-container-height) max-height)]
max-height))
(defn empty-input?
[text images reply?]
(and (empty? text) (empty? images) (not reply?)))
[text images reply? audio?]
(and (empty? text) (empty? images) (not reply?) (not audio?)))
(defn android-elevation?
[lines images reply?]
(or (> lines 1) (seq images) reply?))
[lines images reply? edit?]
(or (> lines 1) (seq images) reply? edit?))
(defn cancel-edit-message
[{:keys [text-value maximized?]}
{:keys [height saved-height last-height]}]
(when-not @maximized?
(reanimated/animate height constants/input-height)
(reanimated/set-shared-value saved-height constants/input-height)
(reanimated/set-shared-value last-height constants/input-height))
(reset! text-value "")
(rf/dispatch [:chat.ui/set-input-content-height constants/input-height]))
(defn update-input
[{:keys [input-ref]}
{:keys [text-value]}
input-text]
(when (and input-text (not= @text-value input-text))
(reset! text-value input-text)
(when @input-ref
(.setNativeProps ^js @input-ref (clj->js {:text input-text})))))
(defn count-lines
[s]
(-> s
(string/split #"\n" -1)
(butlast)
count))
(defn cursor-y-position-relative-to-container
[{:keys [scroll-y]}
{:keys [cursor-position text-value]}]
(let [sub-text (subs @text-value 0 @cursor-position)
sub-text-lines (count-lines sub-text)
scrolled-lines (Math/round (/ @scroll-y constants/line-height))
sub-text-lines-in-view (- sub-text-lines scrolled-lines)]
(* sub-text-lines-in-view constants/line-height)))
(defn calc-suggestions-position
[cursor-pos max-height size
{:keys [maximized?]}
{:keys [insets curr-height window-height keyboard-height edit reply]}]
(let [base (+ constants/composer-default-height (:bottom insets) 8)
base (+ base (- curr-height constants/input-height))
base (if edit
(+ base constants/edit-container-height)
base)
base (if reply
(+ base constants/reply-container-height)
base)
view-height (- window-height keyboard-height (:top insets))
container-height (bounded-val
(* (/ constants/mentions-max-height 4) size)
(/ constants/mentions-max-height 4)
constants/mentions-max-height)]
(if @maximized?
(if (< (+ cursor-pos container-height) max-height)
(+ constants/actions-container-height (:bottom insets))
(+ constants/actions-container-height (:bottom insets) (- max-height cursor-pos) 18))
(if (< (+ base container-height) view-height)
base
(+ constants/actions-container-height (:bottom insets) (- curr-height cursor-pos) 18)))))
@@ -7,10 +7,13 @@
[react-native.reanimated :as reanimated]
[reagent.core :as reagent]
[utils.i18n :as i18n]
[utils.re-frame :as rf]
[oops.core :as oops]
[status-im2.contexts.chat.bottom-sheet-composer.style :as style]
[status-im2.contexts.chat.bottom-sheet-composer.images.view :as images]
[status-im2.contexts.chat.bottom-sheet-composer.reply.view :as reply]
[utils.re-frame :as rf]
[status-im2.contexts.chat.bottom-sheet-composer.edit.view :as edit]
[status-im2.contexts.chat.bottom-sheet-composer.mentions.view :as mentions]
[status-im2.contexts.chat.bottom-sheet-composer.utils :as utils]
[status-im2.contexts.chat.bottom-sheet-composer.constants :as constants]
[status-im2.contexts.chat.bottom-sheet-composer.actions.view :as actions]
@@ -19,135 +22,163 @@
[status-im2.contexts.chat.bottom-sheet-composer.effects :as effects]
[status-im2.contexts.chat.bottom-sheet-composer.gesture :as drag-gesture]
[status-im2.contexts.chat.bottom-sheet-composer.handlers :as handler]
[status-im2.contexts.chat.bottom-sheet-composer.gradients.view :as gradients]))
[status-im2.contexts.chat.bottom-sheet-composer.gradients.view :as gradients]
[status-im2.contexts.chat.bottom-sheet-composer.selectable-input.view :as selectable-input]))
(defn sheet
[insets window-height blur-height opacity background-y]
[:f>
(fn []
(let [props {:input-ref (atom nil)
:keyboard-show-listener (atom nil)
:keyboard-frame-listener (atom nil)
:keyboard-hide-listener (atom nil)
:emoji-kb-extra-height (atom nil)
:saved-emoji-kb-extra-height (atom nil)
:replying? (atom nil)
:sending-images? (atom nil)}
state {:text-value (reagent/atom "")
:cursor-position (reagent/atom 0)
:saved-cursor-position (reagent/atom 0)
:gradient-z-index (reagent/atom 0)
:kb-default-height (reagent/atom nil)
:gesture-enabled? (reagent/atom true)
:lock-selection? (reagent/atom true)
:focused? (reagent/atom false)
:lock-layout? (reagent/atom false)
:maximized? (reagent/atom false)}]
(let [props {:input-ref (atom nil)
:keyboard-show-listener (atom nil)
:keyboard-frame-listener (atom nil)
:keyboard-hide-listener (atom nil)
:emoji-kb-extra-height (atom nil)
:saved-emoji-kb-extra-height (atom nil)
:replying? (atom nil)
:sending-images? (atom nil)
:editing? (atom nil)
:record-permission? (atom nil)
:record-reset-fn (atom nil)
:scroll-y (atom 0)}
state {:text-value (reagent/atom "")
:cursor-position (reagent/atom 0)
:saved-cursor-position (reagent/atom 0)
:gradient-z-index (reagent/atom 0)
:kb-default-height (reagent/atom nil)
:gesture-enabled? (reagent/atom true)
:lock-selection? (reagent/atom true)
:focused? (reagent/atom false)
:lock-layout? (reagent/atom false)
:maximized? (reagent/atom false)
:recording? (reagent/atom false)}
selectable-input-ref (atom nil)
menu-items (reagent/atom selectable-input/first-level-menu-items)
manager (rn/selectable-text-input-manager)]
[:f>
(fn []
(let [images (rf/sub [:chats/sending-image])
reply (rf/sub [:chats/reply-message])
(let [images (rf/sub [:chats/sending-image])
audio (rf/sub [:chats/sending-audio])
reply (rf/sub [:chats/reply-message])
edit (rf/sub [:chats/edit-message])
{:keys [input-text input-content-height]
:as chat-input} (rf/sub [:chats/current-chat-input])
content-height (reagent/atom (or input-content-height
constants/input-height))
:as chat-input} (rf/sub [:chats/current-chat-input])
content-height (reagent/atom (or input-content-height
constants/input-height))
{:keys [keyboard-shown keyboard-height]} (hooks/use-keyboard)
kb-height (kb/get-kb-height keyboard-height
@(:kb-default-height state))
max-height (utils/calc-max-height window-height
kb-height
insets
(seq images)
reply)
lines (utils/calc-lines @content-height)
max-lines (utils/calc-lines max-height)
initial-height (if (> lines 1)
constants/multiline-minimized-height
constants/input-height)
animations {:gradient-opacity (reanimated/use-shared-value
0)
:container-opacity (reanimated/use-shared-value
(if (utils/empty-input?
input-text
images
reply)
0.7
1))
:height (reanimated/use-shared-value
initial-height)
:saved-height (reanimated/use-shared-value
initial-height)
:last-height (reanimated/use-shared-value
(utils/bounded-val
@content-height
constants/input-height
max-height))
:opacity opacity
:background-y background-y}
dimensions {:content-height content-height
:max-height max-height
:window-height window-height
:lines lines
:max-lines max-lines}
show-bottom-gradient? (utils/show-bottom-gradient? state dimensions)
android-elevation? (utils/android-elevation? lines images reply)]
kb-height (kb/get-kb-height keyboard-height
@(:kb-default-height state))
max-height (utils/calc-max-height window-height
kb-height
insets
(boolean (seq images))
reply
edit)
lines (utils/calc-lines @content-height)
max-lines (utils/calc-lines max-height)
initial-height (if (> lines 1)
constants/multiline-minimized-height
constants/input-height)
animations {:gradient-opacity (reanimated/use-shared-value
0)
:container-opacity (reanimated/use-shared-value
(if (utils/empty-input?
input-text
images
reply
audio)
0.7
1))
:height (reanimated/use-shared-value
initial-height)
:saved-height (reanimated/use-shared-value
initial-height)
:last-height (reanimated/use-shared-value
(utils/bounded-val
@content-height
constants/input-height
max-height))
:opacity opacity
:background-y background-y}
dimensions {:content-height content-height
:max-height max-height
:window-height window-height
:lines lines
:max-lines max-lines}
show-bottom-gradient? (utils/show-bottom-gradient? state dimensions)
cursor-pos (utils/cursor-y-position-relative-to-container
props
state)]
(effects/initialize props
state
animations
dimensions
chat-input
keyboard-height
(seq images)
reply)
[gesture/gesture-detector
{:gesture (drag-gesture/drag-gesture props state animations dimensions keyboard-shown)}
[reanimated/view
{:style (style/sheet-container insets
(:container-opacity animations)
android-elevation?)
:on-layout #(handler/layout % state blur-height)}
[sub-view/bar]
[reply/view]
[reanimated/touchable-opacity
{:active-opacity 1
:on-press (when @(:input-ref props) #(.focus ^js @(:input-ref props)))
:style (style/input-container (:height animations) max-height)
:accessibility-label :message-input-container}
[rn/text-input
{:ref #(reset! (:input-ref props) %)
:default-value @(:text-value state)
:on-focus #(handler/focus props state animations dimensions)
:on-blur #(handler/blur state animations dimensions images reply)
:on-content-size-change #(handler/content-size-change %
state
animations
dimensions
keyboard-shown)
:on-scroll #(handler/scroll % state animations dimensions)
:on-change-text #(handler/change-text % props state)
:on-selection-change #(handler/selection-change % state)
:max-height max-height
:max-font-size-multiplier 1
:multiline true
:placeholder (i18n/label :t/type-something)
:placeholder-text-color (colors/theme-colors colors/neutral-40 colors/neutral-50)
:style (style/input @(:maximized? state)
@(:saved-emoji-kb-extra-height props))
:accessibility-label :chat-message-input}]
[gradients/view props state animations show-bottom-gradient?]]
[images/images-list]
[actions/view props state animations window-height insets (seq images)]]]))]))])
(boolean (seq images))
reply
edit
audio)
(rn/use-effect (fn []
(let [selectable-text-input-handle (rn/find-node-handle @selectable-input-ref)
text-input-handle (rn/find-node-handle @(:input-ref props))]
(oops/ocall manager :setupMenuItems selectable-text-input-handle text-input-handle))))
(utils/update-input props state input-text)
[:<>
[mentions/view props state animations max-height cursor-pos]
[gesture/gesture-detector
{:gesture (drag-gesture/drag-gesture props state animations dimensions keyboard-shown)}
[reanimated/view
{:style (style/sheet-container insets state animations)
:on-layout #(handler/layout % state blur-height)}
[sub-view/bar]
[reply/view state]
[edit/view edit #(utils/cancel-edit-message state animations)]
[reanimated/touchable-opacity
{:active-opacity 1
:on-press (when @(:input-ref props) #(.focus ^js @(:input-ref props)))
:style (style/input-container (:height animations) max-height)
:accessibility-label :message-input-container}
[rn/selectable-text-input {:ref #(reset! selectable-input-ref %)
:menuItems @menu-items}
[rn/text-input
{:ref #(reset! (:input-ref props) %)
:default-value @(:text-value state)
:on-focus #(handler/focus props state animations dimensions)
:on-blur #(handler/blur state animations dimensions images reply)
:on-content-size-change #(handler/content-size-change %
state
animations
dimensions
(or keyboard-shown edit))
:on-scroll #(handler/scroll % props state animations dimensions)
:on-change-text #(handler/change-text % props state)
:on-selection-change #(handler/selection-change % state)
:on-selection (fn [e] (println "onselection"))
:max-height max-height
:max-font-size-multiplier 1
:multiline true
:placeholder (i18n/label :t/type-something)
:placeholder-text-color (colors/theme-colors colors/neutral-40 colors/neutral-50)
:style (style/input props state)
:accessibility-label :chat-message-input}]]
[gradients/view props state animations show-bottom-gradient?]]
[images/images-list]
[actions/view props state animations window-height insets
(boolean (seq images))]]]]))]))])
(defn f-bottom-sheet-composer
[insets]
(let [window-height (rf/sub [:dimensions/window-height])
opacity (reanimated/use-shared-value 0)
background-y (reanimated/use-shared-value (- window-height))
blur-height (reanimated/use-shared-value (+ constants/composer-default-height
(:bottom insets)))]
[rn/view
[reanimated/view {:style (style/background opacity background-y window-height)}]
[sub-view/blur-view blur-height]
[sheet insets window-height blur-height opacity background-y]]))
(defn bottom-sheet-composer
[insets]
[:f>
(fn []
(let [window-height (rf/sub [:dimensions/window-height])
opacity (reanimated/use-shared-value 0)
background-y (reanimated/use-shared-value (- window-height))
blur-height (reanimated/use-shared-value (+ constants/composer-default-height
(:bottom insets)))]
[rn/view
[reanimated/view {:style (style/background opacity background-y window-height)}]
[sub-view/blur-view blur-height]
[sheet insets window-height blur-height opacity background-y]]))])
[:f> f-bottom-sheet-composer insets])
+2 -3
View File
@@ -15,7 +15,7 @@
[react-native.blur :as blur]
[status-im2.contexts.chat.home.style :as style]
[react-native.platform :as platform]
[status-im2.contexts.chat.sheets.view :as home.sheet]))
[status-im2.contexts.chat.actions.view :as home.sheet]))
(defn get-item-layout
[_ index]
@@ -117,8 +117,7 @@
[common.home/top-nav]
[common.home/title-column
{:label (i18n/label :t/messages)
:handler #(rf/dispatch [:show-bottom-sheet
{:content home.sheet/new-chat-bottom-sheet}])
:handler #(rf/dispatch [:show-bottom-sheet {:content home.sheet/new-chat}])
:accessibility-label :new-chat-button}]
[quo/discover-card
{:title (i18n/label :t/invite-friends-to-status)
@@ -124,6 +124,7 @@
(defn render-parsed-text
[{:keys [content chat-id edited-at]}]
^{:key (:parsed-text content)}
[rn/view {:style style/parsed-text-block}
(reduce (fn [acc e]
(render-block acc e chat-id))
@@ -4,11 +4,13 @@
[react-native.background-timer :as background-timer]
[react-native.core :as rn]
[react-native.platform :as platform]
[react-native.reanimated :as reanimated]
[reagent.core :as reagent]
[status-im.ui.screens.chat.group :as chat.group]
[status-im.ui.screens.chat.message.gap :as message.gap]
[status-im2.common.not-implemented :as not-implemented]
[status-im2.constants :as constants]
[status-im2.contexts.chat.bottom-sheet-composer.utils :as utils]
[status-im2.contexts.chat.messages.content.deleted.view :as content.deleted]
[status-im2.contexts.chat.messages.content.view :as message]
[status-im2.contexts.chat.messages.list.state :as state]
@@ -103,6 +105,47 @@
[content.deleted/deleted-message message-data context]
[message/message-with-reactions message-data context keyboard-shown])]))])
(defn calc-shell-position
[y]
(let [{:keys [input-content-height focused?]} (rf/sub [:chats/current-chat-input])
reply (rf/sub [:chats/reply-message])
edit (rf/sub [:chats/edit-message])
lines (utils/calc-lines input-content-height)
base (if (or reply edit)
(- composer.constants/edit-container-height)
0)]
(if (not focused?)
(if (> lines 1) (+ -18 base) base)
(if (> lines 12)
(reanimated/get-shared-value y)
(if (> lines 1) (- (- input-content-height composer.constants/input-height base)) base)))))
(defn shell-button
[insets]
(let [y (reanimated/use-shared-value 0)
shell-position (calc-shell-position y)]
(rn/use-effect (fn []
(reanimated/animate y shell-position))
[shell-position])
[reanimated/view
{:style (reanimated/apply-animations-to-style
{:transform [{:translate-y y}]}
{:bottom (+ composer.constants/composer-default-height (:bottom insets) 6)
:position :absolute
:left 0
:right 0})}
[quo/floating-shell-button
(merge {:jump-to
{:on-press #(do
(rf/dispatch [:chat/close true])
(rf/dispatch [:shell/navigate-to-jump-to]))
:label (i18n/label :t/jump-to)
:style {:align-self :center}}}
(when @show-floating-scroll-down-button
{:scroll-to-bottom {:on-press scroll-to-bottom}}))
{}]]))
(defn messages-list-content
[{:keys [chat-id] :as chat} insets keyboard-shown]
(fn []
@@ -139,16 +182,8 @@
:inverted (when platform/ios? true)
:style (when platform/android? {:scaleY -1})
:on-layout on-messages-view-layout}]
[quo/floating-shell-button
(merge {:jump-to
{:on-press #(do
(rf/dispatch [:chat/close true])
(rf/dispatch [:shell/navigate-to-jump-to]))
:label (i18n/label :t/jump-to)}}
(when @show-floating-scroll-down-button
{:scroll-to-bottom {:on-press scroll-to-bottom}}))
{:position :absolute
:bottom (+ (:bottom insets) composer.constants/composer-default-height 6)}]])))
[:f> shell-button insets]])))
(defn use-keyboard-visibility
[]
@@ -1,40 +0,0 @@
(ns status-im2.contexts.chat.sheets.view
(:require [quo2.core :as quo]
[utils.i18n :as i18n]
[quo2.foundations.colors :as colors]
[utils.re-frame :as rf]))
(defn new-chat-bottom-sheet
[]
[:<>
[quo/menu-item
{:type :transparent
:title (i18n/label :t/new-chat)
:icon-bg-color :transparent
:container-padding-vertical 12
:title-column-style {:margin-left 2}
:style-props {:border-bottom-width 1
:border-bottom-color (colors/theme-colors colors/neutral-10
colors/neutral-90)}
:icon-color (colors/theme-colors colors/neutral-50 colors/neutral-40)
:accessibility-label :start-a-new-chat
:icon :i/new-message
:on-press (fn []
(rf/dispatch [:group-chat/clear-contacts])
(rf/dispatch [:open-modal :start-a-new-chat]))}]
[quo/menu-item
{:type :transparent
:title (i18n/label :t/add-a-contact)
:icon-bg-color :transparent
:icon-container-style {:padding-horizontal 0}
:container-padding-horizontal {:padding-horizontal 4}
:style-props {:margin-top 18
:margin-bottom 9}
:container-padding-vertical 12
:title-column-style {:margin-left 2}
:icon-color (colors/theme-colors colors/neutral-50 colors/neutral-40)
:accessibility-label :add-a-contact
:subtitle (i18n/label :t/enter-a-chat-key)
:subtitle-color colors/neutral-50
:icon :i/add-user
:on-press #(rf/dispatch [:open-modal :new-contact])}]])
@@ -1,8 +1,8 @@
(ns status-im2.contexts.communities.menus.community-options.component-spec
(ns status-im2.contexts.communities.actions.community-options.component-spec
(:require [re-frame.core :as re-frame]
[test-helpers.component :as h]
[status-im2.contexts.communities.menus.community-options.view :as options]))
[status-im2.contexts.communities.actions.community-options.view :as options]))
(defn setup-subs
[subs]
@@ -1,9 +1,9 @@
(ns status-im2.contexts.communities.menus.community-options.view
(ns status-im2.contexts.communities.actions.community-options.view
(:require [utils.i18n :as i18n]
[utils.re-frame :as rf]
[quo2.core :as quo]
[status-im2.contexts.communities.menus.see-rules.view :as see-rules]
[status-im2.contexts.communities.menus.leave.view :as leave-menu]))
[status-im2.contexts.communities.actions.see-rules.view :as see-rules]
[status-im2.contexts.communities.actions.leave.view :as leave-menu]))
(defn hide-sheet-and-dispatch
[event]
@@ -1,4 +1,4 @@
(ns status-im2.contexts.communities.menus.community-rules-list.style
(ns status-im2.contexts.communities.actions.community-rules-list.style
(:require [quo2.foundations.colors :as colors]))
(def community-rule
@@ -1,6 +1,6 @@
(ns status-im2.contexts.communities.menus.community-rules-list.view
(ns status-im2.contexts.communities.actions.community-rules-list.view
(:require [react-native.core :as rn]
[status-im2.contexts.communities.menus.community-rules-list.style :as style]
[status-im2.contexts.communities.actions.community-rules-list.style :as style]
[quo2.core :as quo]))
;; TODO: update with real data
@@ -1,4 +1,4 @@
(ns status-im2.contexts.communities.menus.generic-menu.style)
(ns status-im2.contexts.communities.actions.generic-menu.style)
(def container
{:flex 1
@@ -1,6 +1,6 @@
(ns status-im2.contexts.communities.menus.generic-menu.view
(ns status-im2.contexts.communities.actions.generic-menu.view
(:require [quo2.core :as quo]
[status-im2.contexts.communities.menus.generic-menu.style :as style]
[status-im2.contexts.communities.actions.generic-menu.style :as style]
[react-native.core :as rn]
[utils.re-frame :as rf]))
@@ -0,0 +1,15 @@
(ns status-im2.contexts.communities.actions.home-plus.view
(:require [quo2.core :as quo]
[utils.re-frame :as rf]))
(defn view
[]
[quo/action-drawer
[[{:icon :i/download
:accessibility-label :import-community
:label "Import community"
:on-press #(rf/dispatch [:navigate-to :community-import])}
{:icon :i/communities
:accessibility-label :create-community
:label "Create community (only for e2e)"
:on-press #(rf/dispatch [:legacy-only-for-e2e/open-create-community])}]]])
@@ -1,4 +1,4 @@
(ns status-im2.contexts.communities.menus.leave.style)
(ns status-im2.contexts.communities.actions.leave.style)
(def button-container
{:margin-top 20
@@ -1,8 +1,8 @@
(ns status-im2.contexts.communities.menus.leave.view
(ns status-im2.contexts.communities.actions.leave.view
(:require [utils.i18n :as i18n]
[quo2.core :as quo]
[status-im2.contexts.communities.menus.generic-menu.view :as generic-menu]
[status-im2.contexts.communities.menus.leave.style :as style]
[status-im2.contexts.communities.actions.generic-menu.view :as generic-menu]
[status-im2.contexts.communities.actions.leave.style :as style]
[react-native.core :as rn]
[utils.re-frame :as rf]))
@@ -1,4 +1,4 @@
(ns status-im2.contexts.communities.menus.request-to-join.style
(ns status-im2.contexts.communities.actions.request-to-join.style
(:require [quo2.foundations.colors :as colors]))
(def page-container
@@ -1,8 +1,8 @@
(ns status-im2.contexts.communities.menus.request-to-join.view
(ns status-im2.contexts.communities.actions.request-to-join.view
(:require [react-native.core :as rn]
[status-im2.contexts.communities.menus.community-rules-list.view :as community-rules]
[status-im2.contexts.communities.actions.community-rules-list.view :as community-rules]
[reagent.core :as reagent]
[status-im2.contexts.communities.menus.request-to-join.style :as style]
[status-im2.contexts.communities.actions.request-to-join.style :as style]
[quo2.core :as quo]
[utils.i18n :as i18n]
[utils.re-frame :as rf]
@@ -56,7 +56,8 @@
[quo/disclaimer
{:accessibility-label :rules-disclaimer-checkbox
:container-style {:margin-top 20}
:on-change #(swap! agreed-to-rules? not)}
:on-change #(swap! agreed-to-rules? not)
:checked? @agreed-to-rules?}
(i18n/label :t/accept-community-rules)]
[rn/view {:style (style/bottom-container)}
[quo/button
@@ -0,0 +1,12 @@
(ns status-im2.contexts.communities.actions.see-rules.view
(:require [status-im2.contexts.communities.actions.generic-menu.view :as generic-menu]
[status-im2.contexts.communities.actions.community-rules-list.view :as community-rules]
[utils.i18n :as i18n]))
(defn view
[id]
[generic-menu/view
{:id id
:title (i18n/label :t/community-rules)}
[community-rules/view community-rules/rules]])
@@ -1 +0,0 @@
(ns status-im2.contexts.communities.actions.view)
@@ -7,7 +7,7 @@
[react-native.platform :as platform]
[reagent.core :as reagent]
[status-im2.common.resources :as resources]
[status-im2.contexts.communities.menus.community-options.view :as options]
[status-im2.contexts.communities.actions.community-options.view :as options]
[status-im.ui.screens.communities.community :as community]
[status-im.ui.components.react :as react]
[status-im2.common.scroll-page.view :as scroll-page]
@@ -4,13 +4,14 @@
[reagent.core :as reagent]
[react-native.core :as rn]
[status-im2.common.home.view :as common.home]
[status-im2.contexts.communities.menus.community-options.view :as options]
[status-im2.contexts.communities.actions.community-options.view :as options]
[utils.re-frame :as rf]
[react-native.safe-area :as safe-area]
[react-native.blur :as blur]
[quo2.foundations.colors :as colors]
[status-im2.contexts.communities.home.style :as style]
[react-native.platform :as platform]))
[react-native.platform :as platform]
[status-im2.contexts.communities.actions.home-plus.view :as actions.home-plus]))
(defn item-render
[{:keys [id] :as item}]
@@ -58,7 +59,7 @@
[common.home/top-nav]
[common.home/title-column
{:label (i18n/label :t/communities)
:handler #(rf/dispatch [:bottom-sheet/show-sheet-old :add-new {}])
:handler #(rf/dispatch [:show-bottom-sheet {:content actions.home-plus/view}])
:accessibility-label :new-chat-button}]
[quo/discover-card
{:on-press #(rf/dispatch [:navigate-to :discover-communities])
@@ -1,12 +0,0 @@
(ns status-im2.contexts.communities.menus.see-rules.view
(:require [status-im2.contexts.communities.menus.generic-menu.view :as generic-menu]
[status-im2.contexts.communities.menus.community-rules-list.view :as community-rules]
[utils.i18n :as i18n]))
(defn view
[id]
[generic-menu/view
{:id id
:title (i18n/label :t/community-rules)
}
[community-rules/view community-rules/rules]])
@@ -10,7 +10,7 @@
[status-im2.constants :as constants]
[status-im2.common.scroll-page.view :as scroll-page]
[status-im2.contexts.communities.overview.style :as style]
[status-im2.contexts.communities.menus.community-options.view :as options]
[status-im2.contexts.communities.actions.community-options.view :as options]
[quo2.components.navigation.floating-shell-button :as floating-shell-button]
[status-im2.contexts.communities.overview.utils :as utils]
[utils.re-frame :as rf]))
@@ -166,7 +166,7 @@
[rn/view {:style style/disclaimer-container}
[quo/disclaimer
{:blur? true
:on-change #(reset! accepts-disclaimer? %)
:on-change #(swap! accepts-disclaimer? not)
:checked? @accepts-disclaimer?}
(i18n/label :t/password-creation-disclaimer)]]
+1 -1
View File
@@ -1,3 +1,3 @@
(ns status-im2.core-spec
(:require
[status-im2.contexts.communities.menus.community-options.component-spec]))
[status-im2.contexts.communities.actions.community-options.component-spec]))
-4
View File
@@ -160,8 +160,6 @@
;; OVERLAY
(def dissmiss-overlay navigation/dissmiss-overlay)
(def dissmiss-all-overlays navigation/dissmiss-all-overlays)
(defn show-overlay
([comp] (show-overlay comp {}))
([comp opts]
@@ -175,8 +173,6 @@
:overlay {:interceptTouchOutside true}}
opts)}})))
(re-frame/reg-fx :dissmiss-all-overlays-fx dissmiss-all-overlays)
;; toast
(navigation/register-component "toasts" (fn [] views/toasts) js/undefined)
+11 -5
View File
@@ -143,8 +143,14 @@
(rf/defn dismiss-all-overlays
{:events [:dissmiss-all-overlays]}
[{:keys [db]}]
{:dissmiss-all-overlays-fx nil
:db (-> db
(dissoc :popover/popover)
(dissoc :visibility-status-popover/popover)
(assoc-in [:bottom-sheet :hide?] true))})
{:dispatch-n [[:hide-popover]
[:hide-visibility-status-popover]
[:hide-bottom-sheet]
[:bottom-sheet-hidden]
[:hide-wallet-connect-sheet]
[:hide-wallet-connect-success-sheet]
[:hide-wallet-connect-app-management-sheet]
[:hide-signing-sheet]
[:hide-select-acc-sheet]
[:bottom-sheet/hide-old-navigation-overlay]
[:toasts/close-all-toasts]]})
+1 -1
View File
@@ -28,7 +28,7 @@
[status-im2.navigation.options :as options]
[status-im2.contexts.chat.group-details.view :as group-details]
[status-im.ui.screens.screens :as old-screens]
[status-im2.contexts.communities.menus.request-to-join.view :as join-menu]
[status-im2.contexts.communities.actions.request-to-join.view :as join-menu]
[status-im2.contexts.syncing.setup-syncing.view :as settings-setup-syncing]))
(defn screens
+5 -49
View File
@@ -2,16 +2,13 @@
(:require [clojure.string :as string]
[quo.design-system.colors :as colors]
[re-frame.core :as re-frame]
[status-im.add-new.db :as db]
[status-im.communities.core :as communities]
[status-im.group-chats.core :as group-chat]
[status-im.group-chats.db :as group-chats.db]
[status-im.multiaccounts.core :as multiaccounts]
[utils.image-server :as image-server]
[status-im2.config :as config]
[status-im2.constants :as constants]
[status-im2.contexts.chat.events :as chat.events]
[utils.i18n :as i18n]
[quo2.theme :as theme]))
(re-frame/reg-sub
@@ -328,10 +325,11 @@
(:editing-message metadata)))
(re-frame/reg-sub
:chats/sending-contact-request
:<- [:chats/current-chat-input]
(fn [{:keys [metadata]}]
(:sending-contact-request metadata)))
:chats/sending-audio
:<- [:chats/current-chat-id]
:<- [:chat/inputs]
(fn [[chat-id inputs]]
(get-in inputs [chat-id :audio])))
(re-frame/reg-sub
:chats/timeline-sending-image
@@ -339,48 +337,6 @@
(fn [{:keys [metadata]}]
(:sending-image metadata)))
(re-frame/reg-sub
:chats/chat-toolbar
:<- [:multiaccounts/login]
:<- [:chats/sending-image]
:<- [:mainnet?]
:<- [:current-chat/one-to-one-chat?]
:<- [:current-chat/metadata]
:<- [:chats/reply-message]
:<- [:chats/edit-message]
:<- [:chats/sending-contact-request]
(fn [[{:keys [processing]} sending-image mainnet? one-to-one-chat? {:keys [public?]} reply edit
sending-contact-request]]
(let [sending-image (seq sending-image)]
{:send (not processing)
:stickers (and (or config/stickers-test-enabled? mainnet?)
(not sending-image)
(not sending-contact-request)
(not reply))
:image (and (not reply)
(not edit)
(not sending-contact-request)
(not public?))
:extensions (and one-to-one-chat?
(or config/commands-enabled? mainnet?)
(not edit)
(not sending-contact-request)
(not reply))
:audio (and (not sending-image)
(not reply)
(not edit)
(not sending-contact-request)
(not public?))
:sending-image sending-image})))
(re-frame/reg-sub
:public-chat.new/topic-error-message
:<- [:public-group-topic]
(fn [topic]
(when-not (or (empty? topic)
(db/valid-topic? topic))
(i18n/label :topic-name-error))))
(defn filter-selected-contacts
[selected-contacts contacts]
(filter #(:added? (contacts %)) selected-contacts))
-15
View File
@@ -5,17 +5,6 @@
[cljs.test :refer [is testing]]
[status-im2.constants :as constants]))
(def public-profile-timeline-chats
{"0xpublic-chat" {:chat-type constants/public-chat-type
:unviewed-messages-count 5
:unviewed-mentions-count 6}
"0xprofile-chat" {:chat-type constants/profile-chat-type
:unviewed-messages-count 5
:unviewed-mentions-count 6}
"0xtimeline-chat" {:chat-type constants/timeline-chat-type
:unviewed-messages-count 5
:unviewed-mentions-count 6}})
(def expected-notification-data-for-public-profile-timeline-chats
{:communities-stack {:new-notifications? false
:notification-indicator :unread-dot
@@ -66,10 +55,6 @@
(h/deftest-sub :shell/bottom-tabs-notifications-data
[sub-name]
(testing "public, profile and timeline chats should not affect shell bottom tab indicator"
(swap! rf-db/app-db assoc :chats public-profile-timeline-chats)
(is (= (rf/sub [sub-name]) expected-notification-data-for-public-profile-timeline-chats)))
(testing "chats with only unviewed-messages, without unviewed-mentions count should use unread-dot"
(swap! rf-db/app-db assoc :chats one-to-one-group-community-chats1)
(is (= (rf/sub [sub-name]) expected-notification-data-for-one-to-one-group-community-chats1)))
@@ -25,7 +25,7 @@ class TestCommandsMultipleDevicesMerged(MultipleSharedDeviceTestCase):
profile = home.profile_button.click()
profile.profile_notifications_button.scroll_and_click()
profile.wallet_push_notifications.click()
self.recipient_public_key, self.recipient_username = self.home_2.get_public_key_and_username(
self.recipient_public_key, self.recipient_username = self.home_2.get_public_key(
return_username=True)
self.wallet_1, self.wallet_2 = self.home_1.wallet_button.click(), self.home_2.wallet_button.click()
[wallet.home_button.click() for wallet in (self.wallet_1, self.wallet_2)]
@@ -222,7 +222,7 @@ class TestOneToOneChatMultipleSharedDevices(MultipleSharedDeviceTestCase):
self.profile_1 = self.home_1.profile_button.click()
self.default_username_1 = self.profile_1.default_username_text.text
self.profile_1.home_button.click()
self.public_key_2, self.default_username_2 = self.home_2.get_public_key_and_username(return_username=True)
self.public_key_2, self.default_username_2 = self.home_2.get_public_key()
self.chat_1 = self.home_1.add_contact(self.public_key_2)
self.chat_1.send_message('hey')
self.home_2.home_button.double_click()
@@ -369,7 +369,7 @@ class TestContactBlockMigrateKeycardMultipleSharedDevices(MultipleSharedDeviceTe
self.profile_2.backup_recovery_phrase_button.click()
recovery_phrase = self.profile_2.backup_recovery_phrase()
self.recovery_phrase = ' '.join(recovery_phrase.values())
self.public_key_2, self.default_username_2 = self.home_2.get_public_key_and_username(return_username=True)
self.public_key_2, self.default_username_2 = self.home_2.get_public_key()
self.chat_1 = self.home_1.add_contact(self.public_key_2, add_in_contacts=False)
self.chat_1.chat_options.click()
self.chat_1.view_profile_button.click()
@@ -907,17 +907,16 @@ class TestOneToOneChatMultipleSharedDevicesNewUi(MultipleSharedDeviceTestCase):
def prepare_devices(self):
self.drivers, self.loop = create_shared_drivers(2)
self.device_1, self.device_2 = SignInView(self.drivers[0]), SignInView(self.drivers[1])
self.loop.run_until_complete(run_in_parallel(((self.device_1.create_user, {'enable_notifications': True}),
(self.device_2.create_user, {'enable_notifications': True}))))
self.username_1, self.username_2 = 'sender', 'receiver'
self.loop.run_until_complete(run_in_parallel(((self.device_1.create_user, {'enable_notifications': True,
'username': self.username_1}),
(self.device_2.create_user, {'enable_notifications': True,
'username': self.username_2}))))
self.home_1, self.home_2 = self.device_1.get_home_view(), self.device_2.get_home_view()
self.profile_1 = self.home_1.get_profile_view()
self.profile_2 = self.home_2.get_profile_view()
users = self.loop.run_until_complete(run_in_parallel(
((self.home_1.get_public_key_and_username, {'return_username': True}),
(self.home_2.get_public_key_and_username, {'return_username': True}))
))
self.public_key_1, self.default_username_1 = users[0]
self.public_key_2, self.default_username_2 = users[1]
self.homes = (self.home_1, self.home_2)
self.profile_1, self.profile_2 = (home.get_profile_view() for home in self.homes)
self.public_key_2 = self.home_2.get_public_key()
self.profile_1.just_fyi("Sending contact request via Profile > Contacts")
for home in (self.home_1, self.home_2):
@@ -926,13 +925,13 @@ class TestOneToOneChatMultipleSharedDevicesNewUi(MultipleSharedDeviceTestCase):
self.home_1.send_contact_request_via_bottom_sheet(self.public_key_2)
self.home_2.just_fyi("Accepting contact request from activity centre")
self.home_2.handle_contact_request(self.default_username_1)
self.home_2.handle_contact_request(self.username_1)
self.profile_1.just_fyi("Sending message to contact via Messages > Recent")
self.chat_1 = self.home_1.get_chat(self.default_username_2).click()
self.chat_1 = self.home_1.get_chat(self.username_2).click()
self.chat_1.send_message('hey')
self.home_2.click_system_back_button_until_element_is_shown()
self.chat_2 = self.home_2.get_chat(self.default_username_1).click()
self.chat_2 = self.home_2.get_chat(self.username_1).click()
self.message_1, self.message_2, self.message_3, self.message_4 = \
"Message 1", "Message 2", "Message 3", "Message 4"
@@ -998,18 +997,22 @@ class TestOneToOneChatMultipleSharedDevicesNewUi(MultipleSharedDeviceTestCase):
replied_message = self.chat_1.chat_element_by_text(reply)
if replied_message.replied_message_text != url_message:
self.errors.append("Reply for '%s' not present in message received in public chat" % url_message)
# The "open_in_status" feature is not implemented yet
# url_message = 'http://status.im'
# self.chat_1.send_message(url_message)
# self.chat_2.element_starts_with_text(url_message, 'button').click()
# web_view = self.chat_2.open_in_status_button.click()
# if not web_view.element_by_text('Private, Secure Communication').is_element_displayed(60):
# self.errors.append('URL was not opened from 1-1 chat')
self.home_2.just_fyi(("Check 'Open in Status' option"))
url_message = 'http://status.im'
self.chat_1.send_message(url_message)
self.chat_2.element_starts_with_text(url_message, 'button').click_inside_element_by_coordinate(0.2, 0.5)
web_view = self.chat_2.open_in_status_button.click()
if not web_view.element_by_text('Private, Secure Communication').is_element_displayed(60):
self.errors.append('URL was not opened from 1-1 chat')
self.errors.verify_no_errors()
@marks.testrail_id(702731)
def test_1_1_chat_pin_messages(self):
self.home_1.just_fyi("Check that Device1 can pin own message in 1-1 chat")
self.chat_2.jump_to_card_by_text(self.username_1)
self.chat_1.send_message(self.message_1)
self.chat_1.send_message(self.message_2)
self.chat_1.chat_element_by_text(self.message_1).wait_for_status_to_be("Delivered")
@@ -1031,9 +1034,9 @@ class TestOneToOneChatMultipleSharedDevicesNewUi(MultipleSharedDeviceTestCase):
if pinned_by.is_element_displayed():
text = pinned_by.text.strip()
if chat_number == 0:
expected_text = "You" if message == self.message_1 else self.default_username_2
expected_text = "You" if message == self.message_1 else self.username_2
else:
expected_text = "You" if message == self.message_2 else self.default_username_1
expected_text = "You" if message == self.message_2 else self.username_1
if text != expected_text:
self.errors.append(
"Pinned by '%s' doesn't match expected '%s' for user %s" % (
@@ -1105,9 +1108,7 @@ class TestOneToOneChatMultipleSharedDevicesNewUi(MultipleSharedDeviceTestCase):
self.profile_1.chats_tab.click()
self.chat_2.just_fyi("Send messages with non-latin symbols")
if not self.chat_1.chat_message_input.is_element_displayed():
self.chat_1.click_system_back_button_until_element_is_shown()
self.home_1.get_chat(self.default_username_2).click()
self.home_1.jump_to_card_by_text(self.username_2)
messages = ['hello', '¿Cómo estás tu año?', 'ё, доброго вечерочка', '® æ ç ♥']
[self.chat_2.send_message(message) for message in messages]
for message in messages:
@@ -1115,6 +1116,7 @@ class TestOneToOneChatMultipleSharedDevicesNewUi(MultipleSharedDeviceTestCase):
self.errors.append("Message with test '%s' was not received" % message)
self.chat_2.just_fyi("Checking updated member photo, timestamp and username on message")
self.chat_2.hide_keyboard_if_shown()
timestamp = self.chat_2.chat_element_by_text(messages[0]).timestamp
sent_time_variants = self.chat_2.convert_device_time_to_chat_timestamp()
if timestamp not in sent_time_variants:
@@ -1131,7 +1133,7 @@ class TestOneToOneChatMultipleSharedDevicesNewUi(MultipleSharedDeviceTestCase):
self.chat_1.just_fyi("Go back to chat view and checking that profile photo is updated")
if not self.chat_2.chat_message_input.is_element_displayed():
self.home_2.get_chat(self.default_username_1).click()
self.home_2.get_chat(self.username_1).click()
if self.chat_2.chat_element_by_text(message).member_photo.is_element_differs_from_template("member3.png",
diff=5):
self.errors.append("Image of user in 1-1 chat is too different from template!")
@@ -1141,24 +1143,25 @@ class TestOneToOneChatMultipleSharedDevicesNewUi(MultipleSharedDeviceTestCase):
def test_1_1_chat_push_emoji(self):
message_no_pn, message = 'No PN', 'Text push notification'
[device.click_system_back_button_until_element_is_shown() for device in
(self.device_1, self.device_2)]
[home.click_system_back_button_until_element_is_shown() for home in self.homes]
self.home_2.profile_button.click()
self.home_1.chats_tab.click()
self.device_2.just_fyi("Device 2 puts app on background being on Profile view to receive PN with text")
self.device_2.put_app_to_background()
self.device_2.open_notification_bar()
if not self.chat_1.chat_message_input.is_element_displayed():
self.home_1.get_chat(self.default_username_2).click()
self.home_1.get_chat(self.username_2).click()
self.chat_1.send_message(message)
self.device_1.just_fyi("Device 1 puts app on background to receive emoji push notification")
self.device_1.click_system_back_button_until_element_is_shown()
self.device_1.profile_button.click()
self.device_1.click_system_home_button()
self.device_2.just_fyi("Check text push notification and tap it")
self.device_2.open_notification_bar()
if not self.home_2.get_pn(message):
self.device_2.click_system_back_button()
self.device_2.status_in_background_button.click()
self.device_2.driver.fail("Push notification with text was not received")
chat_2 = self.device_2.click_upon_push_notification_by_text(message)
@@ -1168,8 +1171,11 @@ class TestOneToOneChatMultipleSharedDevicesNewUi(MultipleSharedDeviceTestCase):
chat_2.send_message(emoji.emojize(emoji_message))
self.device_1.just_fyi("Device 1 checks PN with emoji")
self.device_1.put_app_to_background()
self.device_1.open_notification_bar()
if not self.device_1.element_by_text_part(emoji_unicode).is_element_displayed(60):
self.device_1.click_system_back_button()
self.device_1.status_in_background_button.click()
self.device_1.driver.fail("Push notification with emoji was not received")
chat_1 = self.device_1.click_upon_push_notification_by_text(emoji_unicode)
@@ -1179,7 +1185,7 @@ class TestOneToOneChatMultipleSharedDevicesNewUi(MultipleSharedDeviceTestCase):
self.device_1.driver.fail("Failed to open chat view after tap on PN")
self.device_1.just_fyi("Checks there are no PN after message was seen")
[device.open_notification_bar() for device in (self.device_1, self.device_2)]
[home.open_notification_bar() for home in self.homes]
if (self.device_2.element_by_text_part(message).is_element_displayed()
or self.device_1.element_by_text_part(emoji_unicode).is_element_displayed()):
self.errors.append("PN are keep staying after message was seen by user")
@@ -1187,12 +1193,9 @@ class TestOneToOneChatMultipleSharedDevicesNewUi(MultipleSharedDeviceTestCase):
@marks.testrail_id(702855)
def test_1_1_chat_edit_message(self):
[device.click_system_back_button_until_element_is_shown() for device in
(self.device_1, self.device_2)]
if not self.chat_1.chat_message_input.is_element_displayed():
self.home_1.get_chat(self.default_username_2).click()
if not self.chat_2.chat_message_input.is_element_displayed():
self.home_2.get_chat(self.default_username_1).click()
[home.click_system_back_button_until_element_is_shown() for home in self.homes]
self.chat_2.jump_to_card_by_text(self.username_1)
self.chat_1.jump_to_card_by_text(self.username_2)
self.device_2.just_fyi(
"Device 1 sends text message and edits it in 1-1 chat. Device2 checks edited message is shown")
@@ -1207,12 +1210,8 @@ class TestOneToOneChatMultipleSharedDevicesNewUi(MultipleSharedDeviceTestCase):
@marks.testrail_id(702733)
def test_1_1_chat_text_message_delete_push_disappear(self):
[device.click_system_back_button_until_element_is_shown() for device in
(self.device_1, self.device_2)]
if not self.chat_1.chat_message_input.is_element_displayed():
self.home_1.get_chat(self.default_username_2).click()
if not self.chat_2.chat_message_input.is_element_displayed():
self.home_2.get_chat(self.default_username_1).click()
self.chat_2.jump_to_card_by_text(self.username_1)
self.chat_1.jump_to_card_by_text(self.username_2)
self.device_2.just_fyi("Verify Device1 can not edit and delete received message from Device2")
message_after_edit_1_1 = 'smth I should edit'
@@ -1248,9 +1247,12 @@ class TestOneToOneChatMultipleSharedDevicesNewUi(MultipleSharedDeviceTestCase):
self.device_2.just_fyi("Send one more message and check that PN will be deleted with message deletion")
message_to_delete = 'DELETE ME'
self.home_1.put_app_to_background()
self.chat_2.send_message(message_to_delete)
self.home_1.open_notification_bar()
if not self.home_1.get_pn(message_to_delete):
self.home_1.click_system_back_button()
self.home_1.status_in_background_button.click()
self.errors.append("Push notification doesn't appear")
self.chat_2.delete_message_in_chat(message_to_delete)
pn_to_disappear = self.home_1.get_pn(message_to_delete)
@@ -1262,13 +1264,10 @@ class TestOneToOneChatMultipleSharedDevicesNewUi(MultipleSharedDeviceTestCase):
@marks.testrail_id(702783)
def test_1_1_chat_is_shown_message_sent_delivered_from_offline(self):
if not self.chat_1.chat_message_input.is_element_displayed():
self.home_1.get_chat(self.default_username_2).click()
if not self.chat_2.chat_message_input.is_element_displayed():
self.home_2.get_chat(self.default_username_1).click()
self.chat_2.jump_to_card_by_text(self.username_1)
self.chat_1.jump_to_card_by_text(self.username_2)
self.home_1.just_fyi('Turn on airplane mode and check that offline status is shown on home view')
[home.toggle_airplane_mode() for home in (self.home_1, self.home_2)]
[home.toggle_airplane_mode() for home in self.homes]
# Not implemented yet
# self.home_1.connection_offline_icon.wait_and_click(20)
@@ -1288,12 +1287,12 @@ class TestOneToOneChatMultipleSharedDevicesNewUi(MultipleSharedDeviceTestCase):
self.errors.append('Message status is not "Sending", it is "%s"!' % status)
self.home_2.just_fyi('Device2 goes back online and checks that status of the message is changed to "delivered"')
for i, home in enumerate([self.home_1, self.home_2]):
for i, home in enumerate(self.homes):
home.toggle_airplane_mode()
if "im.status.ethereum" not in home.driver.current_activity:
home.click_system_back_button_until_element_is_shown()
home.chats_tab.click()
home.get_chat(self.default_username_2 if i == 0 else self.default_username_1).click()
home.get_chat(self.username_2 if i == 0 else self.username_1).click()
try:
chat_element.wait_for_status_to_be(expected_status='Delivered', timeout=120)
except TimeoutException:
@@ -1311,11 +1310,11 @@ class TestOneToOneChatMultipleSharedDevicesNewUi(MultipleSharedDeviceTestCase):
self.home_2.chats_tab.click()
self.home_2.just_fyi("Deleting chat via delete button and check it will not reappear after relaunching app")
self.home_2.delete_chat_long_press(username=self.default_username_1)
if self.home_2.get_chat_from_home_view(self.default_username_1).is_element_displayed():
self.errors.append('Deleted %s chat is shown, but the chat has been deleted' % self.default_username_1)
self.home_2.delete_chat_long_press(username=self.username_1)
if self.home_2.get_chat_from_home_view(self.username_1).is_element_displayed():
self.errors.append('Deleted %s chat is shown, but the chat has been deleted' % self.username_1)
self.home_2.reopen_app()
if self.home_2.get_chat_from_home_view(self.default_username_1).is_element_displayed(15):
if self.home_2.get_chat_from_home_view(self.username_1).is_element_displayed(15):
self.errors.append(
'Deleted chat %s is shown after re-login, but the chat has been deleted' % self.default_username_1)
'Deleted chat %s is shown after re-login, but the chat has been deleted' % self.username_1)
self.errors.verify_no_errors()
@@ -20,7 +20,7 @@ class TestGroupChatMultipleDeviceMerged(MultipleSharedDeviceTestCase):
sign_in = SignInView(self.drivers[key])
self.homes[key] = sign_in.create_user(enable_notifications=True)
SignInView(self.drivers[2]).put_app_to_background_and_back()
self.public_keys[key], self.usernames[key] = sign_in.get_public_key_and_username(True)
self.public_keys[key], self.usernames[key] = sign_in.get_public_key(True)
sign_in.home_button.click()
SignInView(self.drivers[0]).put_app_to_background_and_back()
self.chat_name = self.homes[0].get_random_chat_name()
@@ -150,31 +150,29 @@ class TestGroupChatMultipleDeviceMergedNewUI(MultipleSharedDeviceTestCase):
self.message_to_admin = 'Hey, admin!'
self.public_keys, self.usernames, self.chats = {}, {}, {}
sign_in_views = [SignInView(self.drivers[key]) for key in self.drivers]
self.usernames = ('user admin', 'member_1', 'member_2')
self.loop.run_until_complete(
run_in_parallel(
(
(sign_in_views[0].create_user, {'enable_notifications': True}),
(sign_in_views[1].create_user, {'enable_notifications': True, 'username': "test user1"}),
(sign_in_views[2].create_user, {'enable_notifications': True, 'username': "test user2"})
(sign_in_views[0].create_user, {'enable_notifications': True, 'username': self.usernames[0]}),
(sign_in_views[1].create_user, {'enable_notifications': True, 'username': self.usernames[1]}),
(sign_in_views[2].create_user, {'enable_notifications': True, 'username': self.usernames[2]})
)
)
)
self.homes = [sign_in.get_home_view() for sign_in in sign_in_views]
users = self.loop.run_until_complete(
self.public_keys = self.loop.run_until_complete(
run_in_parallel(
(
(self.homes[0].get_public_key_and_username, {'return_username': True}),
(self.homes[1].get_public_key_and_username, {'return_username': True}),
(self.homes[2].get_public_key_and_username, {'return_username': True})
(self.homes[0].get_public_key,),
(self.homes[1].get_public_key,),
(self.homes[2].get_public_key,)
)
)
)
self.homes[0].just_fyi('Admin adds future members to contacts')
for i in range(3):
self.public_keys[i], self.usernames[i] = users[i]
for i in range(3):
self.homes[i].click_system_back_button_until_element_is_shown()
self.homes[i].chats_tab.click()
@@ -198,8 +196,7 @@ class TestGroupChatMultipleDeviceMergedNewUI(MultipleSharedDeviceTestCase):
self.chat_name = self.homes[0].get_random_chat_name()
self.homes[0].chats_tab.click()
self.chats[0] = self.homes[0].create_group_chat(user_names_to_add=[self.usernames[1], self.usernames[2]],
group_chat_name=self.chat_name,
new_ui=True)
group_chat_name=self.chat_name)
for i in range(1, 3):
self.chats[i] = ChatView(self.drivers[i])
@@ -239,7 +239,7 @@ class TestRestoreOneDeviceMerged(MultipleSharedDeviceTestCase):
@marks.testrail_id(700748)
def test_restore_uppercase_whitespaces_seed_phrase_special_char_passw_logcat(self):
profile = self.home.profile_button.click()
public_key, username = self.sign_in.get_public_key_and_username(return_username=True)
public_key, username = self.sign_in.get_public_key()
self.sign_in.just_fyi("Check public key matches expected and no back up seed phrase is available")
profile.privacy_and_security_button.click()
@@ -453,7 +453,7 @@ class TestRestoreOneDeviceMerged(MultipleSharedDeviceTestCase):
self.errors.append('Restored address %s does not match expected' % address)
self.sign_in.just_fyi('Check that after migration username and public key match expected')
public_key, default_username = self.sign_in.get_public_key_and_username(return_username=True)
public_key, default_username = self.sign_in.get_public_key()
profile = self.sign_in.get_profile_view()
if public_key != self.user['public_key']:
self.errors.append('Public key %s does not match expected' % public_key)
@@ -312,7 +312,6 @@ class TestCommunityOneDeviceMerged(MultipleSharedDeviceTestCase):
self.channel_name = 'general'
self.community = self.home.create_community(name=self.community_name, description='test description')
self.home.jump_to_communities_home()
self.home.get_chat(self.community_name, community=True).click()
community_view = self.home.get_community_view()
self.channel = community_view.get_channel(self.channel_name).click()
@@ -330,6 +329,7 @@ class TestCommunityOneDeviceMerged(MultipleSharedDeviceTestCase):
self.drivers[0].fail("Not navigated to channel view after reopening app")
@marks.testrail_id(702742)
@marks.xfail(reason='flaky test; sometimes can not be copied through appium')
def test_community_copy_and_paste_message_in_chat_input(self):
message_texts = ['mmmeowesage_text', 'https://status.im']
@@ -359,50 +359,42 @@ class TestCommunityMultipleDeviceMerged(MultipleSharedDeviceTestCase):
def prepare_devices(self):
self.drivers, self.loop = create_shared_drivers(2)
self.device_1, self.device_2 = SignInView(self.drivers[0]), SignInView(self.drivers[1])
self.loop.run_until_complete(run_in_parallel(((self.device_1.create_user, {'enable_notifications': True}),
(self.device_2.create_user,))))
self.home_1, self.home_2 = self.device_1.get_home_view(), self.device_2.get_home_view()
self.public_key_1, self.default_username_1 = self.home_1.get_public_key_and_username(return_username=True)
self.public_key_2, self.default_username_2 = self.home_2.get_public_key_and_username(return_username=True)
self.username_1, self.username_2 = "user_1", "user_2"
self.loop.run_until_complete(run_in_parallel(((self.device_1.create_user, {'enable_notifications': True,
'username': self.username_1}),
(self.device_2.create_user, {'username': self.username_2}))))
self.homes = self.home_1, self.home_2 = self.device_1.get_home_view(), self.device_2.get_home_view()
self.public_key_2 = self.home_2.get_public_key()
self.profile_1 = self.home_1.get_profile_view()
[home.click_system_back_button_until_element_is_shown() for home in (self.home_1, self.home_2)]
[home.chats_tab.click() for home in (self.home_1, self.home_2)]
[home.click_system_back_button_until_element_is_shown() for home in self.homes]
[home.chats_tab.click() for home in self.homes]
self.home_1.add_contact(self.public_key_2)
self.home_2.handle_contact_request(self.default_username_1)
self.home_2.handle_contact_request(self.username_1)
self.text_message = 'hello'
self.home_2.just_fyi("Send message to contact (need for blocking contact) test")
self.chat_1 = self.home_1.get_chat(self.default_username_2).click()
self.chat_1 = self.home_1.get_chat(self.username_2).click()
self.chat_1.send_message('hey')
self.chat_2 = self.home_2.get_chat(self.default_username_1).click()
self.chat_2 = self.home_2.get_chat(self.username_1).click()
self.chat_2.send_message(self.text_message)
[home.click_system_back_button_until_element_is_shown() for home in (self.home_1, self.home_2)]
[home.click_system_back_button_until_element_is_shown() for home in self.homes]
self.home_1.just_fyi("Open community to message")
self.home_1.communities_tab.click()
self.community_name = self.home_1.get_random_chat_name()
self.channel_name = 'general'
self.home_1.create_community(name=self.community_name, description='community to test', require_approval=False)
self.home_1.jump_to_communities_home()
self.home_1.get_chat(self.community_name, community=True).click()
community_view = self.home_1.get_community_view()
self.channel_1 = community_view.get_channel(self.channel_name).click()
self.channel_1 = self.home_1.get_to_community_channel_from_home(self.community_name)
self.channel_1.send_message(self.text_message)
self.community_1 = CommunityView(self.drivers[0])
self.community_1.send_invite_to_community(self.community_name, self.default_username_2)
self.chat_2 = self.home_2.get_chat(self.default_username_1).click()
self.community_1, self.community_2 = self.home_1.get_community_view(), self.home_2.get_community_view()
self.community_1.send_invite_to_community(self.community_name, self.username_2)
self.home_1.get_to_community_channel_from_home(self.community_name)
self.chat_2 = self.home_2.get_chat(self.username_1).click()
self.chat_2.element_by_text_part('View').click()
self.community_2 = CommunityView(self.drivers[1])
self.community_2.join_community()
self.home_1.just_fyi("Reopen community view to use new interface")
for home in (self.home_1, self.home_2):
home.jump_to_communities_home()
home.get_chat(self.community_name, community=True).click()
community_view = home.get_community_view()
community_view.get_channel(self.channel_name).click()
self.channel_2 = self.home_2.get_chat_view()
self.channel_2 = self.community_2.get_channel(self.channel_name).click()
@marks.testrail_id(702838)
@marks.xfail(reason="blocked by 14797")
@@ -416,7 +408,7 @@ class TestCommunityMultipleDeviceMerged(MultipleSharedDeviceTestCase):
(", ".join(sent_time_variants), timestamp))
for channel in self.channel_1, self.channel_2:
channel.verify_message_is_under_today_text(message, self.errors)
if self.channel_2.chat_element_by_text(message).username.text != self.default_username_1:
if self.channel_2.chat_element_by_text(message).username.text != self.username_1:
self.errors.append("Default username '%s' is not shown next to the received message" % self.username_1)
self.errors.verify_no_errors()
@@ -456,6 +448,7 @@ class TestCommunityMultipleDeviceMerged(MultipleSharedDeviceTestCase):
self.errors.verify_no_errors()
@marks.testrail_id(702840)
@marks.xfail(reason='flaky test; sometimes can not be copied through appium')
def test_community_emoji_send_copy_paste_reply(self):
emoji_name = random.choice(list(emoji.EMOJI_UNICODE))
emoji_unicode = emoji.EMOJI_UNICODE[emoji_name]
@@ -561,7 +554,7 @@ class TestCommunityMultipleDeviceMerged(MultipleSharedDeviceTestCase):
@marks.testrail_id(702894)
def test_community_contact_block_unblock_offline(self):
[home.jump_to_card_by_text('# %s' % self.channel_name) for home in [self.home_1, self.home_2]]
[home.jump_to_card_by_text('# %s' % self.channel_name) for home in self.homes]
self.channel_1.send_message('message to get avatar of user 2 visible in next message')
self.channel_2.just_fyi("Sending message before block")
@@ -579,7 +572,7 @@ class TestCommunityMultipleDeviceMerged(MultipleSharedDeviceTestCase):
if self.chat_1.chat_element_by_text(message_to_disappear).is_element_displayed():
self.errors.append("Messages from blocked user is not cleared in public chat ")
self.chat_1.jump_to_messages_home()
if self.home_1.element_by_text(self.default_username_2).is_element_displayed():
if self.home_1.element_by_text(self.username_2).is_element_displayed():
self.errors.append("1-1 chat from blocked user is not removed!")
self.chat_1.toggle_airplane_mode()
@@ -602,7 +595,7 @@ class TestCommunityMultipleDeviceMerged(MultipleSharedDeviceTestCase):
self.chat_1.profile_button.click()
profile_1.contacts_button.wait_and_click()
profile_1.blocked_users_button.wait_and_click()
profile_1.element_by_text(self.default_username_2).click()
profile_1.element_by_text(self.username_2).click()
self.chat_1.unblock_contact_button.click()
self.chat_1.close_button.click()
self.chat_1.click_system_back_button_until_element_is_shown()
@@ -613,44 +606,43 @@ class TestCommunityMultipleDeviceMerged(MultipleSharedDeviceTestCase):
if not self.chat_1.chat_element_by_text(message_unblocked).is_element_displayed(30):
self.errors.append("Message was not received in public chat after user unblock!")
# TODO: 15279 - user is not removed from contacts mutually
# self.home_2.just_fyi("Add blocked user to contacts again after removing(removed automatically when blocked)")
# chat_element = self.channel_1.chat_element_by_text(message_unblocked)
# chat_element.find_element()
# chat_element.member_photo.click()
# self.channel_1.profile_add_to_contacts_button.click()
# self.channel_1.profile_send_message_button.click()
# self.chat_1.send_message("piy")
#
# self.home_2.just_fyi("Check message in 1-1 chat after unblock")
# self.home_2.jump_to_messages_home()
# self.home_2.get_chat(self.default_username_1).click()
# self.chat_2.send_message(message_unblocked)
# # self.home_1.get_chat(self.default_username_2, wait_time=30).click()
# if not self.chat_1.chat_element_by_text(message_unblocked).is_element_displayed():
# self.errors.append("Message was not received in 1-1 chat after user unblock!")
self.home_2.just_fyi("Add blocked user to contacts again after removing(removed automatically when blocked)")
chat_element = self.channel_1.chat_element_by_text(message_unblocked)
chat_element.find_element()
chat_element.member_photo.click()
self.channel_1.profile_add_to_contacts_button.click()
self.home_2.jump_to_messages_home()
self.home_2.handle_contact_request(self.username_1)
self.channel_1.profile_send_message_button.wait_and_click()
self.chat_1.send_message("piy")
self.home_2.just_fyi("Check message in 1-1 chat after unblock")
self.home_2.get_chat(self.username_1).click()
self.chat_2.send_message(message_unblocked)
if not self.chat_1.chat_element_by_text(message_unblocked).is_element_displayed(30):
self.errors.append("Message was not received in 1-1 chat after user unblock!")
self.errors.verify_no_errors()
# @marks.testrail_id(702842)
# Skipped until implemented in NEW UI
# def test_community_mark_all_messages_as_read(self):
# self.channel_1.jump_to_communities_home()
# self.home_1.get_chat(self.community_name, community=True).click()
# self.channel_2.send_message(self.text_message)
# #self.home_1.get_chat(self.community_name).click()
# channel_1_element = self.community_1.get_channel(self.channel_name)
# if not channel_1_element.new_messages_public_chat.is_element_displayed():
# self.errors.append('New messages counter is not shown in public chat')
# mark_as_read_button = self.community_1.mark_all_messages_as_read_button
# channel_1_element.long_press_until_element_is_shown(mark_as_read_button)
# mark_as_read_button.click()
# if channel_1_element.new_messages_public_chat.is_element_displayed():
# self.errors.append('Unread messages badge is shown in community channel while there are no unread messages')
@marks.testrail_id(703086)
def test_community_mark_all_messages_as_read(self):
self.channel_1.jump_to_communities_home()
self.home_2.jump_to_card_by_text('# %s' % self.channel_name)
self.channel_2.send_message(self.text_message)
community_1_element = self.community_1.get_chat(self.community_name)
if not community_1_element.new_messages_public_chat.is_element_displayed(90):
self.errors.append('New messages counter is not shown in home > Commmunity element')
mark_as_read_button = self.community_1.mark_all_messages_as_read_button
community_1_element.long_press_until_element_is_shown(mark_as_read_button)
mark_as_read_button.click()
if community_1_element.new_messages_public_chat.is_element_displayed():
self.errors.append('Unread messages badge is shown in community channel while there are no unread messages')
# TODO: there should be one more check for community channel, which is still not ready
# self.community_1.click_system_back_button_until_element_is_shown()
# community_1_element = self.home_1.get_chat(self.community_name, community=True)
# if community_1_element.new_messages_community.is_element_displayed():
# self.errors.append('New messages community badge is shown on community after marking messages as read')
# self.errors.verify_no_errors()
self.errors.verify_no_errors()
@marks.testrail_id(702786)
def test_community_mentions_push_notification(self):
@@ -663,14 +655,14 @@ class TestCommunityMultipleDeviceMerged(MultipleSharedDeviceTestCase):
self.device_2.just_fyi("Invited member sends a message with a mention")
self.channel_2.send_message("hi")
self.channel_2.mention_user(self.default_username_1)
self.channel_2.mention_user(self.username_1)
self.channel_2.send_message_button.click()
self.device_1.just_fyi("Admin gets push notification with the mention and tap it")
self.device_1.open_notification_bar()
if self.home_1.get_pn(self.default_username_1):
self.device_1.click_upon_push_notification_by_text(self.default_username_1)
if not self.channel_1.chat_element_by_text(self.default_username_1).is_element_displayed():
if self.home_1.get_pn(self.username_1):
self.device_1.click_upon_push_notification_by_text(self.username_1)
if not self.channel_1.chat_element_by_text(self.username_1).is_element_displayed():
if self.channel_1.chat_message_input.is_element_displayed():
self.errors.append("Message with the mention is not shown in the chat for the admin")
else:
@@ -681,13 +673,14 @@ class TestCommunityMultipleDeviceMerged(MultipleSharedDeviceTestCase):
# ToDo: this part is skipped because of an issue - sent messages stuck without any status for a long time
# and can not be edited during that time
# self.device_2.just_fyi("Sender edits the message with a mention")
# self.channel_2.chat_element_by_text(self.default_username_1).long_press_element_by_coordinate(rel_y=0)
# self.channel_2.chat_element_by_text(self.username_1).wait_for_sent_state()
# self.channel_2.chat_element_by_text(self.username_1).long_press_element_by_coordinate(rel_y=0)
# try:
# self.channel_2.element_by_translation_id("edit-message").click()
# for i in range(29, 32):
# self.channel_2.driver.press_keycode(i)
# self.channel_2.send_message_button.click()
# edited_message = self.default_username_1 + " abc"
# edited_message = self.username_1 + " abc"
# if not self.channel_2.chat_element_by_text(edited_message).is_element_displayed():
# self.errors.append("Edited message is not shown correctly for the sender")
# if not self.channel_1.chat_element_by_text(edited_message).is_element_displayed():
@@ -704,14 +697,14 @@ class TestCommunityMultipleDeviceMerged(MultipleSharedDeviceTestCase):
# self.community_1.get_channel(self.channel_name).click()
#
# self.device_1.just_fyi("Admin sends a message with a mention")
# self.channel_1.mention_user(self.default_username_2)
# self.channel_1.mention_user(self.username_2)
# self.channel_1.send_message_button.click()
# self.device_2.just_fyi("Invited member gets push notification with the mention and tap it")
# self.device_2.open_notification_bar()
# if not self.home_2.get_pn(self.default_username_2):
# if not self.home_2.get_pn(self.username_2):
# self.device_2.driver.fail("Push notification with the mention was not received by the invited member")
# self.device_2.click_upon_push_notification_by_text(self.default_username_2)
# if not self.channel_2.chat_element_by_text(self.default_username_2).is_element_displayed():
# self.device_2.click_upon_push_notification_by_text(self.username_2)
# if not self.channel_2.chat_element_by_text(self.username_2).is_element_displayed():
# if self.channel_2.chat_message_input.is_element_displayed():
# self.device_2.driver.fail("Message with the mention is not shown in the chat for the invited member")
# else:
@@ -301,7 +301,7 @@ class TestKeycardTxOneDeviceMerged(MultipleSharedDeviceTestCase):
@marks.testrail_id(700768)
def test_keycard_relogin_after_restore(self):
self.sign_in.just_fyi('Check that username and public key match expected')
public_key, default_username = self.sign_in.get_public_key_and_username(return_username=True)
public_key, default_username = self.sign_in.get_public_key()
profile = self.sign_in.get_profile_view()
if public_key != self.user['public_key']:
self.errors.append('Public key %s does not match expected' % public_key)
@@ -431,7 +431,7 @@ class TestKeycardTxOneDeviceMerged(MultipleSharedDeviceTestCase):
self.sign_in.profile_button.wait_for_visibility_of_element(30)
wallet_1 = self.sign_in.wallet_button.click()
wallet_address = wallet_1.get_wallet_address()
public_key, default_username = self.sign_in.get_public_key_and_username(return_username=True)
public_key, default_username = self.sign_in.get_public_key()
profile_1 = self.sign_in.get_profile_view()
profile_1.logout()
@@ -469,7 +469,7 @@ class TestKeycardTxOneDeviceMerged(MultipleSharedDeviceTestCase):
wallet_2.wallet_button.double_click()
if wallet_address != wallet_address_2:
self.errors.append('Wallet address on restored multiaccount is not equal to created keycard multiaccount')
public_key_2, default_username_2 = self.sign_in.get_public_key_and_username(return_username=True)
public_key_2, default_username_2 = self.sign_in.get_public_key()
if public_key != public_key_2:
self.errors.append('Public key on restored multiaccount is not equal to created keycard multiaccount')
if default_username_2 != default_username:
+49 -138
View File
@@ -1,76 +1,8 @@
import pytest
from tests import marks, run_in_parallel, common_password
from tests import marks, run_in_parallel
from tests.base_test_case import MultipleSharedDeviceTestCase, create_shared_drivers
from views.sign_in_view import SignInView
from views.chat_view import CommunityView
@pytest.mark.xdist_group(name="four_2")
@marks.medium
class TestActivityCenterMultipleDeviceMedium(MultipleSharedDeviceTestCase):
def prepare_devices(self):
self.drivers, self.loop = create_shared_drivers(2)
self.device_1, self.device_2 = SignInView(self.drivers[0]), SignInView(self.drivers[1])
self.home_1, self.home_2 = self.device_1.create_user(enable_notifications=True), self.device_2.create_user()
self.public_key_user_1, self.username_1 = self.home_1.get_public_key_and_username(return_username=True)
self.public_key_user_2, self.username_2 = self.home_2.get_public_key_and_username(return_username=True)
[self.group_chat_name_1, self.group_chat_name_2] = "GroupChat1", "GroupChat2"
self.message_from_sender = "Message sender"
self.home_2.home_button.double_click()
self.device_2_one_to_one_chat = self.home_2.add_contact(self.public_key_user_1)
@marks.testrail_id(702185)
def test_activity_center_notifications_on_mentions_in_groups_and_empty_state(self):
[home.home_button.double_click() for home in [self.home_1, self.home_2]]
if not self.home_1.element_by_text_part(self.username_2).is_element_displayed():
self.home_1.handle_contact_request(self.username_2)
self.home_1.home_button.double_click()
self.device_2.just_fyi('Device2 creates Group chat 3')
self.home_2.create_group_chat([self.username_1], group_chat_name=self.group_chat_name_1)
self.home_2.home_button.double_click()
self.home_1.just_fyi("Device1 joins Group chat 3")
group_chat_1 = self.home_1.get_chat(self.group_chat_name_1).click()
group_chat_1.join_chat_button.click_if_shown()
group_chat_1.home_button.double_click()
self.home_2.just_fyi("Device2 mentions Device1 in Group chat 3")
chat_2 = self.home_2.get_chat_from_home_view(self.group_chat_name_1).click()
chat_2.select_mention_from_suggestion_list(self.username_1, self.username_1[:2])
chat_2.send_as_keyevent("group")
group_chat_message = self.username_1 + " group"
chat_2.send_message_button.click()
self.home_1.just_fyi("Device1 checks unread indicator on Activity center bell")
if not self.home_1.notifications_unread_badge.is_element_displayed():
self.errors.append("Unread badge is NOT shown after receiving mentions from Group")
self.home_1.notifications_unread_badge.click_until_absense_of_element(self.home_1.plus_button, 6)
self.home_1.just_fyi("Check that notification from group is presented in Activity Center")
if not self.home_1.get_element_from_activity_center_view(
self.username_2).chat_message_preview == group_chat_message:
self.errors.append("No mention in Activity Center for Group Chat")
self.home_1.just_fyi("Open group chat where user mentioned")
self.home_1.get_element_from_activity_center_view(self.username_2).click()
self.home_1.home_button.double_click()
self.home_1.just_fyi("Check there are no unread messages counter on chats after message is read")
if (self.home_1.notifications_unread_badge.is_element_displayed() or
self.home_1.get_chat_from_home_view(self.group_chat_name_1).new_messages_counter.text == "1"):
self.errors.append("Unread message indicator is kept after message is read in chat")
self.home_1.just_fyi("Check there is an empty view on Activity Center")
self.home_1.notifications_button.click()
if not self.home_1.element_by_translation_id('empty-activity-center').is_element_displayed():
self.errors.append("Activity Center still has some chats after user has opened all of them")
self.errors.verify_no_errors()
@pytest.mark.xdist_group(name="new_two_2")
@@ -80,19 +12,15 @@ class TestActivityCenterContactRequestMultipleDevicePR(MultipleSharedDeviceTestC
def prepare_devices(self):
self.drivers, self.loop = create_shared_drivers(2)
self.device_1, self.device_2 = SignInView(self.drivers[0]), SignInView(self.drivers[1])
self.loop.run_until_complete(run_in_parallel(((self.device_1.create_user, {'enable_notifications': True}),
(self.device_2.create_user,))))
self.home_1, self.home_2 = self.device_1.get_home_view(), self.device_2.get_home_view()
self.username_1, self.username_2 = 'sender', 'receiver'
self.loop.run_until_complete(run_in_parallel(((self.device_1.create_user, {'enable_notifications': True,
'username': self.username_1}),
(self.device_2.create_user, {'username': self.username_2}))))
self.homes = self.home_1, self.home_2 = self.device_1.get_home_view(), self.device_2.get_home_view()
self.profile_1, self.profile_2 = self.home_1.get_profile_view(), self.home_2.get_profile_view()
users = self.loop.run_until_complete(run_in_parallel(
((self.home_1.get_public_key_and_username, {'return_username': True}),
(self.home_2.get_public_key_and_username, {'return_username': True}))
))
self.public_key_1, self.default_username_1 = users[0]
self.public_key_2, self.default_username_2 = users[1]
[home.click_system_back_button_until_element_is_shown() for home in [self.home_1, self.home_2]]
[home.chats_tab.click() for home in [self.home_1, self.home_2]]
self.public_key_1, self.public_key_2 = (home.get_public_key() for home in self.homes)
[home.click_system_back_button_until_element_is_shown() for home in self.homes]
[home.chats_tab.click() for home in self.homes]
@marks.testrail_id(702850)
@marks.xfail(reason="Blocked by 15500")
@@ -104,7 +32,7 @@ class TestActivityCenterContactRequestMultipleDevicePR(MultipleSharedDeviceTestC
self.home_2.add_a_contact_chat_bottom_sheet_button.click()
self.home_2.element_by_translation_id("paste").click()
self.home_2.element_by_translation_id("user-found").wait_for_visibility_of_element(10)
if not self.home_2.element_by_text(self.default_username_1).is_element_displayed():
if not self.home_2.element_by_text(self.username_1).is_element_displayed():
self.errors.append("Username is not shown on 'Add contact' page after entering valid public key")
chat = self.home_2.get_chat_view()
@@ -127,17 +55,20 @@ class TestActivityCenterContactRequestMultipleDevicePR(MultipleSharedDeviceTestC
self.errors.append("The amount of contact requests is not shown for incoming CR!")
self.device_1.just_fyi('Device1 declines pending contact request')
self.home_1.handle_contact_request(username=self.default_username_2, action='decline')
self.home_1.handle_contact_request(username=self.username_2, action='decline')
for indicator in (self.home_1.notifications_unread_badge, self.home_1.contact_new_badge, self.home_1.pending_contact_request_text):
if indicator.is_element_displayed():
self.errors.append("Unread indicator on contacts tab or on activity center is shown after declining contact request!")
self.device_1.just_fyi("Check that it is still pending contact after declining on sender device")
self.home_2.jump_to_messages_home()
self.home_2.contacts_tab.click()
if self.home_2.pending_contact_request_text.text != '1':
self.errors.append("No pending CR for sender anymore after receiver has declined CR!")
self.home_2.recent_tab.click()
self.home_2.open_activity_center_button.click()
self.home_2.activity_unread_filter_button.click()
activity_center_element = self.home_2.get_element_from_activity_center_view(self.username_1)
if activity_center_element.message_body.text != self.home_2.get_translation_by_key("add-me-to-your-contacts"):
self.errors.append("Pending contact request is not shown on unread notification element on Activity center!,"
" actual is '%s'" % activity_center_element.message_body.text)
self.home_2.close_activity_centre.click()
self.errors.verify_no_errors()
@@ -152,7 +83,7 @@ class TestActivityCenterContactRequestMultipleDevicePR(MultipleSharedDeviceTestC
self.home_1.open_activity_center_button.click()
self.home_1.just_fyi("Mark all as read")
cr_element = self.home_1.get_element_from_activity_center_view(self.default_username_2)
cr_element = self.home_1.get_element_from_activity_center_view(self.username_2)
self.home_1.more_options_activity_button.click()
self.home_1.mark_all_read_activity_button.click()
if cr_element.is_element_displayed():
@@ -164,13 +95,13 @@ class TestActivityCenterContactRequestMultipleDevicePR(MultipleSharedDeviceTestC
self.home_1.activity_notification_swipe_button.click()
self.home_1.close_activity_centre.click()
self.home_1.contacts_tab.click()
if not self.home_1.contact_details(username=self.default_username_2).is_element_displayed(20):
if not self.home_1.contact_details(username=self.username_2).is_element_displayed(20):
self.errors.append("Contact was not added to contact list after accepting contact request (as receiver)")
self.device_2.just_fyi('Device1 check that contact appeared in contact list mutually')
self.home_2.chats_tab.click()
self.home_2.contacts_tab.click()
if not self.home_2.contact_details(username=self.default_username_1).is_element_displayed(20):
if not self.home_2.contact_details(username=self.username_1).is_element_displayed(20):
self.errors.append("Contact was not added to contact list after accepting contact request (as sender)")
self.errors.verify_no_errors()
@@ -183,63 +114,50 @@ class TestActivityMultipleDevicePR(MultipleSharedDeviceTestCase):
def prepare_devices(self):
self.drivers, self.loop = create_shared_drivers(2)
self.device_1, self.device_2 = SignInView(self.drivers[0]), SignInView(self.drivers[1])
self.username_1, self.username_2 = 'user1', 'user2'
self.loop.run_until_complete(
run_in_parallel(((self.device_1.create_user, {'username': 'user1'}),
(self.device_2.create_user, {'username': 'user2'}))))
self.home_1, self.home_2 = self.device_1.get_home_view(), self.device_2.get_home_view()
run_in_parallel(((self.device_1.create_user, {'username': self.username_1}),
(self.device_2.create_user, {'username': self.username_2}))))
self.homes = self.home_1, self.home_2 = self.device_1.get_home_view(), self.device_2.get_home_view()
self.profile_1, self.profile_2 = self.home_1.get_profile_view(), self.home_2.get_profile_view()
users = self.loop.run_until_complete(run_in_parallel(
((self.home_1.get_public_key_and_username, {'return_username': True}),
(self.home_2.get_public_key_and_username, {'return_username': True}))
))
self.public_key_1, self.default_username_1 = users[0]
self.public_key_2, self.default_username_2 = users[1]
[home.click_system_back_button_until_element_is_shown() for home in (self.home_1, self.home_2)]
[home.chats_tab.click() for home in (self.home_1, self.home_2)]
self.public_key_2 = self.home_2.get_public_key()
self.home_2.click_system_back_button_until_element_is_shown()
[home.chats_tab.click() for home in self.homes]
self.home_1.add_contact(self.public_key_2)
self.home_2.handle_contact_request(self.default_username_1)
self.home_2.handle_contact_request(self.username_1)
self.text_message = 'hello'
self.one_to_one_message = 'one-t-one message'
self.home_2.just_fyi("Send message to contact (need for jump to) test")
self.chat_1 = self.home_1.get_chat(self.default_username_2).click()
self.chat_1 = self.home_1.get_chat(self.username_2).click()
self.chat_1.send_message(self.one_to_one_message)
self.chat_2 = self.home_2.get_chat(self.default_username_1).click()
self.chat_2 = self.home_2.get_chat(self.username_1).click()
self.chat_2.send_message(self.text_message)
[home.click_system_back_button_until_element_is_shown() for home in (self.home_1, self.home_2)]
[home.click_system_back_button_until_element_is_shown() for home in self.homes]
self.home_1.just_fyi("Open community to message")
self.home_1.communities_tab.click()
self.community_name = self.home_1.get_random_chat_name()
self.channel_name = 'general'
self.home_1.create_community(name=self.community_name, description='community to test', require_approval=False)
self.home_1.jump_to_communities_home()
self.home_1.get_chat(self.community_name, community=True).click()
community_view = self.home_1.get_community_view()
self.channel_1 = community_view.get_channel(self.channel_name).click()
self.channel_1 = self.home_1.get_to_community_channel_from_home(self.community_name)
self.channel_1.send_message(self.text_message)
self.community_1 = CommunityView(self.drivers[0])
self.community_1.send_invite_to_community(self.community_name, self.default_username_2)
self.chat_2 = self.home_2.get_chat(self.default_username_1).click()
self.community_1, self.community_2 = self.home_1.get_community_view(), self.home_2.get_community_view()
self.community_1.send_invite_to_community(self.community_name, self.username_2)
self.home_1.get_to_community_channel_from_home(self.community_name)
self.chat_2 = self.home_2.get_chat(self.username_1).click()
self.chat_2.element_by_text_part('View').click()
self.community_2 = CommunityView(self.drivers[1])
self.community_2.join_community()
self.home_1.just_fyi("Reopen community view to use new interface")
for home in (self.home_1, self.home_2):
home.jump_to_communities_home()
home.get_chat(self.community_name, community=True).click()
community_view = home.get_community_view()
community_view.get_channel(self.channel_name).click()
self.channel_2 = self.home_2.get_chat_view()
self.channel_2 = self.community_2.get_channel(self.channel_name).click()
@marks.testrail_id(702936)
def test_navigation_jump_to(self):
self.community_1.just_fyi("Check Jump to screen and redirect on tap")
self.community_1.jump_to_button.click()
for card in (self.community_name, self.default_username_2):
for card in (self.community_name, self.username_2):
if not self.community_1.element_by_text_part(card).is_element_displayed(20):
self.errors.append("Card %s is not shown on Jump to screen!" % card)
self.community_1.element_by_translation_id("community-channel").click()
@@ -247,7 +165,7 @@ class TestActivityMultipleDevicePR(MultipleSharedDeviceTestCase):
self.errors.append("User was not redirected to community channel after tapping on community channel card!")
self.channel_1.click_system_back_button()
self.community_1.jump_to_button.click()
self.community_1.element_by_text_part(self.default_username_2).click()
self.community_1.element_by_text_part(self.username_2).click()
if not self.chat_1.chat_element_by_text(self.one_to_one_message).is_element_displayed(20):
self.errors.append("User was not redirected to 1-1 chat after tapping card!")
@@ -332,13 +250,12 @@ class TestActivityMultipleDevicePR(MultipleSharedDeviceTestCase):
self.errors.verify_no_errors()
@marks.testrail_id(702957)
@marks.xfail(reason="Blocked by 15500")
def test_activity_center_mentions(self):
self.home_1.jump_to_communities_home()
self.home_2.jump_to_card_by_text('# %s' % self.channel_name)
self.device_2.just_fyi("Invited member sends a message with a mention")
self.channel_2.mention_user(self.default_username_1)
self.channel_2.mention_user(self.username_1)
self.channel_2.send_message_button.click()
self.home_1.just_fyi("Checking unread indicators")
@@ -352,26 +269,25 @@ class TestActivityMultipleDevicePR(MultipleSharedDeviceTestCase):
self.home_1.just_fyi("Checking mention attributes in activity center")
self.home_1.open_activity_center_button.click()
mention_element = self.home_1.get_element_from_activity_center_view('@%s' % self.default_username_1)
mention_element = self.home_1.get_element_from_activity_center_view('@%s' % self.username_1)
if mention_element.title.text != 'Mention':
self.errors.append("Expected title is not shown, '%s' is instead!" % mention_element.title)
if not mention_element.unread_indicator.is_element_displayed():
self.errors.append("No unread dot is shown on activity center element (mention)!")
if mention_element.message_body.text != '@%s' % self.default_username_1:
if mention_element.message_body.text != '@%s' % self.username_1:
self.errors.append("Mention body in activity center does not match expected, it is %s!" % mention_element.message_body.text)
self.home_1.just_fyi("Tap on it and check redirect to channel")
mention_element.click()
if not self.channel_1.chat_element_by_text(self.default_username_1).is_element_displayed():
if not self.channel_1.chat_element_by_text(self.username_1).is_element_displayed():
self.errors.append("Was not redirected to chat after tapping on mention!")
self.errors.verify_no_errors()
@marks.testrail_id(702958)
@marks.xfail(reason="Blocked by 15500")
def test_activity_center_admin_notification_accept_swipe(self):
self.home_2.just_fyi("Clearing history")
self.home_2.jump_to_messages_home()
self.home_2.clear_chat_long_press(self.default_username_1)
self.home_2.clear_chat_long_press(self.username_1)
[home.jump_to_communities_home() for home in (self.home_1, self.home_2)]
self.home_1.just_fyi("Open community to message")
@@ -381,11 +297,11 @@ class TestActivityMultipleDevicePR(MultipleSharedDeviceTestCase):
self.home_1.create_community(name=community_name, description='community to test', require_approval=True)
self.home_1.reopen_app()
community_element = self.home_1.get_chat(community_name, community=True)
self.community_1.share_community(community_element, self.default_username_2)
self.community_1.share_community(community_element, self.username_2)
self.home_2.just_fyi("Request access to community")
self.home_2.jump_to_messages_home()
self.chat_2 = self.home_2.get_chat(self.default_username_1).click()
self.chat_2 = self.home_2.get_chat(self.username_1).click()
self.chat_2.element_by_text_part('View').click()
self.community_2.join_community()
[home.jump_to_communities_home() for home in (self.home_1, self.home_2)]
@@ -393,7 +309,7 @@ class TestActivityMultipleDevicePR(MultipleSharedDeviceTestCase):
self.home_1.just_fyi("Checking unread indicators")
self.home_1.notifications_unread_badge.wait_for_visibility_of_element(120)
self.home_1.open_activity_center_button.click()
reply_element = self.home_1.get_element_from_activity_center_view(self.default_username_2)
reply_element = self.home_1.get_element_from_activity_center_view(self.username_2)
if reply_element.title.text != 'Join request':
self.errors.append("Expected title is not shown, '%s' is instead!" % reply_element.title)
if not reply_element.unread_indicator.is_element_displayed():
@@ -406,8 +322,3 @@ class TestActivityMultipleDevicePR(MultipleSharedDeviceTestCase):
if not self.home_2.element_by_text_part(community_name).is_element_displayed(30):
self.errors.append("Community is not appeared in the list after accepting admin request from activity centre")
self.errors.verify_no_errors()
@@ -185,7 +185,7 @@ class TestBrowserProfileOneDevice(MultipleSharedDeviceTestCase):
@marks.testrail_id(702159)
def test_profile_invite_friends(self):
chat_key = self.home.get_public_key_and_username()
chat_key = self.home.get_public_key()
self.home.home_button.double_click()
self.home.just_fyi("Check it via 'Invite friends' on home view")
+8 -9
View File
@@ -20,8 +20,8 @@ class TestTimelineHistoryNodesBootnodesMultipleDeviceMergedMedium(MultipleShared
device_1, device_2 = SignInView(self.drivers[0]), SignInView(self.drivers[1])
self.home_1, self.home_2 = device_1.create_user(), device_2.create_user()
self.profile_1, self.profile_2 = self.home_1.profile_button.click(), self.home_2.profile_button.click()
self.public_key_1, self.username_1 = self.profile_1.get_public_key_and_username(return_username=True)
self.public_key_2, self.username_2 = self.profile_2.get_public_key_and_username(return_username=True)
self.public_key_1, self.username_1 = self.profile_1.get_public_key()
self.public_key_2, self.username_2 = self.profile_2.get_public_key()
self.text_message = 'hello'
[home.home_button.click() for home in (self.home_1, self.home_2)]
self.public_chat_name = self.home_1.get_random_chat_name()
@@ -304,8 +304,8 @@ class TestChatMediumMultipleDevice(MultipleSharedDeviceTestCase):
self.drivers, self.loop = create_shared_drivers(2)
self.device_1, self.device_2 = SignInView(self.drivers[0]), SignInView(self.drivers[1])
self.home_1, self.home_2 = self.device_1.create_user(enable_notifications=True), self.device_2.create_user()
self.public_key_1, self.default_username_1 = self.home_1.get_public_key_and_username(return_username=True)
self.public_key_2, self.default_username_2 = self.home_2.get_public_key_and_username(return_username=True)
self.public_key_1, self.default_username_1 = self.home_1.get_public_key()
self.public_key_2, self.default_username_2 = self.home_2.get_public_key()
[home.home_button.click() for home in (self.home_1, self.home_2)]
self.home_1.just_fyi("Creating 1-1 chats")
@@ -687,7 +687,7 @@ class TestGroupChatMultipleDeviceMediumMerged(MultipleSharedDeviceTestCase):
self.sign_ins[key] = SignInView(self.drivers[key])
self.homes[key] = self.sign_ins[key].create_user()
SignInView(self.drivers[2]).put_app_to_background_and_back()
self.public_keys[key], self.usernames[key] = self.sign_ins[key].get_public_key_and_username(True)
self.public_keys[key], self.usernames[key] = self.sign_ins[key].get_public_key(True)
self.sign_ins[key].home_button.click()
SignInView(self.drivers[0]).put_app_to_background_and_back()
@@ -822,8 +822,7 @@ class TestChatKeycardMentionsMediumMultipleDevice(MultipleSharedDeviceTestCase):
self.device_1.just_fyi('Grab user data for transactions and public chat, set up wallets')
self.home_1 = self.device_1.create_user(keycard=True, enable_notifications=True)
self.device_2.put_app_to_background_and_back()
self.recipient_public_key, self.recipient_username = self.home_1.get_public_key_and_username(
return_username=True)
self.recipient_public_key, self.recipient_username = self.home_1.get_public_key()
self.amount = self.device_1.get_unique_amount()
self.asset_name = 'STT'
self.wallet_1 = self.home_1.wallet_button.click()
@@ -1024,8 +1023,8 @@ class TestMutualContactRequests(MultipleSharedDeviceTestCase):
self.drivers, self.loop = create_shared_drivers(2)
self.device_1, self.device_2 = SignInView(self.drivers[0]), SignInView(self.drivers[1])
self.home_1, self.home_2 = self.device_1.create_user(enable_notifications=True), self.device_2.create_user()
self.public_key_1, self.default_username_1 = self.home_1.get_public_key_and_username(return_username=True)
self.public_key_2, self.default_username_2 = self.home_2.get_public_key_and_username(return_username=True)
self.public_key_1, self.default_username_1 = self.home_1.get_public_key()
self.public_key_2, self.default_username_2 = self.home_2.get_public_key()
[home.tap_mutual_cr_switcher() for home in (self.home_1, self.home_2)]
[home.home_button.click() for home in (self.home_1, self.home_2)]
@@ -16,7 +16,7 @@ class TestDeeplinkChatProfileOneDevice(MultipleSharedDeviceTestCase):
self.drivers, self.loop = create_shared_drivers(1)
self.sign_in = SignInView(self.drivers[0])
self.home = self.sign_in.create_user()
self.public_key, self.default_username = self.home.get_public_key_and_username(return_username=True)
self.public_key, self.default_username = self.home.get_public_key()
self.home.home_button.click()
self.public_chat_name = 'pubchat'
self.nickname = 'dummy_user'
@@ -343,7 +343,7 @@ class TestDeeplinkChatProfileOneDevice(MultipleSharedDeviceTestCase):
# self.drivers, self.loop = create_shared_drivers(1)
# self.sign_in = SignInView(self.drivers[0])
# self.home = self.sign_in.create_user()
# self.public_key, self.default_username = self.home.get_public_key_and_username(return_username=True)
# self.public_key, self.default_username = self.home.get_public_key()
# self.home.click_system_back_button_until_element_is_shown()
# self.home.chats_tab.click_until_presence_of_element(self.home.plus_button)
#
@@ -18,7 +18,7 @@ class TestPairingSyncMediumMultipleDevicesMerged(MultipleSharedDeviceTestCase):
self.drivers[1]), SignInView(self.drivers[2])
self.home_1 = self.device_1.create_user()
self.public_key_1, self.username_1 = self.home_1.get_public_key_and_username(return_username=True)
self.public_key_1, self.username_1 = self.home_1.get_public_key()
self.profile_1 = self.home_1.profile_button.click()
self.profile_1.privacy_and_security_button.click()
@@ -29,7 +29,7 @@ class TestPairingSyncMediumMultipleDevicesMerged(MultipleSharedDeviceTestCase):
self.profile_1.home_button.click()
self.device_2.put_app_to_background_and_back()
self.home_3 = self.device_3.create_user()
self.public_key_3, self.username_3 = self.home_3.get_public_key_and_username(return_username=True)
self.public_key_3, self.username_3 = self.home_3.get_public_key()
self.device_3.home_button.click()
self.device_1.put_app_to_background_and_back()
self.comm_before_sync_name, self.channel, self.message = 'b-%s' % self.home_1.get_random_chat_name(), 'some-rand-chann', 'comm_message'

Some files were not shown because too many files have changed in this diff Show More