Compare commits
20
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d433285acb | ||
|
|
eb16f4b6c4 | ||
|
|
9268060aa9 | ||
|
|
7ab9e7abd0 | ||
|
|
2430bde3d5 | ||
|
|
739556f2b4 | ||
|
|
f4ac7a4c51 | ||
|
|
36fac66eac | ||
|
|
4774b0f5e5 | ||
|
|
6aa38de7c7 | ||
|
|
a973976123 | ||
|
|
03aac0e4ce | ||
|
|
fac368521b | ||
|
|
51b9253734 | ||
|
|
08e6b8164e | ||
|
|
9a8354f783 | ||
|
|
6c0c742676 | ||
|
|
e0ed2a250b | ||
|
|
2f988fcd47 | ||
|
|
ee71117111 |
@@ -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]]])
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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])}})
|
||||
@@ -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))))
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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)}}))
|
||||
@@ -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))))
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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})}
|
||||
|
||||
@@ -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 #{}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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]}]
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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")})
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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})
|
||||
@@ -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})
|
||||
@@ -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]
|
||||
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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?]))
|
||||
|
||||
|
||||
@@ -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]))})
|
||||
|
||||
@@ -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])
|
||||
|
||||
@@ -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])}]])
|
||||
+2
-2
@@ -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]
|
||||
+3
-3
@@ -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
-1
@@ -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
|
||||
+2
-2
@@ -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
-1
@@ -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
|
||||
+2
-2
@@ -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
-1
@@ -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
|
||||
+3
-3
@@ -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
-1
@@ -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
|
||||
+5
-4
@@ -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,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]))
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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]]})
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user