Compare commits

..
Author SHA1 Message Date
Andrea Maria Piana 1e7c701b90 Revert "revert fleet changes"
https://github.com/status-im/status-go/compare/53044060...53044060

This reverts commit 2cc531c46fc50367680bd189999ebc519d3fe818.
2024-02-27 11:09:11 +02:00
Andrea Maria Piana f05261a1e9 revert fleet changes 2024-02-27 11:09:10 +02:00
68 changed files with 1239 additions and 1397 deletions
-1
View File
@@ -34,4 +34,3 @@ STICKERS_TEST_ENABLED=1
LOCAL_PAIRING_ENABLED=1
TEST_STATEOFUS=1
FAST_CREATE_COMMUNITY_ENABLED=1
FLAG_NEW_CONTACT_UI_ENABLED=0
+1 -1
View File
@@ -359,7 +359,7 @@ test-watch-for-repl: ##@test Watch all Clojure tests and support REPL connection
"until [ -f $$SHADOW_OUTPUT_TO ] ; do sleep 1 ; done ; node --require ./test-resources/override.js $$SHADOW_OUTPUT_TO --repl"
test-unit: export SHADOW_OUTPUT_TO := target/unit_test/test.js
test-unit: export SHADOW_NS_REGEXP := ^(?!tests\.integration-test)(?!tests\.contract-test).*-test$$
test-unit: export SHADOW_NS_REGEXP := ^(?!tests\.integration-test)(?!tests-im\.contract-test).*-test$$
test-unit: ##@test Run unit tests
test-unit: _test-clojure
+1 -1
View File
@@ -15,7 +15,7 @@ pipeline {
buildDiscarder(logRotator(
numToKeepStr: '10',
daysToKeepStr: '20',
artifactNumToKeepStr: '1',
artifactNumToKeepStr: '10',
))
/* Allows combined build to copy */
copyArtifactPermission('/status-mobile/*')
+1 -1
View File
@@ -13,7 +13,7 @@ pipeline {
buildDiscarder(logRotator(
numToKeepStr: '10',
daysToKeepStr: '30',
artifactNumToKeepStr: '1',
artifactNumToKeepStr: '10',
))
}
-1
View File
@@ -23,7 +23,6 @@ pipeline {
buildDiscarder(logRotator(
numToKeepStr: '10',
daysToKeepStr: '30',
artifactNumToKeepStr: '1',
))
}
+1 -1
View File
@@ -23,7 +23,7 @@ pipeline {
buildDiscarder(logRotator(
numToKeepStr: '10',
daysToKeepStr: '20',
artifactNumToKeepStr: '1',
artifactNumToKeepStr: '10',
))
/* Allows combined build to copy */
copyArtifactPermission('/status-mobile/*')
+2 -10
View File
@@ -10,12 +10,12 @@ pipeline {
options {
timestamps()
/* Prevent Jenkins jobs from running forever */
timeout(time: 20, unit: 'MINUTES')
timeout(time: 15, unit: 'MINUTES')
/* Limit builds retained */
buildDiscarder(logRotator(
numToKeepStr: '10',
daysToKeepStr: '20',
artifactNumToKeepStr: '1',
artifactNumToKeepStr: '10',
))
/* Abort old PR builds. */
disableConcurrentBuilds(
@@ -62,14 +62,6 @@ pipeline {
}
}
}
stage('Contract Tests') {
steps {
sh """#!/bin/bash
set -eo pipefail
make test-contract 2>&1 | tee -a ${LOG_FILE}
"""
}
}
stage('Integration Tests') {
steps {
sh """#!/bin/bash
-5
View File
@@ -29,11 +29,6 @@ pipeline {
options {
disableConcurrentBuilds()
buildDiscarder(logRotator(
numToKeepStr: '10',
daysToKeepStr: '30',
artifactNumToKeepStr: '1',
))
}
stages {
-5
View File
@@ -47,11 +47,6 @@ pipeline {
options {
disableConcurrentBuilds()
timeout(time: 90, unit: 'MINUTES')
buildDiscarder(logRotator(
numToKeepStr: '10',
daysToKeepStr: '30',
artifactNumToKeepStr: '1',
))
}
stages {
-5
View File
@@ -28,11 +28,6 @@ pipeline {
options {
disableConcurrentBuilds()
buildDiscarder(logRotator(
numToKeepStr: '10',
daysToKeepStr: '30',
artifactNumToKeepStr: '1',
))
}
-1
View File
@@ -34,7 +34,6 @@ pipeline {
buildDiscarder(logRotator(
numToKeepStr: '20',
daysToKeepStr: '30',
artifactNumToKeepStr: '1',
))
}
+1 -3
View File
@@ -74,8 +74,6 @@
</dict>
<key>NSCameraUsageDescription</key>
<string>Status uses camera to take pictures and scan QR codes.</string>
<key>NSLocalNetworkUsageDescription</key>
<string>Status needs access to the local network to give you the ability to connect with peers.</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>Location access is required for some DApps to function properly.</string>
<key>NSLocationWhenInUseUsageDescription</key>
@@ -135,7 +133,7 @@
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
<true/>
<key>com.apple.developer.nfc.readersession.iso7816.select-identifiers</key>
<array>
<string>A00000080400010101</string>
@@ -4,25 +4,10 @@
#import "Statusgo.h"
#import "Utils.h"
@interface NetworkManager() <NSNetServiceBrowserDelegate>
@property (nonatomic, strong) NSNetServiceBrowser *serviceBrowser;
@property (nonatomic, copy) RCTResponseSenderBlock callback;
@end
@implementation NetworkManager
RCT_EXPORT_MODULE();
- (instancetype)init {
if ((self = [super init])) {
self.serviceBrowser = [[NSNetServiceBrowser alloc] init];
self.serviceBrowser.delegate = self;
}
return self;
}
RCT_EXPORT_METHOD(startSearchForLocalPairingPeers:(RCTResponseSenderBlock)callback) {
NSString *result = StatusgoStartSearchForLocalPairingPeers();
callback(@[result]);
@@ -110,39 +95,6 @@ RCT_EXPORT_METHOD(callPrivateRPC:(NSString *)payload
});
}
RCT_EXPORT_METHOD(requestLocalNetworkAccess:(RCTResponseSenderBlock)callback) {
self.callback = callback;
// Start browsing for services using TCP on the local network.
dispatch_async(dispatch_get_main_queue(), ^{
[self.serviceBrowser searchForServicesOfType:@"_http._tcp." inDomain:@""];
});
}
// NSNetServiceBrowser delegate method
- (void)netServiceBrowser:(NSNetServiceBrowser *)browser didNotSearch:(NSDictionary<NSString *,NSNumber *> *)errorDict {
RCTLogInfo(@"Failed to search for services: %@", errorDict);
if (self.callback) {
self.callback(@[@"Failed to search for services"]);
}
}
// NSNetServiceBrowser delegate method
- (void)netServiceBrowser:(NSNetServiceBrowser *)browser didFindService:(NSNetService *)service moreComing:(BOOL)moreComing {
RCTLogInfo(@"Found service: %@", service);
// we stop the search after finding the first service or wait until the search is finished.
[browser stop];
if (self.callback) {
self.callback(@[[NSNull null], @"Requested local network access and found service"]);
}
}
// NSNetServiceBrowser delegate method
- (void)netServiceBrowserDidStopSearch:(NSNetServiceBrowser *)browser {
RCTLogInfo(@"Stopped searching for services");
}
#pragma mark - Recover
RCT_EXPORT_METHOD(recover:(NSString *)message
+15
View File
@@ -72,3 +72,18 @@
{:events [:show-tooltip]}
[_ tooltip-id]
{:show-tooltip tooltip-id})
(rf/defn show-profile
{:events [:chat.ui/show-profile]}
[{:keys [db]} identity ens-name]
(let [my-public-key (get-in db [:profile/profile :public-key])]
(if (not= my-public-key identity)
{:db (-> db
(assoc :contacts/identity identity)
(assoc :contacts/ens-name ens-name))
:dispatch [:contacts/build-contact
{:pubkey identity
:ens ens-name
:success-fn (fn [_]
{:dispatch [:open-modal :profile]})}]}
{:dispatch [:navigate-to :my-profile]})))
@@ -8,6 +8,24 @@
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(defn local-notifications
[]
(let [{:keys [enabled?]} (rf/sub [:push-notifications/wallet-transactions])
{:keys [notifications-enabled?]} (rf/sub [:profile/profile])]
[:<>
[quo/separator
{:color (:ui-02 @colors/theme)
:style {:margin-vertical 8}}]
[quo/list-header (i18n/label :t/local-notifications)]
[list.item/list-item
{:size :small
:title (i18n/label :t/notifications-transactions)
:accessibility-label :notifications-button
:active (and notifications-enabled? enabled?)
:on-press #(rf/dispatch [:push-notifications.wallet/switch-transactions
(not enabled?)])
:accessory :switch}]]))
(defn notifications-settings-ios
[]
(let [{:keys [notifications-enabled?
@@ -45,7 +63,8 @@
:on-press #(rf/dispatch
[:push-notifications/switch-block-mentions
(not push-notifications-block-mentions?)])
:accessory :switch}]]))
:accessory :switch}]
[local-notifications]]))
(defn notifications-settings-android
[]
@@ -57,7 +76,8 @@
:subtitle (i18n/label :t/local-notifications-subtitle)
:active notifications-enabled?
:on-press #(rf/dispatch [:push-notifications/switch (not notifications-enabled?)])
:accessory :switch}]]))
:accessory :switch}]
[local-notifications]]))
(defn notifications-settings
[]
+1 -1
View File
@@ -53,7 +53,7 @@
:FlatList {}
:SectionList {}
:Text {}
:StatusBar {:setBarStyle identity}
:StatusBar {}
:ScrollView {}
:SafeAreaView {}
:KeyboardAvoidingView {}
-5
View File
@@ -258,11 +258,6 @@
(log/debug "[native-module] set-soft-input-mode")
(.setSoftInputMode ^js (ui-helper) mode))
(defn request-local-network-access
[callback]
(log/debug "[native-module] request-local-network-access")
(.requestLocalNetworkAccess ^js (network) callback))
(defn call-rpc
[payload callback]
(log/debug "[native-module] call-rpc")
@@ -6,7 +6,8 @@
[quo.foundations.colors :as colors]
[quo.theme :as quo.theme]
[react-native.core :as rn]
[react-native.platform :as platform]))
[react-native.platform :as platform]
[reagent.core :as reagent]))
(defn remove-http-https-www
[value]
@@ -67,86 +68,78 @@
[:cursor-color :placeholder-text-color :editable :on-change-text :on-focus
:on-blur :on-clear :value :disabled? :blur? :customization-color :theme])
(defn view
[{:keys [disabled? blur? on-change-text customization-color
on-clear on-focus on-blur get-ref locked?
favicon favicon-color favicon-size default-value]
:or {default-value ""}
:as props}]
(let [ref (rn/use-ref-atom nil)
on-ref (rn/use-callback
(fn [r]
(reset! ref r)
(when get-ref (get-ref r)))
[get-ref])
theme (quo.theme/use-theme)
[state set-state] (rn/use-state :default)
[value set-value] (rn/use-state default-value)
on-clear (rn/use-callback
(fn []
(.clear ^js @ref)
(set-value "")
(when on-clear (on-clear)))
[on-clear])
focus-input (rn/use-callback
(fn []
(set-state :active)
(.focus ^js @ref)))
on-blur (rn/use-callback
(fn []
(set-state :default)
(when on-blur (on-blur)))
[on-blur])
on-change-text (rn/use-callback
(fn [new-text]
(set-value new-text)
(when on-change-text (on-change-text new-text)))
[on-change-text])
on-focus (rn/use-callback
(fn []
(set-state :active)
(when on-focus (on-focus)))
[on-focus])
clean-props (apply dissoc props props-to-remove)]
[rn/view {:style style/root-container}
(when (and (seq value) (= state :default))
[rn/touchable-opacity
{:style style/default-container
:on-press focus-input}
(when favicon
[icon/icon favicon
{:accessibility-label :browser-input-favicon
:color favicon-color
:container-style style/favicon-icon-container
:size favicon-size}])
[rn/text
{:accessibility-label :browser-input-label
:style (style/text)}
(remove-http-https-www value)]
(when locked?
[lock-icon {:blur? blur? :theme theme}])])
[rn/view {:style (style/active-container (or (empty? value) (= state :active)))}
[rn/text-input
(merge
clean-props
{:accessibility-label :browser-input
:auto-capitalize :none
:auto-correct false
:cursor-color (cursor-color customization-color theme)
:editable (not disabled?)
:keyboard-appearance (colors/theme-colors :light :dark theme)
:keyboard-type :web-search
:on-blur on-blur
:on-change-text on-change-text
:on-focus on-focus
:placeholder-text-color (placeholder-color state blur? theme)
:ref on-ref
:selection-color (when platform/ios?
(cursor-color customization-color theme))
:select-text-on-focus true
:style (style/input disabled?)})]
(when (seq value)
[clear-button
{:blur? blur?
:on-press on-clear
:theme theme}])]]))
(defn- view-internal
[{:keys [default-value]
:or {default-value ""}}]
(let [state (reagent/atom :default)
value (reagent/atom default-value)
set-active #(reset! state :active)
set-default #(reset! state :default)
set-value #(reset! value %)
ref (atom nil)
clear-input (fn []
(.clear ^js @ref)
(reset! value ""))
focus-input (fn []
(set-active)
(.focus ^js @ref))]
(fn [{:keys [disabled? blur? on-change-text customization-color
on-clear on-focus on-blur theme get-ref locked?
favicon favicon-color favicon-size]
:as props}]
(let [clean-props (apply dissoc props props-to-remove)]
[rn/view {:style style/root-container}
(when (and (seq @value) (= @state :default))
[rn/touchable-opacity
{:style style/default-container
:on-press focus-input}
(when favicon
[icon/icon favicon
{:accessibility-label :browser-input-favicon
:color favicon-color
:container-style style/favicon-icon-container
:size favicon-size}])
[rn/text
{:accessibility-label :browser-input-label
:style (style/text)} (remove-http-https-www @value)]
(when locked?
[lock-icon
{:blur? blur?
:theme theme}])])
[rn/view {:style (style/active-container (or (empty? @value) (= @state :active)))}
[rn/text-input
(merge
clean-props
{:accessibility-label :browser-input
:auto-capitalize :none
:auto-correct false
:cursor-color (cursor-color customization-color theme)
:editable (not disabled?)
:keyboard-appearance (colors/theme-colors :light :dark theme)
:keyboard-type :web-search
:on-blur (fn []
(set-default)
(when on-blur (on-blur)))
:on-change-text (fn [new-text]
(set-value new-text)
(when on-change-text (on-change-text new-text)))
:on-focus (fn []
(set-active)
(when on-focus (on-focus)))
:placeholder-text-color (placeholder-color @state blur? theme)
:ref (fn [r]
(reset! ref r)
(when get-ref (get-ref r)))
:selection-color (when platform/ios?
(cursor-color customization-color theme))
:select-text-on-focus true
:style (style/input disabled?)})]
(when (seq @value)
[clear-button
{:blur? blur?
:on-press (fn []
(clear-input)
(when on-clear (on-clear)))
:theme theme}])]]))))
(def view (quo.theme/with-theme view-internal))
+99 -99
View File
@@ -7,9 +7,10 @@
[quo.foundations.customization-colors :as customization-colors]
[quo.theme :as theme]
[react-native.blur :as blur]
[react-native.core :as rn]))
[react-native.core :as rn]
[reagent.core :as reagent]))
(defn button
(defn- button-internal
"with label
[button opts \"label\"]
opts
@@ -28,103 +29,102 @@
:theme :light/:dark
only icon
[button {:icon-only? true} :i/close-circle]"
[{:keys [on-press on-long-press disabled? type background size icon-left icon-right icon-top
customization-color accessibility-label icon-only? container-style inner-style
pressed? on-press-in on-press-out allow-multiple-presses?]
:or {type :primary
size 40
customization-color (if (= type :primary) :blue nil)}}
children]
(let [[pressed-state? set-pressed-state] (rn/use-state false)
theme (theme/use-theme-value)
{:keys [icon-color background-color label-color border-color blur-type
blur-overlay-color border-radius overlay-customization-color]}
(button-properties/get-values {:customization-color customization-color
:background background
:type type
:theme theme
:pressed? (if pressed? pressed? pressed-state?)
:icon-only? icon-only?})
icon-size (when (= 24 size) 12)
on-press-in-cb (rn/use-callback
(fn []
(set-pressed-state true)
(when on-press-in (on-press-in))))
on-press-out-cb (rn/use-callback
(fn []
(set-pressed-state nil)
(when on-press-out (on-press-out))))]
[rn/touchable-without-feedback
{:disabled disabled?
:accessibility-label accessibility-label
:on-press-in on-press-in-cb
:on-press-out on-press-out-cb
:on-press on-press
:allow-multiple-presses? allow-multiple-presses?
:on-long-press on-long-press}
[rn/view
{:style (merge
(style/shape-style-container size border-radius)
container-style)}
[rn/view
{:style (merge
(style/style-container {:size size
:disabled? disabled?
:border-radius border-radius
:background-color background-color
:border-color border-color
:icon-only? icon-only?
:icon-top icon-top
:icon-left icon-left
:icon-right icon-right})
inner-style)}
(when overlay-customization-color
[customization-colors/overlay
{:customization-color overlay-customization-color
:theme theme
:pressed? (if pressed? pressed? pressed-state?)}])
(when (= background :photo)
[blur/view
{:blur-radius 20
:blur-type blur-type
:overlay-color blur-overlay-color
:style style/blur-view}])
(when icon-top
[_ _]
(let [pressed-state? (reagent/atom false)]
(fn
[{:keys [on-press on-long-press disabled? type background size icon-left icon-right icon-top
customization-color theme accessibility-label icon-only? container-style inner-style
pressed? on-press-in on-press-out allow-multiple-presses?]
:or {type :primary
size 40
customization-color (if (= type :primary) :blue nil)}}
children]
(let [{:keys [icon-color background-color label-color border-color blur-type
blur-overlay-color border-radius overlay-customization-color]}
(button-properties/get-values {:customization-color customization-color
:background background
:type type
:theme theme
:pressed? (if pressed? pressed? @pressed-state?)
:icon-only? icon-only?})
icon-size (when (= 24 size) 12)]
[rn/touchable-without-feedback
{:disabled disabled?
:accessibility-label accessibility-label
:on-press-in (fn []
(reset! pressed-state? true)
(when on-press-in (on-press-in)))
:on-press-out (fn []
(reset! pressed-state? nil)
(when on-press-out (on-press-out)))
:on-press on-press
:allow-multiple-presses? allow-multiple-presses?
:on-long-press on-long-press}
[rn/view
[quo.icons/icon icon-top
{:container-style {:margin-bottom 2}
:color icon-color
:size icon-size}]])
(when icon-left
[rn/view
{:style (style/icon-left-icon-style
{:size size
:icon-size icon-size})}
[quo.icons/icon icon-left
{:color icon-color
:size icon-size}]])
[rn/view
(cond
icon-only?
[quo.icons/icon children
{:color label-color
:size icon-size}]
{:style (merge
(style/shape-style-container size border-radius)
container-style)}
[rn/view
{:style (merge
(style/style-container {:size size
:disabled? disabled?
:border-radius border-radius
:background-color background-color
:border-color border-color
:icon-only? icon-only?
:icon-top icon-top
:icon-left icon-left
:icon-right icon-right})
inner-style)}
(when overlay-customization-color
[customization-colors/overlay
{:customization-color overlay-customization-color
:theme theme
:pressed? (if pressed? pressed? @pressed-state?)}])
(when (= background :photo)
[blur/view
{:blur-radius 20
:blur-type blur-type
:overlay-color blur-overlay-color
:style style/blur-view}])
(when icon-top
[rn/view
[quo.icons/icon icon-top
{:container-style {:margin-bottom 2}
:color icon-color
:size icon-size}]])
(when icon-left
[rn/view
{:style (style/icon-left-icon-style
{:size size
:icon-size icon-size})}
[quo.icons/icon icon-left
{:color icon-color
:size icon-size}]])
[rn/view
(cond
icon-only?
[quo.icons/icon children
{:color label-color
:size icon-size}]
(string? children)
[text/text
{:size (when (#{56 24} size) :paragraph-2)
:weight :medium
:number-of-lines 1
:style {:color label-color}}
children]
(string? children)
[text/text
{:size (when (#{56 24} size) :paragraph-2)
:weight :medium
:number-of-lines 1
:style {:color label-color}}
children]
(vector? children)
children)]
(when icon-right
[rn/view
{:style (style/icon-right-icon-style
{:size size
:icon-size icon-size})}
[quo.icons/icon icon-right
{:color icon-color
:size icon-size}]])]]]))
(vector? children)
children)]
(when icon-right
[rn/view
{:style (style/icon-right-icon-style
{:size size
:icon-size icon-size})}
[quo.icons/icon icon-right
{:color icon-color
:size icon-size}]])]]]))))
(def button (theme/with-theme button-internal))
@@ -3,24 +3,28 @@
[quo.components.buttons.composer-button.style :as style]
[quo.components.icon :as quo.icons]
[quo.theme :as theme]
[react-native.core :as rn]))
[react-native.core :as rn]
[reagent.core :as reagent]))
(defn view
[{:keys [on-press on-long-press disabled? blur? icon accessibility-label container-style]}]
(let [[pressed? set-pressed] (rn/use-state false)
theme (theme/use-theme-value)
on-press-in (rn/use-callback #(set-pressed true))
on-press-out (rn/use-callback #(set-pressed nil))]
[rn/pressable
{:accessibility-label (or accessibility-label :composer-button)
:on-press on-press
:on-press-in on-press-in
:on-press-out on-press-out
:on-long-press on-long-press
:disabled disabled?
:style (merge (style/main {:pressed? pressed?
:blur? blur?
:theme theme
:disabled? disabled?})
container-style)}
[quo.icons/icon icon {:color (style/get-label-color {:blur? blur? :theme theme})}]]))
(defn- view-internal
[_ _]
(let [pressed? (reagent/atom false)]
(fn
[{:keys [on-press on-long-press disabled? theme blur? icon accessibility-label container-style]}]
[rn/pressable
{:accessibility-label (or accessibility-label :composer-button)
:on-press on-press
:on-press-in #(reset! pressed? true)
:on-press-out #(reset! pressed? nil)
:on-long-press on-long-press
:disabled disabled?
:style (merge (style/main {:pressed? @pressed?
:blur? blur?
:theme theme
:disabled? disabled?})
container-style)}
[quo.icons/icon icon
{:color (style/get-label-color {:blur? blur?
:theme theme})}]])))
(def view (theme/with-theme view-internal))
@@ -5,7 +5,8 @@
[quo.components.markdown.text :as text]
[quo.foundations.colors :as colors]
[quo.theme :as quo.theme]
[react-native.core :as rn]))
[react-native.core :as rn]
[reagent.core :as reagent]))
(defn- get-button-color
[{:keys [type pressed? customization-color theme]}]
@@ -44,48 +45,48 @@
:color (get-icon-and-text-color type theme)
:container-style (style/container type)}])
(defn view
(defn- view-internal
"[dynamic-button opts]
opts
{:type :jump-to/:mention/:notification-down/:notification-up/:search/:search-with-label/:scroll-to-bottom
:on-press fn
:count mentions or notifications count
:customization-color customize jump-to and mention button color}"
[{:keys [type label on-press customization-color style] :as args}]
(let [theme (quo.theme/use-theme-value)
[pressed? set-pressed] (rn/use-state false)
button-color (get-button-color {:type type
:pressed? pressed?
:customization-color (or customization-color :primary)
:theme theme})
on-press-in (rn/use-callback #(set-pressed true))
on-press-out (rn/use-callback #(set-pressed false))]
[rn/touchable-opacity
{:on-press-in on-press-in
:on-press-out on-press-out
:on-press on-press
:active-opacity 1
:hit-slop {:top 5 :bottom 5 :left 5 :right 5}
:pointer-events :auto
:style {:height 24}
:accessibility-label type}
[rn/view
{:style (merge
{:flex-direction :row
:height 24
:border-radius 12
:background-color button-color}
style)}
(when (#{:mention :search :search-with-label :scroll-to-bottom} type)
[icon-view type])
(when (#{:jump-to :mention :notification-down :notification-up :search-with-label} type)
[text/text
{:weight :medium
:size :paragraph-2
:style (assoc (style/text type) :color (get-icon-and-text-color type theme))}
(case type
:jump-to label
:search-with-label label
(:mention :notification-down :notification-up) (str (:count args)))])
(when (#{:jump-to :notification-down :notification-up} type)
[icon-view type theme])]]))
[_]
(let [pressed? (reagent/atom false)]
(fn [{:keys [type label on-press customization-color style theme] :as args}]
[rn/touchable-opacity
{:on-press-in #(reset! pressed? true)
:on-press-out #(reset! pressed? false)
:on-press on-press
:active-opacity 1
:hit-slop {:top 5 :bottom 5 :left 5 :right 5}
:pointer-events :auto
:style {:height 24}
:accessibility-label type}
[rn/view
{:style (merge
{:flex-direction :row
:height 24
:border-radius 12
:background-color (get-button-color {:type type
:pressed? @pressed?
:customization-color (or customization-color
:primary)
:theme theme})}
style)}
(when (#{:mention :search :search-with-label :scroll-to-bottom} type)
[icon-view type])
(when (#{:jump-to :mention :notification-down :notification-up :search-with-label} type)
[text/text
{:weight :medium
:size :paragraph-2
:style (assoc (style/text type) :color (get-icon-and-text-color type theme))}
(case type
:jump-to label
:search-with-label label
(:mention :notification-down :notification-up) (str (:count args)))])
(when (#{:jump-to :notification-down :notification-up} type)
[icon-view type theme])]])))
(def view (quo.theme/with-theme view-internal))
@@ -6,25 +6,29 @@
[quo.foundations.colors :as colors]
[quo.theme :as quo.theme]
[react-native.core :as rn]
[reagent.core :as reagent]
[utils.i18n :as i18n]))
(defn view
[{:keys [on-press on-long-press disabled? container-style]}]
(let [theme (quo.theme/use-theme-value)
[pressed? set-pressed] (rn/use-state false)
on-press-in (rn/use-callback #(set-pressed true))
on-press-out (rn/use-callback #(set-pressed nil))]
[rn/pressable
{:accessibility-label :log-out-button
:on-press on-press
:on-press-in on-press-in
:on-press-out on-press-out
:on-long-press on-long-press
:disabled disabled?
:style (merge (style/main {:pressed? pressed?
:theme theme
:disabled? disabled?})
container-style)}
[icon/icon :i/log-out {:color (if pressed? colors/white-opa-40 colors/white-opa-70)}]
[text/text {:weight :medium :size :paragraph-1}
(i18n/label :t/logout)]]))
(defn- view-internal
[_]
(let [pressed? (reagent/atom false)
on-press-in #(reset! pressed? true)
on-press-out #(reset! pressed? nil)]
(fn
[{:keys [on-press on-long-press disabled? theme container-style]}]
[rn/pressable
{:accessibility-label :log-out-button
:on-press on-press
:on-press-in on-press-in
:on-press-out on-press-out
:on-long-press on-long-press
:disabled disabled?
:style (merge (style/main {:pressed? @pressed?
:theme theme
:disabled? disabled?})
container-style)}
[icon/icon :i/log-out {:color (if pressed? colors/white-opa-40 colors/white-opa-70)}]
[text/text {:weight :medium :size :paragraph-1}
(i18n/label :t/logout)]])))
(def view (quo.theme/with-theme view-internal))
@@ -1,5 +1,9 @@
(ns quo.components.buttons.slide-button.animations
(:require [react-native.reanimated :as reanimated]))
(:require
[oops.core :as oops]
[quo.components.buttons.slide-button.utils :as utils]
[react-native.gesture :as gesture]
[react-native.reanimated :as reanimated]))
(def ^:private extrapolation
{:extrapolateLeft "clamp"
@@ -62,6 +66,36 @@
:damping 30
:stiffness 400}))
(defn- complete-animation
[sliding-complete?]
(reset! sliding-complete? true))
(defn reset-track-position
[x-pos]
(animate-spring x-pos 0))
;; Gestures
(defn drag-gesture
[x-pos
gestures-disabled?
disabled?
track-width
sliding-complete?]
(let [gestures-enabled? (not (or disabled? @gestures-disabled?))]
(-> (gesture/gesture-pan)
(gesture/with-test-ID :slide-button-gestures)
(gesture/enabled gestures-enabled?)
(gesture/min-distance 0)
(gesture/on-update (fn [event]
(let [x-translation (oops/oget event "translationX")
clamped-x (utils/clamp-value x-translation 0 track-width)
reached-end? (>= clamped-x track-width)]
(reanimated/set-shared-value x-pos clamped-x)
(when (and reached-end? (not @sliding-complete?))
(reset! gestures-disabled? true)
(complete-animation sliding-complete?)))))
(gesture/on-end (fn [event]
(let [x-translation (oops/oget event "translationX")
reached-end? (>= x-translation track-width)]
(when (not reached-end?)
(reset-track-position x-pos))))))))
+90 -100
View File
@@ -11,35 +11,94 @@
[quo.theme :as quo.theme]
[react-native.core :as rn]
[react-native.gesture :as gesture]
[react-native.reanimated :as reanimated]))
[react-native.reanimated :as reanimated]
[reagent.core :as reagent]))
(defn drag-gesture
[x-pos gestures-disabled? set-gestures-disabled disabled? track-width sliding-complete?
set-sliding-complete
on-complete reset-fn]
(let [gestures-enabled? (not (or disabled? gestures-disabled?))]
(-> (gesture/gesture-pan)
(gesture/with-test-ID :slide-button-gestures)
(gesture/enabled gestures-enabled?)
(gesture/min-distance 0)
(gesture/on-update (fn [event]
(let [x-translation (oops/oget event "translationX")
clamped-x (utils/clamp-value x-translation 0 track-width)
reached-end? (>= clamped-x track-width)]
(reanimated/set-shared-value x-pos clamped-x)
(when (and reached-end? (not sliding-complete?))
(set-gestures-disabled true)
(set-sliding-complete true)
(when on-complete (on-complete reset-fn))))))
(gesture/on-end (fn [event]
(let [x-translation (oops/oget event "translationX")
reached-end? (>= x-translation track-width)]
(when (not reached-end?)
(animations/reset-track-position x-pos))))))))
(defn- f-slider
[{:keys [disabled?]}]
(let [track-width (reagent/atom nil)
sliding-complete? (reagent/atom false)
gestures-disabled? (reagent/atom disabled?)
on-track-layout (fn [evt]
(let [width (oops/oget evt "nativeEvent.layout.width")]
(reset! track-width width)))]
(fn [{:keys [on-reset
on-complete
track-text
track-icon
disabled?
customization-color
size
container-style
theme
type
blur?]}]
(let [x-pos (reanimated/use-shared-value 0)
dimensions (partial utils/get-dimensions
(or @track-width constants/default-width)
size)
interpolate-track (partial animations/interpolate-track
x-pos
(dimensions :usable-track)
(dimensions :thumb))
custom-color (if (= type :danger) :danger customization-color)]
(rn/use-effect (fn []
(when @sliding-complete?
(on-complete)))
[@sliding-complete?])
(rn/use-effect (fn []
(when on-reset
(reset! sliding-complete? false)
(reset! gestures-disabled? false)
(animations/reset-track-position x-pos)
(on-reset)))
[on-reset])
[gesture/gesture-detector
{:gesture (animations/drag-gesture x-pos
gestures-disabled?
disabled?
(dimensions :usable-track)
sliding-complete?)}
[reanimated/view
{:test-ID :slide-button-track
:style (merge (style/track {:disabled? disabled?
:customization-color custom-color
:height (dimensions :track-height)
:blur? blur?})
container-style)
:on-layout (when-not (some? @track-width)
on-track-layout)}
[reanimated/view {:style (style/track-cover interpolate-track)}
[rn/view {:style (style/track-cover-text-container @track-width)}
[icon/icon track-icon
{:color (utils/text-color custom-color theme blur?)
:size 20}]
[rn/view {:width 4}]
[text/text
{:weight :medium
:size :paragraph-1
:style (style/track-text custom-color theme blur?)}
track-text]]]
[reanimated/view
{:style (style/thumb-container {:interpolate-track interpolate-track
:thumb-size (dimensions :thumb)
:customization-color custom-color
:theme theme
:blur? blur?})}
[reanimated/view {:style (style/arrow-icon-container interpolate-track)}
[icon/icon :arrow-right
{:color colors/white
:size 20}]]
[reanimated/view
{:style (style/action-icon interpolate-track
(dimensions :thumb))}
[icon/icon track-icon
{:color colors/white
:size 20}]]]]]))))
(defn view
(defn- view-internal
"Options
- `on-complete` Callback called when the sliding is complete, returns reset fn as a parameter
- `on-complete` Callback called when the sliding is complete
- `disabled?` Boolean that disables the button
(_and gestures_)
- `size` :size/s-40`/`:size/s-48`
@@ -47,78 +106,9 @@
- `track-icon` Key of the icon shown on the track
(e.g. `:face-id`)
- `customization-color` Customization color
- `on-reset` A callback which can be used to reset the component and run required functionality
"
[{:keys [on-complete track-text track-icon disabled? customization-color size
container-style type blur?]}]
(let [theme (quo.theme/use-theme-value)
x-pos (reanimated/use-shared-value 0)
[track-width set-track-width] (rn/use-state nil)
[sliding-complete?
set-sliding-complete] (rn/use-state false)
[gestures-disabled?
set-gestures-disabled] (rn/use-state disabled?)
on-track-layout (rn/use-callback
#(set-track-width (oops/oget % "nativeEvent.layout.width")))
reset-fn (rn/use-callback
(fn []
(set-sliding-complete false)
(set-gestures-disabled false)
(animations/reset-track-position x-pos)))
dimensions (rn/use-callback
(partial utils/get-dimensions
(or track-width constants/default-width)
size)
[track-width])
interpolate-track (rn/use-callback
(partial animations/interpolate-track
x-pos
(dimensions :usable-track)
(dimensions :thumb))
[dimensions])
custom-color (if (= type :danger) :danger customization-color)
gesture (rn/use-memo #(drag-gesture x-pos
gestures-disabled?
set-gestures-disabled
disabled?
(dimensions :usable-track)
sliding-complete?
set-sliding-complete
on-complete
reset-fn)
[gestures-disabled? sliding-complete? disabled?])]
[gesture/gesture-detector
{:gesture gesture}
[reanimated/view
{:test-ID :slide-button-track
:style (merge (style/track {:disabled? disabled?
:customization-color custom-color
:height (dimensions :track-height)
:blur? blur?})
container-style)
:on-layout on-track-layout}
[reanimated/view {:style (style/track-cover interpolate-track)}
[rn/view {:style (style/track-cover-text-container track-width)}
[icon/icon track-icon
{:color (utils/text-color custom-color theme blur?)
:size 20}]
[rn/view {:width 4}]
[text/text
{:weight :medium
:size :paragraph-1
:style (style/track-text custom-color theme blur?)}
track-text]]]
[reanimated/view
{:style (style/thumb-container {:interpolate-track interpolate-track
:thumb-size (dimensions :thumb)
:customization-color custom-color
:theme theme
:blur? blur?})}
[reanimated/view {:style (style/arrow-icon-container interpolate-track)}
[icon/icon :arrow-right
{:color colors/white
:size 20}]]
[reanimated/view
{:style (style/action-icon interpolate-track (dimensions :thumb))}
[icon/icon track-icon
{:color colors/white
:size 20}]]]]]))
[props]
[:f> f-slider props])
(def view (quo.theme/with-theme view-internal))
@@ -4,24 +4,26 @@
[quo.components.icon :as quo.icons]
[quo.foundations.colors :as colors]
[quo.theme :as theme]
[react-native.core :as rn]))
[react-native.core :as rn]
[reagent.core :as reagent]))
(defn view
[{:keys [on-press on-long-press disabled? icon accessibility-label container-style]}]
(let [theme (theme/use-theme-value)
[pressed? set-pressed] (rn/use-state false)
on-press-in (rn/use-callback #(set-pressed true))
on-press-out (rn/use-callback #(set-pressed nil))]
[rn/pressable
{:accessibility-label (or accessibility-label :wallet-button)
:on-press on-press
:on-press-in on-press-in
:on-press-out on-press-out
:on-long-press on-long-press
:disabled disabled?
:style (merge (style/main {:pressed? pressed?
:theme theme
:disabled? disabled?})
container-style)}
[quo.icons/icon icon
{:color (colors/theme-colors colors/neutral-100 colors/white theme)}]]))
(defn- view-internal
[]
(let [pressed? (reagent/atom false)]
(fn
[{:keys [on-press on-long-press disabled? icon accessibility-label container-style theme]}]
[rn/pressable
{:accessibility-label (or accessibility-label :wallet-button)
:on-press on-press
:on-press-in #(reset! pressed? true)
:on-press-out #(reset! pressed? nil)
:on-long-press on-long-press
:disabled disabled?
:style (merge (style/main {:pressed? @pressed?
:theme theme
:disabled? disabled?})
container-style)}
[quo.icons/icon icon
{:color (colors/theme-colors colors/neutral-100 colors/white theme)}]])))
(def view (theme/with-theme view-internal))
+31 -31
View File
@@ -8,36 +8,36 @@
[quo.components.calendar.calendar.years-list.view :as years-list]
[quo.theme :as theme]
[react-native.core :as rn]
[reagent.core :as reagent]
[utils.number :as utils.number]))
(defn view
[{:keys [on-change start-date end-date]}]
(let [theme (theme/use-theme-value)
[selected-year set-selected-year] (rn/use-state (utils/current-year))
[selected-month set-selected-month] (rn/use-state (utils/current-month))
on-change-year (rn/use-callback #(set-selected-year %))
on-change-month (rn/use-callback
(fn [new-date]
(set-selected-year
(utils.number/parse-int (:year new-date)))
(set-selected-month
(utils.number/parse-int (:month new-date)))))]
[rn/view
{:style (style/container theme)}
[years-list/view
{:on-change-year on-change-year
:year selected-year}]
[rn/view
{:style style/container-main}
[month-picker/view
{:year selected-year
:month selected-month
:on-change on-change-month}]
[weekdays-header/view]
[days-grid/view
{:year selected-year
:month selected-month
:start-date start-date
:end-date end-date
:on-change on-change
:customization-color :blue}]]]))
(defn- view-internal
[]
(let [selected-year (reagent/atom (utils/current-year))
selected-month (reagent/atom (utils/current-month))
on-change-year #(reset! selected-year %)
on-change-month (fn [new-date]
(reset! selected-year (utils.number/parse-int (:year new-date)))
(reset! selected-month (utils.number/parse-int (:month new-date))))]
(fn [{:keys [on-change start-date end-date theme]}]
[rn/view
{:style (style/container theme)}
[years-list/view
{:on-change-year on-change-year
:year @selected-year}]
[rn/view
{:style style/container-main}
[month-picker/view
{:year @selected-year
:month @selected-month
:on-change on-change-month}]
[weekdays-header/view]
[days-grid/view
{:year @selected-year
:month @selected-month
:start-date start-date
:end-date end-date
:on-change on-change
:customization-color :blue}]]])))
(def view (theme/with-theme view-internal))
@@ -3,7 +3,13 @@
[quo.components.colors.color.constants :as constants]
[quo.components.colors.color.view :as color]
[quo.foundations.colors :as colors]
[react-native.core :as rn]))
[react-native.core :as rn]
[reagent.core :as reagent]))
(defn- on-change-handler
[selected color-name on-change]
(reset! selected color-name)
(when on-change (on-change color-name)))
(defn get-item-layout
[_ index]
@@ -12,34 +18,15 @@
:offset (* (+ constants/color-size 8) index)
:index index})
(defn view
(defn- view-internal
"Options
- `default-selected` Default selected color name.
- `on-change` Callback called when a color is selected `(fn [color-name])`.
- `blur?` Boolean to enable blur background support.}"
[{:keys [default-selected blur? on-change feng-shui? container-style]}]
(let [[selected set-selected] (rn/use-state default-selected)
{window-width :width} (rn/get-window)
ref (rn/use-ref-atom nil)
on-ref (rn/use-callback #(reset! ref %))
render-fn (rn/use-callback
(fn [color idx]
[color/view
{:selected? (= color selected)
:on-press (fn [color-name]
(.scrollToIndex ^js @ref
#js
{:animated true
:index idx
:viewPosition 0.5})
(set-selected color-name)
(when on-change (on-change color-name)))
:blur? blur?
:key color
:color color
:idx idx
:window-width window-width}])
[selected blur? on-change @ref])]
(let [selected (reagent/atom default-selected)
{window-width :width} (rn/get-window)
ref (atom nil)]
(rn/use-mount
(fn []
(js/setTimeout
@@ -53,14 +40,32 @@
:viewPosition 0.5})))))
50)))
[rn/flat-list
{:ref on-ref
{:ref #(reset! ref %)
;; TODO: using :feng-shui? temporarily while b & w is being developed.
;; https://github.com/status-im/status-mobile/discussions/16676
:data (if feng-shui?
(conj colors/account-colors :feng-shui)
colors/account-colors)
:render-fn render-fn
:render-fn (fn [color idx]
[color/view
{:selected? (= color @selected)
:on-press (fn [e]
(.scrollToIndex ^js @ref
#js
{:animated true
:index idx
:viewPosition 0.5})
(on-change-handler selected e on-change))
:blur? blur?
:key color
:color color
:idx idx
:window-width window-width}])
:get-item-layout get-item-layout
:horizontal true
:shows-horizontal-scroll-indicator false
:content-container-style container-style}]))
(defn view
[props]
[:f> view-internal props])
@@ -35,11 +35,12 @@
(defn image
"Same as rn/image but cache the image source in a js/Set, so the image won't
flicker when re-render on android"
[props]
(let [[loaded-source set-loaded-source] (rn/use-state nil)
on-source-loaded (rn/use-callback #(set-loaded-source %))]
(if platform/ios?
[rn/image props]
[:<>
[rn/image (assoc props :source loaded-source)]
[caching-image props on-source-loaded]])))
[]
(let [loaded-source (reagent/atom nil)
on-source-loaded #(reset! loaded-source %)]
(fn [props]
(if platform/ios?
[rn/image props]
[:<>
[rn/image (assoc props :source @loaded-source)]
[caching-image props on-source-loaded]]))))
@@ -3,23 +3,25 @@
[quo.components.dropdowns.network-dropdown.style :as style]
[quo.components.list-items.preview-list.view :as preview-list]
[quo.theme :as quo.theme]
[react-native.core :as rn]))
[react-native.core :as rn]
[reagent.core :as reagent]))
(defn view
[{:keys [on-press state] :as props} networks]
(let [theme (quo.theme/use-theme-value)
[pressed? set-pressed] (rn/use-state false)
on-press-in (rn/use-callback #(set-pressed true))
on-press-out (rn/use-callback #(set-pressed false))]
[rn/pressable
{:style (style/dropdown-container (merge props {:pressed? pressed? :theme theme}))
:accessibility-label :network-dropdown
:disabled (= state :disabled)
:on-press on-press
:on-press-in on-press-in
:on-press-out on-press-out}
[preview-list/view
{:type :network
:list-size (count networks)
:size :size-20}
networks]]))
(defn- internal-view
[_ _]
(let [pressed? (reagent/atom false)]
(fn
[{:keys [on-press state] :as props} networks]
[rn/pressable
{:style (style/dropdown-container (merge props {:pressed? @pressed?}))
:accessibility-label :network-dropdown
:disabled (= state :disabled)
:on-press on-press
:on-press-in (fn [] (reset! pressed? true))
:on-press-out (fn [] (reset! pressed? false))}
[preview-list/view
{:type :network
:list-size (count networks)
:size :size-20}
networks]])))
(def view (quo.theme/with-theme internal-view))
@@ -14,6 +14,7 @@
(def initial-spacing 56)
(def end-spacing 22)
(def y-axis-label-width -33)
(def inspecting? (reagent/atom false))
(defn- pointer
[customization-color]
@@ -31,9 +32,14 @@
:pointer-color customization-color
:pointer-strip-enable-gradient true})
(defn- get-pointer-props
[pointer-props]
(let [pointer-index (.-pointerIndex ^js pointer-props)]
(reset! inspecting? (not= pointer-index -1))))
(defn- get-line-color
[state theme inspecting?]
(if inspecting?
[state theme]
(if @inspecting?
(colors/theme-colors colors/neutral-80-opa-40
colors/white-opa-20
theme)
@@ -45,13 +51,11 @@
colors/danger-60
theme))))
(defn view
[{:keys [data state customization-color reference-value reference-prefix decimal-separator]
(defn- view-internal
[{:keys [data state customization-color theme reference-value reference-prefix decimal-separator]
:or {reference-prefix "$"
decimal-separator :dot}}]
(let [theme (quo.theme/use-theme-value)
[inspecting? set-inspecting] (rn/use-state false)
data (if (> (count data) max-data-points)
(let [data (if (> (count data) max-data-points)
(utils/downsample-data data max-data-points)
data)
highest-value (utils/find-highest-value data)
@@ -60,11 +64,7 @@
max-value (- (utils/calculate-rounded-max highest-value) min-value)
step-value (/ max-value 4)
width (:width (rn/get-window))
line-color (get-line-color state theme inspecting?)
get-pointer-props (rn/use-callback
(fn [pointer-props]
(let [pointer-index (.-pointerIndex ^js pointer-props)]
(set-inspecting (not= pointer-index -1)))))
line-color (get-line-color state theme)
rules-color (colors/theme-colors colors/neutral-80-opa-10
colors/white-opa-5
theme)
@@ -119,7 +119,7 @@
:show-strip-on-focus true
:reference-line-1-config {:color rules-color}
:reference-line-1-position 0
:show-reference-line-2 (and (not inspecting?)
:show-reference-line-2 (and (not @inspecting?)
(<= reference-value highest-value)
(>= reference-value lowest-value))
:reference-line-2-config {:color y-axis-label-text-color
@@ -138,3 +138,5 @@
:x-axis-label-text-style (style/x-axis-label-text (/ width (count x-axis-label-texts))
y-axis-label-text-color)
:x-axis-label-texts x-axis-label-texts}]]))
(def view (quo.theme/with-theme view-internal))
@@ -20,7 +20,7 @@
(h/fire-event :on-focus (h/get-by-label-text :address-text-input))
(h/has-prop (h/get-by-label-text :address-text-input)
:placeholder-text-color
colors/neutral-30)))
colors/neutral-40)))
(h/test "on focus with blur? true"
(with-redefs [clipboard/get-string #(% "")]
@@ -30,22 +30,27 @@
(h/fire-event :on-focus (h/get-by-label-text :address-text-input))
(h/has-prop (h/get-by-label-text :address-text-input)
:placeholder-text-color
colors/neutral-80-opa-20)))
colors/neutral-80-opa-40)))
(h/test "default value is properly set"
(let [default-value "default-value"]
(h/test "scanned value is properly set"
(let [on-change-text (h/mock-fn)
scanned-value "scanned-value"]
(with-redefs [clipboard/get-string #(% "")]
(h/render [address-input/address-input
{:default-value default-value
:ens-regex ens-regex}])
(h/has-prop (h/get-by-label-text :address-text-input)
:value
default-value))))
{:scanned-value scanned-value
:on-change-text on-change-text
:ens-regex ens-regex}])
(-> (h/wait-for #(h/get-by-label-text :clear-button))
(.then (fn []
(h/was-called-with on-change-text scanned-value)
(h/has-prop (h/get-by-label-text :address-text-input)
:default-value
scanned-value)))))))
(h/test "clear icon is shown when input has text"
(with-redefs [clipboard/get-string #(% "")]
(h/render [address-input/address-input
{:default-value "default value"
{:scanned-value "scanned value"
:ens-regex ens-regex}])
(-> (h/wait-for #(h/get-by-label-text :clear-button-container))
(.then #(h/is-truthy (h/get-by-label-text :clear-button))))))
@@ -53,7 +58,7 @@
(h/test "on blur with text and blur? false"
(with-redefs [clipboard/get-string #(% "")]
(h/render [address-input/address-input
{:default-value "default value"
{:scanned-value "scanned value"
:ens-regex ens-regex}])
(-> (h/wait-for #(h/get-by-label-text :clear-button))
(.then (fn []
@@ -66,7 +71,7 @@
(h/test "on blur with text blur? true"
(with-redefs [clipboard/get-string #(% "")]
(h/render [address-input/address-input
{:default-value "default value"
{:scanned-value "scanned value"
:blur? true
:ens-regex ens-regex}])
(-> (h/wait-for #(h/get-by-label-text :clear-button))
@@ -101,7 +106,7 @@
(let [on-clear (h/mock-fn)]
(with-redefs [clipboard/get-string #(% "")]
(h/render [address-input/address-input
{:default-value "default value"
{:scanned-value "scanned value"
:on-clear on-clear
:ens-regex ens-regex}])
(-> (h/wait-for #(h/get-by-label-text :clear-button))
@@ -143,7 +148,7 @@
(-> (h/wait-for #(h/get-by-label-text :clear-button))
(.then (fn []
(h/has-prop (h/get-by-label-text :address-text-input)
:value
:default-value
clipboard)))))))
(h/test "ENS loading state and call on-detect-ens"
+122 -132
View File
@@ -8,6 +8,7 @@
[react-native.clipboard :as clipboard]
[react-native.core :as rn]
[react-native.platform :as platform]
[reagent.core :as reagent]
[utils.i18n :as i18n]))
(defn- icon-color
@@ -54,135 +55,124 @@
(and (not= status :default) (not blur?))
(colors/theme-colors colors/neutral-30 colors/neutral-60 theme)))
(defn address-input
[{:keys [default-value blur? on-change-text on-blur on-focus on-clear on-scan
on-detect-ens on-detect-address on-detect-unclassified address-regex ens-regex
valid-ens-or-address? container-style]}]
(let [theme (quo.theme/use-theme-value)
[status set-status] (rn/use-state :default)
value (rn/use-ref-atom nil)
[_ trigger-render-value] (rn/use-state @value)
[focused? set-focused] (rn/use-state false)
on-change (rn/use-callback
(fn [text]
(let [address? (when address-regex
(boolean (re-matches address-regex text)))
ens? (when ens-regex
(boolean (re-matches ens-regex text)))]
(reset! value text)
(if (> (count text) 0)
(set-status :typing)
(set-status :active))
(when on-change-text
(on-change-text text))
(when (and on-detect-ens ens?)
(set-status :loading)
(on-detect-ens text #(set-status :typing)))
(when (and address? on-detect-address)
(set-status :loading)
(on-detect-address text))
(when (and (not address?)
(not ens?)
on-detect-unclassified)
(on-detect-unclassified text)))))
set-value (rn/use-callback
(fn [new-value]
(reset! value new-value)
(on-change new-value)
(trigger-render-value new-value)))
on-paste (rn/use-callback
(fn []
(clipboard/get-string
(fn [clipboard]
(when-not (empty? clipboard)
(set-value clipboard))))))
on-clear (rn/use-callback
(fn []
(set-value "")
(set-status (if focused? :active :default))
(when on-change-text
(on-change-text ""))
(when on-clear
(on-clear)))
[focused?])
on-clear (rn/use-callback
(fn []
(set-value "")
(set-status (if focused? :active :default))
(when on-change-text
(on-change-text ""))
(when on-clear
(on-clear)))
[focused?])
on-scan (when on-scan (rn/use-callback #(on-scan set-value)))
on-focus (rn/use-callback
(fn []
(when (= (count @value) 0)
(set-status :active))
(set-focused true)
(when on-focus (on-focus))))
on-blur (rn/use-callback
(fn []
(when (= status :active)
(set-status :default))
(set-focused false)
(when on-blur (on-blur)))
[status])
placeholder-text-color (rn/use-memo #(get-placeholder-text-color status theme blur?)
[status theme blur?])]
(rn/use-mount #(on-change (or default-value "")))
[rn/view {:style (style/container container-style)}
[rn/text-input
{:accessibility-label :address-text-input
:style (style/input-text theme)
:placeholder (i18n/label :t/name-ens-or-address)
:placeholder-text-color placeholder-text-color
:value @value
:auto-complete (when platform/ios? :off)
:auto-capitalize :none
:auto-correct false
:spell-check false
:keyboard-appearance (quo.theme/theme-value :light :dark theme)
:on-focus on-focus
:on-blur on-blur
:on-change-text on-change}]
(when (or (= status :default)
(= status :active))
[rn/view
{:style style/buttons-container
:accessibility-label :paste-scan-buttons-container}
[button/button
{:accessibility-label :paste-button
:type :outline
:size 24
:container-style {:margin-right 8}
:inner-style (style/accessory-button blur? theme)
:on-press on-paste}
(i18n/label :t/paste)]
(when on-scan
[button/button
{:accessibility-label :scan-button
:icon-only? true
:type :outline
:size 24
:inner-style (style/accessory-button blur? theme)
:on-press on-scan}
:main-icons/scan])])
(when (= status :typing)
[rn/view
{:style style/buttons-container
:accessibility-label :clear-button-container}
[clear-button
{:on-press on-clear
:blur? blur?
:theme theme}]])
(when (and (= status :loading) (not valid-ens-or-address?))
[rn/view
{:style style/buttons-container
:accessibility-label :loading-button-container}
[loading-icon blur? theme]])
(when (and (= status :loading) valid-ens-or-address?)
[rn/view
{:style style/buttons-container
:accessibility-label :positive-button-container}
[positive-state-icon theme]])]))
(defn- f-address-input-internal
[]
(let [status (reagent/atom :default)
value (reagent/atom "")
focused? (atom false)]
(fn [{:keys [scanned-value theme blur? on-change-text on-blur on-focus on-clear on-scan
on-detect-ens on-detect-address on-detect-unclassified address-regex ens-regex
valid-ens-or-address? container-style]}]
(let [on-change (fn [text]
(when (not= @value text)
(let [address? (when address-regex
(boolean (re-matches address-regex text)))
ens? (when ens-regex
(boolean (re-matches ens-regex text)))]
(if (> (count text) 0)
(reset! status :typing)
(reset! status :active))
(reset! value text)
(when on-change-text
(on-change-text text))
(when (and on-detect-ens ens?)
(reset! status :loading)
(on-detect-ens text #(reset! status :typing)))
(when (and address? on-detect-address)
(reset! status :loading)
(on-detect-address text))
(when (and (not address?)
(not ens?)
on-detect-unclassified)
(on-detect-unclassified text)))))
on-paste (fn []
(clipboard/get-string
(fn [clipboard]
(when-not (empty? clipboard)
(on-change clipboard)
(reset! value clipboard)))))
on-clear (fn []
(reset! value "")
(reset! status (if @focused? :active :default))
(when on-change-text
(on-change-text ""))
(when on-clear
(on-clear)))
on-scan #(when on-scan
(on-scan))
on-focus (fn []
(when (= (count @value) 0)
(reset! status :active))
(reset! focused? true)
(when on-focus (on-focus)))
on-blur (fn []
(when (= @status :active)
(reset! status :default))
(reset! focused? false)
(when on-blur (on-blur)))
placeholder-text-color (get-placeholder-text-color @status theme blur?)]
(rn/use-effect (fn []
(when-not (empty? scanned-value)
(on-change scanned-value)))
[scanned-value])
[rn/view {:style (style/container container-style)}
[rn/text-input
{:accessibility-label :address-text-input
:style (style/input-text theme)
:placeholder (i18n/label :t/name-ens-or-address)
:placeholder-text-color placeholder-text-color
:default-value @value
:auto-complete (when platform/ios? :off)
:auto-capitalize :none
:auto-correct false
:spell-check false
:keyboard-appearance (quo.theme/theme-value :light :dark theme)
:on-focus on-focus
:on-blur on-blur
:on-change-text on-change}]
(when (or (= @status :default)
(= @status :active))
[rn/view
{:style style/buttons-container
:accessibility-label :paste-scan-buttons-container}
[button/button
{:accessibility-label :paste-button
:type :outline
:size 24
:container-style {:margin-right 8}
:inner-style (style/accessory-button blur? theme)
:on-press on-paste}
(i18n/label :t/paste)]
[button/button
{:accessibility-label :scan-button
:icon-only? true
:type :outline
:size 24
:inner-style (style/accessory-button blur? theme)
:on-press on-scan}
:main-icons/scan]])
(when (= @status :typing)
[rn/view
{:style style/buttons-container
:accessibility-label :clear-button-container}
[clear-button
{:on-press on-clear
:blur? blur?
:theme theme}]])
(when (and (= @status :loading) (not valid-ens-or-address?))
[rn/view
{:style style/buttons-container
:accessibility-label :loading-button-container}
[loading-icon blur? theme]])
(when (and (= @status :loading) valid-ens-or-address?)
[rn/view
{:style style/buttons-container
:accessibility-label :positive-button-container}
[positive-state-icon theme]])]))))
(defn address-input-internal
[props]
[:f> f-address-input-internal props])
(def address-input
(quo.theme/with-theme address-input-internal))
+103 -101
View File
@@ -5,7 +5,8 @@
[quo.components.markdown.text :as text]
[quo.theme :as quo.theme]
[react-native.core :as rn]
[react-native.platform :as platform]))
[react-native.platform :as platform]
[reagent.core :as reagent]))
(defn- label-&-counter
[{:keys [label current-chars char-limit variant-colors]}]
@@ -60,104 +61,99 @@
:container-style])
(defn- base-input
[{:keys [blur? theme error? right-icon left-icon disabled? small? button
label char-limit multiline? clearable? on-focus on-blur container-style
on-change-text on-char-limit-reach weight default-value]
:as props}]
(let [[status set-status] (rn/use-state :default)
internal-on-focus (rn/use-callback #(set-status :focus))
internal-on-blur (rn/use-callback #(set-status :default))
[multiple-lines?
set-multiple-lines] (rn/use-state false)
on-content-size-change (rn/use-callback
(fn [event]
(let [height (oops/oget event "nativeEvent.contentSize.height")
;; In Android height comes with padding
min-height (if platform/android? 40 22)]
(if (> height min-height)
(set-multiple-lines true)
(set-multiple-lines false)))))
[char-count
set-char-count] (rn/use-state (count default-value))
on-change-text (rn/use-callback
(fn [new-text]
(when on-change-text (on-change-text new-text))
(let [amount-chars (count new-text)]
(set-char-count amount-chars)
(when (and (>= amount-chars char-limit) on-char-limit-reach)
(on-char-limit-reach amount-chars)))))
status-kw (cond
disabled? :disabled
error? :error
:else status)
colors-by-status (style/status-colors status-kw blur? theme)
variant-colors (style/variants-colors blur? theme)
clean-props (apply dissoc props custom-props)]
[rn/view {:style container-style}
(when (or label char-limit)
[label-&-counter
{:variant-colors variant-colors
:label label
:current-chars char-count
:char-limit char-limit}])
[rn/view {:style (style/input-container colors-by-status small? disabled?)}
(when-let [{:keys [icon-name]} left-icon]
[left-accessory
{:variant-colors variant-colors
:small? small?
:icon-name icon-name}])
[rn/text-input
(cond-> {:style (style/input colors-by-status small? multiple-lines? weight)
:accessibility-label :input
:placeholder-text-color (:placeholder colors-by-status)
:keyboard-appearance (quo.theme/theme-value :light :dark theme)
:cursor-color (:cursor variant-colors)
:editable (not disabled?)
:on-focus (fn []
(when on-focus (on-focus))
(internal-on-focus))
:on-blur (fn []
(when on-blur (on-blur))
(internal-on-blur))}
:always (merge clean-props)
multiline? (assoc :multiline true
:on-content-size-change on-content-size-change)
char-limit (assoc :on-change-text on-change-text))]
(when-let [{:keys [on-press icon-name style-fn]} right-icon]
[right-accessory
{:variant-colors variant-colors
:small? small?
:disabled? disabled?
:icon-style-fn style-fn
:icon-name icon-name
:on-press (fn []
(when clearable? (set-char-count 0))
(on-press))}])
(when-let [{:keys [on-press text]} button]
[right-button
{:colors-by-status colors-by-status
:variant-colors variant-colors
:small? small?
:disabled? disabled?
:on-press on-press
:text text}])]]))
[{:keys [on-change-text on-char-limit-reach weight default-value]}]
(let [status (reagent/atom :default)
internal-on-focus #(reset! status :focus)
internal-on-blur #(reset! status :default)
multiple-lines? (reagent/atom false)
set-multiple-lines! #(let [height (oops/oget % "nativeEvent.contentSize.height")
;; In Android height comes with padding
min-height (if platform/android? 40 22)]
(if (> height min-height)
(reset! multiple-lines? true)
(reset! multiple-lines? false)))
char-count (reagent/atom (count default-value))
update-char-limit! (fn [new-text char-limit]
(when on-change-text (on-change-text new-text))
(let [amount-chars (count new-text)]
(reset! char-count amount-chars)
(when (and (>= amount-chars char-limit) on-char-limit-reach)
(on-char-limit-reach amount-chars))))]
(fn [{:keys [blur? theme error? right-icon left-icon disabled? small? button
label char-limit multiline? clearable? on-focus on-blur container-style]
:as props}]
(let [status-kw (cond
disabled? :disabled
error? :error
:else @status)
colors-by-status (style/status-colors status-kw blur? theme)
variant-colors (style/variants-colors blur? theme)
clean-props (apply dissoc props custom-props)]
[rn/view {:style container-style}
(when (or label char-limit)
[label-&-counter
{:variant-colors variant-colors
:label label
:current-chars @char-count
:char-limit char-limit}])
[rn/view {:style (style/input-container colors-by-status small? disabled?)}
(when-let [{:keys [icon-name]} left-icon]
[left-accessory
{:variant-colors variant-colors
:small? small?
:icon-name icon-name}])
[rn/text-input
(cond-> {:style (style/input colors-by-status small? @multiple-lines? weight)
:accessibility-label :input
:placeholder-text-color (:placeholder colors-by-status)
:keyboard-appearance (quo.theme/theme-value :light :dark theme)
:cursor-color (:cursor variant-colors)
:editable (not disabled?)
:on-focus (fn []
(when on-focus (on-focus))
(internal-on-focus))
:on-blur (fn []
(when on-blur (on-blur))
(internal-on-blur))}
:always (merge clean-props)
multiline? (assoc :multiline true
:on-content-size-change set-multiple-lines!)
char-limit (assoc :on-change-text #(update-char-limit! % char-limit)))]
(when-let [{:keys [on-press icon-name style-fn]} right-icon]
[right-accessory
{:variant-colors variant-colors
:small? small?
:disabled? disabled?
:icon-style-fn style-fn
:icon-name icon-name
:on-press (fn []
(when clearable? (reset! char-count 0))
(on-press))}])
(when-let [{:keys [on-press text]} button]
[right-button
{:colors-by-status colors-by-status
:variant-colors variant-colors
:small? small?
:disabled? disabled?
:on-press on-press
:text text}])]]))))
(defn- password-input
[{:keys [default-shown?]
:or {default-shown? false}
:as props}]
(let [[password-shown? set-password-shown] (rn/use-state default-shown?)]
[base-input
(assoc props
:accessibility-label :password-input
:auto-capitalize :none
:auto-complete :password
:secure-text-entry (not password-shown?)
:right-icon {:style-fn style/password-icon
:icon-name (if password-shown? :i/hide-password :i/reveal)
:on-press #(set-password-shown (not password-shown?))})]))
:or {default-shown? false}}]
(let [password-shown? (reagent/atom default-shown?)]
(fn [props]
[base-input
(assoc props
:accessibility-label :password-input
:auto-capitalize :none
:auto-complete :password
:secure-text-entry (not @password-shown?)
:right-icon {:style-fn style/password-icon
:icon-name (if @password-shown? :i/hide-password :i/reveal)
:on-press #(swap! password-shown? not)})])))
(defn input
(defn input-internal
"This input supports the following properties:
- :type - Can be `:text`(default) or `:password`.
- :blur? - Boolean to set the blur color variant.
@@ -181,15 +177,21 @@
- :on-change-text
...
"
[{:keys [type clearable? on-clear icon-name]
[{:keys [type clearable? on-clear on-change-text icon-name]
:or {type :text}
:as props}]
(let [base-props (cond-> props
icon-name (assoc-in [:left-icon :icon-name] icon-name)
clearable? (assoc :right-icon
{:style-fn style/clear-icon
:icon-name :i/clear
:on-press #(when on-clear (on-clear))}))]
icon-name (assoc-in [:left-icon :icon-name] icon-name)
clearable? (assoc :right-icon
{:style-fn style/clear-icon
:icon-name :i/clear
:on-press #(when on-clear (on-clear))})
on-change-text (assoc :on-change-text
(fn [new-text]
(on-change-text new-text)
(reagent/flush))))]
(if (= type :password)
[password-input base-props]
[base-input base-props])))
(def input (quo.theme/with-theme input-internal))
@@ -39,7 +39,7 @@
{:keys [ok-words error-words]} (group-by #(if (string? %) :ok-words :error-words)
children-text-nodes)]
(h/is-equal (apply str ok-words) "Text with some that the ")
(h/is-truthy (= (map #(-> % :props :argv first) error-words)
(h/is-truthy (= (map #(-> % :props :argv second) error-words)
["error" "words" "don't" "satisfy" "predicate"]))))
(h/test "Marked when words exceed the limit given"
@@ -55,7 +55,7 @@
(h/is-equal (string/trim (apply str ok-words))
"these are ok words,")
(h/is-equal (->> error-words
(map #(-> % :props :argv first))
(map #(-> % :props :argv second))
(interpose " ")
(apply str))
"these words exceed the limit")))))
@@ -3,7 +3,8 @@
[clojure.string :as string]
[quo.components.inputs.recovery-phrase.style :as style]
[quo.theme :as quo.theme]
[react-native.core :as rn]))
[react-native.core :as rn]
[reagent.core :as reagent]))
(def ^:private custom-props
[:customization-color :theme :blur? :cursor-color :multiline :on-focus :on-blur
@@ -37,42 +38,42 @@
:idx 0})
:result)))
(defn recovery-phrase-input
[{:keys [customization-color blur? on-focus on-blur mark-errors?
error-pred-current-word error-pred-written-words word-limit
container-style]
:or {customization-color :blue
word-limit ##Inf
error-pred-current-word (constantly false)
error-pred-written-words (constantly false)}
:as props}
text]
(let [theme (quo.theme/use-theme-value)
[state set-state] (rn/use-state :default)
on-focus (rn/use-callback
(fn []
(set-state :focused)
(when on-focus (on-focus))))
on-blur (rn/use-callback
(fn []
(set-state :default)
(when on-blur (on-blur))))
extra-props (apply dissoc props custom-props)]
[rn/view {:style (style/container container-style)}
[rn/text-input
(merge {:accessibility-label :recovery-phrase-input
:style (style/input)
:placeholder-text-color (style/placeholder-color state theme blur?)
:cursor-color (style/cursor-color customization-color theme)
:keyboard-appearance (quo.theme/theme-value :light :dark theme)
:multiline true
:on-focus on-focus
:on-blur on-blur}
extra-props)
(if mark-errors?
(mark-error-words {:pred-last-word error-pred-current-word
:pred-previous-words error-pred-written-words
:text text
:word-limit word-limit
:theme theme})
text)]]))
(defn recovery-phrase-input-internal
[_ _]
(let [state (reagent/atom :default)
set-focused #(reset! state :focused)
set-default #(reset! state :default)]
(fn [{:keys [customization-color theme blur? on-focus on-blur mark-errors?
error-pred-current-word error-pred-written-words word-limit
container-style]
:or {customization-color :blue
word-limit ##Inf
error-pred-current-word (constantly false)
error-pred-written-words (constantly false)}
:as props}
text]
(let [extra-props (apply dissoc props custom-props)]
[rn/view {:style (style/container container-style)}
[rn/text-input
(merge {:accessibility-label :recovery-phrase-input
:style (style/input)
:placeholder-text-color (style/placeholder-color @state theme blur?)
:cursor-color (style/cursor-color customization-color theme)
:keyboard-appearance (quo.theme/theme-value :light :dark theme)
:multiline true
:on-focus (fn []
(set-focused)
(when on-focus (on-focus)))
:on-blur (fn []
(set-default)
(when on-blur (on-blur)))}
extra-props)
(if mark-errors?
(mark-error-words {:pred-last-word error-pred-current-word
:pred-previous-words error-pred-written-words
:text text
:word-limit word-limit
:theme theme})
text)]]))))
(def recovery-phrase-input (quo.theme/with-theme recovery-phrase-input-internal))
@@ -4,7 +4,8 @@
[quo.components.icon :as icon]
[quo.components.inputs.search-input.style :as style]
[quo.foundations.colors :as colors]
[react-native.core :as rn]))
[react-native.core :as rn]
[reagent.core :as reagent]))
(def ^:private tag-separator [rn/view {:style style/tag-separator}])
@@ -40,52 +41,54 @@
text-input))
(defn search-input
[{:keys [value tags disabled? blur? on-change-text customization-color
on-clear on-focus on-blur override-theme container-style]
:or {customization-color :blue}
:as props}
& children]
(let [[state set-state] (rn/use-state :default)
on-focus (rn/use-callback
(fn []
(set-state :active)
(when on-focus (on-focus))))
on-blur (rn/use-callback
(fn []
(set-state :default)
(when on-blur (on-blur))))
scroll-view-ref (rn/use-ref-atom nil)
on-scroll-view-ref (rn/use-callback #(reset! scroll-view-ref %))
on-key-press (rn/use-callback #(handle-backspace % @scroll-view-ref))
use-value? (boolean value)
clean-props (apply dissoc props props-to-remove)]
[rn/view
{:accessibility-label :search-input
:style (style/container container-style)}
[rn/scroll-view
{:ref on-scroll-view-ref
:style style/scroll-container
:content-container-style style/scroll-content
:horizontal true
:shows-horizontal-scroll-indicator false}
(when (seq tags)
[inner-tags tags])
(add-children
[rn/text-input
(cond-> {:style (style/input-text disabled?)
:cursor-color (style/cursor customization-color override-theme)
:placeholder-text-color (style/placeholder-color state blur? override-theme)
:editable (not disabled?)
:on-key-press on-key-press
:keyboard-appearance (colors/theme-colors :light :dark override-theme)
:on-change-text on-change-text
:on-focus on-focus
:on-blur on-blur}
use-value? (assoc :value value)
(seq clean-props) (merge clean-props))]
(when-not use-value? children))]
(when (or (seq value) (seq children))
[clear-button
{:on-press on-clear
:blur? blur?
:override-theme override-theme}])]))
[{:keys [value]}]
(let [state (reagent/atom :default)
set-active #(reset! state :active)
set-default #(reset! state :default)
scroll-view-ref (atom nil)
use-value? (boolean value)]
(fn [{:keys [value tags disabled? blur? on-change-text customization-color
on-clear on-focus on-blur override-theme container-style]
:or {customization-color :blue}
:as props}
& children]
(let [clean-props (apply dissoc props props-to-remove)]
[rn/view
{:accessibility-label :search-input
:style (style/container container-style)}
[rn/scroll-view
{:ref #(reset! scroll-view-ref %)
:style style/scroll-container
:content-container-style style/scroll-content
:horizontal true
:shows-horizontal-scroll-indicator false}
(when (seq tags)
[inner-tags tags])
(add-children
[rn/text-input
(cond-> {:style (style/input-text disabled?)
:cursor-color (style/cursor customization-color override-theme)
:placeholder-text-color (style/placeholder-color @state blur? override-theme)
:editable (not disabled?)
:on-key-press #(handle-backspace % @scroll-view-ref)
:keyboard-appearance (colors/theme-colors :light :dark override-theme)
:on-change-text (fn [new-text]
(when on-change-text
(on-change-text new-text))
(reagent/flush))
:on-focus (fn []
(set-active)
(when on-focus (on-focus)))
:on-blur (fn []
(set-default)
(when on-blur (on-blur)))}
use-value? (assoc :value value)
(seq clean-props) (merge clean-props))]
(when-not use-value? children))]
(when (or (seq value) (seq children))
[clear-button
{:on-press on-clear
:blur? blur?
:override-theme override-theme}])]))))
+77 -65
View File
@@ -4,7 +4,8 @@
[quo.components.inputs.title-input.style :as style]
[quo.components.markdown.text :as text]
[quo.theme :as quo.theme]
[react-native.core :as rn]))
[react-native.core :as rn]
[reagent.core :as reagent]))
(defn- pad-0
[value]
@@ -12,70 +13,81 @@
(str 0 value)
value))
(defn view
[{:keys [blur? on-change-text auto-focus placeholder max-length default-value return-key-type
size on-focus on-blur container-style customization-color disabled?]
(defn- view-internal
[{:keys [blur?
on-change-text
auto-focus
placeholder
max-length
default-value
return-key-type
size
theme
on-focus
on-blur
container-style]
:or {max-length 0
auto-focus false
default-value ""}}]
(let [theme (quo.theme/use-theme-value)
[focused? set-focused] (rn/use-state auto-focus)
[value set-value] (rn/use-state default-value)
input-ref (rn/use-ref-atom nil)
on-inpur-ref (rn/use-callback #(reset! input-ref %))
on-press (rn/use-callback
#(when-not disabled? (.focus ^js @input-ref))
[disabled?])
on-change (rn/use-callback
(fn [v]
(set-value v)
(when on-change-text (on-change-text v))))
on-focus (rn/use-callback
(fn []
(when (fn? on-focus) (on-focus))
(set-focused true)))
on-blur (rn/use-callback
(fn []
(when (fn? on-blur) (on-blur))
(set-focused false)))]
[rn/view
{:style (merge (style/container disabled?) container-style)}
[rn/view {:style style/text-input-container}
[rn/text-input
{:style (text/text-style
{:size (or size :heading-1)
:weight :semi-bold
:style (style/title-text theme)})
:default-value default-value
:accessibility-label :profile-title-input
:keyboard-appearance (quo.theme/theme-value :light :dark theme)
:return-key-type return-key-type
:on-focus on-focus
:on-blur on-blur
:auto-focus auto-focus
:input-mode :text
:on-change-text on-change
:editable (not disabled?)
:max-length max-length
:placeholder placeholder
:ref on-inpur-ref
:selection-color (style/get-selection-color customization-color blur? theme)
:placeholder-text-color (if focused?
(style/get-focused-placeholder-color blur? theme)
(style/get-placeholder-color blur? theme))}]]
[rn/view
{:style (style/counter-container focused?)}
(if focused?
[text/text
[text/text
{:style (style/char-count blur? theme)
:size :paragraph-2}
(pad-0
(str
(count value)))]
[text/text
{:style (style/char-count blur? theme)
:size :paragraph-2}
(str "/" (pad-0 (str max-length)))]]
[rn/pressable {:on-press on-press}
[icon/icon :i/edit {:color (style/get-char-count-color blur? theme)}]])]]))
(let [focused? (reagent/atom auto-focus)
value (reagent/atom default-value)
input-ref (atom nil)
on-change (fn [v]
(reset! value v)
(when on-change-text
(on-change-text v)))]
(fn [{:keys [customization-color disabled?]}]
[rn/view
{:style (merge (style/container disabled?) container-style)}
[rn/view {:style style/text-input-container}
[rn/text-input
{:style
(text/text-style
{:size (or size :heading-1)
:weight :semi-bold
:style (style/title-text theme)})
:default-value default-value
:accessibility-label :profile-title-input
:keyboard-appearance (quo.theme/theme-value :light :dark theme)
:return-key-type return-key-type
:on-focus (fn []
(when (fn? on-focus)
(on-focus))
(reset! focused? true))
:on-blur (fn []
(when (fn? on-blur)
(on-blur))
(reset! focused? false))
:auto-focus auto-focus
:input-mode :text
:on-change-text on-change
:editable (not disabled?)
:max-length max-length
:placeholder placeholder
:ref #(reset! input-ref %)
:selection-color (style/get-selection-color customization-color blur? theme)
:placeholder-text-color (if @focused?
(style/get-focused-placeholder-color blur? theme)
(style/get-placeholder-color blur? theme))}]]
[rn/view
{:style (style/counter-container @focused?)}
(if @focused?
[text/text
[text/text
{:style (style/char-count blur? theme)
:size :paragraph-2}
(pad-0
(str
(count @value)))]
[text/text
{:style (style/char-count blur? theme)
:size :paragraph-2}
(str "/"
(pad-0
(str max-length)))]]
[rn/pressable
{:on-press #(when-not disabled?
(.focus ^js @input-ref))}
[icon/icon :i/edit {:color (style/get-char-count-color blur? theme)}]])]])))
(def view (quo.theme/with-theme view-internal))
-8
View File
@@ -122,8 +122,6 @@
(def memo react/memo)
(def use-state react/useState)
(def create-ref react/createRef)
(def use-ref react/useRef)
@@ -181,10 +179,6 @@
([handler deps]
(react/useCallback handler (get-js-deps deps))))
(defn use-memo
[handler deps]
(react/useMemo handler (get-js-deps deps)))
(def layout-animation (.-LayoutAnimation ^js react-native))
(def configure-next (.-configureNext ^js layout-animation))
@@ -210,5 +204,3 @@
(def linking (.-Linking react-native))
(defn open-url [link] (.openURL ^js linking link))
(def set-status-bar-style react-native/StatusBar.setBarStyle)
+80 -73
View File
@@ -9,6 +9,7 @@
[react-native.gesture :as gesture]
[react-native.hooks :as hooks]
[react-native.reanimated :as reanimated]
[reagent.core :as reagent]
[status-im.common.bottom-sheet.style :as style]
[utils.re-frame :as rf]))
@@ -56,77 +57,83 @@
(show translate-y bg-opacity)
(hide translate-y bg-opacity window-height on-close))))))
(defn view
[{:keys [hide? insets]}
{:keys [content selected-item padding-bottom-override border-radius on-close shell?
gradient-cover? customization-color hide-handle? blur-radius]
:or {border-radius 12}}]
(let [theme (quo.theme/use-theme-value)
sheet-height (rn/use-ref-atom 0)
item-height (rn/use-ref-atom 0)
{window-height :height} (rn/get-window)
bg-opacity (reanimated/use-shared-value 0)
translate-y (reanimated/use-shared-value window-height)
sheet-gesture (get-sheet-gesture translate-y
bg-opacity
window-height
on-close)
selected-item-smaller-than-sheet? (< @item-height
(- window-height
@sheet-height
(:top insets)
(:bottom insets)
bottom-margin))
top (- window-height (:top insets) @sheet-height)
bottom (if selected-item-smaller-than-sheet?
(+ @sheet-height bottom-margin)
(:bottom insets))]
(rn/use-effect
#(if hide?
(hide translate-y bg-opacity window-height on-close)
(show translate-y bg-opacity))
[hide?])
(hooks/use-back-handler (fn []
(when (fn? on-close)
(on-close))
(rf/dispatch [:hide-bottom-sheet])
true))
[rn/view {:style {:flex 1}}
;; backdrop
[rn/pressable
{:on-press #(rf/dispatch [:hide-bottom-sheet])
:style {:flex 1}}
[reanimated/view
{:style (reanimated/apply-animations-to-style
{:opacity bg-opacity}
{:flex 1 :background-color colors/neutral-100-opa-70})}]]
;; sheet
[gesture/gesture-detector {:gesture sheet-gesture}
[reanimated/view
{:style (reanimated/apply-animations-to-style
{:transform [{:translateY translate-y}]}
(style/sheet insets window-height selected-item))}
(when shell?
[blur/ios-view
{:style style/shell-bg
:blur-radius (or blur-radius 20)
:blur-type :transparent
:overlay-color :transparent}])
(when selected-item
[rn/view
{:on-layout #(reset! item-height (.-nativeEvent.layout.height ^js %))
:style
(style/selected-item theme top bottom selected-item-smaller-than-sheet? border-radius)}
[selected-item]])
(defn- f-view
[_ _]
(let [sheet-height (reagent/atom 0)
item-height (reagent/atom 0)]
(fn [{:keys [hide? insets theme]}
{:keys [content selected-item padding-bottom-override border-radius on-close shell?
gradient-cover? customization-color hide-handle? blur-radius]
:or {border-radius 12}}]
(let [{window-height :height} (rn/get-window)
bg-opacity (reanimated/use-shared-value 0)
translate-y (reanimated/use-shared-value window-height)
sheet-gesture (get-sheet-gesture translate-y
bg-opacity
window-height
on-close)
selected-item-smaller-than-sheet? (< @item-height
(- window-height
@sheet-height
(:top insets)
(:bottom insets)
bottom-margin))
top (- window-height (:top insets) @sheet-height)
bottom (if selected-item-smaller-than-sheet?
(+ @sheet-height bottom-margin)
(:bottom insets))]
(rn/use-effect
#(if hide?
(hide translate-y bg-opacity window-height on-close)
(show translate-y bg-opacity))
[hide?])
(hooks/use-back-handler (fn []
(when (fn? on-close)
(on-close))
(rf/dispatch [:hide-bottom-sheet])
true))
[rn/view {:style {:flex 1}}
;; backdrop
[rn/pressable
{:on-press #(rf/dispatch [:hide-bottom-sheet])
:style {:flex 1}}
[reanimated/view
{:style (reanimated/apply-animations-to-style
{:opacity bg-opacity}
{:flex 1 :background-color colors/neutral-100-opa-70})}]]
;; sheet
[gesture/gesture-detector {:gesture sheet-gesture}
[reanimated/view
{:style (reanimated/apply-animations-to-style
{:transform [{:translateY translate-y}]}
(style/sheet insets window-height selected-item))}
(when shell?
[blur/ios-view
{:style style/shell-bg
:blur-radius (or blur-radius 20)
:blur-type :transparent
:overlay-color :transparent}])
(when selected-item
[rn/view
{:on-layout #(reset! item-height (.-nativeEvent.layout.height ^js %))
:style
(style/selected-item theme top bottom selected-item-smaller-than-sheet? border-radius)}
[selected-item]])
[rn/view
{:style (style/sheet-content theme padding-bottom-override insets shell? bottom-margin)
:on-layout #(reset! sheet-height (.-nativeEvent.layout.height ^js %))}
(when (and gradient-cover? customization-color)
[rn/view {:style style/gradient-bg}
[quo/gradient-cover
{:customization-color customization-color
:opacity 0.4}]])
(when-not hide-handle?
[quo/drawer-bar])
[content]]]]]))
[rn/view
{:style (style/sheet-content theme padding-bottom-override insets shell? bottom-margin)
:on-layout #(reset! sheet-height (.-nativeEvent.layout.height ^js %))}
(when (and gradient-cover? customization-color)
[rn/view {:style style/gradient-bg}
[quo/gradient-cover
{:customization-color customization-color
:opacity 0.4}]])
(when-not hide-handle?
[quo/drawer-bar])
[content]]]]]))))
(defn- internal-view
[args sheet]
[:f> f-view args sheet])
(def view (quo.theme/with-theme internal-view))
@@ -1,11 +0,0 @@
(ns status-im.common.scalable-avatar.style)
(defn wrapper
[{:keys [scale margin-top margin border-color]}]
[{:transform [{:scale scale}]
:margin-top margin-top
:margin-left margin
:margin-bottom margin}
{:border-width 4
:border-color border-color
:border-radius 100}])
@@ -75,9 +75,3 @@
:width picture-diameter
:height picture-diameter
:background-color (colors/theme-colors colors/white colors/neutral-95 theme)})
(defn cover-background
[cover-color]
{:background-color cover-color
:height 167
:margin-bottom -16})
+4 -8
View File
@@ -98,9 +98,9 @@
(defn scroll-page
[_ _ _]
(let [scroll-height (reagent/atom negative-scroll-position-0)]
(fn [{:keys [theme cover-image cover-color logo on-scroll
(fn [{:keys [theme cover-image logo on-scroll
collapsed? height top-nav title-colum background-color navigate-back? page-nav-props
overlay-shown? sticky-header children-style]}
overlay-shown? sticky-header]}
children]
[:<>
[:f> f-scroll-page-header
@@ -125,8 +125,6 @@
"nativeEvent.contentOffset.y")))
(when on-scroll
(on-scroll @scroll-height)))}
(when cover-color
[rn/view {:style (style/cover-background cover-color)}])
(when cover-image
[rn/view {:style {:height (if collapsed? 110 151)}}
[rn/image
@@ -138,10 +136,8 @@
:flex 1}}]])
(when children
[rn/view
{:style (style/children-container (merge
children-style
{:border-radius (diff-with-max-min @scroll-height 16 0)
:background-color background-color}))}
{:style (style/children-container {:border-radius (diff-with-max-min @scroll-height 16 0)
:background-color background-color})}
(when (and (not collapsed?) cover-image)
[:f> f-display-picture @scroll-height logo theme])
children])]])))
@@ -12,7 +12,7 @@
[utils.re-frame :as rf]
[utils.security.core :as security]))
(defn- get-error-message
(defn get-error-message
[error]
(if (and (some? error)
(or (= error "file is not a database")
@@ -21,62 +21,31 @@
(i18n/label :t/oops-wrong-password)
error))
(defn- error-info
[error-message processing shell?]
(let [theme (quo.theme/use-theme-value)
on-press (rn/use-callback
(fn []
(rn/dismiss-keyboard!)
(rf/dispatch [:show-bottom-sheet
{:content #(forgot-password-doc/view {:shell? shell?})
:theme theme
:shell? shell?}]))
[theme])]
[rn/view {:style style/error-message}
[quo/info-message
{:type :error
:size :default
:icon :i/info}
error-message]
[rn/pressable
{:hit-slop {:top 6 :bottom 20 :left 0 :right 0}
:disabled processing
:on-press on-press}
[rn/text
{:style {:text-decoration-line :underline
:color (colors/resolve-color :danger theme)}
:size :paragraph-2
:suppress-highlighting true}
(i18n/label :t/forgot-password)]]]))
(defn- on-change-password
[entered-password]
(debounce/debounce-and-dispatch [:profile/on-password-input-changed
{:password (security/mask-data entered-password)
:error ""}]
100))
(defn view
[{:keys [shell? on-press-biometrics blur?]}]
(defn- view-internal
[{:keys [default-password theme shell? on-press-biometrics blur?]}]
(let [{:keys [error processing]} (rf/sub [:profile/login])
error-message (rn/use-memo #(get-error-message error) [error])
error? (boolean (seq error-message))
default-value (rn/use-ref-atom "") ;;bug on Android
;;https://github.com/status-im/status-mobile/issues/19004
on-change-password (rn/use-callback
(fn [entered-password]
(reset! default-value entered-password)
(debounce/debounce-and-dispatch [:profile/on-password-input-changed
{:password (security/mask-data
entered-password)
:error ""}]
100)))]
error-message (get-error-message error)
error? (boolean (seq error-message))]
[:<>
[rn/view {:style {:flex-direction :row}}
[quo/input
{:container-style {:flex 1}
:type :password
:default-value @default-value
:blur? blur?
:disabled? processing
:placeholder (i18n/label :t/type-your-password)
:auto-focus true
:error? error?
:label (i18n/label :t/profile-password)
:on-change-text on-change-password}]
:on-change-text on-change-password
:default-value (security/safe-unmask-data default-password)}]
(when on-press-biometrics
[quo/button
{:container-style style/auth-button
@@ -86,5 +55,26 @@
:type :outline}
:i/face-id])]
(when error?
[error-info error-message processing shell?])]))
[rn/view {:style style/error-message}
[quo/info-message
{:type :error
:size :default
:icon :i/info}
error-message]
[rn/pressable
{:hit-slop {:top 6 :bottom 20 :left 0 :right 0}
:disabled processing
:on-press (fn []
(rn/dismiss-keyboard!)
(rf/dispatch [:show-bottom-sheet
{:content #(forgot-password-doc/view {:shell? shell?})
:theme theme
:shell? shell?}]))}
[rn/text
{:style {:text-decoration-line :underline
:color (colors/resolve-color :danger theme)}
:size :paragraph-2
:suppress-highlighting true}
(i18n/label :t/forgot-password)]]])]))
(def view (quo.theme/with-theme view-internal))
@@ -3,32 +3,45 @@
[quo.core :as quo]
[quo.theme :as quo.theme]
[react-native.core :as rn]
[reagent.core :as reagent]
[status-im.common.standard-authentication.standard-auth.authorize :as authorize]
[status-im.constants :as constants]
[utils.re-frame :as rf]))
(defn view
[{:keys [track-text customization-color auth-button-label on-auth-success on-auth-fail
auth-button-icon-left size blur? container-style]
:or {container-style {:flex 1}}}]
(let [theme (quo.theme/use-theme-value)
(defn- view-internal
[_]
(let [reset-slider? (reagent/atom false)
on-close (fn []
(js/setTimeout
#(reset! reset-slider? true)
200))
auth-method (rf/sub [:auth-method])
biometric-auth? (= auth-method constants/auth-method-biometric)
on-complete (rn/use-callback
(fn [reset]
(authorize/authorize {:on-close #(js/setTimeout reset 200)
:auth-button-icon-left auth-button-icon-left
:theme theme
:blur? blur?
:biometric-auth? biometric-auth?
:on-auth-success on-auth-success
:on-auth-fail on-auth-fail
:auth-button-label auth-button-label}))
[theme])]
[quo/slide-button
{:container-style container-style
:size size
:customization-color customization-color
:on-complete on-complete
:track-icon (if biometric-auth? :i/face-id :password)
:track-text track-text}]))
biometric-auth? (= auth-method constants/auth-method-biometric)]
(fn [{:keys [track-text
customization-color
auth-button-label
on-auth-success
on-auth-fail
auth-button-icon-left
size
theme
blur?
container-style]
:or {container-style {:flex 1}}}]
[rn/view {:style container-style}
[quo/slide-button
{:size size
:customization-color customization-color
:on-reset (when @reset-slider? #(reset! reset-slider? false))
:on-complete #(authorize/authorize {:on-close on-close
:auth-button-icon-left auth-button-icon-left
:theme theme
:blur? blur?
:biometric-auth? biometric-auth?
:on-auth-success on-auth-success
:on-auth-fail on-auth-fail
:auth-button-label auth-button-label})
:track-icon (if biometric-auth? :i/face-id :password)
:track-text track-text}]])))
(def view (quo.theme/with-theme view-internal))
-18
View File
@@ -14,7 +14,6 @@
[status-im.contexts.chat.messenger.messages.delete-message-for-me.events :as delete-for-me]
[status-im.contexts.chat.messenger.messages.delete-message.events :as delete-message]
[status-im.contexts.chat.messenger.messages.list.state :as chat.state]
[status-im.feature-flags :as ff]
[status-im.navigation.events :as navigation]
[taoensso.timbre :as log]
[utils.datetime :as datetime]
@@ -432,20 +431,3 @@
[:chat/inputs current-chat-id :metadata :sending-image]
dissoc
(:uri original))})))
(rf/reg-event-fx :chat.ui/show-profile
(fn [{:keys [db]} [public-key ens-name]]
(let [my-public-key (get-in db [:profile/profile :public-key])]
(if (not= my-public-key public-key)
{:db (-> db
(assoc :contacts/identity public-key)
(assoc :contacts/ens-name ens-name))
:dispatch [:contacts/build-contact
{:pubkey public-key
:ens ens-name
:success-fn (fn [_]
{:dispatch [:open-modal
(if (ff/enabled? ::ff/profile.new-contact-ui)
:contact-profile
:profile)]})}]}
{:dispatch [:navigate-to :my-profile]}))))
@@ -10,7 +10,6 @@
[status-im.contexts.onboarding.new-to-status.style :as style]
[utils.debounce :as debounce]
[utils.i18n :as i18n]
[native-module.core :as native-module]
[utils.re-frame :as rf]))
(defn sign-in-options
@@ -96,8 +95,7 @@
(defn new-to-status
[]
(let [{:keys [top]} (safe-area/get-insets)
_ (native-module/request-local-network-access (fn [response] (log/info "request-local-network-access ->" response)))]
(let [{:keys [top]} (safe-area/get-insets)]
[rn/view {:style style/content-container}
[quo/page-nav
{:margin-top top
@@ -48,7 +48,7 @@
:disabled? (:disabled? @state)
:blur? @blur?
:type (:type @state)
:on-complete (fn [_]
:on-complete (fn []
(js/setTimeout (fn [] (reset! complete? true))
1000)
(js/alert "I don't wanna slide anymore"))}]
@@ -25,8 +25,8 @@
:blur? (:blur? @state)
:show-blur-background? true}
[quo/address-input
(merge (dissoc @state :scanned-value)
{:on-scan (fn [on-result] (on-result (:scanned-value @state)))
(merge @state
{:on-scan #(js/alert "Not implemented yet")
:ens-regex constants/regx-ens
:on-detect-ens (fn [_]
(swap! state assoc :valid-ens-or-address? false)
+1 -1
View File
@@ -535,7 +535,7 @@
[quo/button
{:type :outline
:container-style {:margin-vertical 8}
:on-press #(rf/dispatch [:open-modal category-name])}
:on-press #(rf/dispatch [:navigate-to category-name])}
(name category-name)]))])))
(defn- main-screen
@@ -1,17 +0,0 @@
(ns status-im.contexts.profile.contact.header.style
(:require [quo.foundations.colors :as colors]
[react-native.reanimated :as reanimated]))
(def avatar-wrapper
{:margin-top -40
:padding-left 20
:align-items :flex-start})
(defn header-container
[border-radius theme margin-top]
(reanimated/apply-animations-to-style
{:border-top-left-radius border-radius
:border-top-right-radius border-radius}
{:background-color (colors/theme-colors colors/white colors/neutral-95 theme)
:padding-horizontal 20
:margin-top margin-top}))
@@ -1,34 +0,0 @@
(ns status-im.contexts.profile.contact.header.view
(:require [quo.core :as quo]
[quo.foundations.colors :as colors]
[quo.theme]
[react-native.core :as rn]
[status-im.common.scalable-avatar.view :as avatar]
[status-im.contexts.profile.contact.header.style :as style]
[status-im.contexts.profile.utils :as profile.utils]
[utils.re-frame :as rf]))
(defn view
[{:keys [scroll-y]}]
(let [{:keys [public-key customization-color
emoji-hash bio]
:as profile} (rf/sub [:contacts/current-contact])
customization-color (or customization-color :blue)
full-name (profile.utils/displayed-name profile)
profile-picture (profile.utils/photo profile)
online? (rf/sub [:visibility-status-updates/online? public-key])
theme (quo.theme/use-theme-value)]
[rn/view {:style style/header-container}
[rn/view {:style style/avatar-wrapper}
[avatar/view
{:scroll-y scroll-y
:full-name full-name
:online? online?
:profile-picture profile-picture
:border-color (colors/theme-colors colors/white colors/neutral-95 theme)
:customization-color customization-color}]]
[quo/page-top
{:title full-name
:description :text
:description-text bio
:emoji-dash emoji-hash}]]))
@@ -1,24 +0,0 @@
(ns status-im.contexts.profile.contact.view
(:require [quo.foundations.colors :as colors]
[quo.theme]
[react-native.reanimated :as reanimated]
[status-im.common.not-implemented :as not-implemented]
[status-im.common.scroll-page.view :as scroll-page]
[status-im.contexts.profile.contact.header.view :as contact-header]
[utils.re-frame :as rf]))
(defn view
[]
(let [{:keys [customization-color]} (rf/sub [:contacts/current-contact])
scroll-y (reanimated/use-shared-value 0)
theme (quo.theme/use-theme-value)]
[scroll-page/scroll-page
{:navigate-back? true
:height 148
:on-scroll #(reanimated/set-shared-value scroll-y %)
;TODO remove colors/primary-50 when #18733 merged.
:cover-color (or customization-color colors/primary-50)
:background-color (colors/theme-colors colors/white colors/neutral-95 theme)
:page-nav-props {:right-side [{:icon-name :i/options
:on-press not-implemented/alert}]}}
[contact-header/view {:scroll-y scroll-y}]]))
@@ -5,6 +5,7 @@
[react-native.core :as rn]
[react-native.reanimated :as reanimated]
[react-native.safe-area :as safe-area]
[reagent.core :as reagent]
[status-im.common.confirmation-drawer.view :as confirmation-drawer]
[status-im.common.standard-authentication.core :as standard-authentication]
[status-im.config :as config]
@@ -132,8 +133,8 @@
[:profile.login/login-with-biometric-if-available key-uid])
(when-not keycard-pairing (set-hide-profiles)))}]))
(defn- profiles-section
[{:keys [hide-profiles]}]
(defn- f-profiles-section
[{:keys [set-hide-profiles]}]
(let [profiles (vals (rf/sub [:profile/profiles-overview]))
translate-x (reanimated/use-shared-value @translate-x-atom)]
(rn/use-mount (fn []
@@ -164,38 +165,42 @@
:key-fn :key-uid
:content-container-style {:padding-bottom 20}
:render-data {:last-index (dec (count profiles))
:set-hide-profiles hide-profiles}
:set-hide-profiles set-hide-profiles}
:render-fn profile-card}]]))
(defn profiles-section
[props]
[:f> f-profiles-section props])
(defn password-input
[]
(let [auth-method (rf/sub [:auth-method])
on-press-biometrics (when (= auth-method constants/auth-method-biometric)
(rn/use-callback
(fn []
(rf/dispatch [:biometric/authenticate
{:on-success #(rf/dispatch
[:profile.login/biometric-success])
:on-fail #(rf/dispatch
[:profile.login/biometric-auth-fail
%])}]))))]
(let [password (rf/sub [:profile/login-password])
auth-method (rf/sub [:auth-method])]
[standard-authentication/password-input
{:shell? true
:blur? true
:on-press-biometrics on-press-biometrics}]))
:on-press-biometrics (when (= auth-method constants/auth-method-biometric)
(fn []
(rf/dispatch [:biometric/authenticate
{:on-success #(rf/dispatch
[:profile.login/biometric-success])
:on-fail #(rf/dispatch
[:profile.login/biometric-auth-fail
%])}])))
:default-password password}]))
(defn login-section
[{:keys [show-profiles]}]
(let [processing (rf/sub [:profile/login-processing])
{:keys [key-uid name
customization-color]} (rf/sub [:profile/login-profile])
sign-in-enabled? (rf/sub [:sign-in-enabled?])
profile-picture (rf/sub [:profile/login-profiles-picture key-uid])
login-multiaccount (rn/use-callback #(rf/dispatch [:profile.login/login]))]
[{:keys [set-show-profiles]}]
(let [processing (rf/sub [:profile/login-processing])
{:keys [key-uid name customization-color]} (rf/sub [:profile/login-profile])
sign-in-enabled? (rf/sub [:sign-in-enabled?])
profile-picture (rf/sub [:profile/login-profiles-picture key-uid])
login-multiaccount #(rf/dispatch [:profile.login/login])]
[rn/keyboard-avoiding-view
{:style style/login-container
:keyboardVerticalOffset (- (safe-area/get-bottom))}
[rn/view {:style style/multi-profile-button-container}
[rn/view
{:style style/multi-profile-button-container}
(when config/quo-preview-enabled?
[quo/button
{:size 32
@@ -212,7 +217,7 @@
:type :grey
:background :blur
:icon-only? true
:on-press show-profiles
:on-press set-show-profiles
:disabled? processing
:accessibility-label :show-profiles}
:i/multi-profile]]
@@ -236,13 +241,16 @@
:container-style {:margin-bottom (+ (safe-area/get-bottom) 12)}}
(i18n/label :t/log-in)]]))
;; we had to register it here, because of hotreload, overwise on hotreload it will be reseted
(defonce show-profiles? (reagent/atom false))
(defn view
[]
(let [[show-profiles? set-show-profiles] (rn/use-state false)
show-profiles (rn/use-callback #(set-show-profiles true))
hide-profiles (rn/use-callback #(set-show-profiles false))]
[:<>
[background/view true]
(if show-profiles?
[profiles-section {:hide-profiles hide-profiles}]
[login-section {:show-profiles show-profiles}])]))
(let [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}])])))
@@ -1,14 +1,16 @@
(ns status-im.common.scalable-avatar.view
(ns status-im.contexts.profile.settings.header.avatar
(:require [quo.core :as quo]
[quo.theme :as quo.theme]
[react-native.reanimated :as reanimated]
[status-im.common.scalable-avatar.style :as style]))
[status-im.contexts.profile.settings.header.style :as style]))
(def scroll-animation-input-range [0 50])
(def header-extrapolation-option
{:extrapolateLeft "clamp"
:extrapolateRight "clamp"})
(defn f-avatar
[{:keys [scroll-y full-name online? profile-picture customization-color border-color]}]
[{:keys [scroll-y full-name online? profile-picture customization-color]}]
(let [image-scale-animation (reanimated/interpolate scroll-y
scroll-animation-input-range
[1 0.4]
@@ -19,13 +21,14 @@
header-extrapolation-option)
image-side-margin-animation (reanimated/interpolate scroll-y
scroll-animation-input-range
[-4 -20]
header-extrapolation-option)]
[0 -20]
header-extrapolation-option)
theme (quo.theme/get-theme)]
[reanimated/view
{:style (style/wrapper {:scale image-scale-animation
:margin-top image-top-margin-animation
:margin image-side-margin-animation
:border-color border-color})}
{:style (style/avatar-container theme
image-scale-animation
image-top-margin-animation
image-side-margin-animation)}
[quo/user-avatar
{:full-name full-name
:online? online?
@@ -1,10 +1,9 @@
(ns status-im.contexts.profile.settings.header.view
(:require [clojure.string :as string]
[quo.core :as quo]
[quo.foundations.colors :as colors]
[quo.theme]
[quo.theme :as quo.theme]
[react-native.core :as rn]
[status-im.common.scalable-avatar.view :as avatar]
[status-im.contexts.profile.settings.header.avatar :as header.avatar]
[status-im.contexts.profile.settings.header.header-shape :as header.shape]
[status-im.contexts.profile.settings.header.style :as style]
[status-im.contexts.profile.settings.header.utils :as header.utils]
@@ -14,31 +13,28 @@
(defn- f-view
[{:keys [theme scroll-y]}]
(let [{:keys [public-key emoji-hash bio] :as profile} (rf/sub [:profile/profile-with-image])
online? (rf/sub [:visibility-status-updates/online?
public-key])
status (rf/sub
[:visibility-status-updates/visibility-status-update
public-key])
customization-color (rf/sub [:profile/customization-color])
full-name (profile.utils/displayed-name profile)
profile-picture (profile.utils/photo profile)
emoji-string (string/join emoji-hash)
{:keys [status-title status-icon]} (header.utils/visibility-status-type-data status)
border-theme (quo.theme/get-theme)]
(let [{:keys [public-key emoji-hash] :as profile} (rf/sub [:profile/profile-with-image])
online? (rf/sub [:visibility-status-updates/online?
public-key])
status (rf/sub
[:visibility-status-updates/visibility-status-update
public-key])
customization-color (rf/sub [:profile/customization-color])
bio (:bio profile)
full-name (profile.utils/displayed-name profile)
profile-picture (profile.utils/photo profile)
emoji-string (string/join emoji-hash)
{:keys [status-title status-icon]} (header.utils/visibility-status-type-data status)]
[:<>
[header.shape/view
{:scroll-y scroll-y
:customization-color customization-color
:theme theme}]
[rn/view {:style style/avatar-row-wrapper}
[avatar/view
[header.avatar/view
{:scroll-y scroll-y
:display-name full-name
:online? online?
:border-color (colors/theme-colors colors/border-avatar-light
colors/neutral-80-opa-80
border-theme)
:customization-color customization-color
:profile-picture profile-picture}]
[rn/view {:style {:margin-bottom 4}}
@@ -21,14 +21,10 @@
(h/fire-event :change-text
(h/get-by-label-text :add-address-to-watch)
"0x12E838Ae1f769147b12956485dc56e57138f3AC8")
(-> (h/wait-for #(h/get-by-translation-text :t/address-already-in-use))
(.then (fn []
(h/is-truthy (h/get-by-translation-text :t/address-already-in-use))))))
(h/is-truthy (h/get-by-translation-text :t/address-already-in-use)))
(h/test "validation messages show for invalid address"
(h/render [add-address-to-watch/view])
(h/is-falsy (h/query-by-label-text :error-message))
(h/fire-event :change-text (h/get-by-label-text :add-address-to-watch) "0x12E838Ae1f769147b")
(-> (h/wait-for #(h/get-by-translation-text :t/invalid-address))
(.then (fn []
(h/is-truthy (h/get-by-translation-text :t/invalid-address)))))))
(h/is-truthy (h/get-by-translation-text :t/invalid-address))))
-1
View File
@@ -57,7 +57,6 @@
(react-native-shake/add-shake-listener #(re-frame/dispatch [:shake-event]))
(universal-links/initialize)
(interceptors/register-global-interceptors)
; (native-module/request-local-network-access (fn [response] (log/info "request-local-network-access ->" response)))
;; Shell
(async-storage/get-item :selected-stack-id #(shell.utils/change-selected-stack-id % nil nil))
+1 -2
View File
@@ -13,8 +13,7 @@
{::wallet.edit-default-keypair (enabled-in-env? :FLAG_EDIT_DEFAULT_KEYPAIR_ENABLED)
::wallet.bridge-token (enabled-in-env? :FLAG_BRIDGE_TOKEN_ENABLED)
::wallet.remove-account (enabled-in-env? :FLAG_REMOVE_ACCOUNT_ENABLED)
::wallet.network-filter (enabled-in-env? :FLAG_NETWORK_FILTER_ENABLED)
::profile.new-contact-ui (enabled-in-env? :FLAG_NEW_CONTACT_UI_ENABLED)}))
::wallet.network-filter (enabled-in-env? :FLAG_NETWORK_FILTER_ENABLED)}))
(defn feature-flags [] @feature-flags-config)
+3 -16
View File
@@ -1,7 +1,5 @@
(ns status-im.navigation.effects
(:require
[quo.theme]
[react-native.core :as rn]
[react-native.navigation :as navigation]
[status-im.navigation.options :as options]
[status-im.navigation.roots :as roots]
@@ -10,20 +8,10 @@
[taoensso.timbre :as log]
[utils.re-frame :as rf]))
(defn- set-status-bar-color
[theme]
(rn/set-status-bar-style
(if (= theme :dark)
"light-content"
"dark-content")
true))
(rf/reg-fx :set-view-id-fx
(fn [view-id]
(rf/dispatch [:screens/on-will-focus view-id])
(when-let [{:keys [on-focus options]} (get views/screens view-id)]
(set-status-bar-color (or (:theme options)
(quo.theme/get-theme)))
(when-let [{:keys [on-focus]} (get views/screens view-id)]
(when on-focus
(rf/dispatch on-focus)))))
@@ -129,12 +117,11 @@
(defn open-modal
[component]
(let [{:keys [options name]} (get views/screens component)
sheet? (:sheet? options)]
(let [{:keys [options]} (get views/screens component)
sheet? (:sheet? options)]
(if @state/dissmissing
(reset! state/dissmissing component)
(do
(set-view-id name) ; TODO https://github.com/status-im/status-mobile/issues/18811
(reset! state/curr-modal true)
(swap! state/modals conj component)
(navigation/show-modal
+3
View File
@@ -137,6 +137,9 @@
:decelerate
:factor 1.5}}]}}})
(def camera-screen
{:navigationBar {:backgroundColor colors/black}})
(defn merge-top-bar
[root-options options]
(let [options (:topBar options)]
+1 -15
View File
@@ -1,7 +1,6 @@
(ns status-im.navigation.screens
(:require
[legacy.status-im.ui.screens.screens :as old-screens]
[quo.foundations.colors :as colors]
[status-im.common.emoji-picker.view :as emoji-picker]
[status-im.common.lightbox.view :as lightbox]
[status-im.config :as config]
@@ -37,7 +36,6 @@
[status-im.contexts.preview.quo.component-preview.view :as component-preview]
[status-im.contexts.preview.quo.main :as quo.preview]
[status-im.contexts.preview.status-im.main :as status-im-preview]
[status-im.contexts.profile.contact.view :as contact-profile]
[status-im.contexts.profile.edit.accent-colour.view :as edit-accent-colour]
[status-im.contexts.profile.edit.bio.view :as edit-bio]
[status-im.contexts.profile.edit.name.view :as edit-name]
@@ -143,8 +141,7 @@
:component photo-selector/photo-selector}
{:name :camera-screen
:options {:navigationBar {:backgroundColor colors/black}
:theme :dark}
:options options/camera-screen
:component camera-screen/camera-screen}
{:name :new-contact
@@ -205,10 +202,6 @@
:options options/transparent-modal-screen-options
:component edit-bio/view}
{:name :contact-profile
:options {:modalPresentationStyle :overCurrentContext}
:component contact-profile/view}
{:name :new-to-status
:options {:theme :dark
:layout options/onboarding-transparent-layout
@@ -435,13 +428,6 @@
:options options/transparent-modal-screen-options
:component settings-password/view}]
[{:name :shell
:options {:theme :dark}}
{:name :communities-stack}
{:name :chats-stack}
{:name :wallet-stack}
{:name :browser-stack}]
(when js/goog.DEBUG
[{:name :dev-component-preview
:options {:sheet? true}
+6 -14
View File
@@ -17,8 +17,6 @@
[status-im.setup.hot-reload :as reloader]
[utils.re-frame :as rf]))
(def functional-compiler (reagent/create-compiler {:function-components true}))
(defn get-screens
[]
(reduce
@@ -74,8 +72,7 @@
(when js/goog.DEBUG
[:<>
[reloader/reload-view]
[schema.view/view]])]))
functional-compiler))
[schema.view/view]])]))))
(def bottom-sheet
(reagent/reactify-component
@@ -93,8 +90,7 @@
:keyboard-vertical-offset (- (max 20 (:bottom insets)))}
(when sheet
[bottom-sheet/view {:insets insets :hide? hide?}
sheet])]]))
functional-compiler))
sheet])]]))))
(def toasts (reagent/reactify-component toasts/toasts))
@@ -107,8 +103,7 @@
[inactive]
[popover/popover]
(when js/goog.DEBUG
[reloader/reload-view])])
functional-compiler))
[reloader/reload-view])])))
(def visibility-status-popover-comp
(reagent/reactify-component
@@ -118,8 +113,7 @@
[inactive]
[visibility-status-views/visibility-status-popover]
(when js/goog.DEBUG
[reloader/reload-view])])
functional-compiler))
[reloader/reload-view])])))
(def sheet-comp-old
(reagent/reactify-component
@@ -127,8 +121,7 @@
^{:key (str "sheet-old" @reloader/cnt)}
[:<>
[inactive]
[bottom-sheets-old/bottom-sheet]])
functional-compiler))
[bottom-sheets-old/bottom-sheet]])))
(def signing-comp
(reagent/reactify-component
@@ -138,5 +131,4 @@
[inactive]
[signing/signing]
(when js/goog.DEBUG
[reloader/reload-view])])
functional-compiler))
[reloader/reload-view])])))
@@ -1,7 +1,6 @@
(ns test-helpers.component-tests-preload
{:dev/always true}
(:require
[reagent.core :as reagent]
;; NOTE: Do NOT sort i18n-resources because it MUST be loaded first.
[status-im.setup.i18n-resources :as i18n-resources]
#_{:clj-kondo/ignore [:unsorted-required-namespaces]}
@@ -16,7 +15,6 @@
should never be directly required. However, it will be loaded automatically
before any component test runs."
[]
(reagent/set-default-compiler! (reagent/create-compiler {:function-components true}))
(interceptors/register-global-interceptors)
(i18n/set-language "en")
(i18n-resources/load-language "en"))
+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.176.2",
"commit-sha1": "00f50a4112ef80cc29737f8edf34cdb1cf181709",
"src-sha256": "12z9qf0hhb2pc7ask6f86pah0wjp3kyxyv32rpfnkjl42maw0bw6"
"version": "v0.175.4",
"commit-sha1": "5304406079a5e3e1cfea285fef892ac56f2c3aad",
"src-sha256": "08xprnmpw0nz2zjm1wp8ypjhdyfvgmh7pqrlk69prgr23xa31ady"
}
@@ -59,7 +59,6 @@ class TestActivityCenterContactRequestMultipleDevicePR(MultipleSharedDeviceTestC
self.errors.append("Push notification with text was received for new message in activity centre")
self.device_1.click_system_back_button()
self.device_1.driver.activate_app(app_package)
self.device_1.wait_for_application_to_be_running(app_package)
self.device_1.just_fyi('Device1 verifies pending contact request')
self.home_1.contacts_tab.click()
@@ -271,6 +271,8 @@ class TestOneToOneChatMultipleSharedDevicesNewUi(MultipleSharedDeviceTestCase):
self.home_1.jump_to_messages_home()
self.home_1.profile_button.click()
self.profile_1.edit_profile_picture(image_index=2)
self.profile_1.navigate_back_to_home_view()
self.profile_1.chats_tab.click()
self.chat_2.just_fyi("Send messages with non-latin symbols")
self.home_1.jump_to_card_by_text(self.username_2)
+4 -16
View File
@@ -6,7 +6,6 @@ import time
from datetime import datetime
from appium.webdriver import WebElement
from appium.webdriver.applicationstate import ApplicationState
from appium.webdriver.common.touch_action import TouchAction
from selenium.common.exceptions import NoSuchElementException, TimeoutException
from selenium.webdriver.support import expected_conditions
@@ -659,24 +658,13 @@ class BaseView(object):
self.click_on_floating_jump_to()
self.element_by_text(text).click()
def wait_for_application_to_be_running(self, app_package: str, wait_time: int = 3):
for _ in range(wait_time):
if self.driver.query_app_state(app_package) == ApplicationState.RUNNING_IN_FOREGROUND:
return
time.sleep(1)
raise TimeoutException(msg="Status app is not running in foreground after %s sec" % wait_time)
def wait_for_application_to_not_run(self, app_package: str, wait_time: int = 3):
for _ in range(wait_time):
if self.driver.query_app_state(app_package) == ApplicationState.NOT_RUNNING:
return
time.sleep(1)
raise TimeoutException(msg="Status app is not terminated after %s sec" % wait_time)
def reopen_app(self, password=common_password, sign_in=True):
app_package = self.driver.current_package
self.driver.terminate_app(app_package)
self.wait_for_application_to_not_run(app_package=app_package)
for _ in range(3):
if self.driver.query_app_state(app_package) == 1:
break
time.sleep(1)
self.driver.activate_app(app_package)
if sign_in:
sign_in_view = self.get_sign_in_view()
+6 -11
View File
@@ -199,9 +199,9 @@ class ProfileView(BaseView):
self.online_indicator = Button(self.driver, accessibility_id="online-profile-photo-dot")
self.edit_picture_button = Button(self.driver, accessibility_id="edit-profile-photo-button")
self.confirm_edit_button = Button(self.driver, accessibility_id="done-button")
self.select_from_gallery_button_old = Button(self.driver, translation_id="profile-pic-pick")
self.select_from_gallery_button = Button(self.driver, translation_id="profile-pic-pick")
self.capture_button = Button(self.driver, translation_id="image-source-make-photo")
self.take_photo_button_old = Button(self.driver, accessibility_id="take-photo")
self.take_photo_button = Button(self.driver, accessibility_id="take-photo")
self.crop_photo_button = Button(self.driver, accessibility_id="Crop")
self.decline_photo_crop = Button(self.driver, accessibility_id="Navigate up")
self.shutter_button = Button(self.driver, accessibility_id="Shutter")
@@ -354,12 +354,6 @@ class ProfileView(BaseView):
self.confirm_logout_button = Button(self.driver, translation_id="logout", uppercase=True)
# New profile
self.edit_profile_button = Button(self.driver, accessibility_id="icon, Edit Profile, label-component, icon")
self.change_profile_photo_button = Button(
self.driver,
xpath="//*[@content-desc='user-avatar']/following-sibling::android.view.ViewGroup[@content-desc='icon']")
self.take_photo_button = Button(self.driver, accessibility_id="take-photo-button")
self.select_from_gallery_button = Button(self.driver, accessibility_id="select-from-gallery-button")
self.profile_password_button = Button(self.driver, accessibility_id="icon, Password, label-component, icon")
self.profile_legacy_button = Button(self.driver,
accessibility_id="icon, Legacy settings, label-component, icon")
@@ -444,8 +438,10 @@ class ProfileView(BaseView):
self.driver.info("## Setting custom profile image", device=False)
if not AbstractTestCase().environment == 'sauce':
raise NotImplementedError('Test case is implemented to run on SauceLabs only')
self.edit_profile_button.click()
self.change_profile_photo_button.click()
## pointing to legacy profile until new feature is implemented
self.logout_button.scroll_to_element()
self.profile_legacy_button.click()
self.profile_picture.click()
if update_by == "Gallery":
self.select_from_gallery_button.click()
self.select_photo_from_gallery_by_index(image_index)
@@ -458,7 +454,6 @@ class ProfileView(BaseView):
self.accept_photo_button.click()
self.crop_photo_button.click()
self.driver.info("## Custom profile image has been set", device=False)
self.click_system_back_button()
def take_photo(self):
self.take_photo_button.click()