Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
36b17618a0 |
@@ -41,7 +41,7 @@ KEYSTORE_KEY_PASSWORD=password
|
||||
# By default we build a mostly universal APK
|
||||
ANDROID_ABI_SPLIT=false
|
||||
# Some platforms are excluded though
|
||||
ANDROID_ABI_INCLUDE=armeabi-v7a;arm64-v8a;x86
|
||||
ANDROID_ABI_INCLUDE=armeabi-v7a;arm64-v8a;x86_64
|
||||
|
||||
org.gradle.jvmargs=-Xmx8704M
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
library 'status-jenkins-lib@v1.7.5'
|
||||
library 'status-jenkins-lib@v1.7.3'
|
||||
|
||||
/* Options section can't access functions in objects. */
|
||||
def isPRBuild = utils.isPRBuild()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
library 'status-jenkins-lib@v1.7.5'
|
||||
library 'status-jenkins-lib@v1.7.3'
|
||||
|
||||
pipeline {
|
||||
agent { label 'linux' }
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
library 'status-jenkins-lib@v1.7.5'
|
||||
library 'status-jenkins-lib@v1.7.3'
|
||||
|
||||
/* Options section can't access functions in objects. */
|
||||
def isPRBuild = utils.isPRBuild()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
library 'status-jenkins-lib@v1.7.5'
|
||||
library 'status-jenkins-lib@v1.7.3'
|
||||
|
||||
pipeline {
|
||||
agent { label params.AGENT_LABEL }
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
library 'status-jenkins-lib@v1.7.5'
|
||||
library 'status-jenkins-lib@v1.7.3'
|
||||
|
||||
/* Options section can't access functions in objects. */
|
||||
def isPRBuild = utils.isPRBuild()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
library 'status-jenkins-lib@v1.7.5'
|
||||
library 'status-jenkins-lib@v1.7.3'
|
||||
|
||||
pipeline {
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
library 'status-jenkins-lib@v1.7.5'
|
||||
library 'status-jenkins-lib@v1.7.3'
|
||||
|
||||
pipeline {
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
library 'status-jenkins-lib@v1.7.5'
|
||||
library 'status-jenkins-lib@v1.7.3'
|
||||
|
||||
pipeline {
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
library 'status-jenkins-lib@v1.7.5'
|
||||
library 'status-jenkins-lib@v1.7.3'
|
||||
|
||||
pipeline {
|
||||
agent { label 'macos' }
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
library 'status-jenkins-lib@v1.7.5'
|
||||
library 'status-jenkins-lib@v1.7.3'
|
||||
|
||||
pipeline {
|
||||
agent { label 'linux' }
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
library 'status-jenkins-lib@v1.7.5'
|
||||
library 'status-jenkins-lib@v1.7.3'
|
||||
|
||||
pipeline {
|
||||
agent {
|
||||
|
||||
|
Before Width: | Height: | Size: 838 B After Width: | Height: | Size: 944 B |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 64 KiB |
|
Before Width: | Height: | Size: 112 KiB |
|
Before Width: | Height: | Size: 55 KiB |
|
Before Width: | Height: | Size: 103 KiB |
|
Before Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 274 KiB |
|
Before Width: | Height: | Size: 552 KiB |
|
Before Width: | Height: | Size: 288 KiB |
|
Before Width: | Height: | Size: 587 KiB |
@@ -8,7 +8,7 @@
|
||||
{:label (colors/theme-colors colors/neutral-80-opa-40 colors/white-opa-40 override-theme)
|
||||
:icon (colors/theme-colors colors/neutral-80-opa-70 colors/white-opa-70 override-theme)
|
||||
:button-border (colors/theme-colors colors/neutral-80-opa-30 colors/white-opa-10 override-theme)
|
||||
:password-icon (colors/theme-colors colors/neutral-100 colors/white-opa-70 override-theme)
|
||||
:password-icon (colors/theme-colors colors/neutral-100 colors/white override-theme)
|
||||
:clear-icon (colors/theme-colors colors/neutral-80-opa-30 colors/white-opa-10 override-theme)
|
||||
:cursor (colors/theme-colors (colors/custom-color :blue 50)
|
||||
colors/white
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
(ns quo2.components.keycard.component-spec
|
||||
(:require [quo2.components.keycard.view :as keycard]
|
||||
[test-helpers.component :as h]
|
||||
[utils.i18n :as i18n]))
|
||||
|
||||
(h/describe "keycard component"
|
||||
(h/test "Render of keycard component when: Status = Empty, Locked = False"
|
||||
(h/render [keycard/keycard])
|
||||
(-> (h/expect (h/query-by-label-text :holder-name))
|
||||
(h/is-equal (i18n/label :t/empty-keycard))))
|
||||
|
||||
(h/test "Render of keycard component when: Status = Filled, Locked = False"
|
||||
(h/render [keycard/keycard {:holder-name? "Alisha"}])
|
||||
(-> (h/expect (h/query-by-label-text :holder-name))
|
||||
(h/is-equal (i18n/label :t/user-keycard {:name :holder-name}))))
|
||||
|
||||
(h/test "Render of keycard component when: Status = Filled, Locked = True"
|
||||
(h/render [keycard/keycard {:holder-name? "Alisha"}])
|
||||
(-> (h/expect (h/query-by-label-text :holder-name))
|
||||
(h/is-equal (i18n/label :t/user-keycard {:name :holder-name})))))
|
||||
@@ -1,42 +0,0 @@
|
||||
(ns quo2.components.keycard.style
|
||||
(:require [quo2.foundations.colors :as colors]))
|
||||
|
||||
(def keycard-height 210)
|
||||
(def keycard-chip-height 28)
|
||||
|
||||
(defn card-container
|
||||
[locked?]
|
||||
{:overflow :hidden
|
||||
:height keycard-height
|
||||
:align-items :flex-start
|
||||
:justify-content :space-between
|
||||
:border-width 1
|
||||
:border-color (if locked?
|
||||
colors/white-opa-5
|
||||
(colors/theme-colors colors/neutral-20 colors/neutral-80))
|
||||
:border-style :solid
|
||||
:border-radius 16
|
||||
:padding 16
|
||||
:background-color (if locked?
|
||||
(colors/theme-colors colors/danger colors/danger-opa-40)
|
||||
(colors/theme-colors colors/neutral-5 colors/neutral-90))})
|
||||
|
||||
(defn keycard-logo
|
||||
[locked?]
|
||||
{:tint-color (if locked? colors/white (colors/theme-colors colors/neutral-100 colors/white))})
|
||||
|
||||
(defn keycard-watermark
|
||||
[locked?]
|
||||
{:position :absolute
|
||||
:tint-color (if locked? colors/white-opa-5 (colors/theme-colors colors/neutral-100 colors/white))
|
||||
:align-self :center
|
||||
:height 280.48
|
||||
:transform [{:rotate "-30deg"} {:translateY -30}]
|
||||
:opacity (when-not locked? 0.02)
|
||||
:z-index 1})
|
||||
|
||||
(def keycard-chip
|
||||
{:height keycard-chip-height
|
||||
:position :absolute
|
||||
:right 16
|
||||
:top (/ (- keycard-height 28) 2)})
|
||||
@@ -1,38 +0,0 @@
|
||||
(ns quo2.components.keycard.view
|
||||
(:require [react-native.core :as rn]
|
||||
[quo2.components.keycard.style :as style]
|
||||
[quo2.components.tags.tag :as tag]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[quo2.foundations.resources :as resources]
|
||||
[utils.i18n :as i18n]))
|
||||
|
||||
(defn keycard
|
||||
"This component based on the following properties:
|
||||
- :holder-name - Can be owner's name. Default is Empty
|
||||
- :locked? - Boolean to specify whether the keycard is locked or not
|
||||
"
|
||||
[{:keys [holder-name locked?]}]
|
||||
(let [label (if (boolean holder-name)
|
||||
(i18n/label :t/user-keycard {:name holder-name})
|
||||
(i18n/label :t/empty-keycard))]
|
||||
[rn/view {:style (style/card-container locked?)}
|
||||
[rn/image
|
||||
{:source (resources/get-image :keycard-logo)
|
||||
:style (style/keycard-logo locked?)}]
|
||||
[rn/image
|
||||
{:source (resources/get-image
|
||||
(if (or locked? (colors/dark?)) :keycard-chip-dark :keycard-chip-light))
|
||||
:style style/keycard-chip}]
|
||||
[rn/image
|
||||
{:source (resources/get-image :keycard-watermark)
|
||||
:style (style/keycard-watermark locked?)}]
|
||||
[tag/tag
|
||||
{:size 32
|
||||
:type (when locked? :icon)
|
||||
:label label
|
||||
:labelled? true
|
||||
:blurred? true
|
||||
:resource (when locked? :i/locked)
|
||||
:accessibility-label :holder-name
|
||||
:icon-color colors/white-70-blur
|
||||
:override-theme (when locked? :dark)}]]))
|
||||
@@ -173,7 +173,6 @@
|
||||
reached-max-duration? (atom false)
|
||||
touch-timestamp (atom nil)
|
||||
disabled? (atom false)
|
||||
app-state-listener (atom nil)
|
||||
rec-options
|
||||
(merge
|
||||
audio/default-recorder-options
|
||||
@@ -513,13 +512,7 @@
|
||||
(on-init reset-recorder))
|
||||
(when audio-file
|
||||
(let [filename (last (string/split audio-file "/"))]
|
||||
(reload-player filename)))
|
||||
(reset! app-state-listener
|
||||
(.addEventListener rn/app-state
|
||||
"change"
|
||||
#(when (= % "background")
|
||||
(reset! playing-audio? false))))
|
||||
#(.remove @app-state-listener)))
|
||||
(reload-player filename)))))
|
||||
[rn/view
|
||||
{:style style/bar-container
|
||||
:pointer-events :box-none}
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
(ns quo2.components.share.qr-code.view
|
||||
(:require [quo2.components.share.qr-code.style :as style]
|
||||
[react-native.core :as rn]
|
||||
[react-native.fast-image :as fast-image]))
|
||||
[react-native.core :as rn]))
|
||||
|
||||
(defn qr-code
|
||||
[{:keys [source width height]}]
|
||||
[rn/view
|
||||
{:style style/container}
|
||||
[fast-image/fast-image
|
||||
[rn/image
|
||||
{:source source
|
||||
:style (style/image width height)}]])
|
||||
|
||||
@@ -38,7 +38,6 @@
|
||||
quo2.components.inputs.recovery-phrase.view
|
||||
quo2.components.inputs.search-input.view
|
||||
quo2.components.inputs.title-input.view
|
||||
quo2.components.keycard.view
|
||||
quo2.components.links.url-preview-list.view
|
||||
quo2.components.links.url-preview.view
|
||||
quo2.components.links.link-preview.view
|
||||
@@ -127,7 +126,6 @@
|
||||
|
||||
;;;; CARDS
|
||||
(def small-option-card quo2.components.onboarding.small-option-card.view/small-option-card)
|
||||
(def keycard quo2.components.keycard.view/keycard)
|
||||
|
||||
;;;; COLORS
|
||||
(def color-picker quo2.components.colors.color-picker.view/view)
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
(ns quo2.foundations.resources)
|
||||
|
||||
(def ui
|
||||
{:keycard-logo (js/require "../resources/images/ui2/keycard-logo.png")
|
||||
:keycard-chip-light (js/require "../resources/images/ui2/keycard-chip-light.png")
|
||||
:keycard-chip-dark (js/require "../resources/images/ui2/keycard-chip-dark.png")
|
||||
:keycard-watermark (js/require "../resources/images/ui2/keycard-watermark.png")})
|
||||
|
||||
(defn get-image
|
||||
[k]
|
||||
(get ui k))
|
||||
@@ -130,11 +130,6 @@
|
||||
(when (and player (.-canPlay ^js player))
|
||||
(.-currentTime ^js player)))
|
||||
|
||||
(defn set-player-wake-lock
|
||||
[player wake-lock?]
|
||||
(when player
|
||||
(set! (.-wakeLock player) wake-lock?)))
|
||||
|
||||
(defn toggle-playpause-player
|
||||
[player on-play on-pause on-error]
|
||||
(when (and player (.-canPlay ^js player))
|
||||
|
||||
@@ -70,12 +70,13 @@
|
||||
[{:keys [db] :as cofx} text-input-ref {:keys [primary-name searched-text match public-key] :as user}]
|
||||
(let [chat-id (:current-chat-id db)
|
||||
text (get-in db [:chat/inputs chat-id :input-text])
|
||||
method "wakuext_chatMentionSelectMention"
|
||||
params [chat-id text primary-name public-key]]
|
||||
method "wakuext_chatMentionNewInputTextWithMention"
|
||||
params [chat-id text primary-name]]
|
||||
{:json-rpc/call [{:method method
|
||||
:params params
|
||||
:on-success #(rf/dispatch [:mention/on-select-mention-success %
|
||||
primary-name match searched-text public-key])
|
||||
:on-success #(rf/dispatch [:mention/on-new-input-text-with-mentions-success %
|
||||
primary-name text-input-ref match searched-text
|
||||
public-key])
|
||||
:on-error #(rf/dispatch [:mention/on-error
|
||||
{:method method
|
||||
:params params} %])}]}))
|
||||
@@ -249,21 +250,21 @@
|
||||
[{{:keys [current-chat-id] :as db} :db :as cofx}]
|
||||
(let [{:keys [input-text metadata]} (get-in db [:chat/inputs current-chat-id])
|
||||
editing-message (:editing-message metadata)
|
||||
method "wakuext_chatMentionReplaceWithPublicKey"
|
||||
method "wakuext_chatMentionCheckMentions"
|
||||
params [current-chat-id input-text]]
|
||||
{:json-rpc/call [{:method method
|
||||
:params params
|
||||
:on-error #(rf/dispatch [:mention/on-error {:method method :params params} %])
|
||||
:on-success #(rf/dispatch [:mention/on-replace-with-public-key-success
|
||||
:on-success #(rf/dispatch [:mention/on-check-mentions-success
|
||||
current-chat-id
|
||||
editing-message
|
||||
input-text
|
||||
%])}]}))
|
||||
|
||||
(rf/defn on-replace-with-public-key-success
|
||||
{:events [:mention/on-replace-with-public-key-success]}
|
||||
(rf/defn on-check-mentions-success
|
||||
{:events [:mention/on-check-mentions-success]}
|
||||
[{:keys [db] :as cofx} current-chat-id editing-message input-text new-text]
|
||||
(log/debug "[mentions] on-replace-with-public-key-success"
|
||||
(log/debug "[mentions] on-check-mentions-success"
|
||||
{:chat-id current-chat-id
|
||||
:editing-message editing-message
|
||||
:input-text input-text
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
(ns status-im.chat.models.mentions
|
||||
(:require [clojure.set :as set]
|
||||
[quo.react :as react]
|
||||
[quo.react-native :as rn]
|
||||
[re-frame.core :as re-frame]
|
||||
[utils.re-frame :as rf]
|
||||
[taoensso.timbre :as log]))
|
||||
[taoensso.timbre :as log]
|
||||
[native-module.core :as native-module]))
|
||||
|
||||
(defn- transfer-input-segments
|
||||
[segments]
|
||||
@@ -122,21 +126,47 @@
|
||||
(assoc-in [:chats/mentions chat-id :mentions] state)
|
||||
(assoc-in [:chat/inputs-with-mentions chat-id] input-segments))}))
|
||||
|
||||
(rf/defn on-select-mention-success
|
||||
{:events [:mention/on-select-mention-success]}
|
||||
[{:keys [db] :as cofx} result primary-name match searched-text public-key]
|
||||
(log/debug "[mentions] on-select-mention-success"
|
||||
(rf/defn recheck-at-idxs
|
||||
[{:keys [db]} public-key]
|
||||
(let [chat-id (:current-chat-id db)
|
||||
text (get-in db [:chat/inputs chat-id :input-text])
|
||||
params [chat-id text public-key]
|
||||
method "wakuext_chatMentionRecheckAtIdxs"]
|
||||
{:json-rpc/call [{:method method
|
||||
:params params
|
||||
:on-success #(rf/dispatch [:mention/on-recheck-at-idxs-success %])
|
||||
:on-error #(rf/dispatch [:mention/on-error
|
||||
{:method method
|
||||
:params params} %])}]}))
|
||||
|
||||
(rf/defn on-recheck-at-idxs-success
|
||||
{:events [:mention/on-recheck-at-idxs-success]}
|
||||
[{:keys [db]} result]
|
||||
(log/debug "[mentions] on-recheck-at-idxs-success" {:result result})
|
||||
(let [{:keys [input-segments state chat-id]} (transfer-mention-result result)]
|
||||
{:db (-> db
|
||||
(assoc-in [:chats/mentions chat-id :mentions] state)
|
||||
(assoc-in [:chat/inputs-with-mentions chat-id] input-segments))}))
|
||||
|
||||
(rf/defn reset-text-input-cursor
|
||||
[_ ref cursor]
|
||||
{::reset-text-input-cursor [ref cursor]})
|
||||
|
||||
(rf/defn on-new-input-text-with-mentions-success
|
||||
{:events [:mention/on-new-input-text-with-mentions-success]}
|
||||
[{:keys [db] :as cofx} result primary-name text-input-ref match searched-text public-key]
|
||||
(log/debug "[mentions] on-new-input-text-with-mentions-success"
|
||||
{:result result
|
||||
:primary-name primary-name
|
||||
:match match
|
||||
:searched-text searched-text
|
||||
:public-key public-key})
|
||||
(let [{:keys [new-text chat-id state input-segments]} (transfer-mention-result result)]
|
||||
{:db (-> db
|
||||
(assoc-in [:chats/mentions chat-id :mentions] state)
|
||||
(assoc-in [:chat/inputs-with-mentions chat-id] input-segments)
|
||||
(assoc-in [:chats/mention-suggestions chat-id] nil))
|
||||
:dispatch [:chat.ui/set-chat-input-text new-text chat-id]}))
|
||||
(let [{:keys [new-text chat-id]} (transfer-mention-result result)]
|
||||
(rf/merge
|
||||
cofx
|
||||
{:db (assoc-in db [:chats/mention-suggestions chat-id] nil)
|
||||
:dispatch [:chat.ui/set-chat-input-text new-text chat-id]}
|
||||
(recheck-at-idxs public-key))))
|
||||
|
||||
(rf/defn clear-suggestions
|
||||
[{:keys [db]}]
|
||||
@@ -159,3 +189,38 @@
|
||||
:on-error #(log/error "Error while calling wakuext_chatMentionClearMentions"
|
||||
{:error %})}]}
|
||||
(clear-suggestions))))
|
||||
|
||||
(rf/defn check-selection
|
||||
{:events [:mention/on-selection-change]}
|
||||
[{:keys [db]}
|
||||
{:keys [start end]}]
|
||||
(let [chat-id (:current-chat-id db)
|
||||
text (get-in db [:chat/inputs chat-id :input-text])
|
||||
params [chat-id text start end]
|
||||
method "wakuext_chatMentionHandleSelectionChange"]
|
||||
(when text
|
||||
(log/debug "[mentions] check-selection" {:params params})
|
||||
{:json-rpc/call [{:method method
|
||||
:params params
|
||||
:on-success #(rf/dispatch [:mention/on-handle-selection-change-success %])
|
||||
:on-error #(rf/dispatch [:mention/on-error
|
||||
{:method method
|
||||
:params params} %])}]})))
|
||||
|
||||
(rf/defn on-check-selection-success
|
||||
{:events [:mention/on-handle-selection-change-success]}
|
||||
[{:keys [db]} result]
|
||||
(log/debug "[mentions] on-check-selection-success" {:result result})
|
||||
(let [{:keys [state chat-id mentionable-users input-segments]} (transfer-mention-result result)]
|
||||
{:db (-> db
|
||||
(assoc-in [:chats/mention-suggestions chat-id] mentionable-users)
|
||||
(assoc-in [:chats/mentions chat-id :mentions] state)
|
||||
(assoc-in [:chat/inputs-with-mentions chat-id] input-segments))}))
|
||||
|
||||
(re-frame/reg-fx
|
||||
::reset-text-input-cursor
|
||||
(fn [[ref cursor]]
|
||||
(when ref
|
||||
(native-module/reset-keyboard-input
|
||||
(rn/find-node-handle (react/current-ref ref))
|
||||
cursor))))
|
||||
|
||||
@@ -13,8 +13,7 @@
|
||||
[status-im.wallet.choose-recipient.core :as choose-recipient]
|
||||
[status-im2.navigation.events :as navigation]
|
||||
[taoensso.timbre :as log]
|
||||
[native-module.core :as native-module]
|
||||
[react-native.platform :as platform]))
|
||||
[native-module.core :as native-module]))
|
||||
|
||||
;; TODO(yenda) investigate why `handle-universal-link` event is
|
||||
;; dispatched 7 times for the same link
|
||||
@@ -176,15 +175,10 @@
|
||||
|
||||
(rf/defn handle-url
|
||||
"Store url in the database if the user is not logged in, to be processed
|
||||
on login, otherwise just handle it. On Android platform the app-state value
|
||||
in db is `background` immediately after account creation, hence we avoid the
|
||||
app-state check for android platforms to fix this e2e blocker :
|
||||
https://github.com/status-im/status-mobile/issues/15859
|
||||
"
|
||||
on login, otherwise just handle it"
|
||||
{:events [:universal-links/handle-url]}
|
||||
[{:keys [db] :as cofx} url]
|
||||
(if (and (multiaccounts.model/logged-in? db)
|
||||
(or platform/android? (= (:app-state db) "active")))
|
||||
(if (and (multiaccounts.model/logged-in? db) (= (:app-state db) "active"))
|
||||
(route-url cofx url)
|
||||
(store-url-for-later cofx url)))
|
||||
|
||||
|
||||
@@ -3,13 +3,9 @@
|
||||
[quo2.core :as quo]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[react-native.core :as rn]
|
||||
[react-native.navigation :as navigation]
|
||||
[reagent.core :as reagent]
|
||||
[status-im2.common.home.style :as style]
|
||||
[status-im2.common.plus-button.view :as plus-button]
|
||||
[status-im2.constants :as constants]
|
||||
[status-im2.contexts.activity-center.view :as ac]
|
||||
[status-im2.contexts.shell.animation :as shell]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn title-column
|
||||
@@ -70,43 +66,11 @@
|
||||
[quo/text {:accessibility-label :peers-network-type-text} (str "NETWORK TYPE: " network-type)]
|
||||
[quo/text {:accessibility-label :peers-count-text} (str "PEERS COUNT: " peers-count)]]))
|
||||
|
||||
(defn ac-modal
|
||||
[visible? view-id]
|
||||
(let [status-bar-style (if (or (colors/dark?)
|
||||
(not (shell/home-stack-open?)))
|
||||
:light
|
||||
:dark)
|
||||
close-modal (fn []
|
||||
(reset! visible? false)
|
||||
(navigation/merge-options (clj->js view-id)
|
||||
(clj->js {:statusBar {:style status-bar-style}})))]
|
||||
[rn/modal
|
||||
{:visible @visible?
|
||||
:cover-screen true
|
||||
:transparent true
|
||||
:status-bar-translucent true
|
||||
:hardware-accelerated true
|
||||
:animation-type :slide
|
||||
:style {:margin 0
|
||||
:width "100%"}
|
||||
:on-back-button-press close-modal}
|
||||
[ac/view close-modal]]))
|
||||
|
||||
(defn- right-section
|
||||
[{:keys [button-type search?]}]
|
||||
(let [button-common-props (get-button-common-props button-type)
|
||||
network-type (rf/sub [:network/type])
|
||||
visible? (reagent/atom false)
|
||||
view-id (rf/sub [:view-id])
|
||||
open-ac (fn []
|
||||
;; delaying status-bar style update looks nicer
|
||||
(js/setTimeout
|
||||
#(navigation/merge-options (clj->js view-id)
|
||||
(clj->js {:statusBar {:style :light}}))
|
||||
20)
|
||||
(reset! visible? (not @visible?)))]
|
||||
network-type (rf/sub [:network/type])]
|
||||
[rn/view {:style style/right-section}
|
||||
[ac-modal visible? view-id]
|
||||
(when (= network-type "cellular")
|
||||
[quo/button
|
||||
(merge button-common-props
|
||||
@@ -131,18 +95,14 @@
|
||||
(assoc button-common-props :accessibility-label :open-scanner-button)
|
||||
:i/scan]
|
||||
[quo/button
|
||||
(merge button-common-props
|
||||
{:accessibility-label :show-qr-button
|
||||
:on-press #(rf/dispatch [:open-modal :share-shell])})
|
||||
(assoc button-common-props :accessibility-label :show-qr-button)
|
||||
:i/qr-code]
|
||||
[rn/view
|
||||
[unread-indicator]
|
||||
[quo/button
|
||||
(merge button-common-props
|
||||
{:accessibility-label :open-activity-center-button
|
||||
;:on-press #(rf/dispatch [:activity-center/open])
|
||||
:on-press open-ac
|
||||
})
|
||||
:on-press #(rf/dispatch [:activity-center/open])})
|
||||
:i/activity-center]]]))
|
||||
|
||||
(defn top-nav
|
||||
|
||||
@@ -1,24 +1,16 @@
|
||||
(ns status-im2.common.resources)
|
||||
|
||||
(def ui
|
||||
{:add-new-contact (js/require "../resources/images/ui2/add-contact.png")
|
||||
:desktop-how-to-pair-sign-in (js/require "../resources/images/ui2/desktop-how-to-pair-sign-in.png")
|
||||
:desktop-how-to-pair-logged-in (js/require
|
||||
"../resources/images/ui2/desktop-how-to-pair-logged-in.png")
|
||||
:mobile-how-to-pair-sign-in (js/require "../resources/images/ui2/mobile-how-to-pair-sign-in.png")
|
||||
:mobile-how-to-pair-logged-in (js/require "../resources/images/ui2/mobile-how-to-pair-logged-in.png")
|
||||
:lifestyle (js/require "../resources/images/ui2/lifestyle.png")
|
||||
:music (js/require "../resources/images/ui2/music.png")
|
||||
:podcasts (js/require "../resources/images/ui2/podcasts.png")
|
||||
:generate-keys (js/require "../resources/images/ui2/generate-keys.png")
|
||||
:ethereum-address (js/require "../resources/images/ui2/ethereum-address.png")
|
||||
:use-keycard (js/require "../resources/images/ui2/keycard.png")
|
||||
:onboarding-illustration (js/require "../resources/images/ui2/onboarding_illustration.png")
|
||||
:qr-code (js/require "../resources/images/ui2/qr-code.png")
|
||||
:keycard-logo (js/require "../resources/images/ui2/keycard-logo.png")
|
||||
:keycard-chip-light (js/require "../resources/images/ui2/keycard-chip-light.png")
|
||||
:keycard-chip-dark (js/require "../resources/images/ui2/keycard-chip-dark.png")
|
||||
:keycard-watermark (js/require "../resources/images/ui2/keycard-watermark.png")})
|
||||
{:add-new-contact (js/require "../resources/images/ui2/add-contact.png")
|
||||
:lifestyle (js/require "../resources/images/ui2/lifestyle.png")
|
||||
:music (js/require "../resources/images/ui2/music.png")
|
||||
:podcasts (js/require "../resources/images/ui2/podcasts.png")
|
||||
:generate-keys (js/require "../resources/images/ui2/generate-keys.png")
|
||||
:ethereum-address (js/require "../resources/images/ui2/ethereum-address.png")
|
||||
:use-keycard (js/require "../resources/images/ui2/keycard.png")
|
||||
:onboarding-illustration (js/require "../resources/images/ui2/onboarding_illustration.png")
|
||||
:qr-code (js/require "../resources/images/ui2/qr-code.png")
|
||||
})
|
||||
|
||||
(def mock-images
|
||||
{:coinbase (js/require "../resources/images/mock2/coinbase.png")
|
||||
|
||||
@@ -140,7 +140,7 @@
|
||||
(contains? types-with-unread types/system))}]}]))
|
||||
|
||||
(defn header
|
||||
[close]
|
||||
[]
|
||||
[rn/view
|
||||
[rn/view {:style style/header-container}
|
||||
[quo/button
|
||||
@@ -149,8 +149,7 @@
|
||||
:size 32
|
||||
:accessibility-label :close-activity-center
|
||||
:override-theme :dark
|
||||
:on-press (fn []
|
||||
(if close (close) (rf/dispatch [:navigate-back])))}
|
||||
:on-press #(rf/dispatch [:navigate-back])}
|
||||
:i/close]
|
||||
[quo/button
|
||||
{:icon true
|
||||
@@ -214,14 +213,14 @@
|
||||
nil)]))))
|
||||
|
||||
(defn view
|
||||
[close]
|
||||
[]
|
||||
(let [active-swipeable (atom nil)]
|
||||
(rf/dispatch [:activity-center.notifications/fetch-first-page])
|
||||
(fn []
|
||||
(let [notifications (rf/sub [:activity-center/notifications])]
|
||||
[rn/view {:flex 1 :padding-top (navigation/status-bar-height)}
|
||||
[blur/view style/blur]
|
||||
[header close]
|
||||
[header]
|
||||
[rn/flat-list
|
||||
{:data notifications
|
||||
:render-data active-swipeable
|
||||
|
||||
@@ -64,7 +64,7 @@
|
||||
[:f> f-send-button state animations window-height images? btn-opacity z-index]))
|
||||
|
||||
(defn audio-button
|
||||
[{:keys [record-reset-fn input-ref]}
|
||||
[{:keys [record-reset-fn]}
|
||||
{:keys [record-permission? recording? gesture-enabled? focused?]}
|
||||
{:keys [container-opacity]}]
|
||||
(let [audio (rf/sub [:chats/sending-audio])]
|
||||
@@ -86,22 +86,17 @@
|
||||
(reset! recording? false)
|
||||
(reset! gesture-enabled? true)
|
||||
(rf/dispatch [:chat/send-audio file-path duration])
|
||||
(if-not @focused?
|
||||
(when-not @focused?
|
||||
(reanimated/animate container-opacity
|
||||
constants/empty-opacity)
|
||||
(js/setTimeout #(when @input-ref (.focus ^js @input-ref))
|
||||
300))
|
||||
constants/empty-opacity))
|
||||
(rf/dispatch [:chat.ui/set-input-audio nil]))
|
||||
:on-cancel (fn []
|
||||
(when @recording?
|
||||
(reset! recording? false)
|
||||
(reset! gesture-enabled? true)
|
||||
(if-not @focused?
|
||||
(when-not @focused?
|
||||
(reanimated/animate container-opacity
|
||||
constants/empty-opacity)
|
||||
(js/setTimeout #(when @input-ref
|
||||
(.focus ^js @input-ref))
|
||||
300))
|
||||
constants/empty-opacity))
|
||||
(rf/dispatch [:chat.ui/set-input-audio nil])))
|
||||
:on-check-audio-permissions (fn []
|
||||
(permissions/permission-granted?
|
||||
@@ -154,12 +149,11 @@
|
||||
(defn image-button
|
||||
[props animations insets]
|
||||
[quo/button
|
||||
{:on-press #(open-photo-selector props animations insets)
|
||||
:accessibility-label :open-images-button
|
||||
:icon true
|
||||
:type :outline
|
||||
:size 32
|
||||
:style {:margin-right 12}}
|
||||
{:on-press #(open-photo-selector props animations insets)
|
||||
:icon true
|
||||
:type :outline
|
||||
:size 32
|
||||
:style {:margin-right 12}}
|
||||
:i/image])
|
||||
|
||||
(defn reaction-button
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
[status-im2.contexts.chat.composer.keyboard :as kb]
|
||||
[utils.number :as utils.number]
|
||||
[oops.core :as oops]
|
||||
[utils.debounce :as debounce]))
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn reenter-screen-effect
|
||||
[{:keys [text-value saved-cursor-position maximized?]}
|
||||
@@ -159,7 +159,7 @@
|
||||
(when @input-ref
|
||||
(.setNativeProps ^js @input-ref (clj->js {:text input-text})))
|
||||
(reset! text-value input-text)
|
||||
(debounce/debounce-and-dispatch [:mention/on-change-text input-text] 300)))
|
||||
(rf/dispatch [:mention/on-change-text input-text])))
|
||||
[input-text]))
|
||||
|
||||
(defn did-mount
|
||||
|
||||
@@ -8,8 +8,7 @@
|
||||
[status-im2.contexts.chat.composer.keyboard :as kb]
|
||||
[status-im2.contexts.chat.composer.utils :as utils]
|
||||
[status-im2.contexts.chat.composer.selection :as selection]
|
||||
[utils.re-frame :as rf]
|
||||
[utils.debounce :as debounce]))
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn focus
|
||||
[{:keys [input-ref] :as props}
|
||||
@@ -36,30 +35,29 @@
|
||||
|
||||
(defn blur
|
||||
[{:keys [text-value focused? lock-selection? cursor-position saved-cursor-position gradient-z-index
|
||||
maximized? recording?]}
|
||||
maximized?]}
|
||||
{:keys [height saved-height last-height gradient-opacity container-opacity opacity background-y]}
|
||||
{:keys [content-height max-height window-height]}
|
||||
{:keys [images reply]}]
|
||||
(when-not @recording?
|
||||
(let [lines (utils/calc-lines (- @content-height constants/extra-content-offset))
|
||||
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 nil)
|
||||
(reanimated/animate container-opacity constants/empty-opacity))
|
||||
(reanimated/animate gradient-opacity 0)
|
||||
(reset! lock-selection? true)
|
||||
(reset! saved-cursor-position @cursor-position)
|
||||
(reset! gradient-z-index (if (= (reanimated/get-shared-value gradient-opacity) 1) -1 0))
|
||||
(when (not= reopen-height max-height)
|
||||
(reset! maximized? false)
|
||||
(rf/dispatch [:chat.ui/set-input-maximized false])))))
|
||||
(let [lines (utils/calc-lines (- @content-height constants/extra-content-offset))
|
||||
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 nil)
|
||||
(reanimated/animate container-opacity constants/empty-opacity))
|
||||
(reanimated/animate gradient-opacity 0)
|
||||
(reset! lock-selection? true)
|
||||
(reset! saved-cursor-position @cursor-position)
|
||||
(reset! gradient-z-index (if (= (reanimated/get-shared-value gradient-opacity) 1) -1 0))
|
||||
(when (not= reopen-height max-height)
|
||||
(reset! maximized? false)
|
||||
(rf/dispatch [:chat.ui/set-input-maximized false]))))
|
||||
|
||||
(defn content-size-change
|
||||
[event
|
||||
@@ -120,7 +118,7 @@
|
||||
(@record-reset-fn)
|
||||
(reset! recording? false))
|
||||
(rf/dispatch [:chat.ui/set-chat-input-text text])
|
||||
(debounce/debounce-and-dispatch [:mention/on-change-text text] 300))
|
||||
(rf/dispatch [:mention/on-change-text text]))
|
||||
|
||||
(defn selection-change
|
||||
[event
|
||||
|
||||
@@ -34,9 +34,7 @@
|
||||
[:<>
|
||||
[rn/view {:style {:margin-bottom 10}} [text/text-content first-image context]]
|
||||
[rn/view
|
||||
{:style (style/album-container portrait?)
|
||||
:accessible true
|
||||
:accessibility-label :image-container}
|
||||
{:style (style/album-container portrait?)}
|
||||
(map-indexed
|
||||
(fn [index item]
|
||||
(let [images-size-key (if (< images-count constants/max-album-photos)
|
||||
|
||||
@@ -20,8 +20,7 @@
|
||||
|
||||
(h/describe "audio message"
|
||||
(h/before-each
|
||||
#(setup-subs {:mediaserver/port 1000
|
||||
:app-state "active"}))
|
||||
#(setup-subs {:mediaserver/port 1000}))
|
||||
|
||||
(h/test "renders correctly"
|
||||
(h/render [audio-message/audio-message message context])
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
audio-url
|
||||
(fn [base64-data]
|
||||
(let [player (audio/new-player
|
||||
(str "data:audio/aac;base64," base64-data)
|
||||
(str "data:audio/acc;base64," base64-data)
|
||||
{:autoDestroy false
|
||||
:continuesToPlayInBackground false}
|
||||
(fn []
|
||||
@@ -68,7 +68,6 @@
|
||||
(when (and @progress-timer (= @current-player-key player-key))
|
||||
(js/clearInterval @progress-timer)
|
||||
(reset! progress-timer nil))))]
|
||||
(audio/set-player-wake-lock player true)
|
||||
(swap! active-players assoc player-key player)
|
||||
(audio/prepare-player
|
||||
player
|
||||
@@ -91,8 +90,7 @@
|
||||
(when-not playing?
|
||||
(reset! current-player-key player-key))
|
||||
(if (and player
|
||||
(= (@audio-uris player-key) audio-uri)
|
||||
(not= (audio/get-state player) audio/IDLE))
|
||||
(= (@audio-uris player-key) audio-uri))
|
||||
(audio/toggle-playpause-player
|
||||
player
|
||||
(fn []
|
||||
@@ -123,7 +121,7 @@
|
||||
(reset! seeking-audio? false)
|
||||
(if (> @progress 0)
|
||||
(let [seek-time (* audio-duration-ms @progress)
|
||||
checked-seek-time (if (<= @progress 1) seek-time @progress)]
|
||||
checked-seek-time (min audio-duration-ms seek-time)]
|
||||
(seek-player
|
||||
player-key
|
||||
player-state
|
||||
@@ -143,20 +141,13 @@
|
||||
(if (or @seeking-audio? (#{:playing :seeking} @player-state))
|
||||
(if (<= @progress 1) (* duration @progress) @progress)
|
||||
duration)
|
||||
1000)
|
||||
paused? (= (audio/get-state player) audio/PAUSED)
|
||||
app-state (rf/sub [:app-state])]
|
||||
1000)]
|
||||
(rn/use-effect (fn [] #(destroy-player player-key)))
|
||||
(rn/use-effect
|
||||
(fn []
|
||||
(when (or
|
||||
(and (some? @current-player-key)
|
||||
(not= @current-player-key player-key)
|
||||
(= @player-state :playing))
|
||||
(and platform/ios?
|
||||
(= @current-player-key player-key)
|
||||
(not= app-state "active")
|
||||
(= @player-state :playing)))
|
||||
(when (and (some? @current-player-key)
|
||||
(not= @current-player-key player-key)
|
||||
(= @player-state :playing))
|
||||
(play-pause-player {:player-key player-key
|
||||
:player-state player-state
|
||||
:progress progress
|
||||
@@ -164,7 +155,7 @@
|
||||
:audio-duration-ms duration
|
||||
:seeking-audio? seeking-audio?
|
||||
:user-interaction? false})))
|
||||
[@current-player-key app-state])
|
||||
[@current-player-key])
|
||||
(if (= @player-state :error)
|
||||
[quo/text
|
||||
{:style style/error-label
|
||||
@@ -186,12 +177,10 @@
|
||||
:user-interaction? true})
|
||||
:style (style/play-pause-container)}
|
||||
[quo/icon
|
||||
(cond
|
||||
(= @player-state :preparing)
|
||||
:i/loading
|
||||
(and (= @player-state :playing) (not paused?))
|
||||
:i/pause-audio
|
||||
:else :i/play-audio)
|
||||
(case @player-state
|
||||
:preparing :i/loading
|
||||
:playing :i/pause-audio
|
||||
:i/play-audio)
|
||||
{:size 20
|
||||
:color colors/white}]]
|
||||
[:f> quo/soundtrack
|
||||
|
||||
@@ -18,19 +18,18 @@
|
||||
(let [insets (safe-area/get-insets)
|
||||
dimensions (calculate-dimensions (or image-width 1000) (or image-height 1000))
|
||||
shared-element-id (rf/sub [:shared-element-id])]
|
||||
[:<>
|
||||
[rn/touchable-opacity
|
||||
{:active-opacity 1
|
||||
:style {:margin-top (when (pos? index) 10)}
|
||||
:on-long-press on-long-press
|
||||
:on-press #(rf/dispatch [:chat.ui/navigate-to-lightbox
|
||||
message-id
|
||||
{:messages [message]
|
||||
:index 0
|
||||
:insets insets}])}
|
||||
(when (= index 0)
|
||||
[rn/view {:style {:margin-bottom 10}} [text/text-content message context]])
|
||||
[rn/touchable-opacity
|
||||
{:active-opacity 1
|
||||
:style {:margin-top (when (pos? index) 10)}
|
||||
:on-long-press on-long-press
|
||||
:on-press #(rf/dispatch [:chat.ui/navigate-to-lightbox
|
||||
message-id
|
||||
{:messages [message]
|
||||
:index 0
|
||||
:insets insets}])}
|
||||
[fast-image/fast-image
|
||||
{:source {:uri (:image content)}
|
||||
:style (merge dimensions {:border-radius 12})
|
||||
:native-ID (when (= shared-element-id message-id) :shared-element)}]]]))
|
||||
[fast-image/fast-image
|
||||
{:source {:uri (:image content)}
|
||||
:style (merge dimensions {:border-radius 12})
|
||||
:native-ID (when (= shared-element-id message-id) :shared-element)}]]))
|
||||
|
||||
@@ -1,7 +1,19 @@
|
||||
(ns status-im2.contexts.onboarding.create-password.style
|
||||
(:require [quo2.foundations.colors :as colors]))
|
||||
|
||||
(def flex-fill {:flex 1})
|
||||
(def image-background
|
||||
{:height "100%"
|
||||
:width "100%"})
|
||||
|
||||
(def overlay
|
||||
{:position :absolute
|
||||
:top 0
|
||||
:bottom 0
|
||||
:left 0
|
||||
:right 0
|
||||
:background-color colors/neutral-80-opa-80-blur})
|
||||
|
||||
(def content-style {:flex-grow 1})
|
||||
|
||||
(def heading {:margin-bottom 20})
|
||||
(def heading-subtitle {:color colors/white})
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
(ns status-im2.contexts.onboarding.create-password.view
|
||||
(:require
|
||||
[oops.core :refer [ocall]]
|
||||
[quo2.core :as quo]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[react-native.core :as rn]
|
||||
@@ -67,8 +66,7 @@
|
||||
:shown true}
|
||||
:placeholder (i18n/label :t/password-creation-placeholder-1)
|
||||
:on-change-text on-change-password
|
||||
:on-focus on-input-focus
|
||||
:auto-focus true}]
|
||||
:on-focus on-input-focus}]
|
||||
[rn/view {:style style/space-between-inputs}]
|
||||
[password-with-hint
|
||||
{:hint {:text hint-2-text
|
||||
@@ -122,7 +120,7 @@
|
||||
(count)))
|
||||
|
||||
(defn password-form
|
||||
[]
|
||||
[{:keys [scroll-to-end-fn]}]
|
||||
(let [password (reagent/atom "")
|
||||
repeat-password (reagent/atom "")
|
||||
accepts-disclaimer? (reagent/atom false)
|
||||
@@ -136,7 +134,7 @@
|
||||
:as validations} (password-validations @password)
|
||||
password-strength (calc-password-strength validations)
|
||||
empty-password? (empty? @password)
|
||||
same-passwords? (and (not empty-password?) (= @password @repeat-password))
|
||||
same-passwords? (= @password @repeat-password)
|
||||
meet-requirements? (and (not empty-password?)
|
||||
(utils.string/at-least-n-chars? @password 10)
|
||||
same-passwords?
|
||||
@@ -149,7 +147,9 @@
|
||||
:passwords-match? same-passwords?
|
||||
:empty-password? empty-password?
|
||||
:show-password-validation? @show-password-validation?
|
||||
:on-input-focus #(reset! focused-input :password)
|
||||
:on-input-focus (fn []
|
||||
(scroll-to-end-fn)
|
||||
(reset! focused-input :password))
|
||||
:on-change-password (fn [new-value]
|
||||
(reset! password new-value)
|
||||
(when (same-password-length?)
|
||||
@@ -163,14 +163,14 @@
|
||||
(reset! show-password-validation? true))}]]
|
||||
|
||||
[rn/view {:style style/bottom-part}
|
||||
(when same-passwords?
|
||||
[rn/view {:style style/disclaimer-container}
|
||||
[quo/disclaimer
|
||||
{:blur? true
|
||||
:on-change #(swap! accepts-disclaimer? not)
|
||||
:checked? @accepts-disclaimer?}
|
||||
(i18n/label :t/password-creation-disclaimer)]])
|
||||
(when (and (= @focused-input :password) (not same-passwords?))
|
||||
[rn/view {:style style/disclaimer-container}
|
||||
[quo/disclaimer
|
||||
{:blur? true
|
||||
:on-change #(swap! accepts-disclaimer? not)
|
||||
:checked? @accepts-disclaimer?}
|
||||
(i18n/label :t/password-creation-disclaimer)]]
|
||||
|
||||
(when (= @focused-input :password)
|
||||
[help
|
||||
{:validations validations
|
||||
:password-strength password-strength}])
|
||||
@@ -196,45 +196,25 @@
|
||||
(i18n/label
|
||||
:t/create-profile-password-info-box-description)]]])
|
||||
|
||||
(defn- f-create-password
|
||||
[]
|
||||
(let [keyboard-shown? (reagent/atom false)
|
||||
{:keys [top bottom]} (safe-area/get-insets)]
|
||||
(fn []
|
||||
(rn/use-effect
|
||||
(let [will-show-listener (ocall rn/keyboard
|
||||
"addListener"
|
||||
"keyboardWillShow"
|
||||
#(reset! keyboard-shown? true))
|
||||
will-hide-listener (ocall rn/keyboard
|
||||
"addListener"
|
||||
"keyboardWillHide"
|
||||
#(reset! keyboard-shown? false))]
|
||||
(fn []
|
||||
(fn []
|
||||
(ocall will-show-listener "remove")
|
||||
(ocall will-hide-listener "remove"))))
|
||||
[])
|
||||
[rn/touchable-without-feedback
|
||||
{:on-press rn/dismiss-keyboard!
|
||||
:accessible false}
|
||||
[rn/view {:style style/flex-fill}
|
||||
[rn/keyboard-avoiding-view {:style style/flex-fill}
|
||||
[navigation-bar/navigation-bar
|
||||
{:top top
|
||||
:right-section-buttons [{:type :blur-bg
|
||||
:icon :i/info
|
||||
:icon-override-theme :dark
|
||||
:on-press (fn []
|
||||
(rn/dismiss-keyboard!)
|
||||
(rf/dispatch [:show-bottom-sheet
|
||||
{:content create-password-doc
|
||||
:shell? true}]))}]}]
|
||||
[password-form]
|
||||
[rn/view {:style {:height (if-not @keyboard-shown? bottom 0)}}]]]])))
|
||||
|
||||
(defn create-password
|
||||
[]
|
||||
[:<>
|
||||
[background/view true]
|
||||
[:f> f-create-password]])
|
||||
(let [scroll-view-ref (atom nil)
|
||||
scroll-to-end-fn #(js/setTimeout ^js/Function (.-scrollToEnd @scroll-view-ref) 250)]
|
||||
(fn []
|
||||
(let [{:keys [top]} (safe-area/get-insets)]
|
||||
[:<>
|
||||
[background/view true]
|
||||
[rn/scroll-view
|
||||
{:ref #(reset! scroll-view-ref %)
|
||||
:style style/overlay
|
||||
:content-container-style style/content-style}
|
||||
[navigation-bar/navigation-bar
|
||||
{:top top
|
||||
:right-section-buttons [{:type :blur-bg
|
||||
:icon :i/info
|
||||
:icon-override-theme :dark
|
||||
:on-press #(rf/dispatch
|
||||
[:show-bottom-sheet
|
||||
{:content create-password-doc
|
||||
:shell? true}])}]}]
|
||||
[password-form {:scroll-to-end-fn scroll-to-end-fn}]]]))))
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
(ns status-im2.contexts.onboarding.events
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[native-module.core :as native-module]
|
||||
[utils.re-frame :as rf]
|
||||
[taoensso.timbre :as log]
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.ethereum.core :as ethereum]
|
||||
[status-im.utils.types :as types]
|
||||
[status-im2.config :as config]
|
||||
[status-im2.constants :as constants]
|
||||
[taoensso.timbre :as log]
|
||||
[clojure.string :as string]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]
|
||||
[utils.security.core :as security]))
|
||||
[utils.security.core :as security]
|
||||
[native-module.core :as native-module]
|
||||
[status-im.ethereum.core :as ethereum]
|
||||
[status-im2.constants :as constants]
|
||||
[status-im2.contexts.onboarding.profiles.view :as profiles.view]))
|
||||
|
||||
(re-frame/reg-fx
|
||||
:multiaccount/create-account-and-login
|
||||
@@ -139,10 +140,12 @@
|
||||
{:title (i18n/label :t/multiaccount-exists-title)
|
||||
:content (i18n/label :t/multiaccount-exists-content)
|
||||
:confirm-button-text (i18n/label :t/unlock)
|
||||
:on-accept (fn []
|
||||
(re-frame/dispatch [:pop-to-root :profiles])
|
||||
(re-frame/dispatch
|
||||
[:multiaccounts.login.ui/multiaccount-selected key-uid]))
|
||||
:on-accept #(do
|
||||
(re-frame/dispatch [:pop-to-root :profiles])
|
||||
;; FIXME(rasom): obviously not cool
|
||||
(reset! profiles.view/show-profiles? false)
|
||||
(re-frame/dispatch
|
||||
[:multiaccounts.login.ui/multiaccount-selected key-uid]))
|
||||
:on-cancel #(re-frame/dispatch [:pop-to-root :multiaccounts])}}
|
||||
{:db (assoc-in db [:onboarding-2/profile :seed-phrase] seed-phrase)
|
||||
:dispatch [:navigate-to :create-profile]}))
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
[utils.security.core :as security]
|
||||
[utils.transforms :as types]))
|
||||
|
||||
(def show-profiles? (reagent/atom false))
|
||||
|
||||
(defn login-multiaccount
|
||||
[]
|
||||
(rf/dispatch [:multiaccounts.login.ui/password-input-submitted]))
|
||||
@@ -41,14 +43,14 @@
|
||||
:context context
|
||||
:button-text (i18n/label :t/remove)
|
||||
:close-button-text (i18n/label :t/cancel)
|
||||
:on-press (fn []
|
||||
(rf/dispatch [:hide-bottom-sheet])
|
||||
(native-module/delete-multiaccount
|
||||
key-uid
|
||||
(fn [result]
|
||||
(let [{:keys [error]} (types/json->clj result)]
|
||||
(rf/dispatch [:onboarding-2/on-delete-profile-success key-uid])
|
||||
(log/info "profile deleted: error" error)))))}])
|
||||
:on-press #(do
|
||||
(rf/dispatch [:hide-bottom-sheet])
|
||||
(native-module/delete-multiaccount
|
||||
key-uid
|
||||
(fn [result]
|
||||
(let [{:keys [error]} (types/json->clj result)]
|
||||
(rf/dispatch [:onboarding-2/on-delete-profile-success key-uid])
|
||||
(log/info "profile deleted: error" error)))))}])
|
||||
|
||||
(defn show-confirmation
|
||||
[key-uid context]
|
||||
@@ -70,9 +72,7 @@
|
||||
{:content (fn [] [profile-options key-uid context])}]))
|
||||
|
||||
(defn profile-card
|
||||
[{:keys [name key-uid customization-color keycard-pairing last-index set-hide-profiles]
|
||||
:as multiaccount}
|
||||
index]
|
||||
[{:keys [name key-uid customization-color keycard-pairing last-index] :as multiaccount} index]
|
||||
(let [last-item? (= last-index index)
|
||||
profile-picture (:uri (first (:images multiaccount)))]
|
||||
[quo/profile-card
|
||||
@@ -89,18 +89,15 @@
|
||||
{:name name
|
||||
:color customization-color
|
||||
:profile-picture profile-picture})
|
||||
:on-card-press (fn []
|
||||
(rf/dispatch
|
||||
[:multiaccounts.login.ui/multiaccount-selected key-uid])
|
||||
(when-not keycard-pairing (set-hide-profiles)))}]))
|
||||
:on-card-press #(do
|
||||
(rf/dispatch
|
||||
[:multiaccounts.login.ui/multiaccount-selected key-uid])
|
||||
(when-not keycard-pairing (reset! show-profiles? false)))}]))
|
||||
|
||||
(defn profiles-section
|
||||
[{:keys [set-hide-profiles]}]
|
||||
[]
|
||||
(let [multiaccounts (vals (rf/sub [:multiaccounts/multiaccounts]))
|
||||
profiles-data (map #(assoc %
|
||||
:last-index (- (count multiaccounts) 1)
|
||||
:set-hide-profiles set-hide-profiles)
|
||||
multiaccounts)]
|
||||
multiaccounts (map #(assoc % :last-index (- (count multiaccounts) 1)) multiaccounts)]
|
||||
[rn/view
|
||||
{:style style/profiles-container}
|
||||
[rn/view
|
||||
@@ -119,7 +116,7 @@
|
||||
:override-theme :dark}
|
||||
:main-icons/add]]
|
||||
[rn/flat-list
|
||||
{:data (sort-by :timestamp > profiles-data)
|
||||
{:data (sort-by :timestamp > multiaccounts)
|
||||
:key-fn :key-uid
|
||||
:content-container-style {:padding-bottom 20}
|
||||
:render-fn profile-card}]]))
|
||||
@@ -172,8 +169,8 @@
|
||||
(i18n/label :t/forgot-your-password-info-create-new-password-description)]]]]])
|
||||
|
||||
(defn login-section
|
||||
[{:keys [set-show-profiles]}]
|
||||
(let [{:keys [name customization-color error processing password]
|
||||
[]
|
||||
(let [{:keys [name customization-color error processing]
|
||||
:as multiaccount} (rf/sub [:multiaccounts/login])
|
||||
sign-in-enabled? (rf/sub [:sign-in-enabled?])
|
||||
profile-picture (:uri (first (:images multiaccount)))]
|
||||
@@ -183,8 +180,7 @@
|
||||
{:size 32
|
||||
:type :blur-bg
|
||||
:icon true
|
||||
:on-press set-show-profiles
|
||||
:disabled processing
|
||||
:on-press #(reset! show-profiles? true)
|
||||
:override-theme :dark
|
||||
:width 32
|
||||
:accessibility-label :show-profiles
|
||||
@@ -201,18 +197,18 @@
|
||||
[quo/input
|
||||
{:type :password
|
||||
:blur? true
|
||||
:disabled? processing
|
||||
:override-theme :dark
|
||||
:placeholder (i18n/label :t/type-your-password)
|
||||
:auto-focus true
|
||||
:error? (seq error)
|
||||
:error? (when (not-empty error) error)
|
||||
:label (i18n/label :t/profile-password)
|
||||
:secure-text-entry true
|
||||
:on-change-text (fn [password]
|
||||
(rf/dispatch [:set-in [:multiaccounts/login :password]
|
||||
(security/mask-data password)])
|
||||
(rf/dispatch [:set-in [:multiaccounts/login :error] ""]))
|
||||
:default-value (security/safe-unmask-data password)
|
||||
:on-submit-editing (when sign-in-enabled? login-multiaccount)}]
|
||||
(when (seq error)
|
||||
(when (not-empty error)
|
||||
[quo/info-message
|
||||
{:type :error
|
||||
:size :default
|
||||
@@ -223,7 +219,6 @@
|
||||
{:size 40
|
||||
:type :ghost
|
||||
:before :i/info
|
||||
:disabled processing
|
||||
:accessibility-label :forget-password-button
|
||||
:override-theme :dark
|
||||
:style style/forget-password-button
|
||||
@@ -244,12 +239,10 @@
|
||||
|
||||
(defn views
|
||||
[]
|
||||
(let [show-profiles? (reagent/atom false)
|
||||
set-show-profiles #(reset! show-profiles? true)
|
||||
set-hide-profiles #(reset! show-profiles? false)]
|
||||
(fn []
|
||||
[:<>
|
||||
[background/view true]
|
||||
(if @show-profiles?
|
||||
[profiles-section {:set-hide-profiles set-hide-profiles}]
|
||||
[login-section {:set-show-profiles set-show-profiles}])])))
|
||||
(reset! show-profiles? false)
|
||||
(fn []
|
||||
[:<>
|
||||
[background/view true]
|
||||
(if @show-profiles?
|
||||
[profiles-section]
|
||||
[login-section])]))
|
||||
|
||||
@@ -1,11 +1,241 @@
|
||||
(ns status-im2.contexts.onboarding.sign-in.view
|
||||
(:require [utils.i18n :as i18n]
|
||||
(:require [clojure.string :as string]
|
||||
[oops.core :as oops]
|
||||
[quo2.core :as quo]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[react-native.blur :as blur]
|
||||
[react-native.camera-kit :as camera-kit]
|
||||
[react-native.core :as rn]
|
||||
[react-native.hole-view :as hole-view]
|
||||
[react-native.permissions :as permissions]
|
||||
[react-native.platform :as platform]
|
||||
[react-native.safe-area :as safe-area]
|
||||
[reagent.core :as reagent]
|
||||
[status-im2.constants :as constants]
|
||||
[status-im2.contexts.onboarding.common.background.view :as background]
|
||||
[status-im2.contexts.syncing.scan-sync-code.view :as scan-sync-code]))
|
||||
[status-im2.contexts.onboarding.sign-in.style :as style]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]
|
||||
[utils.transforms :as transforms]))
|
||||
|
||||
(defonce camera-permission-granted? (reagent/atom false))
|
||||
|
||||
(defn- header
|
||||
[active-tab read-qr-once?]
|
||||
[:<>
|
||||
[rn/view {:style style/header-container}
|
||||
[quo/button
|
||||
{:icon true
|
||||
:type :blur-bg
|
||||
:size 32
|
||||
:accessibility-label :close-sign-in-by-syncing
|
||||
:override-theme :dark
|
||||
:on-press #(rf/dispatch [:navigate-back])}
|
||||
:i/close]
|
||||
[quo/button
|
||||
{:before :i/info
|
||||
:type :blur-bg
|
||||
:size 32
|
||||
:accessibility-label :find-sync-code
|
||||
:override-theme :dark
|
||||
:on-press #(js/alert "Yet to be implemented")}
|
||||
(i18n/label :t/find-sync-code)]]
|
||||
[quo/text
|
||||
{:size :heading-1
|
||||
:weight :semi-bold
|
||||
:style style/header-text}
|
||||
(i18n/label :t/sign-in-by-syncing)]
|
||||
[quo/text
|
||||
{:size :paragraph-1
|
||||
:weight :regular
|
||||
:style style/header-sub-text}
|
||||
(i18n/label :t/synchronise-your-data-across-your-devices)]
|
||||
[rn/view {:style style/tabs-container}
|
||||
[quo/segmented-control
|
||||
{:size 32
|
||||
:override-theme :dark
|
||||
:blur? true
|
||||
:default-active @active-tab
|
||||
:data [{:id 1 :label (i18n/label :t/scan-sync-qr-code)}
|
||||
{:id 2 :label (i18n/label :t/enter-sync-code)}]
|
||||
:on-change (fn [id]
|
||||
(reset! active-tab id)
|
||||
(reset! read-qr-once? false))}]]])
|
||||
|
||||
(defn- camera-permission-view
|
||||
[request-camera-permission]
|
||||
[rn/view {:style style/camera-permission-container}
|
||||
[quo/text
|
||||
{:size :paragraph-1
|
||||
:weight :medium
|
||||
:style style/enable-camera-access-header}
|
||||
(i18n/label :t/enable-access-to-camera)]
|
||||
[quo/text
|
||||
{:size :paragraph-2
|
||||
:weight :regular
|
||||
:style style/enable-camera-access-sub-text}
|
||||
(i18n/label :t/to-scan-a-qr-enable-your-camera)]
|
||||
[quo/button
|
||||
{:before :i/camera
|
||||
:type :primary
|
||||
:size 32
|
||||
:accessibility-label :request-camera-permission
|
||||
:override-theme :dark
|
||||
:on-press request-camera-permission}
|
||||
(i18n/label :t/enable-camera)]])
|
||||
|
||||
(defn- qr-scan-hole-area
|
||||
[qr-view-finder]
|
||||
[rn/view
|
||||
{:style style/qr-view-finder
|
||||
:on-layout (fn [event]
|
||||
(let [layout (transforms/js->clj (oops/oget event "nativeEvent.layout"))
|
||||
width (:width layout)
|
||||
y (if platform/android?
|
||||
(+ (safe-area/get-top) (:y layout))
|
||||
(:y layout))
|
||||
view-finder (-> layout
|
||||
(assoc :height width)
|
||||
(assoc :y y))]
|
||||
(reset! qr-view-finder view-finder)))}])
|
||||
|
||||
|
||||
(defn- border
|
||||
[border1 border2 corner]
|
||||
[rn/view
|
||||
(assoc {:border-color colors/white :width 80 :height 80} border1 2 border2 2 corner 16)])
|
||||
|
||||
(defn- viewfinder
|
||||
[qr-view-finder]
|
||||
(let [size (:width qr-view-finder)]
|
||||
[rn/view {:style (style/viewfinder-container qr-view-finder)}
|
||||
[rn/view {:width size :height size :justify-content :space-between}
|
||||
[rn/view {:flex-direction :row :justify-content :space-between}
|
||||
[border :border-top-width :border-left-width :border-top-left-radius]
|
||||
[border :border-top-width :border-right-width :border-top-right-radius]]
|
||||
[rn/view {:flex-direction :row :justify-content :space-between}
|
||||
[border :border-bottom-width :border-left-width :border-bottom-left-radius]
|
||||
[border :border-bottom-width :border-right-width :border-bottom-right-radius]]]
|
||||
[quo/text
|
||||
{:size :paragraph-2
|
||||
:weight :regular
|
||||
:style style/viewfinder-text}
|
||||
(i18n/label :t/ensure-qr-code-is-in-focus-to-scan)]]))
|
||||
|
||||
(defn- scan-qr-code-tab
|
||||
[qr-view-finder request-camera-permission]
|
||||
[:<>
|
||||
[rn/view {:style style/scan-qr-code-container}]
|
||||
(when (empty? @qr-view-finder)
|
||||
[qr-scan-hole-area qr-view-finder])
|
||||
(if (and @camera-permission-granted? (boolean (not-empty @qr-view-finder)))
|
||||
[viewfinder @qr-view-finder]
|
||||
[camera-permission-view request-camera-permission])])
|
||||
|
||||
(defn- enter-sync-code-tab
|
||||
[]
|
||||
[rn/view {:style style/enter-sync-code-container}
|
||||
[quo/text
|
||||
{:size :paragraph-1
|
||||
:weight :medium
|
||||
:style {:color colors/white}}
|
||||
"Yet to be implemented"]])
|
||||
|
||||
(defn- bottom-view
|
||||
[insets]
|
||||
[rn/touchable-without-feedback
|
||||
{:on-press #(js/alert "Yet to be implemented")}
|
||||
[rn/view
|
||||
{:style (style/bottom-container (:bottom insets))}
|
||||
[quo/text
|
||||
{:size :paragraph-2
|
||||
:weight :regular
|
||||
:style style/bottom-text}
|
||||
(i18n/label :t/i-dont-have-status-on-another-device)]]])
|
||||
|
||||
(defn- check-qr-code-data
|
||||
[event]
|
||||
(let [connection-string (string/trim (oops/oget event "nativeEvent.codeStringValue"))
|
||||
valid-connection-string? (string/starts-with?
|
||||
connection-string
|
||||
constants/local-pairing-connection-string-identifier)]
|
||||
(if valid-connection-string?
|
||||
(rf/dispatch [:syncing/input-connection-string-for-bootstrapping connection-string])
|
||||
(rf/dispatch [:toasts/upsert
|
||||
{:icon :i/info
|
||||
:icon-color colors/danger-50
|
||||
:override-theme :light
|
||||
:text (i18n/label :t/error-this-is-not-a-sync-qr-code)}]))))
|
||||
|
||||
(defn f-view
|
||||
[]
|
||||
(let [camera-ref (atom nil)
|
||||
read-qr-once? (atom false)
|
||||
insets (safe-area/get-insets)
|
||||
active-tab (reagent/atom 1)
|
||||
qr-view-finder (reagent/atom {})
|
||||
{:keys [height width]} (rf/sub [:dimensions/window])
|
||||
request-camera-permission (fn []
|
||||
(rf/dispatch
|
||||
[:request-permissions
|
||||
{:permissions [:camera]
|
||||
:on-allowed #(reset! camera-permission-granted? true)
|
||||
:on-denied #(rf/dispatch
|
||||
[:toasts/upsert
|
||||
{:icon :i/info
|
||||
:icon-color colors/danger-50
|
||||
:override-theme :light
|
||||
:text (i18n/label
|
||||
:t/camera-permission-denied)}])}]))]
|
||||
(fn []
|
||||
(let [holes (merge @qr-view-finder {:borderRadius 16})
|
||||
scan-qr-code-tab? (= @active-tab 1)
|
||||
show-camera? (and scan-qr-code-tab? @camera-permission-granted?)
|
||||
show-holes? (and show-camera?
|
||||
(boolean (not-empty @qr-view-finder)))
|
||||
on-read-code (fn [data]
|
||||
(when-not @read-qr-once?
|
||||
(reset! read-qr-once? true)
|
||||
(js/setTimeout (fn []
|
||||
(reset! read-qr-once? false))
|
||||
3000)
|
||||
(check-qr-code-data data)))
|
||||
hole-view-wrapper (if show-camera?
|
||||
[hole-view/hole-view
|
||||
{:style style/absolute-fill
|
||||
:holes (if show-holes?
|
||||
[holes]
|
||||
[])}]
|
||||
[:<>])]
|
||||
(rn/use-effect
|
||||
(fn []
|
||||
(when-not @camera-permission-granted?
|
||||
(permissions/permission-granted? :camera
|
||||
#(reset! camera-permission-granted? %)
|
||||
#(reset! camera-permission-granted? false)))))
|
||||
[rn/view {:style (style/root-container (:top insets))}
|
||||
(if show-camera?
|
||||
[camera-kit/camera
|
||||
{:ref #(reset! camera-ref %)
|
||||
:style (merge style/absolute-fill {:height height :width width})
|
||||
:camera-options {:zoomMode :off}
|
||||
:scan-barcode true
|
||||
:on-read-code on-read-code}]
|
||||
[background/view true])
|
||||
(conj hole-view-wrapper
|
||||
[blur/view
|
||||
{:style style/absolute-fill
|
||||
:overlay-color colors/neutral-80-opa-80
|
||||
:blur-type :dark
|
||||
:blur-amount (if platform/ios? 15 5)}])
|
||||
[header active-tab read-qr-once?]
|
||||
(case @active-tab
|
||||
1 [scan-qr-code-tab qr-view-finder request-camera-permission]
|
||||
2 [enter-sync-code-tab]
|
||||
nil)
|
||||
[rn/view {:style style/flex-spacer}]
|
||||
[bottom-view insets]]))))
|
||||
|
||||
(defn view
|
||||
[]
|
||||
[scan-sync-code/view
|
||||
{:title (i18n/label :t/sign-in-by-syncing)
|
||||
:show-bottom-view? true
|
||||
:background [background/view true]}])
|
||||
[:f> f-view])
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
(ns status-im2.contexts.quo-preview.keycard.keycard
|
||||
(:require [status-im2.contexts.quo-preview.preview :as preview]
|
||||
[react-native.core :as rn]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[reagent.core :as reagent]
|
||||
[quo2.core :as quo]))
|
||||
|
||||
(def descriptor
|
||||
[{:label "Holder"
|
||||
:key :holder-name
|
||||
:type :text}
|
||||
{:label "Locked?"
|
||||
:key :locked?
|
||||
:type :boolean}])
|
||||
|
||||
(defn cool-preview
|
||||
[]
|
||||
(let [state (reagent/atom {:holder-name nil
|
||||
:locked? true})]
|
||||
(fn
|
||||
[]
|
||||
[rn/touchable-without-feedback {:on-press rn/dismiss-keyboard!}
|
||||
[rn/view [preview/customizer state descriptor]
|
||||
[quo/keycard
|
||||
{:holder-name? (:holder-name @state)
|
||||
:locked? (:locked? @state)}]]])))
|
||||
|
||||
(defn preview-keycard
|
||||
[]
|
||||
[rn/view
|
||||
{:style {:background-color (colors/theme-colors colors/white colors/neutral-95)
|
||||
:flex 1}}
|
||||
[rn/flat-list
|
||||
{:style {:flex 1}
|
||||
:keyboard-should-persist-taps :always
|
||||
:header [cool-preview]
|
||||
:key-fn str}]])
|
||||
@@ -90,8 +90,7 @@
|
||||
[status-im2.contexts.quo-preview.wallet.lowest-price :as lowest-price]
|
||||
[status-im2.contexts.quo-preview.wallet.network-amount :as network-amount]
|
||||
[status-im2.contexts.quo-preview.wallet.network-breakdown :as network-breakdown]
|
||||
[status-im2.contexts.quo-preview.wallet.token-overview :as token-overview]
|
||||
[status-im2.contexts.quo-preview.keycard.keycard :as keycard]))
|
||||
[status-im2.contexts.quo-preview.wallet.token-overview :as token-overview]))
|
||||
|
||||
(def screens-categories
|
||||
{:foundations [{:name :shadows
|
||||
@@ -345,10 +344,7 @@
|
||||
:component network-breakdown/preview-network-breakdown}
|
||||
{:name :network-amount
|
||||
:options {:topBar {:visible true}}
|
||||
:component network-amount/preview}]
|
||||
:keycard [{:name :keycard-component
|
||||
:options {:topBar {:visible true}}
|
||||
:component keycard/preview-keycard}]})
|
||||
:component network-amount/preview}]})
|
||||
|
||||
(def screens (flatten (map val screens-categories)))
|
||||
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
(ns status-im2.contexts.share.events
|
||||
(:require [utils.re-frame :as rf]
|
||||
[status-im2.common.toasts.events :as toasts]
|
||||
[quo2.foundations.colors :as colors]))
|
||||
|
||||
(rf/defn copy-text-and-show-toast
|
||||
{:events [:share/copy-text-and-show-toast]}
|
||||
[cofx text-to-copy post-copy-message]
|
||||
(rf/merge cofx
|
||||
{:copy-to-clipboard text-to-copy}
|
||||
(toasts/upsert
|
||||
{:icon :correct
|
||||
:icon-color colors/success-50
|
||||
:override-theme :dark
|
||||
:text post-copy-message})))
|
||||
@@ -1,102 +0,0 @@
|
||||
(ns status-im2.contexts.share.style
|
||||
(:require [quo2.foundations.colors :as colors]
|
||||
[react-native.platform :as platform]))
|
||||
|
||||
(def screen-padding 20)
|
||||
|
||||
(def blur
|
||||
{:style {:position :absolute
|
||||
:top 0
|
||||
:left 0
|
||||
:right 0
|
||||
:bottom 0}
|
||||
:overlay-color colors/neutral-80-opa-80
|
||||
:blur-amount 20})
|
||||
|
||||
(def header-button
|
||||
{:margin-bottom 12
|
||||
:margin-left screen-padding})
|
||||
|
||||
(def header-heading
|
||||
{:padding-horizontal screen-padding
|
||||
:padding-vertical 12
|
||||
:color colors/white})
|
||||
|
||||
(def qr-code-container
|
||||
{:padding 12
|
||||
:border-radius 16
|
||||
:margin-top 12
|
||||
:margin-bottom 4
|
||||
:margin-horizontal screen-padding
|
||||
:background-color colors/white-opa-5
|
||||
:flex-direction :column
|
||||
:justify-content :center})
|
||||
|
||||
(def emoji-hash-container
|
||||
{:border-radius 16
|
||||
:margin-top 12
|
||||
:margin-horizontal screen-padding
|
||||
:background-color colors/white-opa-5
|
||||
:flex-direction :row
|
||||
:justify-content :flex-start
|
||||
:align-items :flex-start})
|
||||
|
||||
(def profile-address-column
|
||||
{:flex-direction :column})
|
||||
|
||||
(def emoji-address-column
|
||||
{:flex-direction :column})
|
||||
|
||||
(def profile-address-label
|
||||
{:color colors/white-opa-40
|
||||
:padding-top 10})
|
||||
|
||||
(def profile-address-content
|
||||
{:color colors/white
|
||||
:align-self :flex-start
|
||||
:padding-top 2})
|
||||
|
||||
(def profile-address-container
|
||||
{:flex-direction :row
|
||||
:justify-content :flex-start
|
||||
:margin-top 6
|
||||
:margin-horizontal 4})
|
||||
|
||||
(def emoji-address-container
|
||||
{:flex-direction :row
|
||||
:justify-content :flex-start
|
||||
:margin-top 6
|
||||
:margin-horizontal 4})
|
||||
|
||||
(def emoji-hash-label
|
||||
{:color colors/white-opa-40
|
||||
:margin-top 8
|
||||
:padding-bottom (if platform/ios? 2 0)
|
||||
:padding-left 12})
|
||||
|
||||
|
||||
(def share-button-container
|
||||
{:position :absolute
|
||||
:right 0
|
||||
:top 16})
|
||||
|
||||
(def emoji-share-button-container
|
||||
{:position :absolute
|
||||
:right 4
|
||||
:top 16})
|
||||
|
||||
(def emoji-hash-content
|
||||
{:color colors/white
|
||||
:align-self :flex-start
|
||||
:padding-top 4
|
||||
:padding-bottom 12
|
||||
:padding-left 12
|
||||
:font-size 14})
|
||||
|
||||
(def tabs-container
|
||||
{:padding-horizontal screen-padding
|
||||
:margin-vertical 8})
|
||||
|
||||
(def wip-style
|
||||
{:color colors/white
|
||||
:text-align :center})
|
||||
@@ -1,162 +0,0 @@
|
||||
(ns status-im2.contexts.share.view
|
||||
(:require [utils.i18n :as i18n]
|
||||
[quo2.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[status-im2.contexts.share.style :as style]
|
||||
[utils.re-frame :as rf]
|
||||
[reagent.core :as reagent]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[clojure.string :as string]
|
||||
[react-native.blur :as blur]
|
||||
[status-im.ui.components.list-selection :as list-selection]
|
||||
[utils.image-server :as image-server]
|
||||
[react-native.navigation :as navigation]))
|
||||
|
||||
(defn header
|
||||
[]
|
||||
[:<>
|
||||
[quo/button
|
||||
{:icon true
|
||||
:type :blur-bg
|
||||
:size 32
|
||||
:accessibility-label :close-shell-share-tab
|
||||
:override-theme :dark
|
||||
:style style/header-button
|
||||
:on-press #(rf/dispatch [:navigate-back])}
|
||||
:i/close]
|
||||
[quo/text
|
||||
{:size :heading-1
|
||||
:weight :semi-bold
|
||||
:style style/header-heading}
|
||||
(i18n/label :t/share)]])
|
||||
|
||||
(defn abbreviated-url
|
||||
"The goal here is to generate a string that begins with
|
||||
join.status.im/u/ joined with the 1st 5 characters
|
||||
of the compressed public key followed by an ellipsis followed by
|
||||
the last 12 characters of the compressed public key"
|
||||
[base-url public-pk]
|
||||
(let [first-part-of-public-pk (subs public-pk 0 5)
|
||||
ellipsis "..."
|
||||
public-pk-size (count public-pk)
|
||||
last-part-of-public-pk (subs public-pk (- public-pk-size 12) (- public-pk-size 1))
|
||||
abbreviated-url (str base-url first-part-of-public-pk ellipsis last-part-of-public-pk)]
|
||||
abbreviated-url))
|
||||
|
||||
(defn profile-tab
|
||||
[window-width]
|
||||
(let [multiaccount (rf/sub [:multiaccount])
|
||||
emoji-hash (string/join (get multiaccount :emoji-hash))
|
||||
qr-size (int (- window-width 64))
|
||||
public-pk (get multiaccount :compressed-key)
|
||||
abbreviated-url (abbreviated-url image-server/status-profile-base-url-without-https public-pk)
|
||||
profile-url (str image-server/status-profile-base-url public-pk)
|
||||
port (rf/sub [:mediaserver/port])
|
||||
key-uid (get multiaccount :key-uid)
|
||||
source-uri (image-server/get-account-qr-image-uri {:key-uid key-uid
|
||||
:public-key public-pk
|
||||
:port port
|
||||
:qr-size qr-size})]
|
||||
[:<>
|
||||
[rn/view {:style style/qr-code-container}
|
||||
[quo/qr-code
|
||||
{:source {:uri source-uri}
|
||||
:width qr-size
|
||||
:height qr-size}]
|
||||
[rn/view {:style style/profile-address-container}
|
||||
[rn/view {:style style/profile-address-column}
|
||||
[quo/text
|
||||
{:size :paragraph-2
|
||||
:weight :medium
|
||||
:style style/profile-address-label}
|
||||
(i18n/label :t/link-to-profile)]
|
||||
[rn/touchable-highlight
|
||||
{:active-opacity 1
|
||||
:underlay-color colors/neutral-80-opa-1-blur
|
||||
:background-color :transparent
|
||||
:on-press #(rf/dispatch [:share/copy-text-and-show-toast profile-url
|
||||
(i18n/label :t/link-to-profile-copied)])
|
||||
:on-long-press #(rf/dispatch [:share/copy-text-and-show-toast profile-url
|
||||
(i18n/label :t/link-to-profile-copied)])}
|
||||
[quo/text
|
||||
{:style style/profile-address-content
|
||||
:size :paragraph-1
|
||||
:weight :medium
|
||||
:ellipsize-mode :middle
|
||||
:number-of-lines 1}
|
||||
abbreviated-url]]]
|
||||
[rn/view {:style style/share-button-container}
|
||||
[quo/button
|
||||
{:icon true
|
||||
:type :blur-bg
|
||||
:size 32
|
||||
:accessibility-label :link-to-profile
|
||||
:override-theme :dark
|
||||
:on-press #(list-selection/open-share {:message profile-url})}
|
||||
:i/share]]]]
|
||||
|
||||
[rn/view {:style style/emoji-hash-container}
|
||||
[rn/view {:style style/emoji-address-container}
|
||||
[rn/view {:style style/emoji-address-column}
|
||||
[quo/text
|
||||
{:size :paragraph-2
|
||||
:weight :medium
|
||||
:style style/emoji-hash-label}
|
||||
(i18n/label :t/emoji-hash)]
|
||||
[rn/touchable-highlight
|
||||
{:active-opacity 1
|
||||
:underlay-color colors/neutral-80-opa-1-blur
|
||||
:background-color :transparent
|
||||
:on-press #(rf/dispatch [:share/copy-text-and-show-toast emoji-hash
|
||||
(i18n/label :t/emoji-hash-copied)])
|
||||
:on-long-press #(rf/dispatch [:share/copy-text-and-show-toast emoji-hash
|
||||
(i18n/label :t/emoji-hash-copied)])}
|
||||
[rn/text {:style style/emoji-hash-content} emoji-hash]]]]
|
||||
[rn/view {:style style/emoji-share-button-container}
|
||||
[quo/button
|
||||
{:icon true
|
||||
:type :blur-bg
|
||||
:size 32
|
||||
:accessibility-label :link-to-profile
|
||||
:override-theme :dark
|
||||
:style {:margin-right 12}
|
||||
:on-press #(rf/dispatch [:share/copy-text-and-show-toast emoji-hash
|
||||
(i18n/label :t/emoji-hash-copied)])
|
||||
:on-long-press #(rf/dispatch [:share/copy-text-and-show-toast emoji-hash
|
||||
(i18n/label :t/emoji-hash-copied)])}
|
||||
:i/copy]]]]))
|
||||
|
||||
(defn wallet-tab
|
||||
[]
|
||||
[rn/text {:style style/wip-style} "not implemented"])
|
||||
|
||||
(defn tab-content
|
||||
[window-width]
|
||||
(let [selected-tab (reagent/atom :profile)]
|
||||
(fn []
|
||||
[:<>
|
||||
[header]
|
||||
[rn/view {:style style/tabs-container}
|
||||
[quo/segmented-control
|
||||
{:size 28
|
||||
:blur? true
|
||||
:override-theme :dark
|
||||
:on-change #(reset! selected-tab %)
|
||||
:default-active :profile
|
||||
:data [{:id :profile
|
||||
:label (i18n/label :t/profile)}
|
||||
{:id :wallet
|
||||
:label (i18n/label :t/wallet)}]}]]
|
||||
(if (= @selected-tab :profile)
|
||||
[profile-tab window-width]
|
||||
[wallet-tab])])))
|
||||
|
||||
(defn view
|
||||
[]
|
||||
(let [window-width (rf/sub [:dimensions/window-width])]
|
||||
(fn []
|
||||
[rn/view
|
||||
{:flex 1
|
||||
:padding-top (navigation/status-bar-height)}
|
||||
[blur/view style/blur]
|
||||
[tab-content window-width]])))
|
||||
@@ -1,72 +0,0 @@
|
||||
(ns status-im2.contexts.syncing.how-to-pair.style
|
||||
(:require [quo2.foundations.colors :as colors]
|
||||
[react-native.platform :as platform]))
|
||||
|
||||
(def container-outer
|
||||
{:flex (if platform/ios? 4.5 5)
|
||||
:padding-top 20
|
||||
:padding-bottom 8
|
||||
:padding-horizontal 16
|
||||
:background-color colors/neutral-95})
|
||||
|
||||
(def heading
|
||||
{:margin-bottom 12
|
||||
:color colors/white})
|
||||
|
||||
(def tabs-container
|
||||
{:margin-top 8
|
||||
:margin-bottom 12})
|
||||
|
||||
(def paragraph
|
||||
{:margin-vertical 8
|
||||
:color colors/white})
|
||||
|
||||
(def hr
|
||||
{:margin-top 12
|
||||
:margin-bottom 6
|
||||
:border-bottom-color colors/white-opa-10
|
||||
:border-bottom-width 1})
|
||||
|
||||
(def image
|
||||
{:border-radius 16})
|
||||
|
||||
(def container-image
|
||||
{:flex-direction :row
|
||||
:aspect-ratio 1
|
||||
:justify-content :flex-end
|
||||
:align-items :flex-end
|
||||
:overflow :hidden
|
||||
:background-color colors/white-opa-5
|
||||
:border-radius 16})
|
||||
|
||||
(def list-text
|
||||
{:margin-horizontal 2
|
||||
:color colors/white})
|
||||
|
||||
(def list-icon
|
||||
{:height 18
|
||||
:width 18
|
||||
:border-radius 6
|
||||
:border-width 1
|
||||
:border-color colors/white-opa-10
|
||||
:align-items :center
|
||||
:justify-content :center})
|
||||
|
||||
(def list-icon-text
|
||||
{:color colors/white})
|
||||
|
||||
(def button-grey
|
||||
{:margin-horizontal 2})
|
||||
|
||||
(def button-grey-placeholder
|
||||
{:margin-horizontal 2})
|
||||
|
||||
(def button-primary
|
||||
{:margin-horizontal 2})
|
||||
|
||||
(def numbered-list
|
||||
{:margin-top 12})
|
||||
|
||||
(def numbered-list-item
|
||||
{:flex-direction :row
|
||||
:align-items :center})
|
||||
@@ -1,160 +0,0 @@
|
||||
(ns status-im2.contexts.syncing.how-to-pair.view
|
||||
(:require
|
||||
[react-native.gesture :as gesture]
|
||||
[status-im2.contexts.syncing.how-to-pair.style :as style]
|
||||
[status-im2.common.resources :as resources]
|
||||
[utils.i18n :as i18n]
|
||||
[quo2.core :as quo]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[react-native.core :as rn]
|
||||
[reagent.core :as reagent]))
|
||||
|
||||
(defn render-element
|
||||
[[type value]]
|
||||
(case type
|
||||
:text
|
||||
[quo/text
|
||||
{:size :paragraph-2
|
||||
:weight :regular
|
||||
:style style/list-text} (i18n/label value)]
|
||||
|
||||
:button-primary
|
||||
[quo/button
|
||||
{:type :primary
|
||||
:size 24
|
||||
:style style/button-primary} (i18n/label value)]
|
||||
|
||||
:button-grey
|
||||
[quo/button
|
||||
{:type :grey
|
||||
:override-theme :dark
|
||||
:size 24
|
||||
:style style/button-grey}
|
||||
(i18n/label value)]
|
||||
|
||||
:button-grey-placeholder
|
||||
[quo/button
|
||||
{:type :grey
|
||||
:override-theme :dark
|
||||
:size 24
|
||||
:before :i/placeholder
|
||||
:style style/button-grey-placeholder}
|
||||
(i18n/label value)]
|
||||
|
||||
:context-tag
|
||||
[quo/context-tag
|
||||
{:override-theme :dark
|
||||
:text-style {:color colors/white}}
|
||||
(resources/get-mock-image (:source value))
|
||||
(i18n/label (:label value))]))
|
||||
|
||||
(defn render-item
|
||||
[i item]
|
||||
[rn/view
|
||||
{:margin-vertical 6
|
||||
:style style/numbered-list-item}
|
||||
[rn/view
|
||||
{:margin-right 6
|
||||
:style style/list-icon}
|
||||
[quo/text
|
||||
{:size :label
|
||||
:weight :medium
|
||||
:style style/list-icon-text} i]]
|
||||
(map #(render-element %) item)])
|
||||
|
||||
(defn render-list
|
||||
[{:keys [title image list]}]
|
||||
[rn/view
|
||||
[quo/text
|
||||
{:size :paragraph-1
|
||||
:weight :semi-bold
|
||||
:style style/paragraph} (i18n/label title)]
|
||||
(case (:type image)
|
||||
:container-image [rn/view {:style style/container-image}
|
||||
[rn/image
|
||||
{:source (resources/get-image
|
||||
(:source image))}]]
|
||||
:image [rn/image
|
||||
{:source (resources/get-image (:source image))
|
||||
:style style/image}])
|
||||
[rn/view {:style style/numbered-list}
|
||||
(map-indexed (fn [i item] (render-item (inc i) item)) list)]])
|
||||
|
||||
(def platforms
|
||||
{:mobile
|
||||
[gesture/scroll-view
|
||||
(render-list {:title :t/signing-in-from-another-device
|
||||
:image {:source :mobile-how-to-pair-sign-in
|
||||
:type :image}
|
||||
:list [[[:text :t/open-status-on-your-other-device]]
|
||||
[[:text :t/tap-on]
|
||||
[:button-grey :t/im-new]]
|
||||
[[:button-primary :t/enable-camera]
|
||||
[:text :t/or-tap]
|
||||
[:button-grey :t/enter-sync-code]]
|
||||
[[:text :t/scan-or-enter-sync-code-seen-on-this-device]]]})
|
||||
[rn/view {:style style/hr}]
|
||||
(render-list {:title :t/already-logged-in-on-the-other-device
|
||||
:image {:source :mobile-how-to-pair-logged-in
|
||||
:type :image}
|
||||
:list [[[:text :t/tap-on]
|
||||
[:context-tag
|
||||
{:label :t/profile
|
||||
:source :user-picture-male5}]
|
||||
[:text :t/and]
|
||||
[:button-grey-placeholder :t/syncing]]
|
||||
[[:text :t/press]
|
||||
[:button-grey :t/scan-or-enter-sync-code]]
|
||||
[[:button-primary :t/enable-camera]
|
||||
[:text :t/or-tap]
|
||||
[:button-grey :t/enter-sync-code]]
|
||||
[[:text :t/scan-or-enter-sync-code-seen-on-this-device]]]})]
|
||||
:desktop
|
||||
[gesture/scroll-view
|
||||
(render-list {:title :t/signing-in-from-another-device
|
||||
:image {:source :desktop-how-to-pair-sign-in
|
||||
:type :image}
|
||||
:list [[[:text :t/open-status-on-your-other-device]]
|
||||
[[:text :t/open]
|
||||
[:button-grey :t/settings]
|
||||
[:text :t/and-go-to]
|
||||
[:button-grey :t/syncing]]
|
||||
[[:text :t/tap]
|
||||
[:button-grey :t/scan-or-enter-a-sync-code]]
|
||||
[[:text :t/scan-the-qr-code-or-copy-the-sync-code]]]})
|
||||
[rn/view {:style style/hr}]
|
||||
(render-list {:title :t/already-logged-in-on-the-other-device
|
||||
:image {:source :desktop-how-to-pair-logged-in
|
||||
:type :container-image}
|
||||
:list [[[:text :t/open-status-on-your-other-device]]
|
||||
[[:text :t/tap-on]
|
||||
[:button-grey :t/im-new]]
|
||||
[[:button-primary :t/enable-camera]
|
||||
[:text :t/or-tap]
|
||||
[:button-grey :t/enter-sync-code]]
|
||||
[[:text :t/scan-or-enter-sync-code-seen-on-this-device]]]})]})
|
||||
|
||||
(defn instructions
|
||||
[]
|
||||
(let [platform (reagent/atom :mobile)
|
||||
platform-data (map (fn [platform]
|
||||
{:id platform
|
||||
:label (i18n/label
|
||||
(keyword (str "t/" (name platform))))})
|
||||
(keys platforms))]
|
||||
(fn []
|
||||
[rn/view {:style style/container-outer}
|
||||
[quo/text
|
||||
{:size :heading-1
|
||||
:weight :semi-bold
|
||||
:style style/heading} (i18n/label :t/how-to-pair)]
|
||||
[rn/view {:style style/tabs-container}
|
||||
[quo/segmented-control
|
||||
{:size 28
|
||||
:override-theme :dark
|
||||
:blur? true
|
||||
:default-active :mobile
|
||||
:data platform-data
|
||||
:on-change #(reset! platform %)}]]
|
||||
(@platform platforms)])))
|
||||
|
||||
@@ -1,113 +0,0 @@
|
||||
(ns status-im2.contexts.syncing.scan-sync-code.style
|
||||
(:require [quo2.foundations.colors :as colors]
|
||||
[status-im.utils.platform :as platform]))
|
||||
|
||||
(def screen-padding 20)
|
||||
|
||||
(def flex-spacer {:flex 1})
|
||||
|
||||
(def absolute-fill
|
||||
{:position :absolute
|
||||
:top 0
|
||||
:bottom 0
|
||||
:left 0
|
||||
:right 0})
|
||||
|
||||
(def hole
|
||||
(merge absolute-fill
|
||||
{:z-index 2 :opacity 0.95}))
|
||||
|
||||
(defn root-container
|
||||
[padding-top]
|
||||
{:z-index 5
|
||||
:flex 1
|
||||
:padding-top padding-top})
|
||||
|
||||
(def header-container
|
||||
{:flex-direction :row
|
||||
:justify-content :space-between
|
||||
:padding-horizontal screen-padding
|
||||
:margin-vertical 12})
|
||||
|
||||
(def header-text
|
||||
{:padding-horizontal screen-padding
|
||||
:padding-top 12
|
||||
:padding-bottom 8
|
||||
:color colors/white})
|
||||
|
||||
(def header-sub-text
|
||||
{:padding-horizontal screen-padding
|
||||
:color colors/white})
|
||||
|
||||
(def tabs-container
|
||||
{:padding-horizontal screen-padding
|
||||
:margin-top 20})
|
||||
|
||||
(def scan-qr-code-container
|
||||
{:margin-top 19})
|
||||
|
||||
(def qr-view-finder
|
||||
{:margin-horizontal screen-padding
|
||||
:height 1
|
||||
:display :flex})
|
||||
|
||||
(defn viewfinder-container
|
||||
[viewfinder]
|
||||
{:position :absolute
|
||||
:left (:x viewfinder)
|
||||
:top (:y viewfinder)
|
||||
:overflow :hidden})
|
||||
|
||||
(def viewfinder-text
|
||||
{:color colors/white-opa-70
|
||||
:text-align :center
|
||||
:padding-top 16})
|
||||
|
||||
(def camera-permission-container
|
||||
{:height 335
|
||||
:margin-horizontal screen-padding
|
||||
:background-color colors/white-opa-5
|
||||
:border-color colors/white-opa-10
|
||||
:border-radius 12
|
||||
:align-items :center
|
||||
:justify-content :center})
|
||||
|
||||
(def enable-camera-access-header
|
||||
{:color colors/white})
|
||||
|
||||
(def enable-camera-access-sub-text
|
||||
{:color colors/white-opa-70
|
||||
:margin-bottom 16})
|
||||
|
||||
(def enter-sync-code-container
|
||||
{:margin-top 20
|
||||
:justify-content :center
|
||||
:align-items :center})
|
||||
|
||||
(defn bottom-container
|
||||
[padding-bottom]
|
||||
{:z-index 6
|
||||
:padding-top 12
|
||||
:padding-bottom padding-bottom
|
||||
:background-color colors/white-opa-5
|
||||
:border-top-left-radius 20
|
||||
:border-top-right-radius 20
|
||||
:align-items :center
|
||||
:justify-content :center})
|
||||
|
||||
(def bottom-text
|
||||
{:color colors/white
|
||||
:padding-bottom 12})
|
||||
|
||||
(def camera-style
|
||||
{:height "100%"
|
||||
:borderRadius 16
|
||||
:background-color :transparent})
|
||||
|
||||
(def camera-container
|
||||
{:position :absolute
|
||||
:top (if platform/android? 40 0)
|
||||
:left 0
|
||||
:right 0
|
||||
:bottom 0
|
||||
:border-radius 16})
|
||||
@@ -1,239 +0,0 @@
|
||||
(ns status-im2.contexts.syncing.scan-sync-code.view
|
||||
(:require [clojure.string :as string]
|
||||
[oops.core :as oops]
|
||||
[quo2.core :as quo]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[react-native.camera-kit :as camera-kit]
|
||||
[react-native.core :as rn]
|
||||
[react-native.blur :as blur]
|
||||
[react-native.hole-view :as hole-view]
|
||||
[react-native.permissions :as permissions]
|
||||
[react-native.safe-area :as safe-area]
|
||||
[reagent.core :as reagent]
|
||||
[status-im2.contexts.syncing.scan-sync-code.style :as style]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]
|
||||
[status-im2.contexts.syncing.utils :as sync-utils]))
|
||||
|
||||
(defonce camera-permission-granted? (reagent/atom false))
|
||||
|
||||
(defn- header
|
||||
[active-tab read-qr-once? title]
|
||||
[:<>
|
||||
[rn/view {:style style/header-container}
|
||||
[quo/button
|
||||
{:icon true
|
||||
:type :blur-bg
|
||||
:size 32
|
||||
:accessibility-label :close-sign-in-by-syncing
|
||||
:override-theme :dark
|
||||
:on-press #(rf/dispatch [:navigate-back])}
|
||||
:i/close]
|
||||
[quo/button
|
||||
{:before :i/info
|
||||
:type :blur-bg
|
||||
:size 32
|
||||
:accessibility-label :find-sync-code
|
||||
:override-theme :dark
|
||||
:on-press #(js/alert "Yet to be implemented")}
|
||||
(i18n/label :t/find-sync-code)]]
|
||||
[quo/text
|
||||
{:size :heading-1
|
||||
:weight :semi-bold
|
||||
:style style/header-text}
|
||||
title]
|
||||
[quo/text
|
||||
{:size :paragraph-1
|
||||
:weight :regular
|
||||
:style style/header-sub-text}
|
||||
(i18n/label :t/synchronise-your-data-across-your-devices)]
|
||||
[rn/view {:style style/tabs-container}
|
||||
[quo/segmented-control
|
||||
{:size 32
|
||||
:override-theme :dark
|
||||
:blur? true
|
||||
:default-active @active-tab
|
||||
:data [{:id 1 :label (i18n/label :t/scan-sync-qr-code)}
|
||||
{:id 2 :label (i18n/label :t/enter-sync-code)}]
|
||||
:on-change (fn [id]
|
||||
(reset! active-tab id)
|
||||
(reset! read-qr-once? false))}]]])
|
||||
|
||||
(defn- camera-permission-view
|
||||
[request-camera-permission]
|
||||
[rn/view {:style style/camera-permission-container}
|
||||
[quo/text
|
||||
{:size :paragraph-1
|
||||
:weight :medium
|
||||
:style style/enable-camera-access-header}
|
||||
(i18n/label :t/enable-access-to-camera)]
|
||||
[quo/text
|
||||
{:size :paragraph-2
|
||||
:weight :regular
|
||||
:style style/enable-camera-access-sub-text}
|
||||
(i18n/label :t/to-scan-a-qr-enable-your-camera)]
|
||||
[quo/button
|
||||
{:before :i/camera
|
||||
:type :primary
|
||||
:size 32
|
||||
:accessibility-label :request-camera-permission
|
||||
:override-theme :dark
|
||||
:on-press request-camera-permission}
|
||||
(i18n/label :t/enable-camera)]])
|
||||
|
||||
(defn- qr-scan-hole-area
|
||||
[qr-view-finder]
|
||||
[rn/view
|
||||
{:style style/qr-view-finder
|
||||
:on-layout (fn [event]
|
||||
(let [layout (js->clj (oops/oget event "nativeEvent.layout")
|
||||
:keywordize-keys
|
||||
true)
|
||||
view-finder (assoc layout :height (:width layout))]
|
||||
(reset! qr-view-finder view-finder)))}])
|
||||
|
||||
(defn- border
|
||||
[border1 border2 corner]
|
||||
[rn/view
|
||||
(assoc {:border-color colors/white :width 80 :height 80} border1 2 border2 2 corner 16)])
|
||||
|
||||
(defn- viewfinder
|
||||
[qr-view-finder]
|
||||
(let [size (:width qr-view-finder)]
|
||||
[:<>
|
||||
[rn/view {:style (style/viewfinder-container qr-view-finder)}
|
||||
|
||||
[rn/view {:width size :height size :justify-content :space-between}
|
||||
[rn/view {:flex-direction :row :justify-content :space-between}
|
||||
[border :border-top-width :border-left-width :border-top-left-radius]
|
||||
[border :border-top-width :border-right-width :border-top-right-radius]]
|
||||
[rn/view {:flex-direction :row :justify-content :space-between}
|
||||
[border :border-bottom-width :border-left-width :border-bottom-left-radius]
|
||||
[border :border-bottom-width :border-right-width :border-bottom-right-radius]]]
|
||||
[quo/text
|
||||
{:size :paragraph-2
|
||||
:weight :regular
|
||||
:style style/viewfinder-text}
|
||||
(i18n/label :t/ensure-qr-code-is-in-focus-to-scan)]]]))
|
||||
|
||||
(defn- scan-qr-code-tab
|
||||
[qr-view-finder request-camera-permission]
|
||||
[:<>
|
||||
[rn/view {:style style/scan-qr-code-container}]
|
||||
(when (empty? @qr-view-finder)
|
||||
[qr-scan-hole-area qr-view-finder])
|
||||
(if (and @camera-permission-granted? (boolean (not-empty @qr-view-finder)))
|
||||
[viewfinder @qr-view-finder]
|
||||
[camera-permission-view request-camera-permission])])
|
||||
|
||||
(defn- enter-sync-code-tab
|
||||
[]
|
||||
[rn/view {:style style/enter-sync-code-container}
|
||||
[quo/text
|
||||
{:size :paragraph-1
|
||||
:weight :medium
|
||||
:style {:color colors/white}}
|
||||
"Yet to be implemented"]])
|
||||
|
||||
(defn- bottom-view
|
||||
[insets]
|
||||
[rn/touchable-without-feedback
|
||||
{:on-press #(js/alert "Yet to be implemented")}
|
||||
[rn/view
|
||||
{:style (style/bottom-container (:bottom insets))}
|
||||
[quo/text
|
||||
{:size :paragraph-2
|
||||
:weight :regular
|
||||
:style style/bottom-text}
|
||||
(i18n/label :t/i-dont-have-status-on-another-device)]]])
|
||||
|
||||
(defn- check-qr-code-data
|
||||
[event]
|
||||
(let [connection-string (string/trim (oops/oget event "nativeEvent.codeStringValue"))
|
||||
valid-connection-string? (sync-utils/valid-connection-string? connection-string)]
|
||||
(if valid-connection-string?
|
||||
(rf/dispatch [:syncing/input-connection-string-for-bootstrapping connection-string])
|
||||
(rf/dispatch [:toasts/upsert
|
||||
{:icon :i/info
|
||||
:icon-color colors/danger-50
|
||||
:override-theme :light
|
||||
:text (i18n/label :t/error-this-is-not-a-sync-qr-code)}]))))
|
||||
|
||||
(defn render-camera
|
||||
[show-camera? qr-view-finder camera-ref on-read-code show-holes?]
|
||||
(when (and show-camera? (:x qr-view-finder))
|
||||
[:<>
|
||||
[rn/view {:style style/camera-container}
|
||||
[camera-kit/camera
|
||||
{:ref #(reset! camera-ref %)
|
||||
:style style/camera-style
|
||||
:camera-options {:zoomMode :off}
|
||||
:scan-barcode true
|
||||
:on-read-code on-read-code}]]
|
||||
[hole-view/hole-view
|
||||
{:style style/hole
|
||||
:holes (if show-holes?
|
||||
[(merge qr-view-finder
|
||||
{:borderRadius 16})]
|
||||
[])}
|
||||
[blur/view
|
||||
{:style style/absolute-fill
|
||||
:blur-amount 10
|
||||
:blur-type :transparent
|
||||
:overlay-color colors/neutral-80-opa-80
|
||||
:background-color colors/neutral-80-opa-80}]
|
||||
]]))
|
||||
|
||||
(defn f-view
|
||||
[{:keys [title show-bottom-view? background]}]
|
||||
(let [insets (safe-area/get-insets)
|
||||
active-tab (reagent/atom 1)
|
||||
qr-view-finder (reagent/atom {})
|
||||
request-camera-permission (fn []
|
||||
(rf/dispatch
|
||||
[:request-permissions
|
||||
{:permissions [:camera]
|
||||
:on-allowed #(reset! camera-permission-granted? true)
|
||||
:on-denied #(rf/dispatch
|
||||
[:toasts/upsert
|
||||
{:icon :i/info
|
||||
:icon-color colors/danger-50
|
||||
:override-theme :light
|
||||
:text (i18n/label
|
||||
:t/camera-permission-denied)}])}]))]
|
||||
(fn []
|
||||
(let [camera-ref (atom nil)
|
||||
read-qr-once? (atom false)
|
||||
on-read-code (fn [data]
|
||||
(when-not @read-qr-once?
|
||||
(reset! read-qr-once? true)
|
||||
(js/setTimeout (fn []
|
||||
(reset! read-qr-once? false))
|
||||
3000)
|
||||
(check-qr-code-data data)))
|
||||
scan-qr-code-tab? (= @active-tab 1)
|
||||
show-camera? (and scan-qr-code-tab? @camera-permission-granted?)
|
||||
show-holes? (and show-camera?
|
||||
(boolean (not-empty @qr-view-finder)))]
|
||||
(rn/use-effect
|
||||
(fn []
|
||||
(when-not @camera-permission-granted?
|
||||
(permissions/permission-granted? :camera
|
||||
#(reset! camera-permission-granted? %)
|
||||
#(reset! camera-permission-granted? false)))))
|
||||
[:<>
|
||||
background
|
||||
[render-camera show-camera? @qr-view-finder camera-ref on-read-code show-holes?]
|
||||
[rn/view {:style (style/root-container (:top insets))}
|
||||
[header active-tab read-qr-once? title]
|
||||
(case @active-tab
|
||||
1 [scan-qr-code-tab qr-view-finder request-camera-permission]
|
||||
2 [enter-sync-code-tab]
|
||||
nil)
|
||||
[rn/view {:style style/flex-spacer}]
|
||||
(when show-bottom-view? [bottom-view insets])
|
||||
]]))))
|
||||
|
||||
(defn view
|
||||
[props]
|
||||
[:f> f-view props])
|
||||
@@ -1,10 +0,0 @@
|
||||
(ns status-im2.contexts.syncing.scan-sync-code-page.style
|
||||
(:require [quo2.foundations.colors :as colors]))
|
||||
|
||||
(def background
|
||||
{:position :absolute
|
||||
:top 0
|
||||
:bottom 0
|
||||
:left 0
|
||||
:right 0
|
||||
:background-color colors/neutral-95})
|
||||
@@ -1,12 +0,0 @@
|
||||
(ns status-im2.contexts.syncing.scan-sync-code-page.view
|
||||
(:require [react-native.core :as rn]
|
||||
[status-im2.contexts.syncing.scan-sync-code-page.style :as style]
|
||||
[status-im2.contexts.syncing.scan-sync-code.view :as scan-sync-code]
|
||||
[utils.i18n :as i18n]))
|
||||
|
||||
(defn view
|
||||
[]
|
||||
[scan-sync-code/view
|
||||
{:title (i18n/label :t/scan-sync-code)
|
||||
:background [rn/view
|
||||
{:style style/background} true]}])
|
||||
@@ -1,19 +1,20 @@
|
||||
(ns status-im2.contexts.syncing.setup-syncing.view
|
||||
(:require [utils.i18n :as i18n]
|
||||
[clojure.string :as string]
|
||||
[quo2.core :as quo]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[react-native.core :as rn]
|
||||
[utils.datetime :as datetime]
|
||||
[status-im2.contexts.syncing.setup-syncing.style :as style]
|
||||
[utils.re-frame :as rf]
|
||||
[status-im2.constants :as constants]
|
||||
[react-native.clipboard :as clipboard]
|
||||
[status-im2.contexts.syncing.sheets.enter-password.view :as enter-password]
|
||||
[status-im2.common.qr-code-viewer.view :as qr-code-viewer]
|
||||
[reagent.core :as reagent]
|
||||
[status-im2.common.resources :as resources]
|
||||
[react-native.hooks :as hooks]
|
||||
[react-native.safe-area :as safe-area]
|
||||
[status-im2.contexts.syncing.utils :as sync-utils]))
|
||||
[react-native.safe-area :as safe-area]))
|
||||
|
||||
(def code-valid-for-ms 120000)
|
||||
(def one-min-ms 60000)
|
||||
@@ -32,7 +33,14 @@
|
||||
:label (i18n/label :t/how-to-scan)
|
||||
:icon :i/info
|
||||
:icon-override-theme :dark
|
||||
:on-press #(rf/dispatch [:open-modal :how-to-pair])}]}]])
|
||||
:on-press #(js/alert "to be implemented")}]}]])
|
||||
|
||||
(defn valid-cs?
|
||||
[connection-string]
|
||||
(when connection-string
|
||||
(string/starts-with?
|
||||
connection-string
|
||||
constants/local-pairing-connection-string-identifier)))
|
||||
|
||||
(defn f-use-interval
|
||||
[clock cleanup-clock delay]
|
||||
@@ -45,7 +53,7 @@
|
||||
delay (reagent/atom nil)
|
||||
timestamp (reagent/atom nil)
|
||||
set-code (fn [connection-string]
|
||||
(when (sync-utils/valid-connection-string? connection-string)
|
||||
(when (valid-cs? connection-string)
|
||||
(reset! timestamp (* 1000 (js/Math.ceil (/ (datetime/timestamp) 1000))))
|
||||
(reset! delay 1000)
|
||||
(reset! code connection-string)))
|
||||
@@ -76,14 +84,14 @@
|
||||
:weight :semi-bold
|
||||
:style {:color colors/white}}
|
||||
(i18n/label :t/setup-syncing)]]
|
||||
[rn/view {:style (style/qr-container (sync-utils/valid-connection-string? @code))}
|
||||
(if (sync-utils/valid-connection-string? @code)
|
||||
[rn/view {:style (style/qr-container (valid-cs? @code))}
|
||||
(if (valid-cs? @code)
|
||||
[qr-code-viewer/qr-code-view 331 @code]
|
||||
[quo/qr-code
|
||||
{:source (resources/get-image :qr-code)
|
||||
:height 220
|
||||
:width "100%"}])
|
||||
(when-not (sync-utils/valid-connection-string? @code)
|
||||
(when-not (valid-cs? @code)
|
||||
[quo/button
|
||||
{:on-press (fn []
|
||||
;TODO https://github.com/status-im/status-mobile/issues/15570
|
||||
@@ -95,7 +103,7 @@
|
||||
:size 40
|
||||
:style style/generate-button
|
||||
:before :i/reveal} (i18n/label :t/reveal-sync-code)])
|
||||
(when (sync-utils/valid-connection-string? @code)
|
||||
(when (valid-cs? @code)
|
||||
[rn/view
|
||||
{:style style/valid-cs-container}
|
||||
[rn/view
|
||||
@@ -136,5 +144,5 @@
|
||||
[quo/action-drawer
|
||||
[[{:icon :i/scan
|
||||
:override-theme :dark
|
||||
:on-press #(rf/dispatch [:navigate-to :scan-sync-code-page])
|
||||
:label (i18n/label :t/scan-or-enter-sync-code)}]]]]]])))
|
||||
:on-press #(js/alert "to be implemented")
|
||||
:label (i18n/label :t/Scan-or-enter-sync-code)}]]]]]])))
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
(ns status-im2.contexts.syncing.utils
|
||||
(:require [clojure.string :as string]
|
||||
[status-im2.constants :as constants]))
|
||||
|
||||
(defn valid-connection-string?
|
||||
[connection-string]
|
||||
(when connection-string
|
||||
(string/starts-with?
|
||||
connection-string
|
||||
constants/local-pairing-connection-string-identifier)))
|
||||
@@ -14,7 +14,6 @@
|
||||
[status-im2.db :as db]
|
||||
[utils.re-frame :as rf]
|
||||
[utils.datetime :as datetime]
|
||||
status-im2.contexts.share.events
|
||||
status-im2.contexts.syncing.events
|
||||
status-im2.contexts.chat.events))
|
||||
|
||||
|
||||
@@ -75,7 +75,9 @@
|
||||
(get roots/themes root-id)
|
||||
root-id])
|
||||
(reset! state/root-id (or (get-in root [:root :stack :id]) root-id))
|
||||
(navigation/set-root root))))
|
||||
(if root
|
||||
(navigation/set-root root)
|
||||
(println "root" root-id root)))))
|
||||
|
||||
;; NAVIGATE-TO
|
||||
(defn navigate
|
||||
@@ -87,6 +89,7 @@
|
||||
{:component {:id comp
|
||||
:name comp
|
||||
:options (merge (options/statusbar-and-navbar)
|
||||
{:layout {:orientation :portrait}}
|
||||
options
|
||||
(if (:topBar options)
|
||||
(options/merge-top-bar (options/topbar-options) options)
|
||||
@@ -166,7 +169,7 @@
|
||||
:id comp
|
||||
:options (merge (options/statusbar)
|
||||
{:layout {:componentBackgroundColor :transparent
|
||||
:orientation ["portrait"]}
|
||||
:orientation :portrait}
|
||||
:overlay {:interceptTouchOutside true}}
|
||||
opts)}})))
|
||||
|
||||
@@ -177,8 +180,7 @@
|
||||
(fn []
|
||||
(show-overlay "toasts"
|
||||
{:overlay {:interceptTouchOutside false}
|
||||
:layout {:componentBackgroundColor :transparent
|
||||
:orientation ["portrait"]}})))
|
||||
:layout {:componentBackgroundColor :transparent}})))
|
||||
(re-frame/reg-fx :hide-toasts (fn [] (dissmiss-overlay "toasts")))
|
||||
|
||||
;; bottom sheet
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
(defn default-options
|
||||
[]
|
||||
{:layout {:orientation ["portrait"]}
|
||||
{:layout {:orientation :portrait}
|
||||
:topBar {:visible false}})
|
||||
|
||||
;; Note: Currently, the status bar style provided while setting the root has a high preference,
|
||||
@@ -22,20 +22,12 @@
|
||||
{:statusBar {:style (or status-bar-theme :light)}}))
|
||||
|
||||
(defn default-root
|
||||
[& [status-bar-theme background-color]]
|
||||
[& [status-bar-theme]]
|
||||
(merge (statusbar-and-navbar-root status-bar-theme)
|
||||
{:topBar {:visible false}
|
||||
:layout {:componentBackgroundColor (or background-color
|
||||
(colors/theme-colors colors/white colors/neutral-100))
|
||||
:orientation ["portrait"]
|
||||
:backgroundColor (or background-color
|
||||
(colors/theme-colors colors/white
|
||||
colors/neutral-100))}}))
|
||||
|
||||
(def onboarding-layout
|
||||
{:componentBackgroundColor colors/neutral-80-opa-80-blur
|
||||
:orientation ["portrait"]
|
||||
:backgroundColor colors/neutral-80-opa-80-blur})
|
||||
:layout {:componentBackgroundColor (colors/theme-colors colors/white colors/neutral-100)
|
||||
:orientation :portrait
|
||||
:backgroundColor (colors/theme-colors colors/white colors/neutral-100)}}))
|
||||
|
||||
(defn navbar
|
||||
([dark?]
|
||||
@@ -75,7 +67,7 @@
|
||||
(merge
|
||||
{:modalPresentationStyle :overCurrentContext
|
||||
:layout {:componentBackgroundColor :transparent
|
||||
:orientation ["portrait"]
|
||||
:orientation :portrait
|
||||
:backgroundColor :transparent}}
|
||||
(if platform/android?
|
||||
{:statusBar {:backgroundColor :transparent
|
||||
@@ -85,7 +77,6 @@
|
||||
|
||||
(def sheet-options
|
||||
{:layout {:componentBackgroundColor :transparent
|
||||
:orientation ["portrait"]
|
||||
:backgroundColor :transparent}
|
||||
:modalPresentationStyle :overCurrentContext})
|
||||
|
||||
|
||||
@@ -96,7 +96,7 @@
|
||||
{:stack {:id :intro
|
||||
:children [{:component {:name :intro
|
||||
:id :intro
|
||||
:options (options/default-root nil colors/neutral-100)}}]}}}
|
||||
:options (options/default-root)}}]}}}
|
||||
:shell-stack
|
||||
{:root
|
||||
{:stack {:id :shell-stack
|
||||
|
||||
@@ -24,29 +24,25 @@
|
||||
[status-im2.contexts.onboarding.profiles.view :as profiles]
|
||||
[status-im2.contexts.quo-preview.main :as quo.preview]
|
||||
[status-im2.contexts.shell.view :as shell]
|
||||
[status-im2.contexts.syncing.scan-sync-code-page.view :as scan-sync-code-page]
|
||||
[status-im2.contexts.syncing.syncing-devices-list.view :as settings-syncing]
|
||||
[status-im2.contexts.syncing.how-to-pair.view :as how-to-pair]
|
||||
[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.actions.request-to-join.view :as join-menu]
|
||||
[status-im2.contexts.syncing.setup-syncing.view :as settings-setup-syncing]
|
||||
[status-im2.contexts.share.view :as share]))
|
||||
[status-im2.contexts.syncing.setup-syncing.view :as settings-setup-syncing]))
|
||||
|
||||
(defn screens
|
||||
[]
|
||||
(concat
|
||||
(old-screens/screens)
|
||||
|
||||
[{:name :activity-center
|
||||
[{:name :intro
|
||||
:component intro/view}
|
||||
|
||||
{:name :activity-center
|
||||
:options options/transparent-screen-options
|
||||
:component activity-center/view}
|
||||
|
||||
{:name :share-shell
|
||||
:options options/transparent-screen-options
|
||||
:component share/view}
|
||||
|
||||
{:name :shell-stack
|
||||
:component shell/shell-stack}
|
||||
|
||||
@@ -78,10 +74,6 @@
|
||||
:options {:sheet? true}
|
||||
:component add-new-contact/new-contact}
|
||||
|
||||
{:name :how-to-pair
|
||||
:options {:sheet? true}
|
||||
:component how-to-pair/instructions}
|
||||
|
||||
{:name :discover-communities
|
||||
:component communities.discover/discover}
|
||||
|
||||
@@ -98,67 +90,50 @@
|
||||
:component settings-setup-syncing/view}
|
||||
|
||||
;; Onboarding
|
||||
{:name :intro
|
||||
:component intro/view}
|
||||
|
||||
{:name :profiles
|
||||
:options {:layout options/onboarding-layout}
|
||||
:component profiles/views}
|
||||
|
||||
{:name :new-to-status
|
||||
:options {:layout options/onboarding-layout}
|
||||
:component new-to-status/new-to-status}
|
||||
|
||||
{:name :create-profile
|
||||
:options {:layout options/onboarding-layout}
|
||||
:component create-profile/create-profile}
|
||||
|
||||
{:name :create-profile-password
|
||||
:options {:insets {:top false}
|
||||
:layout options/onboarding-layout}
|
||||
:options {:insets {:top false}}
|
||||
:component create-password/create-password}
|
||||
|
||||
{:name :enable-biometrics
|
||||
:options {:layout options/onboarding-layout}
|
||||
:component enable-biometrics/enable-biometrics}
|
||||
|
||||
{:name :generating-keys
|
||||
:options {:layout options/onboarding-layout
|
||||
:popGesture false
|
||||
:options {:popGesture false
|
||||
:hardwareBackButton {:dismissModalOnPress false
|
||||
:popStackOnPress false}}
|
||||
:component generating-keys/generating-keys}
|
||||
|
||||
{:name :enter-seed-phrase
|
||||
:options {:layout options/onboarding-layout}
|
||||
:component enter-seed-phrase/enter-seed-phrase}
|
||||
|
||||
{:name :enable-notifications
|
||||
:options {:layout options/onboarding-layout
|
||||
:popGesture false
|
||||
:options {:popGesture false
|
||||
:hardwareBackButton {:dismissModalOnPress false
|
||||
:popStackOnPress false}}
|
||||
:component enable-notifications/enable-notifications}
|
||||
|
||||
{:name :identifiers
|
||||
:component identifiers/view
|
||||
:options {:layout options/onboarding-layout
|
||||
:popGesture false
|
||||
:options {:popGesture false
|
||||
:hardwareBackButton {:dismissModalOnPress false
|
||||
:popStackOnPress false}}}
|
||||
{:name :scan-sync-code-page
|
||||
:component scan-sync-code-page/view}
|
||||
|
||||
{:name :sign-in
|
||||
:options {:layout options/onboarding-layout}
|
||||
:component sign-in/view}
|
||||
|
||||
{:name :syncing-devices
|
||||
:options {:layout options/onboarding-layout}
|
||||
:component syncing-devices/syncing-devices}
|
||||
|
||||
{:name :welcome
|
||||
:options {:layout options/onboarding-layout}
|
||||
:component welcome/view}]
|
||||
|
||||
(when config/quo-preview-enabled?
|
||||
|
||||
@@ -992,9 +992,7 @@
|
||||
:your-data-belongs-to-you
|
||||
:your-data-belongs-to-you-description
|
||||
:your-recovery-phrase
|
||||
:your-recovery-phrase-description
|
||||
:empty-keycard
|
||||
:user-keycard})
|
||||
:your-recovery-phrase-description})
|
||||
|
||||
;; NOTE: the rest checkpoints are based on the previous one, defined
|
||||
;; like this:
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
(def ^:const contact-images-action "/contactImages")
|
||||
(def ^:const generate-qr-action "/GenerateQRCode")
|
||||
(def ^:const status-profile-base-url "https://join.status.im/u/")
|
||||
(def ^:const status-profile-base-url-without-https "join.status.im/u/")
|
||||
|
||||
(defn timestamp [] (datetime/timestamp))
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"_comment": "Instead use: scripts/update-status-go.sh <rev>",
|
||||
"owner": "status-im",
|
||||
"repo": "status-go",
|
||||
"version": "v0.151.8",
|
||||
"commit-sha1": "c26f45ae3d238bb8ef6e2771eb2a6c2672f5188f",
|
||||
"src-sha256": "1sygdm09h3rdgb6hyzhlma32kibmp7yissch2w0y65j7bm88m9mq"
|
||||
"version": "v0.150.2",
|
||||
"commit-sha1": "31144ed5a38589fd129945b634f54e800b39645a",
|
||||
"src-sha256": "0jh6bidhf0gs15samqh5whw4iigr7ql11cx0v6ma7achr6j4r1d2"
|
||||
}
|
||||
|
||||
@@ -256,6 +256,81 @@ class TestOneToOneChatMultipleSharedDevices(MultipleSharedDeviceTestCase):
|
||||
|
||||
self.errors.verify_no_errors()
|
||||
|
||||
@marks.testrail_id(6305)
|
||||
def test_1_1_chat_image_send_save_reply(self):
|
||||
self.home_1.get_app_from_background()
|
||||
self.home_2.get_app_from_background()
|
||||
|
||||
self.home_1.home_button.click()
|
||||
self.home_1.get_chat(username=self.default_username_2).click()
|
||||
|
||||
self.home_1.just_fyi('send image in 1-1 chat from Gallery, check options for sender')
|
||||
image_description = 'description'
|
||||
self.chat_1.show_images_button.click()
|
||||
self.chat_1.allow_button.click_if_shown()
|
||||
self.chat_1.first_image_from_gallery.click()
|
||||
if not self.chat_1.cancel_send_image_button.is_element_displayed():
|
||||
self.errors.append("Can't cancel sending images, expected image preview is not shown!")
|
||||
self.chat_1.chat_message_input.set_value(image_description)
|
||||
self.chat_1.send_message_button.click()
|
||||
self.chat_1.chat_message_input.click()
|
||||
for message in self.chat_1.image_message_in_chat, self.chat_1.chat_element_by_text(image_description):
|
||||
if not message.is_element_displayed():
|
||||
self.errors.append('Image or description is not shown in chat after sending for sender')
|
||||
self.chat_1.image_message_in_chat.long_press_element()
|
||||
for element in self.chat_1.reply_message_button, self.chat_1.save_image_button:
|
||||
if not element.is_element_displayed():
|
||||
self.errors.append('Save and reply are not available on long-press on own image messages')
|
||||
if self.chat_1.view_profile_button.is_element_displayed():
|
||||
self.errors.append('"View profile" is shown on long-press on own message')
|
||||
|
||||
self.home_2.just_fyi('check image, description and options for receiver')
|
||||
self.home_2.get_chat(self.default_username_1).click()
|
||||
for message in self.chat_2.image_message_in_chat, self.chat_2.chat_element_by_text(image_description):
|
||||
if not message.is_element_displayed():
|
||||
self.errors.append('Image or description is not shown in chat after sending for receiver')
|
||||
|
||||
self.home_2.just_fyi('check options on long-press image for receiver')
|
||||
self.chat_2.image_message_in_chat.long_press_element()
|
||||
for element in (self.chat_2.reply_message_button, self.chat_2.save_image_button):
|
||||
if not element.is_element_displayed():
|
||||
self.errors.append('Save and reply are not available on long-press on received image messages')
|
||||
|
||||
self.home_1.just_fyi('save image')
|
||||
self.chat_1.save_image_button.click_until_presence_of_element(self.chat_1.show_images_button)
|
||||
self.chat_1.show_images_button.click_until_presence_of_element(self.chat_1.image_from_gallery_button)
|
||||
self.chat_1.image_from_gallery_button.click_until_presence_of_element(self.chat_1.recent_image_in_gallery)
|
||||
if not self.chat_1.recent_image_in_gallery.is_element_displayed():
|
||||
self.errors.append('Saved image is not shown in Recent')
|
||||
self.home_1.click_system_back_button(2)
|
||||
|
||||
self.home_2.just_fyi('reply to image message')
|
||||
self.chat_2.reply_message_button.click()
|
||||
if self.chat_2.quote_username_in_message_input.text != "↪ Replying to %s" % self.default_username_1:
|
||||
self.errors.append("Username is not displayed in reply quote snippet replying to image message")
|
||||
reply_to_message_from_receiver = "image reply"
|
||||
self.chat_2.send_message(reply_to_message_from_receiver)
|
||||
reply_message = self.chat_2.chat_element_by_text(reply_to_message_from_receiver)
|
||||
if not reply_message.image_in_reply.is_element_displayed():
|
||||
self.errors.append("Image is not displayed in reply")
|
||||
|
||||
self.home_2.just_fyi('check share and save options on opened image')
|
||||
self.chat_2.image_message_in_chat.scroll_to_element(direction='up')
|
||||
self.chat_2.image_message_in_chat.click_until_presence_of_element(self.chat_2.share_image_icon_button)
|
||||
self.chat_2.share_image_icon_button.click()
|
||||
self.chat_2.share_via_messenger()
|
||||
if not self.chat_2.image_in_android_messenger.is_element_displayed():
|
||||
self.errors.append("Can't share image")
|
||||
self.chat_2.click_system_back_button_until_element_is_shown(element=self.chat_2.save_image_icon_button)
|
||||
self.chat_2.save_image_icon_button.click()
|
||||
self.chat_2.show_images_button.click()
|
||||
self.chat_2.allow_button.wait_and_click()
|
||||
|
||||
if not self.chat_2.first_image_from_gallery.is_element_image_similar_to_template('saved.png'):
|
||||
self.errors.append("New picture was not saved!")
|
||||
|
||||
self.errors.verify_no_errors()
|
||||
|
||||
@marks.testrail_id(5387)
|
||||
# think about priority of this
|
||||
def test_1_1_chat_delete_via_delete_button_relogin(self):
|
||||
@@ -865,7 +940,6 @@ class TestOneToOneChatMultipleSharedDevicesNewUi(MultipleSharedDeviceTestCase):
|
||||
message_from_sender = "Message sender"
|
||||
self.device_1.just_fyi("Sender start 1-1 chat, set emoji and check counter")
|
||||
self.chat_1.send_message(message_from_sender)
|
||||
self.chat_1.chat_element_by_text(message_from_sender).wait_for_sent_state(120)
|
||||
self.chat_1.set_reaction(message_from_sender)
|
||||
|
||||
message_sender = self.chat_1.chat_element_by_text(message_from_sender)
|
||||
@@ -924,7 +998,8 @@ class TestOneToOneChatMultipleSharedDevicesNewUi(MultipleSharedDeviceTestCase):
|
||||
if replied_message.replied_message_text != url_message:
|
||||
self.errors.append("Reply for '%s' not present in message received in public chat" % url_message)
|
||||
|
||||
self.home_2.just_fyi("Check 'Open in Status' option")
|
||||
# The "open_in_status" feature is not implemented yet
|
||||
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)
|
||||
|
||||
@@ -331,18 +331,24 @@ 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']
|
||||
if not self.channel.chat_message_input.is_element_displayed():
|
||||
|
||||
message_input = self.channel.chat_message_input
|
||||
if not message_input.is_element_displayed():
|
||||
self.home.click_system_back_button_until_element_is_shown()
|
||||
self.home.get_to_community_channel_from_home(self.community_name)
|
||||
|
||||
for message in message_texts:
|
||||
self.channel.send_message(message)
|
||||
message_input.send_keys(message)
|
||||
self.channel.send_message_button.click()
|
||||
|
||||
self.channel.copy_message_text(message)
|
||||
actual_copied_text = self.channel.driver.get_clipboard_text()
|
||||
if actual_copied_text != message:
|
||||
self.errors.append('Message %s text was not copied in community channel, text in clipboard %s' % actual_copied_text)
|
||||
message_input.paste_text_from_clipboard()
|
||||
if message_input.text != message:
|
||||
self.errors.append('Message %s text was not copied in community channel' % message)
|
||||
message_input.clear()
|
||||
|
||||
self.errors.verify_no_errors()
|
||||
|
||||
@@ -358,10 +364,9 @@ class TestCommunityOneDeviceMerged(MultipleSharedDeviceTestCase):
|
||||
for key in ['admin_open', 'member_open', 'admin_closed', 'member_closed']:
|
||||
if not self.home.element_by_text(waku_user.communities[key]).is_element_displayed(30):
|
||||
self.errors.append("%s was not restored from waku-backup!!" % key)
|
||||
# TODO: there is a bug when pending community sometimes restored as joined; needs investigation
|
||||
# self.home.opened_communities_tab.click()
|
||||
# if not self.home.element_by_text(waku_user.communities['member_pending']).is_element_displayed(30):
|
||||
# self.errors.append("Pending community %s was not restored from waku-backup!" % waku_user.communities['member_pending'])
|
||||
self.home.opened_communities_tab.click()
|
||||
if not self.home.element_by_text(waku_user.communities['member_pending']).is_element_displayed(30):
|
||||
self.errors.append("Pending community %s was not restored from waku-backup!" % waku_user.communities['member_pending'])
|
||||
|
||||
self.home.just_fyi("Check contacts/blocked users")
|
||||
self.home.chats_tab.click()
|
||||
@@ -493,60 +498,8 @@ class TestCommunityMultipleDeviceMerged(MultipleSharedDeviceTestCase):
|
||||
self.errors.append("Deleted for me message is deleted all channel members")
|
||||
self.errors.verify_no_errors()
|
||||
|
||||
@marks.testrail_id(702859)
|
||||
def test_1_1_chat_image_send_reply(self):
|
||||
|
||||
self.home_1.just_fyi('Send image in 1-1 chat from Gallery')
|
||||
image_description = 'description'
|
||||
self.channel_1.show_images_button.click()
|
||||
self.channel_1.allow_button.click_if_shown()
|
||||
self.channel_1.first_image_from_gallery.click()
|
||||
self.channel_1.images_confirm_selection_button.click()
|
||||
self.channel_1.chat_message_input.set_value(image_description)
|
||||
self.channel_1.send_message_button.click()
|
||||
self.channel_1.chat_message_input.click()
|
||||
self.channel_1.chat_element_by_text(image_description).image_in_message.click()
|
||||
self.channel_1.click_system_back_button()
|
||||
|
||||
# TODO: options for image are still WIP; add case with edit description of image and after 15901 fix
|
||||
# self.home_2.just_fyi('check image, description and options for receiver')
|
||||
# self.channel_2.chat_element_by_text(image_description).image_in_message.click()
|
||||
# self.home_1.just_fyi('save image')
|
||||
# self.chat_1.save_image_button.click_until_presence_of_element(self.chat_1.show_images_button)
|
||||
# self.chat_1.show_images_button.click_until_presence_of_element(self.chat_1.image_from_gallery_button)
|
||||
# self.chat_1.image_from_gallery_button.click_until_presence_of_element(self.chat_1.recent_image_in_gallery)
|
||||
# if not self.chat_1.recent_image_in_gallery.is_element_displayed():
|
||||
# self.errors.append('Saved image is not shown in Recent')
|
||||
# self.home_1.click_system_back_button(2)
|
||||
# self.home_2.just_fyi('check share and save options on opened image')
|
||||
# self.chat_2.image_message_in_chat.scroll_to_element(direction='up')
|
||||
# self.chat_2.image_message_in_chat.click_until_presence_of_element(self.chat_2.share_image_icon_button)
|
||||
# self.chat_2.share_image_icon_button.click()
|
||||
# self.chat_2.share_via_messenger()
|
||||
# if not self.chat_2.image_in_android_messenger.is_element_displayed():
|
||||
# self.errors.append("Can't share image")
|
||||
# self.chat_2.click_system_back_button_until_element_is_shown(element=self.chat_2.save_image_icon_button)
|
||||
# self.chat_2.save_image_icon_button.click()
|
||||
# self.chat_2.show_images_button.click()
|
||||
# self.chat_2.allow_button.wait_and_click()
|
||||
#
|
||||
# if not self.chat_2.first_image_from_gallery.is_element_image_similar_to_template('saved.png'):
|
||||
# self.errors.append("New picture was not saved!")
|
||||
#
|
||||
# self.channel_2.chat_element_by_text(image_description).image_in_message.save_new_screenshot_of_element('images_test.png')
|
||||
|
||||
self.channel_2.just_fyi("Can reply to images")
|
||||
self.channel_2.quote_message(image_description)
|
||||
message_text = 'reply to image'
|
||||
self.channel_2.chat_message_input.send_keys(message_text)
|
||||
self.channel_2.send_message_button.click()
|
||||
chat_element_1 = self.channel_1.chat_element_by_text(message_text)
|
||||
if not chat_element_1.is_element_displayed(sec=60) or chat_element_1.replied_message_text != 'Image':
|
||||
self.errors.append('Reply message was not received by the sender')
|
||||
|
||||
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]
|
||||
@@ -558,9 +511,9 @@ class TestCommunityMultipleDeviceMerged(MultipleSharedDeviceTestCase):
|
||||
|
||||
self.channel_1.just_fyi("Can copy and paste emojis")
|
||||
self.channel_1.copy_message_text(emoji_unicode)
|
||||
actual_copied_text = self.channel_1.driver.get_clipboard_text()
|
||||
if actual_copied_text != emoji_unicode:
|
||||
self.errors.append('Emoji message was not copied, text in clipboard is %s' % actual_copied_text)
|
||||
self.channel_1.chat_message_input.paste_text_from_clipboard()
|
||||
if self.channel_1.chat_message_input.text != emoji_unicode:
|
||||
self.errors.append('Emoji message was not copied')
|
||||
|
||||
self.channel_1.just_fyi("Can reply to emojis")
|
||||
self.channel_2.quote_message(emoji_unicode)
|
||||
|
||||
@@ -23,6 +23,7 @@ class TestActivityCenterContactRequestMultipleDevicePR(MultipleSharedDeviceTestC
|
||||
[home.chats_tab.click() for home in self.homes]
|
||||
|
||||
@marks.testrail_id(702850)
|
||||
@marks.xfail(reason="Blocked by 15500")
|
||||
def test_activity_center_contact_request_decline(self):
|
||||
self.device_1.put_app_to_background()
|
||||
self.device_2.just_fyi('Device2 sends a contact request to Device1 via Paste button and check user details')
|
||||
@@ -31,9 +32,8 @@ 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)
|
||||
# TODO: Blocked by 15500
|
||||
# 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")
|
||||
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()
|
||||
|
||||
chat.view_profile_new_contact_button.click_until_presence_of_element(chat.profile_block_contact_button)
|
||||
|
||||
@@ -186,6 +186,7 @@ class ChatElementByText(Text):
|
||||
return BaseElement(self.driver, prefix=self.locator,
|
||||
xpath="//*[@content-desc='message-sent']").is_element_displayed(wait_time)
|
||||
|
||||
|
||||
@property
|
||||
def uncollapse(self) -> bool:
|
||||
class Collapse(Button):
|
||||
@@ -273,15 +274,6 @@ class ChatElementByText(Text):
|
||||
|
||||
return EmojisNumber(self.driver, self.locator)
|
||||
|
||||
@property
|
||||
def image_in_message(self):
|
||||
try:
|
||||
self.driver.info("Trying to access image inside message with text '%s'" % self.message_text)
|
||||
ChatElementByText(self.driver, self.message_text).wait_for_sent_state(60)
|
||||
return Button(self.driver, xpath='%s//android.view.ViewGroup/android.widget.ImageView' % self.locator)
|
||||
except NoSuchElementException:
|
||||
self.driver.fail("No image is found in message!")
|
||||
|
||||
@property
|
||||
def pinned_by_label(self):
|
||||
class PinnedByLabelText(Text):
|
||||
@@ -736,11 +728,11 @@ class ChatView(BaseView):
|
||||
self.sticker_message = Button(self.driver, accessibility_id="sticker-message")
|
||||
|
||||
# Images
|
||||
self.show_images_button = Button(self.driver, accessibility_id="open-images-button")
|
||||
self.show_images_button = Button(self.driver, accessibility_id="show-photo-icon")
|
||||
self.take_photo_button = Button(self.driver, accessibility_id="take-picture")
|
||||
self.image_from_gallery_button = Button(self.driver, accessibility_id="open-gallery")
|
||||
self.first_image_from_gallery = Button(self.driver, accessibility_id="image-0")
|
||||
self.images_confirm_selection_button = Button(self.driver, accessibility_id="confirm-selection")
|
||||
self.first_image_from_gallery = Button(self.driver,
|
||||
xpath="//*[@content-desc='open-gallery']/following-sibling::android.view.ViewGroup[1]")
|
||||
self.images_area_in_gallery = Button(self.driver,
|
||||
xpath="//*[@content-desc='open-gallery']/following-sibling::android.view.ViewGroup[1]")
|
||||
self.image_message_in_chat = Button(self.driver, accessibility_id="image-message")
|
||||
|
||||
@@ -207,7 +207,7 @@ class SignInView(BaseView):
|
||||
self.profile_repeat_password_edit_box.click()
|
||||
self.profile_repeat_password_edit_box.send_keys(password)
|
||||
self.checkbox_button.scroll_to_element()
|
||||
self.checkbox_button.click()
|
||||
self.checkbox_button.double_click()
|
||||
self.profile_confirm_password_button.click()
|
||||
|
||||
def set_profile(self, username: str, set_image=False):
|
||||
|
||||
@@ -1219,7 +1219,7 @@
|
||||
"save-password": "Save password",
|
||||
"save-password-unavailable": "Set device passcode to save password",
|
||||
"save-password-unavailable-android": "Save password is unavailable: your device may be rooted or lacks necessary security features.",
|
||||
"scan-or-enter-sync-code": "Scan or enter sync code",
|
||||
"Scan-or-enter-sync-code": "Scan or enter sync code",
|
||||
"scan-qr": "Scan QR code",
|
||||
"scan-qr-code": "Scan a QR code with a wallet address",
|
||||
"search": "Search",
|
||||
@@ -1687,8 +1687,6 @@
|
||||
"database-reset-content": "Chats, contacts and settings have been deleted. You can use your account with your Keycard",
|
||||
"database-reset-warning": "Database will be reset. Chats, contacts and settings will be deleted",
|
||||
"empty-keycard-required": "Requires an empty Keycard",
|
||||
"empty-keycard": "Empty Keycard",
|
||||
"user-keycard": "{{name}} Card",
|
||||
"current": "Current",
|
||||
"choose-storage": "Choose storage",
|
||||
"choose-new-location-for-keystore": "Choose a new location to save your keystore file",
|
||||
@@ -2110,21 +2108,6 @@
|
||||
"community-request-pending-body-text": "You requested to join",
|
||||
"community-kicked-heading": "Kicked from community",
|
||||
"community-kicked-body": "You were kicked from",
|
||||
"signing-in-from-another-device": "Signing in from the other device",
|
||||
"open-status-on-your-other-device": "Open Status on your other device",
|
||||
"im-new": "I'm new",
|
||||
"scan-or-enter-sync-code-seen-on-this-device": "Scan or enter sync code seen on this device",
|
||||
"press": "Press",
|
||||
"tap": "Tap",
|
||||
"or-tap": "or tap",
|
||||
"tap-on": "Tap on",
|
||||
"and-go-to": "and go to",
|
||||
"scan-or-enter-a-sync-code": "Scan or enter a sync code",
|
||||
"scan-the-qr-code-or-copy-the-sync-code": "Scan the QR code or copy the sync code",
|
||||
"already-logged-in-on-the-other-device": "Already logged in on the other device",
|
||||
"how-to-pair": "How to pair",
|
||||
"mobile": "Mobile",
|
||||
"desktop": "Desktop",
|
||||
"error-loading-audio": "Error while loading audio",
|
||||
"you-colon": "You:",
|
||||
"you-replied": "You replied",
|
||||
@@ -2152,9 +2135,5 @@
|
||||
"user-shared-a-community": "{{user}} shared a community",
|
||||
"you-deleted-a-message": "You deleted a message",
|
||||
"this-message-was-deleted": "This message was deleted",
|
||||
"user-deleted-a-message": "{{user}} deleted a message",
|
||||
"link-to-profile": "Link to profile",
|
||||
"emoji-hash": "Emoji Hash",
|
||||
"emoji-hash-copied":"Emojihash copied to clipboard",
|
||||
"link-to-profile-copied":"Link to Profile copied to clipboard"
|
||||
"user-deleted-a-message": "{{user}} deleted a message"
|
||||
}
|
||||
|
||||