Compare commits

..
11 Commits
Author SHA1 Message Date
Yevheniia Berdnyk d2a2c2f48e android 12 try 2023-04-12 03:45:52 +03:00
Yevheniia Berdnyk 7ebf035506 requirements roll back 2023-04-11 23:41:02 +03:00
Yevheniia Berdnyk 7256c66760 fix for stale element 2023-04-10 22:36:17 +03:00
Yevheniia Berdnyk 6a9a6fb52c appium 1.22.1 2023-04-10 21:32:19 +03:00
Yevheniia Berdnyk de05976353 android 11 2023-04-10 16:54:47 +03:00
Yevheniia Berdnyk db9e3bde17 newCommandTimeout 2023-04-10 15:45:41 +03:00
Yevheniia Berdnyk cb0e15eff0 capabilities 2023-04-07 01:34:09 +03:00
Yevheniia Berdnyk d4c275cb09 find element 2023-04-06 22:48:19 +03:00
Yevheniia Berdnyk dc781b73fa updated versions 2023-04-06 14:28:57 +03:00
Yevheniia Berdnyk 321efa053c temp 2023-04-06 09:23:58 +03:00
Yevheniia Berdnyk bdbf00257a e2e: fix for MaxRetryError 2023-04-06 08:46:34 +03:00
50 changed files with 1598 additions and 991 deletions
-9
View File
@@ -12,7 +12,6 @@ stdenv.mkDerivation {
"patchBuildIdPhase"
"patchHermesPhase"
"patchJavaPhase"
"patchYogaNodePackagePhase"
"installPhase"
];
@@ -67,14 +66,6 @@ stdenv.mkDerivation {
patchJavaPhase = ''
${nodejs}/bin/node ./node_modules/jetifier/bin/jetify
'';
# Patch React Native Yoga.cpp file
# FIXME: Remove this once release newer than 1.19.0 is used which includes:
# https://github.com/facebook/yoga/commit/f174de70
patchYogaNodePackagePhase = ''
substituteInPlace ./node_modules/react-native/ReactCommon/yoga/yoga/Yoga.cpp --replace \
'node->getLayout().hadOverflow() |' \
'node->getLayout().hadOverflow() ||'
'';
installPhase = ''
mkdir -p $out
cp -R node_modules $out/
+3 -3
View File
@@ -53,9 +53,9 @@ in {
version = "13.3";
allowHigher = true;
};
go = super.go_1_19;
buildGoPackage = super.buildGo119Package;
buildGoModule = super.buildGo119Module;
go = super.go_1_18;
buildGoPackage = super.buildGo118Package;
buildGoModule = super.buildGo118Module;
gomobile = (super.gomobile.overrideAttrs (old: {
patches = self.fetchurl { # https://github.com/golang/mobile/pull/84
url = "https://github.com/golang/mobile/commit/f20e966e05b8f7e06bed500fa0da81cf6ebca307.patch";
+3 -4
View File
@@ -11,11 +11,10 @@ let
# We follow the master branch of official nixpkgs.
nixpkgsSrc = fetchFromGitHub {
name = "nixpkgs-source";
# FIXME: Fork used to get Cocoapods 1.12.0 and apksigner macOS build.
owner = "status-im";
owner = "status-im"; # FIXME: Fork used to get Cocoapods 1.12.0.
repo = "nixpkgs";
rev = "d0c06fa3d3982a91aa01bd63ed84020cbde3d3ab";
sha256 = "sha256-8blvuUHnuf0hFr/PpBxVohJp5CaGXIXhgJlFN/cv7us=";
rev = "b9b2ed705edc00003d47625950602136be3e1ed5";
sha256 = "sha256-F0qOawdKx7kgiGqwVikYIawL2taJ1XfcgHy0Wn0mho8=";
# To get the compressed Nix sha256, use:
# nix-prefetch-url --unpack https://github.com/${ORG}/nixpkgs/archive/${REV}.tar.gz
};
-87
View File
@@ -1,87 +0,0 @@
(ns quo2.components.code.code.style
(:require [quo2.foundations.colors :as colors]))
;; Example themes:
;; https://github.com/react-syntax-highlighter/react-syntax-highlighter/tree/master/src/styles/hljs
(defn theme
[theme-key]
(case theme-key
:hljs-comment (colors/theme-colors colors/neutral-40 colors/neutral-60)
:hljs-title (colors/custom-color-by-theme :sky 50 60)
:hljs-keyword (colors/custom-color-by-theme :green 50 60)
:hljs-string (colors/custom-color-by-theme :turquoise 50 60)
:hljs-literal (colors/custom-color-by-theme :turquoise 50 60)
:hljs-number (colors/custom-color-by-theme :turquoise 50 60)
:line-number colors/neutral-40
nil))
(defn text-style
[class-names]
(let [text-color (->> class-names
(map keyword)
(some (fn [class-name]
(when-let [text-color (theme class-name)]
text-color))))]
(cond-> {:flex-shrink 1
:line-height 18}
text-color (assoc :color text-color))))
(defn border-color
[]
(colors/theme-colors colors/neutral-20 colors/neutral-80))
(defn container
[]
{:overflow :hidden
:padding 8
:background-color (colors/theme-colors colors/white colors/neutral-80-opa-40)
:border-color (border-color)
:border-width 1
:border-radius 16})
(def gradient-container
{:position :absolute
:bottom 0
:left 0
:right 0
:z-index 1})
(def gradient {:height 48})
(defn line-number-container
[line-number-width]
{:position :absolute
:bottom 0
:top 0
:left 0
:width (+ line-number-width 8 7)
:background-color (colors/theme-colors colors/neutral-5 colors/neutral-80)})
(defn divider
[line-number-width]
{:position :absolute
:bottom 0
:top 0
:left (+ line-number-width 7 7)
:width 1
:z-index 2
:background-color (border-color)})
(def line {:flex-direction :row})
(defn line-number
[width]
{:margin-right 20 ; 8+12 margin
:width width})
(def copy-button
{:position :absolute
:bottom 8
:right 8
:z-index 1})
(defn gradient-color [] (colors/theme-colors colors/white colors/neutral-80))
(defn button-background-color
[]
(colors/theme-colors colors/neutral-80-opa-5 colors/white-opa-5))
+144 -79
View File
@@ -1,110 +1,175 @@
(ns quo2.components.code.snippet
(:require [cljs-bean.core :as bean]
[clojure.string :as string]
[oops.core :as oops]
[quo2.components.buttons.button :as button]
[quo2.components.code.code.style :as style]
[quo2.components.markdown.text :as text]
[quo2.foundations.colors :as colors]
[quo2.theme :as theme]
[react-native.core :as rn]
[react-native.linear-gradient :as linear-gradient]
[react-native.masked-view :as masked-view]
[react-native.syntax-highlighter :as highlighter]
[reagent.core :as reagent]))
;; Example themes:
;; https://github.com/react-syntax-highlighter/react-syntax-highlighter/tree/master/src/styles/hljs
(def ^:private themes
{:light {:hljs-comment {:color colors/neutral-40}
:hljs-title {:color (colors/custom-color :blue 50)}
:hljs-keyword {:color (colors/custom-color :green 50)}
:hljs-string {:color (colors/custom-color :turquoise 50)}
:hljs-literal {:color (colors/custom-color :turquoise 50)}
:hljs-number {:color (colors/custom-color :turquoise 50)}
:line-number {:color colors/neutral-40}}
:dark {:hljs-comment {:color colors/neutral-60}
:hljs-title {:color (colors/custom-color :blue 60)}
:hljs-keyword {:color (colors/custom-color :green 60)}
:hljs-string {:color (colors/custom-color :turquoise 60)}
:hljs-literal {:color (colors/custom-color :turquoise 60)}
:hljs-number {:color (colors/custom-color :turquoise 60)}
:line-number {:color colors/neutral-40}}})
(defn- text-style
[class-names]
(->> class-names
(map keyword)
(reduce #(merge %1 (get-in themes [(theme/get-theme) %2]))
{:flex-shrink 1
;; Round to a nearest whole number to achieve consistent
;; spacing (also important for calculating `max-text-height`).
;; Line height seems to be inconsistent between text being
;; wrapped and text being rendered on a newline using Flexbox
;; layout.
:line-height 18})))
(defn- render-nodes
[nodes]
(map (fn [{:keys [children value last-line?] :as node}]
(map (fn [{:keys [children value] :as node}]
;; Node can have :children or a :value.
(if children
(into [text/text
(cond-> {:weight :code
:size :paragraph-2
:style (style/text-style (get-in node [:properties :className]))}
last-line? (assoc :number-of-lines 1))]
{:weight :code
:size :paragraph-2
:style (text-style (get-in node [:properties :className]))}]
(render-nodes children))
;; Remove newlines as we already render each line separately.
(string/trim-newline value)))
(-> value string/trim-newline)))
nodes))
(defn- line
[{:keys [line-number line-number-width]} children]
[rn/view {:style style/line}
[rn/view {:style (style/line-number line-number-width)}
[text/text
{:style (style/text-style ["line-number"])
:weight :code
:size :paragraph-2}
line-number]]
children])
(defn- code-block
[{:keys [rows line-number-width]}]
[rn/view
[into [:<>]
(->> rows
(render-nodes)
(map-indexed (fn [idx row-content]
[line
{:line-number (inc idx)
:line-number-width line-number-width}
row-content]))
(into [:<>]))])
(defn- mask-view
[{:keys [apply-mask?]} child]
(if apply-mask?
[:<>
[rn/view {:style style/gradient-container}
[linear-gradient/linear-gradient
{:style style/gradient
:colors [:transparent (style/gradient-color)]}
[rn/view {:style style/gradient}]]]
child]
child))
(defn- calc-line-number-width
[font-scale rows-to-show]
(let [max-line-digits (-> rows-to-show str count)]
(if (= 1 max-line-digits)
18 ;; ~ 9 is char width, 18 is width used in Figma.
(* 9 max-line-digits font-scale))))
;; Line numbers
(map-indexed (fn [idx row]
(conj [rn/view {:style {:flex-direction :row}}
[rn/view
{:style {:width line-number-width
;; 8+12 margin
:margin-right 20}}
[text/text
{:weight :code
:size :paragraph-2
:style (text-style ["line-number"])}
(inc idx)]]]
row))))])
(defn- native-renderer
[{:keys [rows max-lines on-copy-press]
:or {max-lines ##Inf}}]
(let [font-scale (:font-scale (rn/use-window-dimensions))
total-rows (count rows)
number-rows-to-show (min (count rows) max-lines)
line-number-width (calc-line-number-width font-scale number-rows-to-show)
truncated? (< number-rows-to-show total-rows)
rows-to-show-coll (if truncated?
(as-> rows $
(update $ number-rows-to-show assoc :last-line? true)
(take (inc number-rows-to-show) $))
rows)]
[rn/view {:style (style/container)}
[rn/view {:style (style/line-number-container line-number-width)}]
[rn/view {:style (style/divider line-number-width)}]
[mask-view {:apply-mask? truncated?}
[code-block
{:rows rows-to-show-coll
:line-number-width line-number-width}]]
[rn/view {:style style/copy-button}
[button/button
{:icon true
:type :grey
:size 24
:on-press on-copy-press
:override-background-color (style/button-background-color)}
:main-icons/copy]]]))
[]
(let [text-height (reagent/atom nil)]
(fn [{:keys [rows max-lines on-copy-press]}]
(let [background-color (colors/theme-colors
colors/white
colors/neutral-80-opa-40)
background-color-left (colors/theme-colors
colors/neutral-5
colors/neutral-80)
border-color (colors/theme-colors
colors/neutral-20
colors/neutral-80)
rows (bean/->clj rows)
font-scale (:font-scale (rn/use-window-dimensions))
max-rows (or max-lines (count rows)) ;; Cut down on rows to process.
max-line-digits (-> rows count (min max-rows) str count)
;; ~ 9 is char width, 18 is width used in Figma.
line-number-width (* font-scale (max 18 (* 9 max-line-digits)))
max-text-height (some-> max-lines
(* font-scale 18)) ;; 18 is font's line height.
truncated? (and max-text-height (< max-text-height @text-height))
maybe-mask-wrapper (if truncated?
[masked-view/masked-view
{:mask-element
(reagent/as-element
[linear-gradient/linear-gradient
{:colors ["black" "transparent"]
:locations [0.75 1]
:style {:flex 1}}])}]
[:<>])]
[rn/view
{:style {:overflow :hidden
:padding 8
:background-color background-color
:border-color border-color
:border-width 1
:border-radius 8
;; Hide on intial render to avoid flicker when mask-wrapper is shown.
:opacity (if @text-height 1 0)}}
;; Line number container
[rn/view
{:style {:position :absolute
:bottom 0
:top 0
:left 0
:width (+ line-number-width 8 8)
:background-color background-color-left
:border-right-color border-color
:border-right-width 1}}]
(conj maybe-mask-wrapper
[rn/view {:max-height max-text-height}
[rn/view
{:on-layout (fn [evt]
(let [height (oops/oget evt "nativeEvent.layout.height")]
(reset! text-height height)))}
[code-block
{:rows (take max-rows rows)
:line-number-width line-number-width}]]])
;; Copy button
[rn/view
{:style {:position :absolute
:bottom 8
:right 8}}
[button/button
{:icon true
:type :grey
:size 24
:on-press on-copy-press}
:main-icons/copy]]]))))
(defn- wrap-renderer-fn
[f {:keys [max-lines on-copy-press]}]
(fn [^js props]
(reagent/as-element [:f> f
{:rows (.-rows props)
:max-lines max-lines
:on-copy-press on-copy-press}])))
(defn snippet
[{:keys [language max-lines on-copy-press]} children]
[highlighter/highlighter
{:language language
:renderer (fn [^js/Object props]
(reagent/as-element
[:f> native-renderer
{:rows (-> props .-rows bean/->clj)
:on-copy-press #(when on-copy-press (on-copy-press children))
:max-lines max-lines}]))
:renderer (wrap-renderer-fn
native-renderer
{:max-lines max-lines
:on-copy-press #(when on-copy-press
(on-copy-press children))})
;; Default props to adapt Highlighter for react-native.
;;:CodeTag react-native/View
;;:PreTag react-native/View
:show-line-numbers false
:style {}
:custom-style {:background-color nil}}
:style #js {}
:custom-style #js {:backgroundColor nil}}
children])
@@ -1,29 +0,0 @@
(ns quo2.components.links.url-preview.component-spec
(:require
[quo2.components.links.url-preview.view :as view]
[test-helpers.component :as h]))
(h/describe "Links - URL Preview"
(h/test "default render"
(h/render [view/view])
(h/is-truthy (h/query-by-label-text :title))
(h/is-truthy (h/query-by-label-text :logo))
(h/is-truthy (h/query-by-label-text :button-clear-preview))
(h/is-null (h/query-by-label-text :url-preview-loading)))
(h/test "on-clear event"
(let [on-clear (h/mock-fn)]
(h/render [view/view {:on-clear on-clear}])
(h/fire-event :press (h/get-by-label-text :button-clear-preview))
(h/was-called on-clear)))
(h/describe "loading state"
(h/test "shows a loading container"
(h/render [view/view {:loading? true :loading-message "Hello"}])
(h/is-null (h/query-by-label-text :title))
(h/is-truthy (h/query-by-label-text :url-preview-loading)))
(h/test "renders if `loading-message` is not passed"
(h/render [view/view {:loading? true}])
(h/is-null (h/query-by-label-text :title))
(h/is-truthy (h/query-by-label-text :url-preview-loading)))))
@@ -1,58 +0,0 @@
(ns quo2.components.links.url-preview.style
(:require [quo2.foundations.colors :as colors]))
(def horizontal-padding 12)
(defn container
[]
{:height 56
:background-color (colors/theme-colors colors/neutral-5 colors/neutral-90)
:padding-vertical 10
:padding-horizontal horizontal-padding
:border-radius 12
:align-self :stretch
:flex-direction :row})
(defn loading-container
[]
{:height 56
:border-width 1
:border-radius 12
:border-style :dashed
:align-items :center
:justify-content :center
:align-self :stretch
:padding horizontal-padding
:border-color (colors/theme-colors colors/neutral-30 colors/neutral-80)})
(defn loading-message
[]
{:color (colors/theme-colors colors/neutral-50 colors/neutral-40)})
(def logo
{:width 16
:height 16
:top 1
:border-radius 8})
(def content-container
{:margin-left 6
:flex 1})
(defn title
[]
{:color (colors/theme-colors colors/neutral-100 colors/white)})
(defn body
[]
{:text-transform :lowercase
:color (colors/theme-colors colors/neutral-50 colors/neutral-40)})
(def clear-button
{:border-color colors/danger-50
:border-width 1})
(def clear-button-container
{:width 20
:height 20
:margin-left 6})
@@ -1,63 +0,0 @@
(ns quo2.components.links.url-preview.view
(:require
[quo2.components.icon :as icon]
[quo2.components.links.url-preview.style :as style]
[quo2.components.markdown.text :as text]
[quo2.foundations.colors :as colors]
[react-native.core :as rn]))
(defn- logo-component
[{:keys [logo]}]
[rn/image
{:accessibility-label :logo
:source logo
:style style/logo}])
(defn- content
[{:keys [title body]}]
[rn/view {:style style/content-container}
[text/text
{:accessibility-label :title
:size :paragraph-2
:weight :semi-bold
:number-of-lines 1
:style (style/title)}
title]
[text/text
{:accessibility-label :body
:size :paragraph-2
:weight :medium
:number-of-lines 1
:style (style/body)}
body]])
(defn- clear-button
[{:keys [on-press]}]
[rn/touchable-opacity
{:on-press on-press
:style style/clear-button-container
:hit-slop {:top 3 :right 3 :bottom 3 :left 3}
:accessibility-label :button-clear-preview}
[icon/icon :i/clear
{:size 20
:container-style style/clear-button
:color (colors/theme-colors colors/neutral-50 colors/neutral-60)}]])
(defn view
[{:keys [title body logo on-clear loading? loading-message container-style]}]
(if loading?
[rn/view
{:accessibility-label :url-preview-loading
:style (merge (style/loading-container) container-style)}
[rn/text
{:size :paragraph-2
:weight :medium
:number-of-lines 1
:style (style/loading-message)}
loading-message]]
[rn/view
{:accessibility-label :url-preview
:style (merge (style/container) container-style)}
[logo-component {:logo logo}]
[content {:title title :body body}]
[clear-button {:on-press on-clear}]]))
-4
View File
@@ -33,7 +33,6 @@
quo2.components.inputs.input.view
quo2.components.inputs.title-input.view
quo2.components.inputs.profile-input.view
quo2.components.links.url-preview.view
quo2.components.list-items.channel
quo2.components.list-items.menu-item
quo2.components.list-items.preview-list
@@ -183,6 +182,3 @@
(def permission-tag quo2.components.tags.permission-tag/tag)
(def status-tag quo2.components.tags.status-tags/status-tag)
(def token-tag quo2.components.tags.token-tag/tag)
;;;; LINKS
(def url-preview quo2.components.links.url-preview.view/view)
+23 -25
View File
@@ -1,26 +1,24 @@
(ns quo2.core-spec
(:require
[quo2.components.avatars.user-avatar.component-spec]
[quo2.components.banners.banner.component-spec]
[quo2.components.buttons.--tests--.buttons-component-spec]
[quo2.components.colors.color-picker.component-spec]
[quo2.components.counter.--tests--.counter-component-spec]
[quo2.components.dividers.--tests--.divider-label-component-spec]
[quo2.components.dividers.strength-divider.component-spec]
[quo2.components.drawers.action-drawers.component-spec]
[quo2.components.drawers.drawer-buttons.component-spec]
[quo2.components.drawers.permission-context.component-spec]
[quo2.components.inputs.input.component-spec]
[quo2.components.inputs.profile-input.component-spec]
[quo2.components.inputs.title-input.component-spec]
[quo2.components.links.url-preview.component-spec]
[quo2.components.markdown.--tests--.text-component-spec]
[quo2.components.onboarding.small-option-card.component-spec]
[quo2.components.password.tips.component-spec]
[quo2.components.profile.select-profile.component-spec]
[quo2.components.record-audio.record-audio.--tests--.record-audio-component-spec]
[quo2.components.record-audio.soundtrack.--tests--.soundtrack-component-spec]
[quo2.components.selectors.--tests--.selectors-component-spec]
[quo2.components.selectors.disclaimer.component-spec]
[quo2.components.selectors.filter.component-spec]
[quo2.components.tags.--tests--.status-tags-component-spec]))
(:require [quo2.components.avatars.user-avatar.component-spec]
[quo2.components.banners.banner.component-spec]
[quo2.components.buttons.--tests--.buttons-component-spec]
[quo2.components.colors.color-picker.component-spec]
[quo2.components.counter.--tests--.counter-component-spec]
[quo2.components.dividers.--tests--.divider-label-component-spec]
[quo2.components.dividers.strength-divider.component-spec]
[quo2.components.drawers.action-drawers.component-spec]
[quo2.components.drawers.drawer-buttons.component-spec]
[quo2.components.drawers.permission-context.component-spec]
[quo2.components.inputs.input.component-spec]
[quo2.components.inputs.profile-input.component-spec]
[quo2.components.inputs.title-input.component-spec]
[quo2.components.markdown.--tests--.text-component-spec]
[quo2.components.onboarding.small-option-card.component-spec]
[quo2.components.password.tips.component-spec]
[quo2.components.profile.select-profile.component-spec]
[quo2.components.record-audio.record-audio.--tests--.record-audio-component-spec]
[quo2.components.record-audio.soundtrack.--tests--.soundtrack-component-spec]
[quo2.components.selectors.--tests--.selectors-component-spec]
[quo2.components.selectors.disclaimer.component-spec]
[quo2.components.selectors.filter.component-spec]
[quo2.components.tags.--tests--.status-tags-component-spec]))
+3 -9
View File
@@ -1,11 +1,5 @@
(ns react-native.syntax-highlighter
(:require ["react-native" :as react-native]
["react-syntax-highlighter" :default Highlighter]))
(:require ["react-syntax-highlighter" :default Highlighter]
[reagent.core :as reagent]))
(defn highlighter
[props code-string]
[:> Highlighter
;; Default props to adapt Highlighter for react-native.
(assoc props :Code-tag react-native/View :Pre-tag react-native/View)
code-string])
(def highlighter (reagent/adapt-react-class Highlighter))
+41 -37
View File
@@ -41,19 +41,36 @@
(rf/defn select-mention
{:events [:chat.ui/select-mention]}
[{:keys [db] :as cofx} text-input-ref {:keys [primary-name searched-text match public-key] :as user}]
(let [chat-id (:current-chat-id db)
text (get-in db [:chat/inputs chat-id :input-text])
method "wakuext_chatMentionNewInputTextWithMention"
params [chat-id text primary-name]]
{:json-rpc/call [{:method method
:params params
: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} %])}]}))
[{:keys [db] :as cofx} text-input-ref {:keys [primary-name searched-text match] :as user}]
(let [chat-id (:current-chat-id db)
new-text (mentions/new-input-text-with-mention cofx user)
at-sign-idx (get-in db [:chats/mentions chat-id :mentions :at-sign-idx])
cursor (+ at-sign-idx (count primary-name) 2)]
(rf/merge
cofx
{:db (-> db
(assoc-in [:chats/cursor chat-id] cursor)
(assoc-in [:chats/mention-suggestions chat-id] nil))
:set-text-input-value [chat-id new-text text-input-ref]}
(set-chat-input-text new-text chat-id)
;; NOTE(rasom): Some keyboards do not react on selection property passed to
;; text input (specifically Samsung keyboard with predictive text set on).
;; In this case, if the user continues typing after the programmatic change,
;; the new text is added to the last known cursor position before
;; programmatic change. By calling `reset-text-input-cursor` we force the
;; keyboard's cursor position to be changed before the next input.
(mentions/reset-text-input-cursor text-input-ref cursor)
;; NOTE(roman): on-text-input event is not dispatched when we change input
;; programmatically, so we have to call `on-text-input` manually
(mentions/on-text-input
(let [match-len (count match)
start (inc at-sign-idx)
end (+ start match-len)]
{:new-text match
:previous-text searched-text
:start start
:end end}))
(mentions/recheck-at-idxs {primary-name user}))))
(rf/defn disable-chat-cooldown
"Turns off chat cooldown (protection against message spamming)"
@@ -165,7 +182,8 @@
(rf/merge cofx
{:set-text-input-value [current-chat-id ""]}
(clean-input current-chat-id)
(mentions/clear-mentions))))
(mentions/clear-mentions)
(mentions/clear-cursor))))
(rf/defn send-messages
[{:keys [db] :as cofx} input-text current-chat-id]
@@ -233,29 +251,13 @@
[{{: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_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-check-mentions-success
current-chat-id
editing-message
input-text
%])}]}))
(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-check-mentions-success"
{:chat-id current-chat-id
:editing-message editing-message
:input-text input-text
:new-text new-text})
(rf/merge cofx
(if editing-message
(send-edited-message new-text editing-message)
(send-messages new-text current-chat-id))))
input-text-with-mentions (mentions/check-mentions cofx input-text)]
(rf/merge cofx
(if editing-message
(send-edited-message input-text-with-mentions editing-message)
(send-messages input-text-with-mentions current-chat-id))
(mentions/clear-mentions)
(mentions/clear-cursor))))
(rf/defn send-contact-request
{:events [:contacts/send-contact-request]}
@@ -269,6 +271,7 @@
:on-error #(log/warn "failed to send a contact request" %)
:on-success #(re-frame/dispatch [:transport/message-sent %])}]}
(mentions/clear-mentions)
(mentions/clear-cursor)
(clean-input (:current-chat-id db))))
(rf/defn cancel-contact-request
@@ -279,6 +282,7 @@
(rf/merge cofx
{:db (assoc-in db [:chat/inputs current-chat-id :metadata :sending-contact-request] nil)}
(mentions/clear-mentions)
(mentions/clear-cursor)
(clean-input (:current-chat-id db)))))
(rf/defn chat-send-sticker
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,323 @@
(ns status-im.chat.models.mentions-test
(:require [cljs.test :as test]
[clojure.string :as string]
[status-im.chat.models.mentions :as mentions]))
(def ->info-input
[[:text "H."]
[:mention
"@helpinghand.eth"]
[:text
" "]])
(def ->info-expected
{:at-sign-idx 2
:mention-end 19
:new-text " "
:previous-text ""
:start 18
:end 18
:at-idxs [{:mention? true
:from 2
:to 17
:checked? true}]})
(test/deftest test->info
(test/testing "->info base case"
(test/is (= ->info-expected (mentions/->info ->info-input)))))
;; No mention
(def mention-text-1 "parse-text")
(def mention-text-result-1 [[:text "parse-text"]])
;; Mention in the middle
(def mention-text-2
"hey @0x04fbce10971e1cd7253b98c7b7e54de3729ca57ce41a2bfb0d1c4e0a26f72c4b6913c3487fa1b4bb86125770f1743fb4459da05c1cbe31d938814cfaf36e252073 he")
(def mention-text-result-2
[[:text "hey "]
[:mention
"0x04fbce10971e1cd7253b98c7b7e54de3729ca57ce41a2bfb0d1c4e0a26f72c4b6913c3487fa1b4bb86125770f1743fb4459da05c1cbe31d938814cfaf36e252073"]
[:text " he"]])
;; Mention at the beginning
(def mention-text-3
"@0x04fbce10971e1cd7253b98c7b7e54de3729ca57ce41a2bfb0d1c4e0a26f72c4b6913c3487fa1b4bb86125770f1743fb4459da05c1cbe31d938814cfaf36e252073 he")
(def mention-text-result-3
[[:mention
"0x04fbce10971e1cd7253b98c7b7e54de3729ca57ce41a2bfb0d1c4e0a26f72c4b6913c3487fa1b4bb86125770f1743fb4459da05c1cbe31d938814cfaf36e252073"]
[:text " he"]])
;; Mention at the end
(def mention-text-4
"hey @0x04fbce10971e1cd7253b98c7b7e54de3729ca57ce41a2bfb0d1c4e0a26f72c4b6913c3487fa1b4bb86125770f1743fb4459da05c1cbe31d938814cfaf36e252073")
(def mention-text-result-4
[[:text "hey "]
[:mention
"0x04fbce10971e1cd7253b98c7b7e54de3729ca57ce41a2bfb0d1c4e0a26f72c4b6913c3487fa1b4bb86125770f1743fb4459da05c1cbe31d938814cfaf36e252073"]])
;; Invalid mention
(def mention-text-5
"invalid @0x04fBce10971e1cd7253b98c7b7e54de3729ca57ce41a2bfb0d1c4e0a26f72c4b6913c3487fa1b4bb86125770f1743fb4459da05c1cbe31d938814cfaf36e252073")
(def mention-text-result-5
[[:text
"invalid @0x04fBce10971e1cd7253b98c7b7e54de3729ca57ce41a2bfb0d1c4e0a26f72c4b6913c3487fa1b4bb86125770f1743fb4459da05c1cbe31d938814cfaf36e252073"]])
(test/deftest test-to-input
(test/testing "only text"
(test/is (= mention-text-result-1 (mentions/->input-field mention-text-1))))
(test/testing "in the middle"
(test/is (= mention-text-result-2 (mentions/->input-field mention-text-2))))
(test/testing "at the beginning"
(test/is (= mention-text-result-3 (mentions/->input-field mention-text-3))))
(test/testing "at the end"
(test/is (= mention-text-result-4 (mentions/->input-field mention-text-4))))
(test/testing "invalid"
(test/is (= mention-text-result-5 (mentions/->input-field mention-text-5)))))
(test/deftest test-replace-mentions
(let [users {"User Number One"
{:primary-name "User Number One"
:public-key "0xpk1"}
"User Number Two"
{:primary-name "user2"
:secondary-name "User Number Two"
:public-key "0xpk2"}
"User Number Three"
{:primary-name "user3"
:secondary-name "User Number Three"
:public-key "0xpk3"}}]
(test/testing "empty string"
(let [text ""
result (mentions/replace-mentions text users)]
(test/is (= result text) (pr-str text))))
(test/testing "no text"
(let [text nil
result (mentions/replace-mentions text users)]
(test/is (= result text) (pr-str text))))
(test/testing "incomlepte mention 1"
(let [text "@"
result (mentions/replace-mentions text users)]
(test/is (= result text) (pr-str text))))
(test/testing "incomplete mention 2"
(let [text "@r"
result (mentions/replace-mentions text users)]
(test/is (= result text) (pr-str text))))
(test/testing "no mentions"
(let [text "foo bar @buzz kek @foo"
result (mentions/replace-mentions text users)]
(test/is (= result text) (pr-str text))))
(test/testing "starts with mention"
(let [text "@User Number One"
result (mentions/replace-mentions text users)]
(test/is (= result "@0xpk1") (pr-str text))))
(test/testing "starts with mention, comma after mention"
(let [text "@User Number One,"
result (mentions/replace-mentions text users)]
(test/is (= result "@0xpk1,") (pr-str text))))
(test/testing "starts with mention but no space after"
(let [text "@User Number Onefoo"
result (mentions/replace-mentions text users)]
(test/is (= result text) (pr-str text))))
(test/testing "starts with mention, some text after mention"
(let [text "@User Number One foo"
result (mentions/replace-mentions text users)]
(test/is (= result "@0xpk1 foo") (pr-str text))))
(test/testing "starts with some text, then mention"
(let [text "text @User Number One"
result (mentions/replace-mentions text users)]
(test/is (= result "text @0xpk1") (pr-str text))))
(test/testing "starts with some text, then mention, then more text"
(let [text "text @User Number One foo"
result (mentions/replace-mentions text users)]
(test/is (= result "text @0xpk1 foo") (pr-str text))))
(test/testing "no space before mention"
(let [text "text@User Number One"
result (mentions/replace-mentions text users)]
(test/is (= result "text@0xpk1") (pr-str text))))
(test/testing "two different mentions"
(let [text "@User Number One @User Number two"
result (mentions/replace-mentions text users)]
(test/is (= result "@0xpk1 @0xpk2") (pr-str text))))
(test/testing "two different mentions, separated with comma"
(let [text "@User Number One,@User Number two"
result (mentions/replace-mentions text users)]
(test/is (= result "@0xpk1,@0xpk2") (pr-str text))))
(test/testing "two different mentions inside text"
(let [text "foo@User Number One bar @User Number two baz"
result (mentions/replace-mentions text users)]
(test/is (= result "foo@0xpk1 bar @0xpk2 baz") (pr-str text))))
(test/testing "ens mention"
(let [text "@user2"
result (mentions/replace-mentions text users)]
(test/is (= result "@0xpk2") (pr-str text))))
(test/testing "multiple mentions"
(let [text (string/join
" "
(repeat 1000 "@User Number One @User Number two"))
result (mentions/replace-mentions text users)
exprected-result (string/join
" "
(repeat 1000 "@0xpk1 @0xpk2"))]
(test/is (= exprected-result result))))
(test/testing "markdown"
(test/testing "single * case 1"
(let [text "*@user2*"
result (mentions/replace-mentions text users)]
(test/is (= result text) (pr-str text))))
(test/testing "single * case 2"
(let [text "*@user2 *"
result (mentions/replace-mentions text users)]
(test/is (= result "*@0xpk2 *") (pr-str text))))
(test/testing "single * case 3"
(let [text "a*@user2*"
result (mentions/replace-mentions text users)]
(test/is (= result text) (pr-str text))))
(test/testing "single * case 4"
(let [text "*@user2 foo*foo"
result (mentions/replace-mentions text users)]
(test/is (= result "*@0xpk2 foo*foo") (pr-str text))))
(test/testing "single * case 5"
(let [text "a *@user2*"
result (mentions/replace-mentions text users)]
(test/is (= result text) (pr-str text))))
(test/testing "single * case 6"
(let [text "*@user2 foo*"
result (mentions/replace-mentions text users)]
(test/is (= result text) (pr-str text))))
(test/testing "single * case 7"
(let [text "@user2 *@user2 foo* @user2"
result (mentions/replace-mentions text users)]
(test/is (= result "@0xpk2 *@user2 foo* @0xpk2") (pr-str text))))
(test/testing "single * case 8"
(let [text "*@user2 foo**@user2 foo*"
result (mentions/replace-mentions text users)]
(test/is (= result text) (pr-str text))))
(test/testing "single * case 9"
(let [text "*@user2 foo***@user2 foo* @user2"
result (mentions/replace-mentions text users)]
(test/is (= result "*@user2 foo***@user2 foo* @0xpk2") (pr-str text))))
(test/testing "double * case 1"
(let [text "**@user2**"
result (mentions/replace-mentions text users)]
(test/is (= result text) (pr-str text))))
(test/testing "double * case 2"
(let [text "**@user2 **"
result (mentions/replace-mentions text users)]
(test/is (= result "**@0xpk2 **") (pr-str text))))
(test/testing "double * case 3"
(let [text "a**@user2**"
result (mentions/replace-mentions text users)]
(test/is (= result text) (pr-str text))))
(test/testing "double * case 4"
(let [text "**@user2 foo**foo"
result (mentions/replace-mentions text users)]
(test/is (= result "**@user2 foo**foo") (pr-str text))))
(test/testing "double * case 5"
(let [text "a **@user2**"
result (mentions/replace-mentions text users)]
(test/is (= result text) (pr-str text))))
(test/testing "double * case 6"
(let [text "**@user2 foo**"
result (mentions/replace-mentions text users)]
(test/is (= result text) (pr-str text))))
(test/testing "double * case 7"
(let [text "@user2 **@user2 foo** @user2"
result (mentions/replace-mentions text users)]
(test/is (= result "@0xpk2 **@user2 foo** @0xpk2") (pr-str text))))
(test/testing "double * case 8"
(let [text "**@user2 foo****@user2 foo**"
result (mentions/replace-mentions text users)]
(test/is (= result text) (pr-str text))))
(test/testing "double * case 9"
(let [text "**@user2 foo*****@user2 foo** @user2"
result (mentions/replace-mentions text users)]
(test/is (= result "**@user2 foo*****@user2 foo** @0xpk2") (pr-str text))))
(test/testing "tripple * case 1"
(let [text "***@user2 foo***@user2 foo*"
result (mentions/replace-mentions text users)]
(test/is (= result "***@user2 foo***@0xpk2 foo*") (pr-str text))))
(test/testing "tripple ~ case 1"
(let [text "~~~@user2 foo~~~@user2 foo~"
result (mentions/replace-mentions text users)]
(test/is (= result text) (pr-str text))))
(test/testing "quote case 1"
(let [text ">@user2"
result (mentions/replace-mentions text users)]
(test/is (= result text) (pr-str text))))
(test/testing "quote case 2"
(let [text "\n>@user2"
result (mentions/replace-mentions text users)]
(test/is (= result text) (pr-str text))))
(test/testing "quote case 3"
(let [text "\n> @user2 \n \n @user2"
result (mentions/replace-mentions text users)]
(test/is (= result "\n> @user2 \n \n @0xpk2") (pr-str text))))
(test/testing "quote case 4"
(let [text ">@user2\n\n>@user2"
result (mentions/replace-mentions text users)]
(test/is (= result text) (pr-str text))))
(test/testing "quote case 5"
(let [text "***hey\n\n>@user2\n\n@user2 foo***"
result (mentions/replace-mentions text users)]
(test/is (= result "***hey\n\n>@user2\n\n@0xpk2 foo***")
(pr-str text))))
(test/testing "code case 1"
(let [text "` @user2 `"
result (mentions/replace-mentions text users)]
(test/is (= result text) (pr-str text))))
(test/testing "code case 2"
(let [text "` @user2 `"
result (mentions/replace-mentions text users)]
(test/is (= result text) (pr-str text))))
(test/testing "code case 3"
(let [text "``` @user2 ```"
result (mentions/replace-mentions text users)]
(test/is (= result text) (pr-str text))))
(test/testing "code case 4"
(let [text "` ` @user2 ``"
result (mentions/replace-mentions text users)]
(test/is (= result "` ` @0xpk2 ``") (pr-str text)))))))
+1 -2
View File
@@ -41,8 +41,7 @@
:albumId :album-id
:imageWidth :image-width
:imageHeight :image-height
:new :new?
:albumImagesCount :album-images-count})
:new :new?})
(update :quoted-message
set/rename-keys
+1 -1
View File
@@ -115,7 +115,7 @@
{:events [:system-theme-mode-changed]}
[{:keys [db] :as cofx} _]
(let [current-theme-type (get-in cofx [:db :multiaccount :appearance])]
(when (and (multiaccounts.model/logged-in? db)
(when (and (multiaccounts.model/logged-in? cofx)
(= current-theme-type status-im2.constants/theme-type-system))
{:multiaccounts.ui/switch-theme-fx
[(get-in db [:multiaccount :appearance])
+1 -1
View File
@@ -238,7 +238,7 @@
:t/keycard-can-use-with-new-passcode
:t/keycard-backup-success-body))}}
(cond
(multiaccounts.model/logged-in? db)
(multiaccounts.model/logged-in? cofx)
(navigation/set-stack-root :profile-stack [:my-profile :keycard-settings])
(:multiaccounts/login db)
+1 -1
View File
@@ -21,7 +21,7 @@
(rf/defn on-network-status-change
[{:keys [db] :as cofx}]
(let [initialized? (get db :network-status/initialized?)
logged-in? (multiaccounts.model/logged-in? db)
logged-in? (multiaccounts.model/logged-in? cofx)
{:keys [remember-syncing-choice?]} (:multiaccount db)]
(apply
rf/merge
@@ -21,10 +21,10 @@
(rf/defn key-and-storage-management-pressed
"This event can be dispatched before login and from profile and needs to redirect accordingly"
{:events [::key-and-storage-management-pressed]}
[{:keys [db] :as cofx}]
[cofx]
(navigation/navigate-to
cofx
(if (multiaccounts.model/logged-in? db)
(if (multiaccounts.model/logged-in? cofx)
:actions-logged-in
:actions-not-logged-in)
nil))
+6 -5
View File
@@ -476,6 +476,9 @@
"Decides which root should be initialised depending on user and app state"
[db]
(cond
(get db :local-pairing/completed-pairing?)
(re-frame/dispatch [:syncing/pairing-completed])
(get db :onboarding-2/new-account?)
(re-frame/dispatch [:onboarding-2/finalize-setup])
@@ -487,9 +490,8 @@
(rf/defn login-only-events
[{:keys [db] :as cofx} key-uid password save-password?]
(let [auth-method (:auth-method db)
new-auth-method (get-new-auth-method auth-method save-password?)
pairing-in-progress? (get-in db [:syncing :pairing-in-progress?])]
(let [auth-method (:auth-method db)
new-auth-method (get-new-auth-method auth-method save-password?)]
(log/debug "[login] login-only-events"
"auth-method" auth-method
"new-auth-method" new-auth-method)
@@ -498,8 +500,7 @@
:json-rpc/call
[{:method "settings_getSettings"
:on-success #(do (re-frame/dispatch [::get-settings-callback %])
(when-not pairing-in-progress?
(redirect-to-root db)))}]}
(redirect-to-root db))}]}
(notifications/load-notification-preferences)
(when save-password?
(keychain/save-user-password key-uid password))
+3 -2
View File
@@ -1,8 +1,9 @@
(ns status-im.multiaccounts.model)
(defn logged-in?
[{:keys [multiaccount]}]
(boolean multiaccount))
[cofx]
(boolean
(get-in cofx [:db :multiaccount])))
(defn credentials
[cofx]
+2 -2
View File
@@ -4,6 +4,6 @@
(deftest logged-in-test
(testing "multiaccount is defined"
(is (multiaccounts.model/logged-in? {:multiaccount {}})))
(is (multiaccounts.model/logged-in? {:db {:multiaccount {}}})))
(testing "multiaccount is not there"
(is (not (multiaccounts.model/logged-in? {})))))
(is (not (multiaccounts.model/logged-in? {:db {}})))))
+21 -37
View File
@@ -1,29 +1,17 @@
(ns status-im.multiaccounts.update.core
(:require [status-im.utils.types :as types]
[status-im2.constants :as constants]
[taoensso.timbre :as log]
[utils.re-frame :as rf]))
(:require [status-im2.constants :as constants]
[utils.re-frame :as rf]
[status-im.utils.types :as types]
[taoensso.timbre :as log]))
(rf/defn send-contact-update
[{:keys [db]}]
(let [{:keys [name preferred-name display-name address]} (:multiaccount db)]
(rf/defn send-multiaccount-update
[{:keys [db] :as cofx}]
(let [multiaccount (:multiaccount db)
{:keys [name preferred-name address]} multiaccount]
{:json-rpc/call [{:method "wakuext_sendContactUpdates"
:params [(or preferred-name display-name name) ""]
:params [(or preferred-name name) ""]
:on-success #(log/debug "sent contact update")}]}))
(rf/defn update-multiaccount-account-name
"This updates the profile name in the profile list before login"
{:events [:multiaccounts.ui/update-name]}
[{:keys [db] :as cofx} raw-multiaccounts-from-status-go]
(let [{:keys [key-uid name preferred-name
display-name]} (:multiaccount db)
account (some #(and (= (:key-uid %) key-uid) %) raw-multiaccounts-from-status-go)]
(when-let [new-name (and account (or preferred-name display-name name))]
(rf/merge cofx
{:json-rpc/call [{:method "multiaccounts_updateAccount"
:params [(assoc account :name new-name)]
:on-success #(log/debug "sent multiaccount update")}]}))))
(rf/defn multiaccount-update
"Takes effects (containing :db) + new multiaccount fields, adds all effects necessary for multiaccount update.
Optionally, one can specify a success-event to be dispatched after fields are persisted."
@@ -37,21 +25,17 @@
(throw
(js/Error.
"Please shake the phone to report this error and restart the app. multiaccount is currently empty, which means something went wrong when trying to update it with"))
(rf/merge
cofx
{:db (if setting-value
(assoc-in db [:multiaccount setting] setting-value)
(update db :multiaccount dissoc setting))
:json-rpc/call
[{:method "settings_saveSetting"
:params [setting setting-value]
:on-success on-success}]}
(when (#{:name :preferred-name} setting)
(constantly {:setup/open-multiaccounts #(rf/dispatch [:multiaccounts.ui/update-name %])}))
(when (and (not dont-sync?) (#{:name :preferred-name} setting))
(send-contact-update))))))
(rf/merge cofx
{:db (if setting-value
(assoc-in db [:multiaccount setting] setting-value)
(update db :multiaccount dissoc setting))
:json-rpc/call
[{:method "settings_saveSetting"
:params [setting setting-value]
:on-success on-success}]}
(when (and (not dont-sync?)
(#{:name :prefered-name} setting))
(send-multiaccount-update))))))
(rf/defn clean-seed-phrase
"A helper function that removes seed phrase from storage."
@@ -60,7 +44,7 @@
(defn augment-synchronized-recent-stickers
"Add 'url' parameter to stickers that are synchronized from other devices.
It is not sent from another devices but we have it in our db."
It is not sent from aanother devices but we have it in our db."
[synced-stickers stickers-from-db]
(mapv #(assoc %
:url
@@ -1,5 +1,5 @@
(ns status-im.multiaccounts.update.core-test
(:require [clojure.test :refer-macros [deftest is testing]]
(:require [clojure.test :refer-macros [deftest is]]
[status-im.multiaccounts.update.core :as multiaccounts.update]))
(deftest test-multiaccount-update
@@ -21,36 +21,3 @@
json-rpc (into #{} (map :method (:json-rpc/call efx)))]
(is (json-rpc "settings_saveSetting"))
(is (nil? (get-in efx [:db :multiaccount :mnemonic])))))
(deftest test-update-multiaccount-account-name
(let [cofx {:db {:multiaccount {:key-uid 1
:name "name"
:preferred-name "preferred-name"
:display-name "display-name"}}}
raw-multiaccounts-from-status-go [{:key-uid 1 :name "old-name"}]]
(testing "wrong account"
(is (nil? (multiaccounts.update/update-multiaccount-account-name cofx []))))
(testing "name priority preferred-name > display-name > name"
(let [new-account-name= (fn [efx new-name]
(-> efx
:json-rpc/call
first
:params
first
:name
(= new-name)))]
(is (new-account-name=
(multiaccounts.update/update-multiaccount-account-name
cofx
raw-multiaccounts-from-status-go)
"preferred-name"))
(is (new-account-name=
(multiaccounts.update/update-multiaccount-account-name
(update-in cofx [:db :multiaccount] dissoc :preferred-name)
raw-multiaccounts-from-status-go)
"display-name"))
(is (new-account-name=
(multiaccounts.update/update-multiaccount-account-name
(update-in cofx [:db :multiaccount] dissoc :preferred-name :display-name)
raw-multiaccounts-from-status-go)
"name"))))))
+2 -2
View File
@@ -247,11 +247,11 @@
[cofx installation-id]
(rf/merge cofx
(enable installation-id)
(multiaccounts.update/send-contact-update)))
(multiaccounts.update/send-multiaccount-update)))
(rf/defn disable-installation-success
{:events [:pairing.callback/disable-installation-success]}
[cofx installation-id]
(rf/merge cofx
(disable installation-id)
(multiaccounts.update/send-contact-update)))
(multiaccounts.update/send-multiaccount-update)))
+9 -13
View File
@@ -60,29 +60,27 @@
[{:keys [db] :as cofx} event]
(log/info "local pairing signal received"
{:event event})
(let [connection-success? (and (= (:type event)
constants/local-pairing-event-connection-success)
(= (:action event)
constants/local-pairing-action-connect))
(let [connection-success? (= (:type event)
constants/local-pairing-event-connection-success)
error-on-pairing? (contains? constants/local-pairing-event-errors (:type event))
completed-pairing? (and (= (:type event)
constants/local-pairing-event-transfer-success)
constants/local-pairing-event-process-success)
(= (:action event)
constants/local-pairing-action-pairing-installation))
logged-in? (multiaccounts.model/logged-in? db)
constants/local-pairing-action-pairing-account))
logged-in? (multiaccounts.model/logged-in? cofx)
;; since `connection-success` event is received on both sender and receiver devices
;; we check the `logged-in?` status to identify the receiver and take the user to next screen
navigate-to-syncing-devices? (and connection-success? (not logged-in?))
user-in-syncing-devices-screen? (= (:view-id db) :syncing-devices)]
(merge {:db (cond-> db
connection-success?
(assoc-in [:syncing :pairing-in-progress?] true)
(assoc :local-pairing/completed-pairing? false)
error-on-pairing?
(update-in [:syncing :pairing-in-progress?] dissoc)
(dissoc :local-pairing/completed-pairing?)
completed-pairing?
(assoc-in [:syncing :pairing-in-progress?] false))}
(assoc :local-pairing/completed-pairing? true))}
(when navigate-to-syncing-devices?
{:dispatch [:navigate-to :syncing-devices]})
(when (and error-on-pairing? user-in-syncing-devices-screen?)
@@ -91,9 +89,7 @@
:icon-color colors/danger-50
:override-theme :light
:text (i18n/label :t/error-syncing-connection-failed)}]
[:navigate-back]]})
(when completed-pairing?
{:dispatch [:syncing/pairing-completed]}))))
[:navigate-back]]}))))
(rf/defn process
{:events [:signals/signal-received]}
@@ -10,7 +10,9 @@
[re-frame.core :as re-frame]
[reagent.core :as reagent]
[status-im2.constants :as chat.constants]
[status-im.chat.models.mentions :as mentions]
[utils.i18n :as i18n]
[status-im.multiaccounts.core :as multiaccounts]
[status-im.ui.components.icons.icons :as icons]
[status-im.ui.components.list.views :as list]
[status-im.ui.screens.chat.components.reply :as reply]
@@ -93,7 +95,7 @@
:color (styles/send-icon-color)}])]])
(defn on-selection-change
[timeout-id last-text-change args]
[timeout-id last-text-change mentionable-users args]
(let [selection (.-selection ^js (.-nativeEvent ^js args))
start (.-start selection)
end (.-end selection)]
@@ -104,9 +106,10 @@
(reset!
timeout-id
(utils.utils/set-timeout
#(re-frame/dispatch [:mention/on-selection-change
#(re-frame/dispatch [::mentions/on-selection-change
{:start start
:end end}])
:end end}
mentionable-users])
50)))
;; NOTE(rasom): on Android we dispatch event only in case if there
;; was no text changes during last 50ms. `on-selection-change` is
@@ -115,9 +118,10 @@
(when (and platform/android?
(or (not @last-text-change)
(< 50 (- (js/Date.now) @last-text-change))))
(re-frame/dispatch [:mention/on-selection-change
(re-frame/dispatch [::mentions/on-selection-change
{:start start
:end end}]))))
:end end}
mentionable-users]))))
(defonce input-texts (atom {}))
(defonce mentions-enabled (reagent/atom {}))
@@ -179,7 +183,7 @@
(re-frame/dispatch [:chat.ui/set-chat-input-text val]))
(defn on-change
[last-text-change timeout-id refs chat-id sending-image args]
[last-text-change timeout-id mentionable-users refs chat-id sending-image args]
(let [text (.-text ^js (.-nativeEvent ^js args))
prev-text (get @input-texts chat-id)]
(when (and (seq prev-text) (empty? text) (not sending-image))
@@ -202,24 +206,46 @@
;; NOTE(rasom): on iOS `on-change` is dispatched after `on-text-input`,
;; that's why mention suggestions are calculated on `on-change`
(when platform/ios?
(re-frame/dispatch [:mention/calculate-suggestions]))))
(re-frame/dispatch [::mentions/calculate-suggestions mentionable-users]))))
(rf/defn set-input-text
"Set input text for current-chat. Takes db and input text and cofx
as arguments and returns new fx. Always clear all validation messages."
{:events [:chat.ui.input/set-chat-input-text]}
[{:keys [db]} text chat-id]
(let [params [chat-id text]
method "wakuext_chatMentionToInputField"]
{:json-rpc/call [{:method method
:params params
:on-success #(rf/dispatch [:mention/on-to-input-field-success %])
:on-error #(rf/dispatch [:mention/on-error
{:method method
:params params} %])}]}))
(let [text-with-mentions (mentions/->input-field text)
all-contacts (:contacts/contacts db)
chat (get-in db [:chats chat-id])
current-multiaccount (:multiaccount db)
community-members (when (= (:chat-type chat) chat.constants/community-chat-type)
(get-in db [:communities (:community-id chat) :members]))
mentionable-users (mentions/get-mentionable-users
chat
all-contacts
current-multiaccount
community-members)
hydrated-mentions (map
(fn [[t mention :as e]]
(if (= t :mention)
(let [mention (multiaccounts/displayed-name
(get mentionable-users mention))]
[:mention
(if (string/starts-with? mention "@")
mention
(str "@" mention))])
e))
text-with-mentions)
info (mentions/->info hydrated-mentions)
new-text (string/join (map second hydrated-mentions))]
{:set-text-input-value [chat-id new-text]
:db
(-> db
(assoc-in [:chats/cursor chat-id] (:mention-end info))
(assoc-in [:chat/inputs-with-mentions chat-id] hydrated-mentions)
(assoc-in [:chats/mentions chat-id :mentions] info))}))
(defn on-text-input
[chat-id args]
[mentionable-users chat-id args]
(let [native-event (.-nativeEvent ^js args)
text (.-text ^js native-event)
previous-text (.-previousText ^js native-event)
@@ -230,7 +256,7 @@
(swap! mentions-enabled assoc chat-id true))
(re-frame/dispatch
[:mention/on-text-input
[::mentions/on-text-input
{:new-text text
:previous-text previous-text
:start start
@@ -239,11 +265,12 @@
;; `on-change`, that's why mention suggestions are calculated
;; on `on-change`
(when platform/android?
(re-frame/dispatch [:mention/calculate-suggestions]))))
(re-frame/dispatch [::mentions/calculate-suggestions mentionable-users]))))
(defn text-input
[{:keys [set-active-panel refs chat-id sending-image]}]
(let [cooldown-enabled? @(re-frame/subscribe [:chats/current-chat-cooldown-enabled?])
mentionable-users @(re-frame/subscribe [:chats/mentionable-users])
timeout-id (atom nil)
last-text-change (atom nil)
mentions-enabled (get @mentions-enabled chat-id)
@@ -269,10 +296,11 @@
:auto-capitalize :sentences
:on-selection-change (partial on-selection-change
timeout-id
last-text-change)
last-text-change
mentionable-users)
:on-change
(partial on-change last-text-change timeout-id refs chat-id sending-image)
:on-text-input (partial on-text-input chat-id)}
(partial on-change last-text-change timeout-id mentionable-users refs chat-id sending-image)
:on-text-input (partial on-text-input mentionable-users chat-id)}
(if mentions-enabled
(for [[idx [type text]] (map-indexed
(fn [idx item]
@@ -76,8 +76,7 @@
(format-reply-author from contact-name current-public-key)]])
(defn reply-message
[{:keys [from identicon content-type contentType parsed-text content deleted? deleted-for-me?
album-images-count]}
[{:keys [from identicon content-type contentType parsed-text content deleted? deleted-for-me?]}
in-chat-input? pin? recording-audio?]
(let [contact-name (rf/sub [:contacts/contact-name-by-identity from])
current-public-key (rf/sub [:multiaccount/public-key])
@@ -114,12 +113,9 @@
(= constants/content-type-audio content-type))
{:color (colors/theme-colors colors/neutral-50 colors/neutral-40)}))}
(case (or content-type contentType)
constants/content-type-image (if album-images-count
(i18n/label :t/images-albums-count
{:album-images-count album-images-count})
(i18n/label :t/image))
constants/content-type-sticker (i18n/label :t/sticker)
constants/content-type-audio (i18n/label :t/audio)
constants/content-type-image "Image"
constants/content-type-sticker "Sticker"
constants/content-type-audio "Audio"
(get-quoted-text-with-mentions (or parsed-text (:parsed-text content))))]])]
(when (and in-chat-input? (not recording-audio?))
[quo2.button/button
@@ -5,6 +5,7 @@
[re-frame.core :as re-frame]
[reagent.core :as reagent]
[status-im2.constants :as chat.constants]
[status-im.chat.models.mentions :as mentions]
[utils.i18n :as i18n]
[utils.re-frame :as rf]
[utils.transforms :as transforms]
@@ -92,7 +93,7 @@
(rf/dispatch [:chat.ui/set-chat-input-text val]))
(defn on-selection-change
[timeout-id last-text-change args]
[timeout-id last-text-change mentionable-users args]
(let [selection (.-selection ^js (.-nativeEvent ^js args))
start (.-start selection)
end (.-end selection)]
@@ -103,9 +104,10 @@
(reset!
timeout-id
(background-timer/set-timeout
#(rf/dispatch [:mention/on-selection-change
#(rf/dispatch [::mentions/on-selection-change
{:start start
:end end}])
:end end}
mentionable-users])
50)))
;; NOTE(rasom): on Android we dispatch event only in case if there
;; was no text changes during last 50ms. `on-selection-change` is
@@ -114,12 +116,13 @@
(when (and platform/android?
(or (not @last-text-change)
(< 50 (- (js/Date.now) @last-text-change))))
(rf/dispatch [:mention/on-selection-change
(rf/dispatch [::mentions/on-selection-change
{:start start
:end end}]))))
:end end}
mentionable-users]))))
(defn on-change
[last-text-change timeout-id refs chat-id sending-image args]
[last-text-change timeout-id mentionable-users refs chat-id sending-image args]
(let [text (.-text ^js (.-nativeEvent ^js args))
prev-text (get @input-texts chat-id)]
(when (and (seq prev-text) (empty? text) (not sending-image))
@@ -144,10 +147,10 @@
;; NOTE(rasom): on iOS `on-change` is dispatched after `on-text-input`,
;; that's why mention suggestions are calculated on `on-change`
(when platform/ios?
(rf/dispatch [:mention/calculate-suggestions]))))
(rf/dispatch [::mentions/calculate-suggestions mentionable-users]))))
(defn on-text-input
[chat-id args]
[mentionable-users chat-id args]
(let [native-event (.-nativeEvent ^js args)
text (.-text ^js native-event)
previous-text (.-previousText ^js native-event)
@@ -158,7 +161,7 @@
(swap! mentions-enabled? assoc chat-id true))
(rf/dispatch
[:mention/on-text-input
[::mentions/on-text-input
{:new-text text
:previous-text previous-text
:start start
@@ -167,7 +170,7 @@
;; `on-change`, that's why mention suggestions are calculated
;; on `on-change`
(when platform/android?
(rf/dispatch [:mention/calculate-suggestions]))))
(rf/dispatch [::mentions/calculate-suggestions mentionable-users]))))
(defn text-input-style
[chat-id]
@@ -190,6 +193,7 @@
(defn text-input
[{:keys [refs chat-id sending-image on-content-size-change]}]
(let [cooldown-enabled? (rf/sub [:chats/current-chat-cooldown-enabled?])
mentionable-users (rf/sub [:chats/mentionable-users])
timeout-id (reagent/atom nil)
last-text-change (reagent/atom nil)
mentions-enabled? (get @mentions-enabled? chat-id)
@@ -216,17 +220,18 @@
:on-content-size-change on-content-size-change
:on-selection-change (partial on-selection-change
timeout-id
last-text-change)
last-text-change
mentionable-users)
:on-change
(partial on-change last-text-change timeout-id refs chat-id sending-image)
:on-text-input (partial on-text-input chat-id)}
(partial on-change last-text-change timeout-id mentionable-users refs chat-id sending-image)
:on-text-input (partial on-text-input mentionable-users chat-id)}
input-with-mentions (rf/sub [:chat/input-with-mentions])
children (fn []
(if mentions-enabled?
(map-indexed
(fn [index [mention-type text]]
^{:key (str index "_" mention-type "_" text)}
[rn/text (when (= mention-type :mention) {:style {:color colors/primary-50}})
(fn [index [_ text]]
^{:key (str index "_" type "_" text)}
[rn/text (when (= type :mention) {:style {:color colors/primary-50}})
text])
input-with-mentions)
(get @input-texts chat-id)))]
@@ -184,7 +184,7 @@
on login, otherwise just handle it"
{:events [:universal-links/handle-url]}
[{:keys [db] :as cofx} url]
(if (and (multiaccounts.model/logged-in? db) (= (:app-state db) "active"))
(if (and (multiaccounts.model/logged-in? cofx) (= (:app-state db) "active"))
(route-url cofx url)
(store-url-for-later cofx url)))
-3
View File
@@ -263,9 +263,6 @@
An example of a connection string is -> cs2:5vd6J6:Jfc:27xMmHKEYwzRGXcvTtuiLZFfXscMx4Mz8d9wEHUxDj4p7:EG7Z13QScfWBJNJ5cprszzDQ5fBVsYMirXo8MaQFJvpF:3 "
"cs")
(def ^:const local-pairing-role-sender "sender")
(def ^:const local-pairing-role-receiver "receiver")
;; sender and receiver events
(def ^:const local-pairing-event-connection-success "connection-success")
(def ^:const local-pairing-event-connection-error "connection-error")
@@ -8,8 +8,7 @@
[react-native.platform :as platform]
[status-im.notifications.core :as notifications]
[status-im2.contexts.onboarding.common.background.view :as background]
[status-im2.contexts.onboarding.enable-notifications.style :as style]
[status-im2.contexts.shell.animation :as shell.animation]))
[status-im2.contexts.onboarding.enable-notifications.style :as style]))
(defn navigation-bar
[]
@@ -42,26 +41,22 @@
(defn enable-notification-buttons
[]
(let [{profile-color :color} (rf/sub [:onboarding-2/profile])]
[rn/view {:style style/enable-notifications-buttons}
[quo/button
{:on-press (fn []
(shell.animation/change-selected-stack-id :communities-stack true)
(rf/dispatch [::notifications/switch true platform/ios?])
(rf/dispatch [:init-root :welcome]))
:type :primary
:before :i/notifications
:accessibility-label :enable-notifications-button
:override-background-color (colors/custom-color profile-color 60)}
(i18n/label :t/intro-wizard-title6)]
[quo/button
{:on-press (fn []
(shell.animation/change-selected-stack-id :communities-stack true)
(rf/dispatch [:init-root :welcome]))
:accessibility-label :enable-notifications-later-button
:override-background-color colors/white-opa-5
:style {:margin-top 12}}
(i18n/label :t/maybe-later)]]))
[rn/view {:style style/enable-notifications-buttons}
[quo/button
{:on-press (fn []
(rf/dispatch [::notifications/switch true platform/ios?])
(rf/dispatch [:init-root :welcome]))
:type :primary
:before :i/notifications
:accessibility-label :enable-notifications-button
:override-background-color (colors/custom-color :magenta 60)}
(i18n/label :t/intro-wizard-title6)]
[quo/button
{:on-press #(rf/dispatch [:init-root :welcome])
:accessibility-label :enable-notifications-later-button
:override-background-color colors/white-opa-5
:style {:margin-top 12}}
(i18n/label :t/maybe-later)]])
(defn enable-notifications
[]
@@ -73,3 +68,4 @@
[quo/text
"[Illustration here]"]]
[enable-notification-buttons]])
@@ -163,7 +163,8 @@
constants/auth-method-biometric
(get-in db [:onboarding-2/profile :auth-method]))]
(cond-> {:dispatch [:navigate-to :enable-notifications]}
(cond-> {:db (dissoc db :onboarding-2/profile)
:dispatch [:navigate-to :enable-notifications]}
biometric-enabled?
(assoc :biometric/enable-and-save-password
{:key-uid key-uid
@@ -15,8 +15,7 @@
[status-im2.contexts.onboarding.common.background.view :as background]
[status-im2.contexts.onboarding.sign-in.style :as style]
[utils.i18n :as i18n]
[utils.re-frame :as rf]
[utils.transforms :as transforms]))
[utils.re-frame :as rf]))
(defonce camera-permission-granted? (reagent/atom false))
@@ -86,20 +85,14 @@
(defn- qr-scan-hole-area
[qr-view-finder]
(let [status-bar-height (rn/status-bar-height)]
[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?
(+ status-bar-height (:y layout))
(:y layout))
view-finder (-> layout
(assoc :height width)
(assoc :y y))]
(reset! qr-view-finder 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]
@@ -39,18 +39,17 @@
(defn view
[]
(let [{profile-color :color} (rf/sub [:onboarding-2/profile])]
[rn/view {:style style/welcome-container}
[background/view true]
[navigation-bar :enable-notifications]
[page-title]
[rn/view {:style style/page-illustration}
[quo/text
"Illustration here"]]
[quo/button
{:on-press #(rf/dispatch [:init-root :shell-stack])
:type :primary
:accessibility-label :welcome-button
:override-background-color (colors/custom-color profile-color 60)
:style {:margin 20}}
(i18n/label :t/start-using-status)]]))
[rn/view {:style style/welcome-container}
[background/view true]
[navigation-bar :enable-notifications]
[page-title]
[rn/view {:style style/page-illustration}
[quo/text
"Illustration here"]]
[quo/button
{:on-press #(rf/dispatch [:init-root :shell-stack])
:type :primary
:accessibility-label :welcome-button
:override-background-color (colors/custom-color :magenta 60)
:style {:margin 20}}
(i18n/label :t/start-using-status)]])
@@ -26,23 +26,6 @@
s.logger.Error(\"failed to set Server.port\", zap.Error(err))
return
}
if s.afterPortChanged != nil {
s.afterPortChanged(s.port)
}
s.run = true
err = s.server.Serve(listener)
if err != http.ErrServerClosed {
s.logger.Error(\"server failed unexpectedly, restarting\", zap.Error(err))
err = s.Start()
if err != nil {
s.logger.Error(\"server start failed, giving up\", zap.Error(err))
}
return
}
s.run = false
}")
(def clojure-example
@@ -76,13 +59,9 @@
:value :clojure}
{:key :go
:value :go}]}
{:label "Max lines:"
:key :max-lines
:type :select
:options (map (fn [n]
{:key n
:value (str n " lines")})
(range 0 41 5))}
{:label "Max lines:"
:key :max-lines
:type :text}
{:label "Syntax highlight:"
:key :syntax
:type :boolean}])
@@ -90,7 +69,7 @@
(defn cool-preview
[]
(let [state (reagent/atom {:language :clojure
:max-lines 40
:max-lines ""
:syntax true})]
(fn []
(let [language (if (:syntax @state) (:language @state) :text)
@@ -1,56 +0,0 @@
(ns status-im2.contexts.quo-preview.links.url-preview
(:require
[quo2.core :as quo]
[quo2.foundations.colors :as colors]
[react-native.core :as rn]
[reagent.core :as reagent]
[status-im2.common.resources :as resources]
[status-im2.contexts.quo-preview.preview :as preview]))
(def descriptor
[{:label "Title"
:key :title
:type :text}
{:label "Body"
:key :body
:type :text}
{:label "Loading?"
:key :loading?
:type :boolean}
{:label "Loading message"
:key :loading-message
:type :text}])
(defn cool-preview
[]
(let [state (reagent/atom
{:title "Status - Private, Secure Communication"
:body "Status.im"
:loading? false
:loading-message "Generating preview"})]
(fn []
[rn/touchable-without-feedback {:on-press rn/dismiss-keyboard!}
[rn/view {:style {:padding-bottom 150}}
[preview/customizer state descriptor]
[rn/view
{:style {:align-items :center
:padding-horizontal 16
:margin-top 50}}
[quo/url-preview
{:title (:title @state)
:body (:body @state)
:logo (resources/get-mock-image :status-logo)
:loading? (:loading? @state)
:loading-message (:loading-message @state)
:on-clear #(js/alert "Clear button pressed")}]]]])))
(defn preview
[]
[rn/view
{:style {:background-color (colors/theme-colors colors/white colors/neutral-95)
:flex 1}}
[rn/flat-list
{:flex 1
:keyboard-should-persist-taps :always
:header [cool-preview]
:key-fn str}]])
@@ -39,7 +39,6 @@
[status-im2.contexts.quo-preview.info.information-box :as information-box]
[status-im2.contexts.quo-preview.inputs.profile-input :as profile-input]
[status-im2.contexts.quo-preview.inputs.title-input :as title-input]
[status-im2.contexts.quo-preview.links.url-preview :as url-preview]
[status-im2.contexts.quo-preview.list-items.channel :as channel]
[status-im2.contexts.quo-preview.list-items.preview-lists :as preview-lists]
[status-im2.contexts.quo-preview.markdown.text :as text]
@@ -178,9 +177,6 @@
{:name :title-input
:insets {:top false}
:component title-input/preview-title-input}]
:links [{:name :url-preview
:options {:insets {:top? true}}
:component url-preview/preview}]
:list-items [{:name :channel
:insets {:top false}
:component channel/preview-channel}
+5 -14
View File
@@ -13,17 +13,10 @@
(rf/defn local-pairing-completed
{:events [:syncing/pairing-completed]}
[{:keys [db]}]
(let [receiver? (= (get-in db [:syncing :role]) constants/local-pairing-role-receiver)]
(merge
{:db (dissoc db :syncing)}
(when receiver?
{:dispatch [:init-root :enable-notifications]}))))
(rf/defn local-pairing-update-role
{:events [:syncing/update-role]}
[{:keys [db]} role]
{:db (assoc-in db [:syncing :role] role)})
[{:keys [db] :as cofx}]
(rf/merge cofx
{:db (dissoc db :local-pairing/completed-pairing?)
:dispatch [:init-root :enable-notifications]}))
(defn- get-default-node-config
[installation-id]
@@ -51,7 +44,6 @@
:nodeConfig final-node-config
:settingCurrentNetwork config/default-network
:deviceType utils.platform/os}}))]
(rf/dispatch [:syncing/update-role constants/local-pairing-role-receiver])
(status/input-connection-string-for-bootstrapping
connection-string
config-map
@@ -69,8 +61,7 @@
[:show-bottom-sheet
{:content (fn []
[sheet/qr-code-view-with-connection-string
connection-string])}])
(rf/dispatch [:syncing/update-role constants/local-pairing-role-sender]))]
connection-string])}]))]
(if valid-password?
(let [sha3-pwd (status/sha3 (str (security/safe-unmask-data entered-password)))
key-uid (get-in db [:multiaccount :key-uid])
+21
View File
@@ -3,6 +3,7 @@
[quo.design-system.colors :as colors]
[re-frame.core :as re-frame]
[status-im.add-new.db :as db]
[status-im.chat.models.mentions :as mentions]
[status-im.communities.core :as communities]
[status-im.group-chats.core :as group-chat]
[status-im.group-chats.db :as group-chats.db]
@@ -437,6 +438,26 @@
(fn [[current-chat pk]]
(group-chat/member-removed? current-chat pk)))
(re-frame/reg-sub
:chats/mentionable-users
:<- [:chats/current-chat]
:<- [:contacts/blocked-set]
:<- [:contacts/contacts]
:<- [:multiaccount]
:<- [:communities/current-community-members]
(fn
[[{:keys [users] :as chat}
blocked
all-contacts
{:keys [public-key] :as current-multiaccount}
community-members]]
(let [mentionable-users (mentions/get-mentionable-users chat
all-contacts
current-multiaccount
community-members)
members-left (into #{} (filter #(group-chat/member-removed? chat %) (keys users)))]
(apply dissoc mentionable-users (conj (concat blocked members-left) public-key)))))
(re-frame/reg-sub
:chat/mention-suggestions
:<- [:chats/current-chat-id]
+1 -1
View File
@@ -29,7 +29,7 @@
(re-frame/reg-sub
:multiaccount/logged-in?
(fn [db]
(multiaccounts.model/logged-in? db)))
(multiaccounts.model/logged-in? {:db db})))
(re-frame/reg-sub
:hide-screen?
+2 -2
View File
@@ -186,5 +186,5 @@
(.toBeNull (js/expect element)))
(defn was-called
[mock]
(.toHaveBeenCalled (js/expect mock)))
[element]
(.toHaveBeenCalled (js/expect element)))
+3 -3
View File
@@ -3,7 +3,7 @@
"_comment": "Instead use: scripts/update-status-go.sh <rev>",
"owner": "status-im",
"repo": "status-go",
"version": "v0.144.0",
"commit-sha1": "ba1ba1ac0203948339be5877ea6e970efb7b8ee0",
"src-sha256": "0r2gxivnx201zfnm69g2mk1izcjid4lf9s4ln721kwrnc1v288sf"
"version": "v0.142.4",
"commit-sha1": "142b170ec99498bbeb41d7f4ce5b7140db597e56",
"src-sha256": "038p3axqj4m2wczs3fg44535rn6y235hr23w9fjriaglp80p2z07"
}
+1 -1
View File
@@ -36,7 +36,7 @@ python-dateutil==2.8.1
pytz==2020.4
PyYAML==5.4
repoze.lru==0.7
requests==2.25.1
requests==2.28.2
rlp==3.0.0
sauceclient==1.0.0
scrypt==0.8.17
+12 -12
View File
@@ -1,23 +1,23 @@
import asyncio
import logging
from datetime import datetime
import os
import functools
import json
import logging
import os
from datetime import datetime
from support.appium_container import AppiumContainer
from support.test_data import TestSuiteData
import functools
import time
async def start_threads(quantity: int, func: type, returns: dict, *args):
loop = asyncio.get_event_loop()
# from tests.conftest import sauce
# for _ in range(60):
# if 16 - len([job for job in sauce.jobs.get_user_jobs() if job['status'] == 'in progress']) < quantity:
# time.sleep(10)
# from tests.conftest import sauce
# for _ in range(60):
# if 16 - len([job for job in sauce.jobs.get_user_jobs() if job['status'] == 'in progress']) < quantity:
# time.sleep(10)
for i in range(quantity):
returns[i] = loop.run_in_executor(None, func, *args)
# returns[i] = loop.run_in_executor(None, functools.partial(func, **kwargs))
for k in returns:
returns[k] = await returns[k]
return returns
@@ -44,6 +44,7 @@ def get_current_time():
def debug(text: str):
logging.debug(text)
appium_root_project_path = os.path.join(os.sep.join(__file__.split(os.sep)[:-1]), '../')
pytest_config_global = dict()
@@ -54,7 +55,7 @@ common_password = 'qwerty1234'
unique_password = 'unique' + get_current_time()
pin = '121212'
puk = '000000000000'
pair_code= '000000'
pair_code = '000000'
background_service_message = 'Background service for notifications'
bootnode_address = "enode://a8a97f126f5e3a340cb4db28a1187c325290ec08b2c9a6b1f19845ac86c46f9fac2ba13328822590" \
@@ -77,6 +78,5 @@ test_dapp_name = 'simpledapp.status.im'
emojis = {'thumbs-up': 2, 'thumbs-down': 3, 'love': 1, 'laugh': 4, 'angry': 6, 'sad': 5}
with open(os.sep.join(__file__.split(os.sep)[:-1]) + '/../../../translations/en.json') as json_file:
transl = json.load(json_file)
+40 -33
View File
@@ -15,7 +15,6 @@ from sauceclient import SauceException
from selenium.common.exceptions import NoSuchElementException
from selenium.common.exceptions import WebDriverException
from selenium.webdriver.support.wait import WebDriverWait
from urllib3.exceptions import MaxRetryError
from support.api.network_api import NetworkApi
from support.github_report import GithubHtmlReport
@@ -70,10 +69,10 @@ def get_capabilities_sauce_lab():
desired_caps['name'] = test_suite_data.current_test.name
desired_caps['platformName'] = 'Android'
desired_caps['appiumVersion'] = '1.18.1'
desired_caps['platformVersion'] = '10.0'
desired_caps['platformVersion'] = '12.0'
desired_caps['deviceName'] = 'Android GoogleAPI Emulator'
desired_caps['deviceOrientation'] = "portrait"
desired_caps['commandTimeout'] = 600
desired_caps['newCommandTimeout'] = 600
desired_caps['idleTimeout'] = 1000
desired_caps['unicodeKeyboard'] = True
desired_caps['automationName'] = 'UiAutomator2'
@@ -301,17 +300,21 @@ def create_shared_drivers(quantity):
capabilities = {'maxDuration': 3600}
print('SC Executor: %s' % executor_sauce_lab)
try:
# options = webdriver.webdriver.AppiumOptions()
# for key, value in update_capabilities_sauce_lab(capabilities).items():
# options.set_capability(key, value)
drivers = loop.run_until_complete(start_threads(quantity,
Driver,
drivers,
executor_sauce_lab,
update_capabilities_sauce_lab(capabilities)))
Driver,
drivers,
executor_sauce_lab,
update_capabilities_sauce_lab(capabilities)))
for i in range(quantity):
test_suite_data.current_test.testruns[-1].jobs[drivers[i].session_id] = i + 1
drivers[i].implicitly_wait(implicit_wait)
return drivers, loop
except MaxRetryError as e:
test_suite_data.current_test.testruns[-1].error = e.reason
except Exception as e:
loop.close()
raise e #from None
class LocalSharedMultipleDeviceTestCase(AbstractTestCase):
@@ -370,12 +373,14 @@ class SauceSharedMultipleDeviceTestCase(AbstractTestCase):
geth_names.append(
'%s_geth%s.log' % (test_suite_data.current_test.name, str(self.drivers[driver].number)))
geth_contents.append(self.pull_geth(self.drivers[driver]))
except (WebDriverException, AttributeError):
pass
finally:
geth = {geth_names[i]: geth_contents[i] for i in range(len(geth_names))}
test_suite_data.current_test.geth_paths = self.github_report.save_geth(geth)
try:
geth = {geth_names[i]: geth_contents[i] for i in range(len(geth_names))}
test_suite_data.current_test.geth_paths = self.github_report.save_geth(geth)
except IndexError:
pass
@pytest.fixture(scope='class', autouse=True)
def prepare(self, request):
@@ -390,28 +395,30 @@ class SauceSharedMultipleDeviceTestCase(AbstractTestCase):
from tests.conftest import sauce
requests_session = requests.Session()
requests_session.auth = (sauce_username, sauce_access_key)
for _, driver in cls.drivers.items():
session_id = driver.session_id
try:
sauce.jobs.update_job(username=sauce_username, job_id=session_id, name=cls.__name__)
except (RemoteDisconnected, SauceException):
pass
try:
driver.quit()
except WebDriverException:
pass
url = 'https://api.%s/rest/v1/%s/jobs/%s/assets/%s' % (apibase, sauce_username, session_id, "log.json")
WebDriverWait(driver, 60, 2).until(lambda _: requests_session.get(url).status_code == 200)
commands = requests_session.get(url).json()
for command in commands:
if hasattr(cls, 'drivers'):
for _, driver in cls.drivers.items():
session_id = driver.session_id
try:
if command['message'].startswith("Started "):
for test in test_suite_data.tests:
if command['message'] == "Started %s" % test.name:
test.testruns[-1].first_commands[session_id] = commands.index(command) + 1
except KeyError:
continue
cls.loop.close()
sauce.jobs.update_job(username=sauce_username, job_id=session_id, name=cls.__name__)
except (RemoteDisconnected, SauceException, ConnectionError):
pass
try:
driver.quit()
except WebDriverException:
pass
url = 'https://api.%s/rest/v1/%s/jobs/%s/assets/%s' % (apibase, sauce_username, session_id, "log.json")
WebDriverWait(driver, 60, 2).until(lambda _: requests_session.get(url).status_code == 200)
commands = requests_session.get(url).json()
for command in commands:
try:
if command['message'].startswith("Started "):
for test in test_suite_data.tests:
if command['message'] == "Started %s" % test.name:
test.testruns[-1].first_commands[session_id] = commands.index(command) + 1
except KeyError:
continue
if hasattr(cls, 'loop'):
cls.loop.close()
for test in test_suite_data.tests:
cls.github_report.save_test(test)
+1
View File
@@ -243,6 +243,7 @@ def should_save_device_stats(config):
return all(db_args)
# @pytest.hookimpl(hookwrapper=True)
@pytest.mark.hookwrapper
def pytest_runtest_makereport(item, call):
outcome = yield
+11 -11
View File
@@ -72,17 +72,17 @@ class BaseElement(object):
return None
def find_element(self):
for _ in range(3):
try:
self.driver.info("Find `%s` by `%s`: `%s`" % (self.name, self.by, self.exclude_emoji(self.locator)))
return self.driver.find_element(self.by, self.locator)
except NoSuchElementException:
raise NoSuchElementException(
"Device %s: %s by %s: `%s` is not found on the screen" % (
self.driver.number, self.name, self.by, self.locator)) from None
except Exception as exception:
if 'Internal Server Error' in str(exception):
continue
# for _ in range(3):
try:
self.driver.info("Find `%s` by `%s`: `%s`" % (self.name, self.by, self.exclude_emoji(self.locator)))
return self.driver.find_element(self.by, self.locator)
except NoSuchElementException:
raise NoSuchElementException(
"Device %s: %s by %s: `%s` is not found on the screen" % (
self.driver.number, self.name, self.by, self.locator)) from None
# except Exception as exception:
# if 'Internal Server Error' in str(exception):
# continue
def find_elements(self):
return self.driver.find_elements(self.by, self.locator)
+8 -1
View File
@@ -1,6 +1,8 @@
import time
from selenium.common.exceptions import TimeoutException, NoSuchElementException
from selenium.common.exceptions import TimeoutException, NoSuchElementException, StaleElementReferenceException
from selenium.webdriver.support import expected_conditions
from selenium.webdriver.support.wait import WebDriverWait
from tests import test_dapp_url
from views.base_element import Button, Text, BaseElement, SilentButton, CheckBox, EditBox
@@ -312,6 +314,11 @@ class HomeView(BaseView):
chat_element.cancel_contact_request()
else:
self.driver.fail("Illegal option for CR!")
try:
element = self.close_activity_centre.find_element()
WebDriverWait(self.driver, 30).until(expected_conditions.staleness_of(element))
except TimeoutException:
pass
self.close_activity_centre.click()
self.chats_tab.wait_for_visibility_of_element()
-1
View File
@@ -2018,7 +2018,6 @@
"you-have-no-contacts": "You have no contacts",
"my-albums": "My albums",
"images": "images",
"images-albums-count": "{{album-images-count}} images",
"only-6-images": "You can only add 6 images to your message",
"delivered": "Delivered",
"mark-all-notifications-as-read": "Mark all notifications as read",