Compare commits
43
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
98b0c218b4 | ||
|
|
eeb8db00f7 | ||
|
|
3499cdc123 | ||
|
|
44b8a4c0f4 | ||
|
|
e45f959c27 | ||
|
|
cd86a1065b | ||
|
|
ffba396e4d | ||
|
|
961692251c | ||
|
|
94fde74b88 | ||
|
|
5402c217df | ||
|
|
4588dafe02 | ||
|
|
edbb06a7c3 | ||
|
|
29a7e4dc1c | ||
|
|
de3c08ba18 | ||
|
|
e5ff46fdd5 | ||
|
|
be79a8e54c | ||
|
|
36d96c6264 | ||
|
|
340213ece5 | ||
|
|
032a8786ff | ||
|
|
15d671275f | ||
|
|
f3533c5f99 | ||
|
|
b18d7b6a2a | ||
|
|
2c23ab4c5d | ||
|
|
646add59b8 | ||
|
|
cd111aeeec | ||
|
|
81b60ce86c | ||
|
|
356dd89147 | ||
|
|
a6102c1133 | ||
|
|
7dfa93f2a2 | ||
|
|
c6271557b1 | ||
|
|
d1f3a33194 | ||
|
|
c6371bf3b3 | ||
|
|
59bc7af00c | ||
|
|
a5737856c0 | ||
|
|
7d0944cfd1 | ||
|
|
099bcf8a17 | ||
|
|
4504f07a2a | ||
|
|
b5d8a641c6 | ||
|
|
11d3bf094a | ||
|
|
32c0f9719c | ||
|
|
b587a8f85e | ||
|
|
53d7d719f0 | ||
|
|
46c023920c |
@@ -32,3 +32,5 @@ METRICS_ENABLED=0
|
||||
DELETE_MESSAGE_ENABLED=1
|
||||
COLLECTIBLES_ENABLED=1
|
||||
COMMANDS_ENABLED=1
|
||||
TWO_MINUTES_SYNCING=1
|
||||
SWAP_ENABLED=1
|
||||
|
||||
@@ -33,3 +33,4 @@ COMMUNITIES_ENABLED=1
|
||||
COMMUNITIES_MANAGEMENT_ENABLED=1
|
||||
METRICS_ENABLED=0
|
||||
DELETE_MESSAGE_ENABLED=1
|
||||
TWO_MINUTES_SYNCING=1
|
||||
|
||||
@@ -35,3 +35,4 @@ COMMUNITIES_ENABLED=1
|
||||
COMMUNITIES_MANAGEMENT_ENABLED=1
|
||||
METRICS_ENABLED=0
|
||||
DELETE_MESSAGE_ENABLED=1
|
||||
TWO_MINUTES_SYNCING=1
|
||||
|
||||
+35
@@ -1,3 +1,38 @@
|
||||
## 1.18.0 Release notes :package:
|
||||
|
||||
### Features
|
||||
* 🚦Online status indicator <https://github.com/status-im/status-react/issues/12547>
|
||||
* 👛 Add possibility to select wallet for ENS names <https://github.com/status-im/status-react/pull/12761>
|
||||
* 🐞 Bug reporting and logs sharing improvements <https://github.com/status-im/status-react/pull/12773>
|
||||
* 🍳 Simplify Keycard onboarding by using defaults for pairing password <https://github.com/status-im/status-react/issues/12685>
|
||||
* 💾 Backup contacts via Waku <https://github.com/status-im/status-react/issues/12550>
|
||||
* 🪙 Added ENS token <https://github.com/status-im/status-react/issues/12807>
|
||||
* 🌠 Using react-native-fast-image for stickers <https://github.com/status-im/status-react/pull/12769>
|
||||
#### Message reliability improvements
|
||||
* 𝌗 Show loading until all messages are processed <https://github.com/status-im/status-react/pull/12834>
|
||||
* 💪🏼 More robust message confirmations handling <https://github.com/status-im/status-react/pull/12824>
|
||||
* 📶 Allow sending messages when offline <https://github.com/status-im/status-react/issues/11889>
|
||||
#### Improvements on device pairing
|
||||
* 🔔💻 Notification in activity centre now sync across devices <https://github.com/status-im/status-react/issues/12571>
|
||||
* ✅💻 Sync read messages across devices <https://github.com/status-im/status-react/pull/12698>
|
||||
#### Network settings improvements
|
||||
* ✨ Add Binance Smart chain <https://github.com/status-im/status-react/pull/12809>
|
||||
* ♏︎ Added custom network symbol <https://github.com/status-im/status-react/commit/c16b0860ec921a61c119857de27c6f29e301e4f6>
|
||||
* 💰 Network fee on xDai chain <https://github.com/status-im/status-react/pull/12845>
|
||||
* 📇 Support tx history (in a way) when on BSC chains <https://github.com/status-im/status-react/pull/12843>
|
||||
* 🙅🏻 Remove POA network from the list <https://github.com/status-im/status-react/pull/12887>
|
||||
|
||||
### Bug Fixes
|
||||
* Fix activity center community invite preview <https://github.com/status-im/status-react/pull/12803>
|
||||
* Missing notifications for some contacts <https://github.com/status-im/status-react/issues/12776>
|
||||
* Fixes scrolling issues on the 'Max priority fee' bottom sheet <https://github.com/status-im/status-react/issues/12530>
|
||||
* Handle Keycard timeout on iOS 15 <https://github.com/status-im/status-react/pull/12826>
|
||||
* Allow user to be reinvited to the same group after leaving <https://github.com/status-im/status-react/pull/12814>
|
||||
* Fix for "TypeError: Network request failed" when switching to Goerli network <https://github.com/status-im/status-react/issues/11964>
|
||||
* Fix for Spin of death on adding custom NFT token contract <https://github.com/status-im/status-react/issues/12365>
|
||||
* Changing screen orientation results in breaking images / layout <https://github.com/status-im/status-react/issues/12858>
|
||||
|
||||
|
||||
## 1.17
|
||||
|
||||
### For iOS and Android
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="alert_text">#ffffff</color>
|
||||
</resources>
|
||||
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="alert_text">#000000</color>
|
||||
</resources>
|
||||
@@ -8,6 +8,7 @@
|
||||
<item name="android:forceDarkAllowed">true</item>
|
||||
<item name="android:windowTranslucentStatus">false</item>
|
||||
<item name="android:statusBarColor">?attr/backgroundColor</item>
|
||||
<item name="android:alertDialogTheme">@style/AlertDialogTheme</item>
|
||||
</style>
|
||||
|
||||
<style name="LightTheme" parent="AppTheme">
|
||||
@@ -21,4 +22,9 @@
|
||||
<item name="backgroundColor">#000000</item>
|
||||
<item name="android:windowLightStatusBar">false</item>
|
||||
</style>
|
||||
|
||||
<style name="AlertDialogTheme" parent="Base.Theme.AppCompat.Light.Dialog.Alert">
|
||||
<item name="android:textColor">@color/alert_text</item>
|
||||
<item name="android:textColorPrimary">@color/alert_text</item>
|
||||
</style>
|
||||
</resources>
|
||||
|
||||
@@ -3,15 +3,15 @@ pipeline {
|
||||
agent { label 'linux' }
|
||||
|
||||
parameters {
|
||||
string(
|
||||
name: 'NETWORK',
|
||||
description: 'Name of test network to use.',
|
||||
defaultValue: 'ropsten',
|
||||
)
|
||||
string(
|
||||
name: 'APK_NAME',
|
||||
description: 'Filename of APK uploaded to SauceLabs.',
|
||||
)
|
||||
string(
|
||||
name: 'KEYWORD_EXPRESSION',
|
||||
description: 'This will run tests which contain names that match the given string expression (Optional)',
|
||||
defaultValue: '',
|
||||
)
|
||||
}
|
||||
|
||||
options {
|
||||
@@ -56,8 +56,8 @@ pipeline {
|
||||
--rerun_count=2 \
|
||||
--testrail_report=True \
|
||||
-m testrail_id \
|
||||
-m "not upgrade" \
|
||||
--network=${params.NETWORK} \
|
||||
-m \"not upgrade\" \
|
||||
-k \"${params.KEYWORD_EXPRESSION}\" \
|
||||
--apk=${params.APK_NAME}
|
||||
"""
|
||||
}
|
||||
|
||||
@@ -8,15 +8,10 @@ pipeline {
|
||||
description: 'Name of the branch to checkout and build.',
|
||||
defaultValue: 'develop',
|
||||
)
|
||||
string(
|
||||
name: 'NETWORK',
|
||||
description: 'Name of test network to use.',
|
||||
defaultValue: 'ropsten',
|
||||
)
|
||||
string(
|
||||
name: 'TEST_MARKERS',
|
||||
description: 'Marker expression for matching tests to run.',
|
||||
defaultValue: 'critical or high',
|
||||
defaultValue: '',
|
||||
)
|
||||
string(
|
||||
name: 'APK_NAME',
|
||||
@@ -26,9 +21,14 @@ pipeline {
|
||||
name: 'PR_ID',
|
||||
description: 'ID of the Pull Request triggering this build.',
|
||||
)
|
||||
string(
|
||||
name: 'KEYWORD_EXPRESSION',
|
||||
description: 'This will run tests which contain names that match the given string expression (Optional)',
|
||||
defaultValue: '',
|
||||
)
|
||||
string(
|
||||
name: 'TR_CASE_IDS',
|
||||
description: 'IDs of the TestRail case, separated by a comma. (Optional)',
|
||||
description: 'IDs of the TestRail case, separated by a comma (Optional)',
|
||||
defaultValue: '',
|
||||
)
|
||||
}
|
||||
@@ -91,8 +91,8 @@ pipeline {
|
||||
--numprocesses 15 \
|
||||
--rerun_count=2 \
|
||||
--testrail_report=True \
|
||||
-m "${params.TEST_MARKERS}" \
|
||||
--network=${params.NETWORK} \
|
||||
-m \"${params.TEST_MARKERS}\" \
|
||||
-k \"${params.KEYWORD_EXPRESSION}\" \
|
||||
--apk=${params.APK_NAME} \
|
||||
--build=PR-${params.PR_ID} \
|
||||
--pr_number=${params.PR_ID} \
|
||||
|
||||
@@ -3,11 +3,6 @@ pipeline {
|
||||
agent { label 'linux' }
|
||||
|
||||
parameters {
|
||||
string(
|
||||
name: 'NETWORK',
|
||||
description: 'Name of test network to use',
|
||||
defaultValue: 'ropsten',
|
||||
)
|
||||
string(
|
||||
name: 'APK_NAME',
|
||||
description: 'Filename of APK uploaded to SauceLabs (base for upgrade, usually release build)',
|
||||
@@ -16,6 +11,16 @@ pipeline {
|
||||
name: 'APK_NAME_UPGRADE',
|
||||
description: 'Filename of APK of upgraded application (installed on top of base)',
|
||||
)
|
||||
string(
|
||||
name: 'KEYWORD_EXPRESSION',
|
||||
description: 'This will run tests which contain names that match the given string expression (Optional)',
|
||||
defaultValue: '',
|
||||
)
|
||||
string(
|
||||
name: 'TR_CASE_IDS',
|
||||
description: 'IDs of the TestRail case, separated by a comma (Optional)',
|
||||
defaultValue: '',
|
||||
)
|
||||
}
|
||||
|
||||
options {
|
||||
@@ -32,7 +37,12 @@ pipeline {
|
||||
} }
|
||||
}
|
||||
stage('Test') {
|
||||
steps {
|
||||
steps { script {
|
||||
/* for managing optional arguments */
|
||||
def extraPytestOpts = ''
|
||||
if (params.TR_CASE_IDS != '') {
|
||||
extraPytestOpts = "--run_testrail_ids='${params.TR_CASE_IDS}'"
|
||||
}
|
||||
withCredentials([
|
||||
usernamePassword(
|
||||
credentialsId: 'test-rail-api',
|
||||
@@ -56,18 +66,19 @@ pipeline {
|
||||
dir('test/appium/tests') {
|
||||
sh """
|
||||
python3 -m pytest \
|
||||
-m upgrade \
|
||||
-m "upgrade" \
|
||||
-k \"${params.KEYWORD_EXPRESSION}\" \
|
||||
--numprocesses 15 \
|
||||
--rerun_count=2 \
|
||||
--testrail_report=True \
|
||||
--network=${params.NETWORK} \
|
||||
--apk=${params.APK_NAME} \
|
||||
--apk_upgrade=${params.APK_NAME_UPGRADE}
|
||||
--apk_upgrade=${params.APK_NAME_UPGRADE} \
|
||||
${extraPytestOpts}
|
||||
"""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} }
|
||||
}
|
||||
|
||||
post {
|
||||
|
||||
+5
-1
@@ -163,4 +163,8 @@ used for some abi encoding primitives
|
||||
|
||||
## "rn-emoji-keyboard": "https://github.com/status-im/rn-emoji-keyboard"
|
||||
|
||||
Used for taking emoji input, for custom emoji thumbnails for community channels
|
||||
Used for taking emoji input, for custom emoji thumbnails for community channels
|
||||
|
||||
## "react-native-draggable-flatlist": "https://github.com/computerjazz/react-native-draggable-flatlist"
|
||||
|
||||
A drag-and-drop-enabled FlatList component for React Native
|
||||
|
||||
+3
-3
@@ -230,7 +230,7 @@ PODS:
|
||||
- React
|
||||
- react-native-status (1.0.0):
|
||||
- React
|
||||
- react-native-status-keycard (2.5.36):
|
||||
- react-native-status-keycard (2.5.37):
|
||||
- Keycard
|
||||
- React
|
||||
- react-native-webview (11.3.0):
|
||||
@@ -626,7 +626,7 @@ SPEC CHECKSUMS:
|
||||
FBLazyVector: 3bb422f41b18121b71783a905c10e58606f7dc3e
|
||||
FBReactNativeSpec: f2c97f2529dd79c083355182cc158c9f98f4bd6e
|
||||
Folly: b73c3869541e86821df3c387eb0af5f65addfab4
|
||||
glog: 5bc68409594b19a3e5c5cbced7b1ecf61053b709
|
||||
glog: 61334f8bdb4deea07543d4fbac3fb5948e78a7a5
|
||||
Keycard: dd96182888da0aacf4de821b641103143bbb26cc
|
||||
libwebp: 98a37e597e40bfdb4c911fc98f2c53d0b12d05fc
|
||||
Permission-Camera: afad27bf90337684d4a86f3825112d648c8c4d3b
|
||||
@@ -653,7 +653,7 @@ SPEC CHECKSUMS:
|
||||
react-native-slider: 12bd76d3d568c9c5500825db54123d44b48e4ad4
|
||||
react-native-splash-screen: 200d11d188e2e78cea3ad319964f6142b6384865
|
||||
react-native-status: 45dbf1302ce3c258b459dfab137cd1c2c68c295d
|
||||
react-native-status-keycard: eb84554a23315510948613a9467e7e3481be340c
|
||||
react-native-status-keycard: 961d01ca190889ddf220206822fd752f8f4f3f7a
|
||||
react-native-webview: af9990b21a9aeafa8e8347746eb4116c0de086af
|
||||
React-RCTActionSheet: 89a0ca9f4a06c1f93c26067af074ccdce0f40336
|
||||
React-RCTAnimation: 1bde3ecc0c104c55df246eda516e0deb03c4e49b
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
"react-native-dark-mode": "^0.2.2",
|
||||
"react-native-device-info": "^7.4.0",
|
||||
"react-native-dialogs": "^1.0.4",
|
||||
"react-native-draggable-flatlist": "^3.0.3",
|
||||
"react-native-fast-image": "8.5.11",
|
||||
"react-native-fetch-polyfill": "^1.1.2",
|
||||
"react-native-fs": "^2.14.1",
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 527 B |
Binary file not shown.
|
After Width: | Height: | Size: 899 B |
Binary file not shown.
|
After Width: | Height: | Size: 196 B |
Binary file not shown.
|
After Width: | Height: | Size: 250 B |
@@ -206,6 +206,9 @@
|
||||
(def rn-emoji-keyboard
|
||||
#js {:EmojiKeyboard #js {}})
|
||||
|
||||
(def react-native-draggable-flatlist
|
||||
#js {:default #js {}})
|
||||
|
||||
;; Update i18n_resources.cljs
|
||||
(defn mock [module]
|
||||
(case module
|
||||
@@ -239,6 +242,7 @@
|
||||
"@react-native-community/push-notification-ios" push-notification-ios
|
||||
"react-native-camera-kit" react-native-camera-kit
|
||||
"rn-emoji-keyboard" rn-emoji-keyboard
|
||||
"react-native-draggable-flatlist" react-native-draggable-flatlist
|
||||
"./fleets.js" default-fleets
|
||||
"./chats.js" default-chats
|
||||
"../translations/ar.json" (js/JSON.parse (slurp "./translations/ar.json"))
|
||||
|
||||
@@ -49,15 +49,15 @@
|
||||
:hold hold
|
||||
:disabled disabled}]]]))))
|
||||
|
||||
(defn switch-view [{:keys [transition hold disabled]}]
|
||||
(defn switch-view [{:keys [transition hold disabled value]}]
|
||||
[animated/view {:style (styles/switch-style transition disabled)
|
||||
:accessibility-label :switch
|
||||
:accessibility-label (str "switch-" (if value "on" "off"))
|
||||
:accessibility-role :switch}
|
||||
[animated/view {:style (styles/switch-bullet-style transition hold)}]])
|
||||
|
||||
(defn radio-view [{:keys [transition hold disabled]}]
|
||||
(defn radio-view [{:keys [transition hold disabled value]}]
|
||||
[animated/view {:style (styles/radio-style transition disabled)
|
||||
:accessibility-label :radio
|
||||
:accessibility-label (str "radio-" (if value "on" "off"))
|
||||
:accessibility-role :radio}
|
||||
[animated/view {:style (styles/radio-bullet-style transition hold)}]])
|
||||
|
||||
@@ -67,15 +67,15 @@
|
||||
[rn/touchable-without-feedback
|
||||
{:on-press (when (and onChange (not disabled)) onChange)}
|
||||
[rn/view {:style (styles/checkbox-style value disabled)
|
||||
:accessibility-label :checkbox
|
||||
:accessibility-label (str "checkbox-" (if value "on" "off"))
|
||||
:accessibility-role :checkbox}
|
||||
[rn/view {:style (styles/check-icon-style value)}
|
||||
[icons/tiny-icon :tiny-icons/tiny-check {:color colors/white}]]]])))
|
||||
|
||||
(defn animated-checkbox-view [{:keys [transition hold disabled]}]
|
||||
(defn animated-checkbox-view [{:keys [transition hold disabled value]}]
|
||||
[animated/view
|
||||
{:style (styles/animated-checkbox-style transition disabled)
|
||||
:accessibility-label :checkbox
|
||||
:accessibility-label (str "checkbox-" (if value "on" "off"))
|
||||
:accessibility-role :checkbox}
|
||||
[animated/view {:style (styles/animated-check-icon-style transition hold)}
|
||||
[icons/tiny-icon :tiny-icons/tiny-check {:color colors/white}]]])
|
||||
|
||||
@@ -55,13 +55,13 @@
|
||||
:small :base
|
||||
:large))
|
||||
|
||||
(defn container [{:keys [size]} & children]
|
||||
(defn container [{:keys [size container-style]} & children]
|
||||
(into [rn/view {:style (merge (:tiny spacing/padding-horizontal)
|
||||
{:min-height (size->container-size size)
|
||||
:padding-vertical 8
|
||||
:flex-direction :row
|
||||
:align-items :center
|
||||
:justify-content :space-between})}]
|
||||
:justify-content :space-between} container-style)}]
|
||||
children))
|
||||
|
||||
(defn icon-column
|
||||
@@ -197,17 +197,19 @@
|
||||
left-side-alignment icon-color icon-bg-color
|
||||
title subtitle subtitle-secondary active on-press on-long-press chevron size text-size
|
||||
accessory-text accessibility-label title-accessibility-label accessory-style
|
||||
haptic-feedback haptic-type error animated animated-accessory? title-text-weight]
|
||||
:or {subtitle-max-lines 1
|
||||
theme :main
|
||||
haptic-feedback true
|
||||
animated platform/ios?
|
||||
haptic-type :selection}}]
|
||||
haptic-feedback haptic-type error animated animated-accessory? title-text-weight container-style
|
||||
active-background-enabled]
|
||||
:or {subtitle-max-lines 1
|
||||
theme :main
|
||||
haptic-feedback true
|
||||
animated platform/ios?
|
||||
active-background-enabled true
|
||||
haptic-type :selection}}]
|
||||
(let [theme (if disabled :disabled theme)
|
||||
{:keys [text-color active-background passive-background]}
|
||||
(themes theme)
|
||||
icon-color (or icon-color (:icon-color (themes theme)))
|
||||
icon-bg-color (or icon-bg-color (:icon-bg-color (themes theme)))
|
||||
icon-color (or icon-color (:icon-color (themes theme)))
|
||||
icon-bg-color (or icon-bg-color (:icon-bg-color (themes theme)))
|
||||
optional-haptic (fn []
|
||||
(when haptic-feedback
|
||||
(haptic/trigger haptic-type)))
|
||||
@@ -223,7 +225,7 @@
|
||||
[component
|
||||
(merge {:type :list-item
|
||||
:disabled disabled
|
||||
:bg-color active-background
|
||||
:bg-color (when active-background-enabled active-background)
|
||||
:accessibility-label accessibility-label}
|
||||
(when on-press
|
||||
{:on-press (fn []
|
||||
@@ -233,7 +235,7 @@
|
||||
{:on-long-press (fn []
|
||||
(optional-haptic)
|
||||
(on-long-press))}))
|
||||
[container {:size size}
|
||||
[container {:size size :container-style container-style}
|
||||
[left-side {:icon-color icon-color
|
||||
:text-color (if on-press
|
||||
text-color
|
||||
|
||||
+23
-10
@@ -5,7 +5,10 @@
|
||||
["react-native" :as rn]
|
||||
["@react-native-community/hooks" :as hooks]
|
||||
["react-native-navigation" :refer (Navigation)]
|
||||
["rn-emoji-keyboard" :refer (EmojiKeyboard)]))
|
||||
["rn-emoji-keyboard" :refer (EmojiKeyboard)]
|
||||
["react-native-draggable-flatlist" :default DraggableFlatList]))
|
||||
|
||||
(def rn-draggable-flatlist (reagent/adapt-react-class DraggableFlatList))
|
||||
|
||||
(def emoji-keyboard (reagent/adapt-react-class EmojiKeyboard))
|
||||
|
||||
@@ -107,7 +110,13 @@
|
||||
|
||||
(defn- wrap-render-fn [f render-data]
|
||||
(fn [data]
|
||||
(reagent/as-element [f (.-item ^js data) (.-index ^js data) (.-separators ^js data) render-data])))
|
||||
(reagent/as-element [f (.-item ^js data) (.-index ^js data)
|
||||
(.-separators ^js data) render-data
|
||||
(.-isActive ^js data) (.-drag ^js data)])))
|
||||
|
||||
(defn- wrap-on-drag-end-fn [f]
|
||||
(fn [data]
|
||||
(f (.-from ^js data) (.-to ^js data) (.-data ^js data))))
|
||||
|
||||
(defn- wrap-key-fn [f]
|
||||
(fn [data index]
|
||||
@@ -115,19 +124,23 @@
|
||||
(f data index)))
|
||||
|
||||
(defn base-list-props
|
||||
[{:keys [key-fn render-fn empty-component header footer separator data render-data] :as props}]
|
||||
[{:keys [key-fn render-fn empty-component header footer separator data render-data on-drag-end-fn] :as props}]
|
||||
(merge {:data (to-array data)}
|
||||
(when key-fn {:keyExtractor (wrap-key-fn key-fn)})
|
||||
(when render-fn {:renderItem (wrap-render-fn render-fn render-data)})
|
||||
(when separator {:ItemSeparatorComponent (fn [] (reagent/as-element separator))})
|
||||
(when empty-component {:ListEmptyComponent (fn [] (reagent/as-element empty-component))})
|
||||
(when header {:ListHeaderComponent (reagent/as-element header)})
|
||||
(when footer {:ListFooterComponent (reagent/as-element footer)})
|
||||
(dissoc props :data :header :footer :empty-component :separator :render-fn :key-fn)))
|
||||
(when key-fn {:keyExtractor (wrap-key-fn key-fn)})
|
||||
(when render-fn {:renderItem (wrap-render-fn render-fn render-data)})
|
||||
(when separator {:ItemSeparatorComponent (fn [] (reagent/as-element separator))})
|
||||
(when empty-component {:ListEmptyComponent (fn [] (reagent/as-element empty-component))})
|
||||
(when header {:ListHeaderComponent (reagent/as-element header)})
|
||||
(when footer {:ListFooterComponent (reagent/as-element footer)})
|
||||
(when on-drag-end-fn {:onDragEnd (wrap-on-drag-end-fn on-drag-end-fn)})
|
||||
(dissoc props :data :header :footer :empty-component :separator :render-fn :key-fn :on-drag-end-fn)))
|
||||
|
||||
(defn flat-list [props]
|
||||
[rn-flat-list (base-list-props props)])
|
||||
|
||||
(defn draggable-flat-list [props]
|
||||
[rn-draggable-flatlist (base-list-props props)])
|
||||
|
||||
(defn animated-flat-list [props]
|
||||
[animated-flat-list-class (base-list-props props)])
|
||||
;; Hooks
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
|
||||
(fx/defn join-public-chat
|
||||
[cofx chat-name]
|
||||
(chat/start-public-chat cofx chat-name {:navigation-reset? true}))
|
||||
(chat/start-public-chat cofx chat-name nil))
|
||||
|
||||
(fx/defn accept-pack
|
||||
{:events [::accept-pack]}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
(def key->string str)
|
||||
|
||||
(defn- set-item! [key value]
|
||||
(defn set-item! [key value]
|
||||
(-> ^js async-storage
|
||||
(.setItem (key->string key)
|
||||
(clj->transit value))
|
||||
|
||||
@@ -199,15 +199,23 @@
|
||||
|
||||
(fx/defn close-chat
|
||||
{:events [:close-chat]}
|
||||
[{:keys [db] :as cofx} target-chat-id]
|
||||
(let [chat-id (:current-chat-id db)]
|
||||
(if (:ignore-close-chat db)
|
||||
{:db (dissoc db :ignore-close-chat)}
|
||||
(when (= target-chat-id chat-id)
|
||||
(chat.state/reset-visible-item)
|
||||
(fx/merge cofx
|
||||
{:db (dissoc db :current-chat-id)}
|
||||
(offload-messages chat-id))))))
|
||||
[{:keys [db] :as cofx}]
|
||||
(let [chat-id (:current-chat-id db)
|
||||
navigate-after-home-to-chat (:navigate-after-home-to-chat db)]
|
||||
(chat.state/reset-visible-item)
|
||||
(if navigate-after-home-to-chat
|
||||
{:db (dissoc db :navigate-after-home-to-chat)}
|
||||
(fx/merge cofx
|
||||
{:db (dissoc db :current-chat-id)}
|
||||
(offload-messages chat-id)))))
|
||||
|
||||
(fx/defn force-close-chat
|
||||
[{:keys [db] :as cofx} chat-id]
|
||||
(do
|
||||
(chat.state/reset-visible-item)
|
||||
(fx/merge cofx
|
||||
{:db (dissoc db :current-chat-id)}
|
||||
(offload-messages chat-id))))
|
||||
|
||||
(fx/defn remove-chat
|
||||
"Removes chat completely from app, producing all necessary effects for that"
|
||||
@@ -234,19 +242,21 @@
|
||||
(fx/defn navigate-to-chat
|
||||
"Takes coeffects map and chat-id, returns effects necessary for navigation and preloading data"
|
||||
{:events [:chat.ui/navigate-to-chat]}
|
||||
[{db :db :as cofx} chat-id dont-reset?]
|
||||
(fx/merge cofx
|
||||
(close-chat (:current-chat-id db))
|
||||
(fn [{:keys [db]}]
|
||||
{:db (assoc db :current-chat-id chat-id :ignore-close-chat true)})
|
||||
(preload-chat-data chat-id)
|
||||
#(when (group-chat? cofx chat-id)
|
||||
(loading/load-chat % chat-id))
|
||||
#(when-not dont-reset?
|
||||
(navigation/change-tab % :chat))
|
||||
#(when-not dont-reset?
|
||||
(navigation/pop-to-root-tab % :chat-stack))
|
||||
(navigation/navigate-to-cofx :chat nil)))
|
||||
[{db :db :as cofx} chat-id]
|
||||
(let [home-view? (= (get db :view-id) :home)]
|
||||
(fx/merge cofx
|
||||
(close-chat)
|
||||
(force-close-chat chat-id)
|
||||
(fn [{:keys [db]}]
|
||||
{:db (assoc db :current-chat-id chat-id :navigate-after-home-to-chat (not home-view?))})
|
||||
(preload-chat-data chat-id)
|
||||
#(when (group-chat? cofx chat-id)
|
||||
(loading/load-chat % chat-id))
|
||||
#(when-not home-view?
|
||||
(navigation/change-tab % :chat))
|
||||
#(when-not home-view?
|
||||
(navigation/pop-to-root-tab % :chat-stack))
|
||||
(navigation/navigate-to-cofx :chat nil))))
|
||||
|
||||
(fx/defn handle-clear-history-response
|
||||
{:events [::history-cleared]}
|
||||
@@ -294,14 +304,11 @@
|
||||
|
||||
(fx/defn handle-public-chat-created
|
||||
{:events [::public-chat-created]}
|
||||
[{:keys [db]} chat-id {:keys [dont-navigate?]} response]
|
||||
(let [chat (chats-store/<-rpc (first (:chats response)))
|
||||
db-with-chat {:db (-> db
|
||||
(assoc-in [:chats chat-id] chat)
|
||||
(update :chats-home-list conj chat-id))}]
|
||||
(if dont-navigate?
|
||||
db-with-chat
|
||||
(assoc db-with-chat :dispatch [:chat.ui/navigate-to-chat chat-id]))))
|
||||
[{:keys [db]} chat-id _ response]
|
||||
{:db (-> db
|
||||
(assoc-in [:chats chat-id] (chats-store/<-rpc (first (:chats response))))
|
||||
(update :chats-home-list conj chat-id))
|
||||
:dispatch [:chat.ui/navigate-to-chat chat-id]})
|
||||
|
||||
(fx/defn create-public-chat-go [_ chat-id opts]
|
||||
{::json-rpc/call [{:method "wakuext_createPublicChat"
|
||||
@@ -312,11 +319,10 @@
|
||||
(fx/defn start-public-chat
|
||||
"Starts a new public chat"
|
||||
{:events [:chat.ui/start-public-chat]}
|
||||
[cofx topic {:keys [dont-navigate? profile-public-key] :as opts}]
|
||||
[cofx topic {:keys [profile-public-key] :as opts}]
|
||||
(if (or (new-public-chat.db/valid-topic? topic) profile-public-key)
|
||||
(if (active-chat? cofx topic)
|
||||
(when-not dont-navigate?
|
||||
(navigate-to-chat cofx topic false))
|
||||
(navigate-to-chat cofx topic)
|
||||
(create-public-chat-go
|
||||
cofx
|
||||
topic
|
||||
|
||||
@@ -42,11 +42,15 @@
|
||||
[{:keys [db]} community-id]
|
||||
{:db (community-failed-to-resolve db community-id)})
|
||||
|
||||
(defn community-link [id]
|
||||
(str "https://join.status.im/c/" id))
|
||||
|
||||
(fx/defn handle-community-resolved
|
||||
{:events [::community-resolved]}
|
||||
[{:keys [db] :as cofx} community-id community]
|
||||
(fx/merge cofx
|
||||
{:db (community-resolved db community-id)}
|
||||
{:db (community-resolved db community-id)
|
||||
:dispatch [::cache-link-preview-data (community-link community-id) community]}
|
||||
(models.communities/handle-community community)))
|
||||
|
||||
(fx/defn resolve-community-info
|
||||
@@ -78,9 +82,6 @@
|
||||
:link-previews-cache
|
||||
(assoc (get multiaccount :link-previews-cache {}) site data)))
|
||||
|
||||
(defn community-link [id]
|
||||
(str "https://join.status.im/c/" id))
|
||||
|
||||
(defn cache-community-preview-data
|
||||
[{:keys [id] :as community}]
|
||||
(re-frame/dispatch [::cache-link-preview-data
|
||||
|
||||
@@ -9,7 +9,8 @@
|
||||
[status-im.utils.utils :as utils]
|
||||
[status-im.native-module.core :as status]
|
||||
[quo.react-native :as rn]
|
||||
[quo.react :as react]))
|
||||
[quo.react :as react]
|
||||
[status-im.multiaccounts.core :as multiaccounts]))
|
||||
|
||||
(def at-sign "@")
|
||||
|
||||
@@ -170,11 +171,55 @@
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(defn add-searchable-phrases
|
||||
[{:keys [alias name nickname] :as user}]
|
||||
(reduce
|
||||
(fn [user s]
|
||||
(if (nil? s)
|
||||
user
|
||||
(let [new-words (concat
|
||||
[s]
|
||||
(rest (string/split s " ")))]
|
||||
(update user :searchable-phrases (fnil concat []) new-words))))
|
||||
user
|
||||
[alias name nickname]))
|
||||
|
||||
(defn add-searchable-phrases-to-contact
|
||||
[{:keys [alias name added? blocked? identicon public-key nickname]} community-chat?]
|
||||
(when (and alias
|
||||
(not (string/blank? alias))
|
||||
(or name
|
||||
nickname
|
||||
added?
|
||||
community-chat?)
|
||||
(not blocked?))
|
||||
(add-searchable-phrases
|
||||
{:alias alias
|
||||
:name (or (utils/safe-replace name ".stateofus.eth" "") alias)
|
||||
:identicon identicon
|
||||
:nickname nickname
|
||||
:public-key public-key})))
|
||||
|
||||
(defn mentionable-commmunity-members [contacts my-public-key community-members]
|
||||
(reduce (fn [acc identity]
|
||||
(let [contact (multiaccounts/contact-by-identity
|
||||
contacts identity)
|
||||
contact (if (string/blank? (:alias contact))
|
||||
(assoc contact :alias
|
||||
(get-in contact [:names :three-words-name]))
|
||||
contact)
|
||||
mentionable-contact (add-searchable-phrases-to-contact
|
||||
contact true)]
|
||||
(if (nil? mentionable-contact) acc
|
||||
(assoc acc identity mentionable-contact))))
|
||||
{}
|
||||
(keys (dissoc community-members my-public-key))))
|
||||
|
||||
(defn get-mentionable-users
|
||||
[{{:keys [current-chat-id]
|
||||
:contacts/keys [contacts] :as db} :db}]
|
||||
(let [{:keys [chat-type users] :as chat}
|
||||
(get-in db [:chats current-chat-id])
|
||||
(let [{:keys [chat-type community-id users] :as chat} (get-in db [:chats current-chat-id])
|
||||
{:keys [name preferred-name public-key]} (:multiaccount db)
|
||||
chat-specific-suggestions
|
||||
(cond
|
||||
(= chat-type constants/private-group-chat-type)
|
||||
@@ -200,9 +245,12 @@
|
||||
current-chat-id
|
||||
(contact.db/public-key->contact contacts current-chat-id))
|
||||
|
||||
:else users)
|
||||
{:keys [name preferred-name public-key]}
|
||||
(:multiaccount db)]
|
||||
(= chat-type constants/community-chat-type)
|
||||
(merge users (mentionable-commmunity-members
|
||||
contacts public-key
|
||||
(get-in db [:communities community-id :members])))
|
||||
|
||||
:else users)]
|
||||
(reduce
|
||||
(fn [acc [key {:keys [alias name identicon]}]]
|
||||
(let [name (utils/safe-replace name ".stateofus.eth" "")]
|
||||
@@ -634,19 +682,6 @@
|
||||
[_ ref cursor]
|
||||
{::reset-text-input-cursor [ref cursor]})
|
||||
|
||||
(defn add-searchable-phrases
|
||||
[{:keys [alias name nickname] :as user}]
|
||||
(reduce
|
||||
(fn [user s]
|
||||
(if (nil? s)
|
||||
user
|
||||
(let [new-words (concat
|
||||
[s]
|
||||
(rest (string/split s " ")))]
|
||||
(update user :searchable-phrases (fnil concat []) new-words))))
|
||||
user
|
||||
[alias name nickname]))
|
||||
|
||||
(defn is-valid-terminating-character? [c]
|
||||
(case c
|
||||
"\t" true ; tab
|
||||
|
||||
@@ -288,7 +288,7 @@
|
||||
(fx/defn edit-channel
|
||||
{:events [::edit-channel-confirmation-pressed]}
|
||||
[{:keys [db] :as cofx}]
|
||||
(let [{:keys [name description color community-id emoji edit-channel-id category-id]}
|
||||
(let [{:keys [name description color community-id emoji edit-channel-id category-id position]}
|
||||
(get db :communities/create-channel)]
|
||||
{::json-rpc/call [{:method "wakuext_editCommunityChat"
|
||||
:params [community-id
|
||||
@@ -298,6 +298,7 @@
|
||||
:color color
|
||||
:emoji emoji}
|
||||
:category_id category-id
|
||||
:position position
|
||||
:permissions {:access constants/community-channel-access-no-membership}}]
|
||||
:js-response true
|
||||
:on-success #(re-frame/dispatch [::community-channel-edited %])
|
||||
@@ -345,7 +346,7 @@
|
||||
|
||||
(fx/defn edit-channel-pressed
|
||||
{:events [::edit-channel-pressed]}
|
||||
[{:keys [db] :as cofx} community-id chat-name description color emoji chat-id category-id]
|
||||
[{:keys [db] :as cofx} community-id chat-name description color emoji chat-id category-id position]
|
||||
(let [{:keys [color emoji]} (if (string/blank? emoji)
|
||||
(rand-nth emoji-thumbnail-styles/emoji-picker-default-thumbnails)
|
||||
{:color color :emoji emoji})]
|
||||
@@ -356,7 +357,8 @@
|
||||
:community-id community-id
|
||||
:emoji emoji
|
||||
:edit-channel-id chat-id
|
||||
:category-id category-id})}
|
||||
:category-id category-id
|
||||
:position position})}
|
||||
(navigation/open-modal :edit-community-channel nil))))
|
||||
|
||||
(fx/defn community-created
|
||||
@@ -564,6 +566,15 @@
|
||||
:on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])
|
||||
:on-error #(log/error "failed to remove chat from community" %)}]}))
|
||||
|
||||
(fx/defn delete-community-chat
|
||||
{:events [:delete-community-chat]}
|
||||
[_ community-id chat-id]
|
||||
{::json-rpc/call [{:method "wakuext_deleteCommunityChat"
|
||||
:params [community-id chat-id]
|
||||
:js-response true
|
||||
:on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])
|
||||
:on-error #(log/error "failed to delete community chat" %)}]})
|
||||
|
||||
(fx/defn delete-category
|
||||
{:events [:delete-community-category]}
|
||||
[_ community-id category-id]
|
||||
@@ -592,6 +603,18 @@
|
||||
(navigation/navigate-back)
|
||||
(remove-chat-from-category community-id id categoryID))))
|
||||
|
||||
(fx/defn reorder-category-chat
|
||||
{:events [::reorder-community-category-chat]}
|
||||
[_ community-id category-id chat-id new-position]
|
||||
{::json-rpc/call [{:method "wakuext_reorderCommunityChat"
|
||||
:params [{:communityId community-id
|
||||
:categoryId category-id
|
||||
:chatId chat-id
|
||||
:position new-position}]
|
||||
:js-response true
|
||||
:on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])
|
||||
:on-error #(log/error "failed to reorder community category chat" %)}]})
|
||||
|
||||
(fx/defn reorder-category
|
||||
{:events [::reorder-community-category]}
|
||||
[_ community-id category-id new-position]
|
||||
|
||||
@@ -146,6 +146,7 @@
|
||||
|
||||
(def ^:const timeline-chat-id "@timeline70bd746ddcc12beb96b2c9d572d0784ab137ffc774f5383e50585a932080b57cca0484b259e61cecbaa33a4c98a300a")
|
||||
|
||||
(def ^:const two-mins (* 2 60))
|
||||
(def ^:const one-day (* 60 60 24))
|
||||
(def ^:const three-days (* one-day 3))
|
||||
(def ^:const one-week (* one-day 7))
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
[status-im.data-store.chats :as chats-store]
|
||||
[status-im.data-store.contacts :as contacts-store]
|
||||
[status-im.navigation :as navigation]
|
||||
[status-im.utils.types :as types]
|
||||
[status-im.notifications-center.core :as notification-center]
|
||||
[status-im.utils.fx :as fx]))
|
||||
|
||||
(fx/defn clean-up-chat
|
||||
@@ -34,13 +36,16 @@
|
||||
(fx/defn contact-blocked
|
||||
{:events [::contact-blocked]}
|
||||
[{:keys [db] :as cofx} {:keys [public-key]} chats]
|
||||
(let [fxs (map #(clean-up-chat public-key %) chats)]
|
||||
(let [fxs (when chats
|
||||
(map #(->> (chats-store/<-rpc %)
|
||||
(clean-up-chat public-key)) (types/js->clj chats)))]
|
||||
(apply fx/merge
|
||||
cofx
|
||||
{:db (-> db
|
||||
(update :chats dissoc public-key)
|
||||
(update :chats-home-list disj public-key)
|
||||
(assoc-in [:contacts/contacts public-key :added] false))}
|
||||
(notification-center/get-activity-center-notifications-count)
|
||||
fxs)))
|
||||
|
||||
(fx/defn block-contact
|
||||
@@ -58,8 +63,10 @@
|
||||
(update :contacts/blocked (fnil conj #{}) public-key)
|
||||
;; update the contact in contacts list
|
||||
(assoc-in [:contacts/contacts public-key] contact))}
|
||||
(contacts-store/block public-key #(do (re-frame/dispatch [::contact-blocked contact (map chats-store/<-rpc %)])
|
||||
(re-frame/dispatch [:hide-popover])))
|
||||
(contacts-store/block
|
||||
public-key #(do (re-frame/dispatch [::contact-blocked contact (.-chats %)])
|
||||
(re-frame/dispatch [:sanitize-messages-and-process-response %])
|
||||
(re-frame/dispatch [:hide-popover])))
|
||||
;; reset navigation to avoid going back to non existing one to one chat
|
||||
(if from-one-to-one-chat?
|
||||
(navigation/pop-to-root-tab :chat-stack)
|
||||
|
||||
@@ -28,7 +28,10 @@
|
||||
:chat-type constants/one-to-one-chat-type
|
||||
:chat-name name
|
||||
:public? false
|
||||
:group-chat false)))
|
||||
:group-chat false)
|
||||
|
||||
:else
|
||||
chat))
|
||||
|
||||
(defn <-rpc [item]
|
||||
(-> item
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
(fx/defn block [_ contact-id on-success]
|
||||
{::json-rpc/call [{:method (json-rpc/call-ext-method "blockContact")
|
||||
:params [contact-id]
|
||||
:js-response true
|
||||
:on-success on-success
|
||||
:on-failure #(log/error "failed to block contact" % contact-id)}]})
|
||||
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
:testnet {:id 3 :name "Ropsten"}
|
||||
:rinkeby {:id 4 :name "Rinkeby"}
|
||||
:xdai {:id 100 :name "xDai"}
|
||||
:poa {:id 99 :name "POA"}
|
||||
:goerli {:id 5 :name "Goerli"}
|
||||
:bsc {:id BSC-mainnet-chain-id
|
||||
:name "BSC"}
|
||||
@@ -57,7 +56,6 @@
|
||||
|
||||
(defn sidechain? [id]
|
||||
(contains? #{(chain-keyword->chain-id :xdai)
|
||||
(chain-keyword->chain-id :poa)
|
||||
(chain-keyword->chain-id :bsc)} id))
|
||||
|
||||
(defn network-with-upstream-rpc? [network]
|
||||
|
||||
@@ -165,6 +165,7 @@
|
||||
"wakuext_reorderCommunityChat" {}
|
||||
"wakuext_editCommunityCategory" {}
|
||||
"wakuext_deleteCommunityCategory" {}
|
||||
"wakuext_deleteCommunityChat" {}
|
||||
"wakuext_ensVerified" {}
|
||||
"wakuext_dismissActivityCenterNotifications" {}
|
||||
"wakuext_acceptActivityCenterNotifications" {}
|
||||
|
||||
@@ -28,10 +28,6 @@
|
||||
:symbol :ETH
|
||||
:symbol-display :ETHri
|
||||
:decimals 18}
|
||||
:poa {:name "POA"
|
||||
:symbol :ETH
|
||||
:symbol-display :POA
|
||||
:decimals 18}
|
||||
:xdai {:name "xDAI"
|
||||
:symbol :ETH
|
||||
:symbol-display :xDAI
|
||||
|
||||
+98
-56
@@ -1,65 +1,66 @@
|
||||
(ns status-im.events
|
||||
(:require [re-frame.core :as re-frame]
|
||||
[status-im.chat.models :as chat]
|
||||
[status-im.i18n.i18n :as i18n]
|
||||
[status-im.mailserver.core :as mailserver]
|
||||
[status-im.multiaccounts.core :as multiaccounts]
|
||||
[status-im.ui.components.react :as react]
|
||||
[status-im.utils.fx :as fx]
|
||||
status-im.utils.logging.core
|
||||
status-im.backup.core
|
||||
[status-im.wallet.core :as wallet]
|
||||
[status-im.keycard.core :as keycard]
|
||||
[status-im.utils.dimensions :as dimensions]
|
||||
[status-im.multiaccounts.biometric.core :as biometric]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.native-module.core :as status]
|
||||
[status-im.ui.components.permissions :as permissions]
|
||||
[status-im.utils.utils :as utils]
|
||||
[status-im.ethereum.json-rpc :as json-rpc]
|
||||
[status-im.anon-metrics.core :as anon-metrics]
|
||||
[status-im.utils.universal-links.core :as universal-links]
|
||||
clojure.set
|
||||
status-im.currency.core
|
||||
status-im.navigation
|
||||
status-im.utils.universal-links.core
|
||||
status-im.wallet.custom-tokens.core
|
||||
status-im.waku.core
|
||||
status-im.wallet.choose-recipient.core
|
||||
status-im.wallet.accounts.core
|
||||
status-im.popover.core
|
||||
status-im.visibility-status-popover.core
|
||||
status-im.visibility-status-updates.core
|
||||
status-im.bottom-sheet.core
|
||||
(:require clojure.set
|
||||
[re-frame.core :as re-frame]
|
||||
status-im.add-new.core
|
||||
status-im.search.core
|
||||
status-im.http.core
|
||||
status-im.profile.core
|
||||
[status-im.anon-metrics.core :as anon-metrics]
|
||||
[status-im.async-storage.core :as async-storage]
|
||||
status-im.backup.core
|
||||
status-im.bootnodes.core
|
||||
[status-im.bottom-sheet.core :as bottom-sheet]
|
||||
status-im.browser.core
|
||||
status-im.browser.permissions
|
||||
[status-im.chat.models :as chat]
|
||||
status-im.chat.models.images
|
||||
status-im.ui.screens.privacy-and-security-settings.events
|
||||
status-im.chat.models.input
|
||||
status-im.chat.models.loading
|
||||
status-im.chat.models.transport
|
||||
[status-im.constants :as constants]
|
||||
status-im.contact.block
|
||||
status-im.contact.chat
|
||||
status-im.contact.core
|
||||
status-im.currency.core
|
||||
[status-im.ethereum.json-rpc :as json-rpc]
|
||||
status-im.ethereum.subscriptions
|
||||
status-im.fleet.core
|
||||
status-im.http.core
|
||||
[status-im.i18n.i18n :as i18n]
|
||||
status-im.init.core
|
||||
[status-im.keycard.core :as keycard]
|
||||
status-im.log-level.core
|
||||
status-im.mailserver.constants
|
||||
[status-im.mailserver.core :as mailserver]
|
||||
[status-im.multiaccounts.biometric.core :as biometric]
|
||||
[status-im.multiaccounts.core :as multiaccounts]
|
||||
status-im.multiaccounts.login.core
|
||||
status-im.multiaccounts.logout.core
|
||||
status-im.multiaccounts.update.core
|
||||
[status-im.native-module.core :as status]
|
||||
[status-im.navigation :as navigation]
|
||||
status-im.notifications-center.core
|
||||
status-im.pairing.core
|
||||
status-im.popover.core
|
||||
status-im.profile.core
|
||||
status-im.search.core
|
||||
status-im.signals.core
|
||||
status-im.stickers.core
|
||||
status-im.transport.core
|
||||
status-im.init.core
|
||||
status-im.log-level.core
|
||||
status-im.mailserver.constants
|
||||
status-im.ethereum.subscriptions
|
||||
status-im.fleet.core
|
||||
status-im.contact.block
|
||||
status-im.contact.core
|
||||
status-im.contact.chat
|
||||
status-im.chat.models.input
|
||||
status-im.chat.models.loading
|
||||
status-im.bootnodes.core
|
||||
status-im.browser.core
|
||||
status-im.browser.permissions
|
||||
status-im.chat.models.transport
|
||||
status-im.notifications-center.core
|
||||
[status-im.navigation :as navigation]))
|
||||
[status-im.ui.components.permissions :as permissions]
|
||||
[status-im.ui.components.react :as react]
|
||||
status-im.ui.screens.privacy-and-security-settings.events
|
||||
[status-im.utils.dimensions :as dimensions]
|
||||
[status-im.utils.fx :as fx]
|
||||
status-im.utils.logging.core
|
||||
[status-im.utils.universal-links.core :as universal-links]
|
||||
[status-im.utils.utils :as utils]
|
||||
status-im.visibility-status-popover.core
|
||||
status-im.visibility-status-updates.core
|
||||
status-im.waku.core
|
||||
status-im.wallet.accounts.core
|
||||
status-im.wallet.choose-recipient.core
|
||||
[status-im.wallet.core :as wallet]
|
||||
status-im.wallet.custom-tokens.core
|
||||
[status-im.navigation.core :as navigation.core]
|
||||
[status-im.multiaccounts.login.core :as login.core]))
|
||||
|
||||
(re-frame/reg-fx
|
||||
:dismiss-keyboard
|
||||
@@ -113,10 +114,35 @@
|
||||
|
||||
(fx/defn system-theme-mode-changed
|
||||
{:events [:system-theme-mode-changed]}
|
||||
[{:keys [db]} theme]
|
||||
(let [cur-theme (get-in db [:multiaccount :appearance])]
|
||||
[{:keys [db] :as cofx} theme]
|
||||
(let [cur-theme (get-in db [:multiaccount :appearance])
|
||||
current-tab (get db :current-tab :chat)
|
||||
view-id (:view-id db)
|
||||
screen-params (get-in db [:navigation/screen-params view-id])
|
||||
root-id @navigation.core/root-id]
|
||||
(navigation.core/dismiss-all-modals)
|
||||
(when (or (nil? cur-theme) (zero? cur-theme))
|
||||
{::multiaccounts/switch-theme (if (= :dark theme) 2 1)})))
|
||||
(fx/merge cofx
|
||||
{::multiaccounts/switch-theme (if (= :dark theme) 2 1)
|
||||
:utils/dispatch-later
|
||||
(cond-> [{:ms 2000 :dispatch
|
||||
(if (= view-id :chat)
|
||||
[:chat.ui/navigate-to-chat (:current-chat-id db)]
|
||||
[:navigate-to view-id screen-params])}]
|
||||
|
||||
(some #(= view-id %) navigation.core/community-screens)
|
||||
(conj {:ms 1000 :dispatch
|
||||
[:navigate-to :community
|
||||
(get-in db [:navigation/screen-params :community])]})
|
||||
|
||||
(= view-id :community-emoji-thumbnail-picker)
|
||||
(conj {:ms 1500 :dispatch
|
||||
[:navigate-to :create-community-channel
|
||||
(get-in db [:navigation/screen-params :create-community-channel])]}))}
|
||||
(bottom-sheet/hide-bottom-sheet)
|
||||
(navigation/init-root root-id)
|
||||
(when (= root-id :chat-stack)
|
||||
(navigation/change-tab current-tab))))))
|
||||
|
||||
(def authentication-options
|
||||
{:reason (i18n/label :t/biometric-auth-reason-login)})
|
||||
@@ -193,8 +219,24 @@
|
||||
(fx/defn on-will-focus
|
||||
{:events [:screens/on-will-focus]
|
||||
:interceptors [anon-metrics/interceptor]}
|
||||
[cofx view-id]
|
||||
[{:keys [db] :as cofx} view-id]
|
||||
(fx/merge cofx
|
||||
(cond
|
||||
(= :chat view-id)
|
||||
{::async-storage/set! {:chat-id (get-in cofx [:db :current-chat-id])
|
||||
:key-uid (get-in cofx [:db :multiaccount :key-uid])}
|
||||
:db (assoc db :screens/was-focused-once? true)}
|
||||
|
||||
(= :login view-id)
|
||||
{}
|
||||
|
||||
(not (get db :screens/was-focused-once?))
|
||||
{:db (assoc db :screens/was-focused-once? true)}
|
||||
|
||||
:else
|
||||
{::async-storage/set! {:chat-id nil
|
||||
:key-uid nil}
|
||||
:db (assoc db :screens/was-focused-once? true)})
|
||||
#(case view-id
|
||||
:keycard-settings (keycard/settings-screen-did-load %)
|
||||
:reset-card (keycard/reset-card-screen-did-load %)
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
[cofx {:keys [chat-id invitation-admin chat-name]}]
|
||||
(if (get-in cofx [:db :chats chat-id])
|
||||
{:dispatch-n [[:accept-all-activity-center-notifications-from-chat chat-id]
|
||||
[:chat.ui/navigate-to-chat chat-id false]]}
|
||||
[:chat.ui/navigate-to-chat chat-id]]}
|
||||
{::json-rpc/call [{:method (json-rpc/call-ext-method "createGroupChatFromInvitation")
|
||||
:params [chat-name chat-id invitation-admin]
|
||||
:js-response true
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
(fx/merge cofx
|
||||
{:db (-> db
|
||||
(assoc-in [:keycard :creating-backup?] backup-type))}
|
||||
(when-not (:multiaccounts/login db)
|
||||
(when (:multiaccount db)
|
||||
(navigation/change-tab :profile))
|
||||
(navigation/navigate-to-cofx :seed-phrase nil)))
|
||||
|
||||
|
||||
@@ -70,7 +70,9 @@
|
||||
(mnemonic/set-mnemonic))
|
||||
(when (= flow :recovery)
|
||||
(onboarding/proceed-with-generating-key)))
|
||||
(recovery/load-pair-screen cofx))))
|
||||
(if (get-in db [:keycard :secrets :password])
|
||||
(onboarding/load-pairing-screen cofx)
|
||||
(recovery/load-pair-screen cofx)))))
|
||||
|
||||
(fx/defn navigate-to-keycard-settings
|
||||
{:events [:profile.ui/keycard-settings-button-pressed]}
|
||||
@@ -523,14 +525,14 @@
|
||||
(fx/merge cofx
|
||||
{:db (assoc-in db [:keycard :card-state] card-state)}
|
||||
(set-setup-step card-state)
|
||||
(common/hide-connection-sheet)
|
||||
|
||||
(when paired?
|
||||
(load-pairing))
|
||||
|
||||
(when (and flow
|
||||
(= card-state :init))
|
||||
(proceed-setup-with-initialized-card flow instance-uid paired?))
|
||||
(if (and flow
|
||||
(= card-state :init))
|
||||
(proceed-setup-with-initialized-card flow instance-uid paired?)
|
||||
(common/hide-connection-sheet))
|
||||
|
||||
(when (= card-state :pre-init)
|
||||
(if (= flow :import)
|
||||
|
||||
@@ -66,7 +66,7 @@
|
||||
:error nil
|
||||
:status nil))
|
||||
:hide-popover nil})
|
||||
(when-not (:multiaccounts/login db)
|
||||
(when (:multiaccount db)
|
||||
(navigation/change-tab :profile))
|
||||
(when-not (:multiaccounts/login db)
|
||||
(if (:popover/popover db)
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
(assoc-in [:keycard :setup-step] :recovery-phrase)
|
||||
(assoc-in [:keycard :secrets :mnemonic] mnemonic))}
|
||||
(common/clear-on-card-connected)
|
||||
(common/hide-connection-sheet)
|
||||
(navigation/navigate-replace :keycard-onboarding-recovery-phrase nil))))
|
||||
|
||||
(fx/defn load-loading-keys-screen
|
||||
|
||||
@@ -236,7 +236,10 @@
|
||||
(assoc-in [:keycard :card-state] :init)
|
||||
(assoc-in [:keycard :setup-step] :secret-keys)
|
||||
(update-in [:keycard :secrets] merge secrets'))}
|
||||
(load-pairing-screen))))
|
||||
(common/show-connection-sheet
|
||||
{:on-card-connected :keycard/get-application-info
|
||||
:on-card-read :keycard/check-card-state
|
||||
:handler (common/get-application-info :keycard/check-card-state)}))))
|
||||
|
||||
(fx/defn on-install-applet-and-init-card-error
|
||||
{:events [:keycard.callback/on-install-applet-and-init-card-error
|
||||
|
||||
@@ -217,9 +217,15 @@
|
||||
:t/keycard-access-reset :t/keycard-backup-success-title))
|
||||
:content (i18n/label (if (= backup-type :recovery-card)
|
||||
:t/keycard-can-use-with-new-passcode :t/keycard-backup-success-body))}}
|
||||
(if (multiaccounts.model/logged-in? cofx)
|
||||
(cond
|
||||
(multiaccounts.model/logged-in? cofx)
|
||||
(navigation/set-stack-root :profile-stack [:my-profile :keycard-settings])
|
||||
(return-to-keycard-login))))
|
||||
|
||||
(:multiaccounts/login db)
|
||||
(return-to-keycard-login)
|
||||
|
||||
:else
|
||||
(navigation/set-stack-root :onboarding [:get-your-keys]))))
|
||||
|
||||
(re-frame/reg-fx
|
||||
::finish-migration
|
||||
|
||||
@@ -184,8 +184,9 @@
|
||||
|
||||
(fx/defn handle-successful-request
|
||||
{:events [::request-success]}
|
||||
[{:keys [db]} response-js]
|
||||
{:db (dissoc db :mailserver/current-request)})
|
||||
[{:keys [db] :as cofx} response-js]
|
||||
{:db (dissoc db :mailserver/current-request)
|
||||
:dispatch [:sanitize-messages-and-process-response response-js]})
|
||||
|
||||
(fx/defn process-next-messages-request
|
||||
{:events [::request-messages]}
|
||||
|
||||
@@ -109,12 +109,15 @@
|
||||
types/json->clj
|
||||
:error
|
||||
string/blank?
|
||||
not)]
|
||||
not)
|
||||
onboarding? (not (or (:multiaccounts/login db) (:multiaccount db)))]
|
||||
(if error?
|
||||
(popover/show-popover cofx {:view :custom-seed-phrase})
|
||||
{::validate-seed-against-key-uid {:seed-phrase (-> db :multiaccounts/key-storage :seed-phrase)
|
||||
;; Unique key-uid of the account for which we are going to move keys
|
||||
:key-uid (or (-> db :multiaccounts/login :key-uid) (-> db :multiaccount :key-uid))}})))
|
||||
:key-uid (or (-> db :multiaccounts/login :key-uid)
|
||||
(-> db :multiaccount :key-uid)
|
||||
(and onboarding? (-> db :keycard :application-info :key-uid)))}})))
|
||||
|
||||
(fx/defn choose-storage-pressed
|
||||
{:events [::choose-storage-pressed]}
|
||||
|
||||
@@ -325,6 +325,19 @@
|
||||
(logging/set-log-level (:log-level multiaccount))
|
||||
(notifications-center/get-activity-center-notifications-count))))
|
||||
|
||||
(re-frame/reg-fx
|
||||
::open-last-chat
|
||||
(fn [key-uid]
|
||||
(async-storage/get-item
|
||||
:chat-id
|
||||
(fn [chat-id]
|
||||
(when chat-id
|
||||
(async-storage/get-item
|
||||
:key-uid
|
||||
(fn [stored-key-uid]
|
||||
(when (= stored-key-uid key-uid)
|
||||
(re-frame/dispatch [:chat.ui/navigate-to-chat chat-id])))))))))
|
||||
|
||||
(fx/defn get-chats-callback
|
||||
{:events [::get-chats-callback]}
|
||||
[{:keys [db] :as cofx}]
|
||||
@@ -339,7 +352,8 @@
|
||||
::initialize-wallet
|
||||
(fn [accounts custom-tokens favourites]
|
||||
(re-frame/dispatch [::initialize-wallet
|
||||
accounts custom-tokens favourites]))}
|
||||
accounts custom-tokens favourites]))
|
||||
::open-last-chat (get-in db [:multiaccount :key-uid])}
|
||||
notifications-enabled?
|
||||
(assoc ::notifications/enable nil))
|
||||
(transport/start-messenger)
|
||||
@@ -381,7 +395,7 @@
|
||||
config/metrics-enabled?)
|
||||
(navigation/navigate-to :anon-metrics-opt-in {})
|
||||
|
||||
:else (re-frame/dispatch [:init-root :chat-stack]))))
|
||||
:else (re-frame/dispatch [:init-root :chat-stack]))))
|
||||
|
||||
(fx/defn login-only-events
|
||||
[{:keys [db] :as cofx} key-uid password save-password?]
|
||||
|
||||
@@ -89,8 +89,7 @@
|
||||
:mainnet #{:SNT}
|
||||
:rinkeby #{:MOKSHA
|
||||
:KDO}
|
||||
:xdai #{}
|
||||
:poa #{}}
|
||||
:xdai #{}}
|
||||
:preview-privacy? true
|
||||
:fleet :eth.prod
|
||||
:identicon "data:image/png;base64iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAMAAAC7IEhfAAADAFBMVEX////YsYwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABPGFwxAAABAHRSTlP//wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKmfXxgAABnNJREFUeNoBaAaX+QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEAAAAAAQEBAQAAAAABAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQAAAAABAQEBAAAAAAEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAAAAAAEBAQEAAAAAAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEAAAAAAQEBAQAAAAABAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQAAAAABAQEBAAAAAAEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAAAAAAEBAQEAAAAAAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEAAAAAAQEBAQAAAAABAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQAAAAABAQEBAAAAAAEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAAAAAAEBAQEAAAAAAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEAAAAAAQEBAQAAAAABAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQAAAAABAQEBAAAAAAEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAAAAAAEBAQEAAAAAAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEBAQEBAAAAAAEBAQEBAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEAAAAAAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQAAAAABAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEBAQEBAAAAAAEBAQEBAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAloYA4a9rBHIAAAAASUVORK5CYII="
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
(ns status-im.navigation
|
||||
(:require [status-im.utils.fx :as fx]
|
||||
[status-im.anon-metrics.core :as anon-metrics]))
|
||||
(:require [status-im.anon-metrics.core :as anon-metrics]
|
||||
[status-im.utils.fx :as fx]))
|
||||
|
||||
(defn- all-screens-params [db view screen-params]
|
||||
(cond-> db
|
||||
|
||||
@@ -1,17 +1,19 @@
|
||||
(ns status-im.navigation.core
|
||||
(:require
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.ui.screens.views :as views]
|
||||
[status-im.utils.platform :as platform]
|
||||
[status-im.navigation.roots :as roots]
|
||||
[status-im.ui.components.react :as react]
|
||||
[quo.components.text-input :as quo.text-input]
|
||||
[status-im.ui.components.icons.icons :as icons]
|
||||
[quo.design-system.colors :as quo.colors]
|
||||
[status-im.utils.fx :as fx]
|
||||
["react-native-navigation" :refer (Navigation)]
|
||||
["react-native" :as rn]
|
||||
[clojure.set :as clojure.set]
|
||||
["react-native-gesture-handler" :refer (gestureHandlerRootHOC)]
|
||||
["react-native" :as rn]))
|
||||
["react-native-navigation" :refer (Navigation)]
|
||||
[quo.components.text-input :as quo.text-input]
|
||||
[quo.design-system.colors :as quo.colors]
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.navigation.roots :as roots]
|
||||
[status-im.ui.components.icons.icons :as icons]
|
||||
[status-im.ui.components.react :as react]
|
||||
[status-im.ui.screens.views :as views]
|
||||
[status-im.utils.fx :as fx]
|
||||
[status-im.utils.platform :as platform]
|
||||
[taoensso.timbre :as log]))
|
||||
|
||||
(def debug? ^boolean js/goog.DEBUG)
|
||||
|
||||
@@ -26,6 +28,7 @@
|
||||
|
||||
;; REGISTER COMPONENT (LAZY)
|
||||
(defn reg-comp [key]
|
||||
(log/debug "reg-comp" key)
|
||||
(if-let [comp (get views/components (keyword key))]
|
||||
(.registerComponent Navigation key (fn [] (views/component comp)))
|
||||
(let [screen (views/screen key)]
|
||||
@@ -35,6 +38,7 @@
|
||||
(.setLazyComponentRegistrator Navigation reg-comp))
|
||||
|
||||
(defn dismiss-all-modals []
|
||||
(log/debug "dissmiss-all-modals")
|
||||
(when @curr-modal
|
||||
(reset! curr-modal false)
|
||||
(reset! dissmissing true)
|
||||
@@ -44,6 +48,7 @@
|
||||
|
||||
;; PUSH SCREEN
|
||||
(defn navigate [comp]
|
||||
(log/debug "NAVIGATE" comp)
|
||||
(let [{:keys [options]} (get views/screens comp)]
|
||||
(.push Navigation
|
||||
(name @root-comp-id)
|
||||
@@ -57,6 +62,7 @@
|
||||
|
||||
;; OPEN MODAL
|
||||
(defn update-modal-topbar-options [options]
|
||||
(log/debug "update-modal-topbar-options" options)
|
||||
(merge options
|
||||
(roots/merge-top-bar {:elevation 0
|
||||
:noBorder true
|
||||
@@ -68,6 +74,7 @@
|
||||
options)))
|
||||
|
||||
(defn open-modal [comp]
|
||||
(log/debug "open-modal" comp)
|
||||
(let [{:keys [options]} (get views/screens comp)]
|
||||
(if @dissmissing
|
||||
(reset! dissmissing comp)
|
||||
@@ -88,6 +95,7 @@
|
||||
|
||||
;; DISSMISS MODAL
|
||||
(defn dissmissModal []
|
||||
(log/debug "dissmissModal")
|
||||
(reset! dissmissing true)
|
||||
(.dismissModal Navigation (name (last @modals))))
|
||||
|
||||
@@ -105,6 +113,7 @@
|
||||
(handler)))))))
|
||||
|
||||
(defn set-view-id [view-id]
|
||||
(log/debug "set-view-id" view-id)
|
||||
(when-let [{:keys [on-focus]} (get views/screens view-id)]
|
||||
(re-frame/dispatch [:set :view-id view-id])
|
||||
(re-frame/dispatch [:screens/on-will-focus view-id])
|
||||
@@ -135,6 +144,7 @@
|
||||
(.events Navigation)
|
||||
(fn [^js evn]
|
||||
(let [view-id (keyword (.-componentName evn))]
|
||||
(log/debug "screen-appear-reg" view-id)
|
||||
(when (get views/screens view-id)
|
||||
(when (and (not= view-id :bottom-sheet)
|
||||
(not= view-id :popover)
|
||||
@@ -148,17 +158,20 @@
|
||||
(.registerComponentDidDisappearListener
|
||||
(.events Navigation)
|
||||
(fn [^js evn]
|
||||
(when-not (#{"popover" "bottom-sheet" "signing-sheet" "visibility-status-popover"}
|
||||
(.-componentName evn))
|
||||
(doseq [[_ {:keys [ref value]}] @quo.text-input/text-input-refs]
|
||||
(.setNativeProps ^js ref (clj->js {:text value})))
|
||||
(doseq [[^js text-input default-value] @react/text-input-refs]
|
||||
(.setNativeProps text-input (clj->js {:text default-value})))))))
|
||||
(let [view-id (keyword (.-componentName evn))]
|
||||
(when-not (#{"popover" "bottom-sheet" "signing-sheet" "visibility-status-popover"}
|
||||
(.-componentName evn))
|
||||
(re-frame/dispatch [::view-disappeared view-id])
|
||||
(doseq [[_ {:keys [ref value]}] @quo.text-input/text-input-refs]
|
||||
(.setNativeProps ^js ref (clj->js {:text value})))
|
||||
(doseq [[^js text-input default-value] @react/text-input-refs]
|
||||
(.setNativeProps text-input (clj->js {:text default-value}))))))))
|
||||
|
||||
;; SET ROOT
|
||||
(re-frame/reg-fx
|
||||
:init-root-fx
|
||||
(fn [new-root-id]
|
||||
(log/debug :init-root-fx new-root-id)
|
||||
(reset! root-comp-id new-root-id)
|
||||
(reset! root-id @root-comp-id)
|
||||
(.setRoot Navigation (clj->js (get (roots/roots) new-root-id)))))
|
||||
@@ -166,6 +179,7 @@
|
||||
(re-frame/reg-fx
|
||||
:init-root-with-component-fx
|
||||
(fn [[new-root-id new-root-comp-id]]
|
||||
(log/debug :init-root-with-component-fx new-root-id new-root-comp-id)
|
||||
(reset! root-comp-id new-root-comp-id)
|
||||
(reset! root-id @root-comp-id)
|
||||
(.setRoot Navigation (clj->js (get (roots/roots) new-root-id)))))
|
||||
@@ -173,6 +187,7 @@
|
||||
(fx/defn set-multiaccount-root
|
||||
{:events [::set-multiaccount-root]}
|
||||
[{:keys [db]}]
|
||||
(log/debug :set-multiaccounts-root)
|
||||
(let [key-uid (get-in db [:multiaccounts/login :key-uid])
|
||||
keycard-account? (boolean (get-in db [:multiaccounts/multiaccounts
|
||||
key-uid
|
||||
@@ -192,6 +207,7 @@
|
||||
(.hide ^js splash-screen))))
|
||||
|
||||
(defn get-screen-component [comp]
|
||||
(log/debug :get-screen-component comp)
|
||||
(let [{:keys [options]} (get views/screens comp)]
|
||||
{:component {:id comp
|
||||
:name comp
|
||||
@@ -203,6 +219,7 @@
|
||||
(re-frame/reg-fx
|
||||
:set-stack-root-fx
|
||||
(fn [[stack comp]]
|
||||
(log/debug :set-stack-root-fx stack comp)
|
||||
(.setStackRoot Navigation
|
||||
(name stack)
|
||||
(clj->js (if (vector? comp)
|
||||
@@ -225,6 +242,7 @@
|
||||
(re-frame/reg-fx
|
||||
:change-tab-fx
|
||||
(fn [tab]
|
||||
(log/debug :change-tab-fx)
|
||||
(reset! root-comp-id (get tab-root-ids (get tab-key-idx tab)))
|
||||
(.mergeOptions Navigation "tabs-stack" (clj->js {:bottomTabs {:currentTabIndex (get tab-key-idx tab)}}))
|
||||
;;when we change tab we want to dismiss all modals
|
||||
@@ -234,6 +252,7 @@
|
||||
(re-frame/reg-fx
|
||||
:change-tab-count-fx
|
||||
(fn [[tab cnt]]
|
||||
(log/debug :change-tab-count-fx tab cnt)
|
||||
(.mergeOptions Navigation
|
||||
(name (get tab-root-ids (get tab-key-idx tab)))
|
||||
(clj->js {:bottomTab (cond
|
||||
@@ -253,6 +272,7 @@
|
||||
(re-frame/reg-fx
|
||||
:pop-to-root-tab-fx
|
||||
(fn [comp]
|
||||
(log/debug :pop-to-root-tab-fx comp)
|
||||
(dismiss-all-modals)
|
||||
(.popToRoot Navigation (name comp))))
|
||||
|
||||
@@ -260,7 +280,10 @@
|
||||
(.registerBottomTabSelectedListener
|
||||
(.events Navigation)
|
||||
(fn [^js evn]
|
||||
(let [comp (get tab-root-ids (.-selectedTabIndex evn))]
|
||||
(let [selected-tab-index (.-selectedTabIndex evn)
|
||||
comp (get tab-root-ids selected-tab-index)
|
||||
tab-key (get (clojure.set/map-invert tab-key-idx) selected-tab-index)]
|
||||
(re-frame/dispatch [:set :current-tab tab-key])
|
||||
(when (and platform/android? (= @root-comp-id comp))
|
||||
(.popToRoot Navigation (name comp)))
|
||||
(reset! root-comp-id comp)))))
|
||||
@@ -343,11 +366,13 @@
|
||||
(re-frame/reg-fx
|
||||
:navigate-to-fx
|
||||
(fn [key]
|
||||
(log/debug :navigate-to-fx key)
|
||||
(navigate key)))
|
||||
|
||||
(re-frame/reg-fx
|
||||
:navigate-back-fx
|
||||
(fn []
|
||||
(log/debug :navigate-back-fx)
|
||||
(if @curr-modal
|
||||
(dissmissModal)
|
||||
(.pop Navigation (name @root-comp-id)))))
|
||||
@@ -355,5 +380,30 @@
|
||||
(re-frame/reg-fx
|
||||
:navigate-replace-fx
|
||||
(fn [view-id]
|
||||
(log/debug :navigate-replace-fx view-id)
|
||||
(.pop Navigation (name @root-comp-id))
|
||||
(navigate view-id)))
|
||||
|
||||
(def community-screens '(:community-management
|
||||
:community-members
|
||||
:community-requests-to-join
|
||||
:create-community-channel
|
||||
:community-emoji-thumbnail-picker
|
||||
:create-community-category
|
||||
:community-edit-chats))
|
||||
|
||||
;; change view-id if it is still same after component is disappeared
|
||||
;; https://github.com/wix/react-native-navigation/issues/5744#issuecomment-563226820
|
||||
(fx/defn view-disappeared
|
||||
{:events [::view-disappeared]}
|
||||
[{:keys [db]} view-id]
|
||||
(when (= view-id (:view-id db))
|
||||
{:db (assoc db :view-id (cond
|
||||
(= view-id :community-emoji-thumbnail-picker)
|
||||
:create-community-channel
|
||||
|
||||
(some #(= view-id %) community-screens)
|
||||
:community
|
||||
|
||||
:else
|
||||
:home))}))
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
|
||||
(defn default-root []
|
||||
{:layout {:componentBackgroundColor colors/white
|
||||
:orientation "portrait"
|
||||
:backgroundColor colors/white}})
|
||||
|
||||
(defn merge-top-bar [root-options options]
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
(ns status-im.notifications.local
|
||||
(:require [status-im.utils.fx :as fx]
|
||||
(:require [status-im.async-storage.core :as async-storage]
|
||||
[status-im.utils.fx :as fx]
|
||||
[status-im.ethereum.decode :as decode]
|
||||
["@react-native-community/push-notification-ios" :default pn-ios]
|
||||
[status-im.notifications.android :as pn-android]
|
||||
@@ -40,6 +41,7 @@
|
||||
|
||||
(defn handle-notification-press [{{deep-link :deepLink} :userInfo
|
||||
interaction :userInteraction}]
|
||||
(async-storage/set-item! (str :chat-id) nil)
|
||||
(when (and deep-link
|
||||
(or platform/ios?
|
||||
(and platform/android? interaction)))
|
||||
|
||||
@@ -6,15 +6,29 @@
|
||||
[status-im.data-store.activities :as data-store.activities]))
|
||||
|
||||
(fx/defn handle-activities [{:keys [db]} activities]
|
||||
{:db (-> db
|
||||
(update-in [:activity.center/notifications :notifications] #(concat activities %))
|
||||
(update :activity.center/notifications-count + (count activities)))
|
||||
:dispatch (cond
|
||||
(= (:view-id db) :notifications-center)
|
||||
[:mark-all-activity-center-notifications-as-read]
|
||||
(let [{:keys [unread-count notifications]}
|
||||
(reduce (fn [acc {:keys [read dismissed accepted] :as notification}]
|
||||
(as-> acc a
|
||||
(if read
|
||||
(update a :unread-count dec)
|
||||
(update a :unread-count inc))
|
||||
|
||||
(= (:view-id db) :chat)
|
||||
[:accept-all-activity-center-notifications-from-chat (:current-chat-id db)])})
|
||||
(if (or dismissed accepted)
|
||||
(update a :notifications (fn [items] (remove #(= (:id notification) (:id %)) items)))
|
||||
(update a :notifications conj notification))))
|
||||
{:unread-count (get db :activity.center/notifications-count 0)
|
||||
:notifications (get-in db [:activity.center/notifications :notifications])}
|
||||
activities)]
|
||||
(merge
|
||||
{:db (-> db
|
||||
(assoc-in [:activity.center/notifications :notifications] notifications)
|
||||
(assoc :activity.center/notifications-count (max 0 unread-count)))}
|
||||
(cond
|
||||
(= (:view-id db) :notifications-center)
|
||||
{:dispatch [:mark-all-activity-center-notifications-as-read]}
|
||||
|
||||
(= (:view-id db) :chat)
|
||||
{:dispatch [:accept-all-activity-center-notifications-from-chat (:current-chat-id db)]}))))
|
||||
|
||||
(fx/defn get-activity-center-notifications-count
|
||||
{:events [:get-activity-center-notifications-count]}
|
||||
|
||||
+49
-43
@@ -34,7 +34,6 @@
|
||||
[status-im.utils.security :as security]
|
||||
[status-im.wallet.db :as wallet.db]
|
||||
[status-im.wallet.utils :as wallet.utils]
|
||||
[status-im.utils.utils :as utils]
|
||||
status-im.ui.screens.keycard.subs
|
||||
[status-im.chat.models.mentions :as mentions]
|
||||
[status-im.notifications.core :as notifications]
|
||||
@@ -181,6 +180,12 @@
|
||||
(reg-root-key-sub :wallet/fetching-collection-assets :wallet/fetching-collection-assets)
|
||||
(reg-root-key-sub :wallet/collectible-assets :wallet/collectible-assets)
|
||||
(reg-root-key-sub :wallet/selected-collectible :wallet/selected-collectible)
|
||||
(reg-root-key-sub :wallet/modal-selecting-source-token? :wallet/modal-selecting-source-token?)
|
||||
(reg-root-key-sub :wallet/swap-from-token :wallet/swap-from-token)
|
||||
(reg-root-key-sub :wallet/swap-to-token :wallet/swap-to-token)
|
||||
(reg-root-key-sub :wallet/swap-from-token-amount :wallet/swap-from-token-amount)
|
||||
(reg-root-key-sub :wallet/swap-to-token-amount :wallet/swap-to-token-amount)
|
||||
(reg-root-key-sub :wallet/swap-advanced-mode? :wallet/swap-advanced-mode?)
|
||||
|
||||
;;commands
|
||||
(reg-root-key-sub :commands/select-account :commands/select-account)
|
||||
@@ -877,6 +882,22 @@
|
||||
(assoc :color colors/blue))
|
||||
chats)))))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:chats/sorted-categories-by-community-id
|
||||
(fn [[_ community-id]]
|
||||
[(re-frame/subscribe [:chats/by-community-id community-id])
|
||||
(re-frame/subscribe [:communities/community-chats community-id])])
|
||||
(fn [[chats comm-chats] [_ community-id]]
|
||||
(let [chat-cat (into {} (map (fn [{:keys [id categoryID position]}]
|
||||
{(str community-id id) {:categoryID categoryID
|
||||
:position position}})
|
||||
(vals comm-chats)))]
|
||||
(group-by :categoryID (sort-by :position
|
||||
(map #(cond-> (merge % (chat-cat (:chat-id %)))
|
||||
(= community-id constants/status-community-id)
|
||||
(assoc :color colors/blue))
|
||||
chats))))))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:chats/category-by-chat-id
|
||||
(fn [[_ community-id _]]
|
||||
@@ -903,7 +924,9 @@
|
||||
:<- [:communities]
|
||||
(fn [communities [_ id]]
|
||||
(->> (get-in communities [id :categories])
|
||||
(sort-by #(:position (get % 1))))))
|
||||
(map #(assoc (get % 1) :community-id id))
|
||||
(sort-by :position)
|
||||
(into []))))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:chats/current-chat-ui-props
|
||||
@@ -1197,19 +1220,6 @@
|
||||
(hydrate-messages messages))))))
|
||||
|
||||
;;we want to keep data unchanged so react doesn't change component when we leave screen
|
||||
(def memo-chat-messages-stream (atom nil))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:chats/chat-messages-stream
|
||||
(fn [[_ chat-id] _]
|
||||
[(re-frame/subscribe [:chats/raw-chat-messages-stream chat-id])
|
||||
(re-frame/subscribe [:chats/chat-no-messages? chat-id])
|
||||
(re-frame/subscribe [:view-id])])
|
||||
(fn [[messages empty view-id]]
|
||||
(when (or (= view-id :chat) empty)
|
||||
(reset! memo-chat-messages-stream messages))
|
||||
@memo-chat-messages-stream))
|
||||
|
||||
(def memo-profile-messages-stream (atom nil))
|
||||
|
||||
(re-frame/reg-sub
|
||||
@@ -1413,22 +1423,11 @@
|
||||
:<- [:contacts/contacts]
|
||||
(fn [contacts]
|
||||
(reduce
|
||||
(fn [acc [key {:keys [alias name added? blocked? identicon public-key nickname]}]]
|
||||
(if (and alias
|
||||
(not= alias "")
|
||||
(or name
|
||||
nickname
|
||||
added?)
|
||||
(not blocked?))
|
||||
(let [name (utils/safe-replace name ".stateofus.eth" "")]
|
||||
(assoc acc public-key
|
||||
(mentions/add-searchable-phrases
|
||||
{:alias alias
|
||||
:name (or name alias)
|
||||
:identicon identicon
|
||||
:nickname nickname
|
||||
:public-key key})))
|
||||
acc))
|
||||
(fn [acc [key contact]]
|
||||
(let [mentionable-contact (mentions/add-searchable-phrases-to-contact
|
||||
contact false)]
|
||||
(if (nil? mentionable-contact) acc
|
||||
(assoc acc key mentionable-contact))))
|
||||
{}
|
||||
contacts)))
|
||||
|
||||
@@ -1438,20 +1437,27 @@
|
||||
:<- [:chats/mentionable-contacts]
|
||||
:<- [:contacts/blocked-set]
|
||||
:<- [:multiaccount]
|
||||
(fn [[{:keys [chat-id users chat-type]} contacts blocked {:keys [name preferred-name public-key]}]]
|
||||
(let [contacts-with-one-to-one (if (= chat-type constants/one-to-one-chat-type)
|
||||
(assoc contacts chat-id (get contacts chat-id (-> chat-id
|
||||
contact.db/public-key->new-contact
|
||||
contact.db/enrich-contact)))
|
||||
contacts)]
|
||||
:<- [:contacts/contacts]
|
||||
(fn [[{:keys [chat-id users contacts community-id chat-type] :as chat}
|
||||
mentionable-contacts blocked {:keys [public-key]} my-contacts]]
|
||||
(let [community-members @(re-frame/subscribe [:communities/community-members
|
||||
community-id])
|
||||
contacts-with-one-to-one (if (= chat-type constants/one-to-one-chat-type)
|
||||
(assoc mentionable-contacts chat-id (get mentionable-contacts chat-id (-> chat-id
|
||||
contact.db/public-key->new-contact
|
||||
contact.db/enrich-contact)))
|
||||
mentionable-contacts)
|
||||
members-left (into #{} (filter #(group-chat/member-removed? chat %) (keys users)))
|
||||
filtered-contacts (select-keys contacts-with-one-to-one (if (nil? community-id)
|
||||
(distinct (concat (seq contacts) (keys users) [chat-id]))
|
||||
(keys community-members)))
|
||||
mentionable-commmunity-members (mentions/mentionable-commmunity-members
|
||||
my-contacts public-key community-members)]
|
||||
(apply dissoc
|
||||
(-> users
|
||||
(merge contacts-with-one-to-one)
|
||||
(assoc public-key (mentions/add-searchable-phrases
|
||||
{:alias name
|
||||
:name (or preferred-name name)
|
||||
:public-key public-key})))
|
||||
(conj blocked public-key)))))
|
||||
(merge filtered-contacts)
|
||||
(merge mentionable-commmunity-members))
|
||||
(conj (concat blocked members-left) public-key)))))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:chat/mention-suggestions
|
||||
|
||||
@@ -81,9 +81,7 @@
|
||||
(fx/merge cofx
|
||||
(process-next response-js sync-handler)
|
||||
(models.contact/ensure-contacts
|
||||
(map data-store.contacts/<-rpc contacts-clj)
|
||||
(when chats
|
||||
(map data-store.chats/<-rpc (types/js->clj chats))))))
|
||||
(map data-store.contacts/<-rpc contacts-clj) chats)))
|
||||
|
||||
(seq communities)
|
||||
(let [communities-clj (types/js->clj communities)]
|
||||
@@ -257,7 +255,9 @@
|
||||
|
||||
(fx/defn update-envelopes-status
|
||||
[{:keys [db] :as cofx} message-id status]
|
||||
(apply fx/merge cofx (map #(update-envelope-status % status) message-id)))
|
||||
(when (or (not= status :not-sent)
|
||||
(= :online (:network db)))
|
||||
(apply fx/merge cofx (map #(update-envelope-status % status) message-id))))
|
||||
|
||||
(fx/defn set-message-envelope-hash
|
||||
"message-type is used for tracking"
|
||||
|
||||
@@ -13,7 +13,9 @@
|
||||
(merge {:style (merge
|
||||
styles/wrapper
|
||||
style)
|
||||
:accessibility-label accessibility-label}
|
||||
:accessibility-label (str accessibility-label
|
||||
"-"
|
||||
(if checked? "on" "off"))}
|
||||
(when on-value-change
|
||||
{:on-press #(on-value-change (not checked?))}))
|
||||
(if checked?
|
||||
|
||||
@@ -6,7 +6,8 @@
|
||||
(defn emoji-thumbnail [emoji color size]
|
||||
(when-not (string/blank? emoji)
|
||||
[react/view (styles/emoji-thumbnail-icon color size)
|
||||
[react/text {:style (styles/emoji-thumbnail-icon-text size)} emoji]]))
|
||||
[react/text {:style (styles/emoji-thumbnail-icon-text size)
|
||||
:accessibility-label :thumbnail-emoji} emoji]]))
|
||||
|
||||
(defn emoji-thumbnail-touchable [emoji color size func]
|
||||
(when-not (string/blank? emoji)
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
(defn emoji-thumbnail-icon-text [size]
|
||||
{:font-size (emoji-utils/emoji-font-size size)
|
||||
:line-height size
|
||||
:accessibility-label :thumbnail-emoji
|
||||
:margin-top (emoji-utils/emoji-top-margin-for-vertical-alignment size)}) ;; Required for vertical alignment bug - Check function defination for more info
|
||||
|
||||
|
||||
|
||||
@@ -86,21 +86,4 @@
|
||||
:style {:width 160 :height 160}}]]
|
||||
[react/text {:style {:text-align :center :margin-bottom 16 :line-height 22}}
|
||||
(i18n/label :t/public-chat-description)]
|
||||
[chat-name-input topic error]]
|
||||
[react/view {:margin-top 32}
|
||||
(for [[section chats] (chat.models/chats)]
|
||||
^{:key section}
|
||||
[react/view
|
||||
[react/view {:margin-right 16 :padding-left 16 :padding-vertical 3
|
||||
:border-bottom-width 1 :border-bottom-color colors/gray-lighter
|
||||
:border-top-width 1 :border-top-color colors/gray-lighter
|
||||
:border-right-width 1 :border-right-color colors/gray-lighter
|
||||
:border-bottom-right-radius 14 :border-top-right-radius 14}
|
||||
[quo/text {:weight :medium} section]]
|
||||
[react/view {:flex-direction :row :flex-wrap :wrap :margin-vertical 8 :padding-horizontal 16}
|
||||
(let [lang-topic (get-language-topic)
|
||||
chats (if (and (= section-featured section) lang-topic)
|
||||
(conj chats lang-topic)
|
||||
chats)]
|
||||
(for [chat chats]
|
||||
(render-topic chat)))]])]]))
|
||||
[chat-name-input topic error]]]))
|
||||
|
||||
@@ -181,7 +181,7 @@
|
||||
:message-id @current-player-message-id}))
|
||||
nil)
|
||||
|
||||
(defview message-content [{:keys [audio audio-duration-ms message-id outgoing]} timestamp-view]
|
||||
(defview message-content [{:keys [audio audio-duration-ms message-id outgoing]}]
|
||||
(letsubs [state (reagent/atom nil)
|
||||
progress (reagent/atom 0)
|
||||
progress-anim (anim/create-value 0)
|
||||
@@ -223,5 +223,4 @@
|
||||
(#{:playing :paused :seeking} (:general @state)) @progress
|
||||
:else (:duration @state))
|
||||
s (quot time 1000)]
|
||||
(gstring/format "%02d:%02d" (quot s 60) (mod s 60)))]
|
||||
timestamp-view]]))))
|
||||
(gstring/format "%02d:%02d" (quot s 60) (mod s 60)))]]]))))
|
||||
|
||||
@@ -12,28 +12,29 @@
|
||||
(re-frame/dispatch [:chat.ui/fill-gaps chat-id gap-ids])))
|
||||
|
||||
(views/defview gap
|
||||
[{:keys [gap-ids chat-id gap-parameters]}]
|
||||
[{:keys [gap-ids chat-id gap-parameters public? community?]}]
|
||||
(views/letsubs [in-progress? [:chats/fetching-gap-in-progress?
|
||||
gap-ids
|
||||
chat-id]
|
||||
connected? [:mailserver/connected?]
|
||||
first-gap? (= gap-ids #{:first-gap})]
|
||||
[react/view {:style (style/gap-container)}
|
||||
[react/touchable-highlight
|
||||
{:on-press (when (and connected? (not in-progress?))
|
||||
(on-press chat-id gap-ids))
|
||||
:style style/touchable}
|
||||
[react/view {:style style/label-container}
|
||||
(if in-progress?
|
||||
[react/activity-indicator]
|
||||
[react/nested-text
|
||||
{:style (style/gap-text connected?)}
|
||||
(i18n/label (if first-gap? :t/load-more-messages :t/fetch-messages))
|
||||
(when first-gap?
|
||||
[{:style style/date}
|
||||
(let [date (datetime/timestamp->long-date
|
||||
(* 1000 (:from gap-parameters)))]
|
||||
(str
|
||||
"\n"
|
||||
(i18n/label :t/load-messages-before
|
||||
{:date date})))])])]]]))
|
||||
(when (or (not first-gap?) public? community?)
|
||||
[react/view {:style (style/gap-container)}
|
||||
[react/touchable-highlight
|
||||
{:on-press (when (and connected? (not in-progress?))
|
||||
(on-press chat-id gap-ids))
|
||||
:style style/touchable}
|
||||
[react/view {:style style/label-container}
|
||||
(if in-progress?
|
||||
[react/activity-indicator]
|
||||
[react/nested-text
|
||||
{:style (style/gap-text connected?)}
|
||||
(i18n/label (if first-gap? :t/load-more-messages :t/fetch-messages))
|
||||
(when first-gap?
|
||||
[{:style style/date}
|
||||
(let [date (datetime/timestamp->long-date
|
||||
(* 1000 (:from gap-parameters)))]
|
||||
(str
|
||||
"\n"
|
||||
(i18n/label :t/load-messages-before
|
||||
{:date date})))])])]]])))
|
||||
|
||||
@@ -24,42 +24,66 @@
|
||||
[status-im.ui.screens.chat.components.reply :as components.reply]
|
||||
[status-im.ui.screens.chat.message.link-preview :as link-preview]
|
||||
[status-im.ui.screens.communities.icon :as communities.icon]
|
||||
[status-im.ui.components.animation :as animation]
|
||||
[status-im.chat.models.pin-message :as models.pin-message])
|
||||
(:require-macros [status-im.utils.views :refer [defview letsubs]]))
|
||||
|
||||
(defn message-timestamp-anim
|
||||
[anim-opacity show-timestamp?]
|
||||
(animation/start
|
||||
(animation/anim-sequence
|
||||
[(animation/timing
|
||||
anim-opacity
|
||||
{:toValue 1
|
||||
:duration 100
|
||||
:easing (.-ease ^js animation/easing)
|
||||
:useNativeDriver true})
|
||||
(animation/timing
|
||||
anim-opacity
|
||||
{:toValue 0
|
||||
:delay 2000
|
||||
:duration 100
|
||||
:easing (.-ease ^js animation/easing)
|
||||
:useNativeDriver true})]) #(reset! show-timestamp? false)))
|
||||
|
||||
(defview mention-element [from]
|
||||
(letsubs [contact-name [:contacts/contact-name-by-identity from]]
|
||||
contact-name))
|
||||
|
||||
(def edited-at-text (str " ⌫ " (i18n/label :t/edited)))
|
||||
|
||||
(defn message-status [{:keys [outgoing content outgoing-status pinned edited-at in-popover?]}]
|
||||
(when-not in-popover? ;; We keep track if showing this message in a list in pin-limit-popover
|
||||
[react/view
|
||||
{:align-self :flex-end
|
||||
:position :absolute
|
||||
:bottom 9 ; 6 Bubble bottom, 3 message baseline
|
||||
(if (:rtl? content) :left :right) 0
|
||||
:flex-direction :row
|
||||
:align-items :flex-end}
|
||||
(when outgoing
|
||||
[icons/icon (case outgoing-status
|
||||
:sending :tiny-icons/tiny-pending
|
||||
:sent :tiny-icons/tiny-sent
|
||||
:not-sent :tiny-icons/tiny-warning
|
||||
:delivered :tiny-icons/tiny-delivered
|
||||
:tiny-icons/tiny-pending)
|
||||
{:width 16
|
||||
:height 12
|
||||
:color (if pinned colors/gray colors/white)
|
||||
:accessibility-label (name outgoing-status)}])
|
||||
(when edited-at [react/text {:style (style/message-status-text (and outgoing (not pinned)))} edited-at-text])]))
|
||||
|
||||
(defn message-timestamp
|
||||
([message]
|
||||
[message-timestamp message false])
|
||||
([{:keys [timestamp-str outgoing content outgoing-status pinned edited-at in-popover?]} justify-timestamp?]
|
||||
(when-not in-popover? ;; We keep track if showing this message in a list in pin-limit-popover
|
||||
[react/view (when justify-timestamp?
|
||||
{:align-self :flex-end
|
||||
:position :absolute
|
||||
:bottom 9 ; 6 Bubble bottom, 3 message baseline
|
||||
(if (:rtl? content) :left :right) 0
|
||||
:flex-direction :row
|
||||
:align-items :flex-end})
|
||||
(when (and outgoing justify-timestamp?)
|
||||
[icons/icon (case outgoing-status
|
||||
:sending :tiny-icons/tiny-pending
|
||||
:sent :tiny-icons/tiny-sent
|
||||
:not-sent :tiny-icons/tiny-warning
|
||||
:delivered :tiny-icons/tiny-delivered
|
||||
:tiny-icons/tiny-pending)
|
||||
{:width 16
|
||||
:height 12
|
||||
:color (if pinned colors/gray colors/white)
|
||||
:accessibility-label (name outgoing-status)}])
|
||||
[react/text {:style (style/message-timestamp-text (and outgoing (not pinned)))}
|
||||
(str
|
||||
timestamp-str
|
||||
(when edited-at edited-at-text))]])))
|
||||
[{:keys [timestamp-str in-popover?] :as message} show-timestamp?]
|
||||
(when-not in-popover? ;; We keep track if showing this message in a list in pin-limit-popover
|
||||
(let [anim-opacity (animation/create-value 0)]
|
||||
[react/animated-view {:style (style/message-timestamp-wrapper message) :opacity anim-opacity}
|
||||
(when @show-timestamp? (message-timestamp-anim anim-opacity show-timestamp?))
|
||||
[react/text
|
||||
{:style (style/message-timestamp-text)
|
||||
:accessibility-label :message-timestamp}
|
||||
timestamp-str]])))
|
||||
|
||||
(defview quoted-message
|
||||
[_ {:keys [from parsed-text image]} outgoing current-public-key public? pinned]
|
||||
@@ -168,19 +192,19 @@
|
||||
(defn render-parsed-text [message tree]
|
||||
(reduce (fn [acc e] (render-block message acc e)) [:<>] tree))
|
||||
|
||||
(defn render-parsed-text-with-timestamp [{:keys [timestamp-str outgoing edited-at in-popover?] :as message} tree]
|
||||
(defn render-parsed-text-with-message-status [{:keys [outgoing edited-at in-popover?] :as message} tree]
|
||||
(let [elements (render-parsed-text message tree)
|
||||
timestamp [react/text {:style (style/message-timestamp-placeholder)}
|
||||
(str (if (and outgoing (not in-popover?)) " " " ") (when-not in-popover? (str timestamp-str (when edited-at edited-at-text))))]
|
||||
message-status [react/text {:style (style/message-status-placeholder)}
|
||||
(str (if (and outgoing (not in-popover?)) " " " ") (when (and (not in-popover?) edited-at) edited-at-text))]
|
||||
last-element (peek elements)]
|
||||
;; Using `nth` here as slightly faster than `first`, roughly 30%
|
||||
;; It's worth considering pure js structures for this code path as
|
||||
;; it's perfomance critical
|
||||
(if (= react/text-class (nth last-element 0))
|
||||
;; Append timestamp to last text
|
||||
(conj (pop elements) (conj last-element timestamp))
|
||||
;; Append timestamp to new block
|
||||
(conj elements timestamp))))
|
||||
;; Append message status to last text
|
||||
(conj (pop elements) (conj last-element message-status))
|
||||
;; Append message status to new block
|
||||
(conj elements message-status))))
|
||||
|
||||
(defn unknown-content-type
|
||||
[{:keys [outgoing content-type content] :as message}]
|
||||
@@ -409,7 +433,8 @@
|
||||
|
||||
(defn collapsible-text-message [{:keys [mentioned]} _]
|
||||
(let [collapsed? (reagent/atom false)
|
||||
collapsible? (reagent/atom false)]
|
||||
collapsible? (reagent/atom false)
|
||||
show-timestamp? (reagent/atom false)]
|
||||
(fn [{:keys [content outgoing current-public-key public? pinned in-popover?] :as message} on-long-press modal]
|
||||
(let [max-height (when-not (or outgoing modal)
|
||||
(if @collapsible?
|
||||
@@ -418,7 +443,8 @@
|
||||
[react/touchable-highlight
|
||||
(when-not modal
|
||||
{:on-press (fn [_]
|
||||
(react/dismiss-keyboard!))
|
||||
(react/dismiss-keyboard!)
|
||||
(reset! show-timestamp? true))
|
||||
:delay-long-press 100
|
||||
:on-long-press (fn []
|
||||
(if @collapsed?
|
||||
@@ -426,40 +452,41 @@
|
||||
(js/setTimeout #(on-long-press-fn on-long-press message content) 200))
|
||||
(on-long-press-fn on-long-press message content)))
|
||||
:disabled in-popover?})
|
||||
[react/view {:style (style/message-view message)}
|
||||
[react/view {:style (style/message-view-content)
|
||||
:max-height max-height}
|
||||
(let [response-to (:response-to content)]
|
||||
[react/view {:on-layout
|
||||
#(when (and (> (.-nativeEvent.layout.height ^js %) max-message-height-px)
|
||||
(not @collapsible?)
|
||||
(not outgoing)
|
||||
(not modal))
|
||||
(reset! collapsed? true)
|
||||
(reset! collapsible? true))}
|
||||
(when (and (seq response-to) (:quoted-message message))
|
||||
[quoted-message response-to (:quoted-message message) outgoing current-public-key public? pinned])
|
||||
[render-parsed-text-with-timestamp message (:parsed-text content)]])
|
||||
(when-not @collapsed?
|
||||
[message-timestamp message true])
|
||||
(when (and @collapsible? (not modal))
|
||||
(if @collapsed?
|
||||
(let [color (if pinned colors/pin-background (if mentioned colors/mentioned-background colors/blue-light))]
|
||||
[react/touchable-highlight
|
||||
{:on-press #(swap! collapsed? not)
|
||||
:style {:position :absolute :bottom 0 :left 0 :right 0 :height 72}}
|
||||
[react/linear-gradient {:colors [(str color "00") color]
|
||||
:start {:x 0 :y 0} :end {:x 0 :y 0.9}}
|
||||
[react/view {:height 72 :align-self :center :justify-content :flex-end
|
||||
:padding-bottom 10}
|
||||
[react/view (style/collapse-button)
|
||||
[icons/icon :main-icons/dropdown
|
||||
{:color colors/white}]]]]])
|
||||
[react/touchable-highlight {:on-press #(swap! collapsed? not)
|
||||
:style {:align-self :center :margin 5}}
|
||||
[react/view (style/collapse-button)
|
||||
[icons/icon :main-icons/dropdown-up
|
||||
{:color colors/white}]]]))]]]))))
|
||||
[react/view (style/message-view-wrapper outgoing)
|
||||
[message-timestamp message show-timestamp?]
|
||||
[react/view {:style (style/message-view message)}
|
||||
[react/view {:style (style/message-view-content)
|
||||
:max-height max-height}
|
||||
(let [response-to (:response-to content)]
|
||||
[react/view {:on-layout
|
||||
#(when (and (> (.-nativeEvent.layout.height ^js %) max-message-height-px)
|
||||
(not @collapsible?)
|
||||
(not outgoing)
|
||||
(not modal))
|
||||
(reset! collapsed? true)
|
||||
(reset! collapsible? true))}
|
||||
(when (and (seq response-to) (:quoted-message message))
|
||||
[quoted-message response-to (:quoted-message message) outgoing current-public-key public? pinned])
|
||||
[render-parsed-text-with-message-status message (:parsed-text content)]])
|
||||
(when-not @collapsible? [message-status message])
|
||||
(when (and @collapsible? (not modal))
|
||||
(if @collapsed?
|
||||
(let [color (if pinned colors/pin-background (if mentioned colors/mentioned-background colors/blue-light))]
|
||||
[react/touchable-highlight
|
||||
{:on-press #(swap! collapsed? not)
|
||||
:style {:position :absolute :bottom 0 :left 0 :right 0 :height 72}}
|
||||
[react/linear-gradient {:colors [(str color "00") color]
|
||||
:start {:x 0 :y 0} :end {:x 0 :y 0.9}}
|
||||
[react/view {:height 72 :align-self :center :justify-content :flex-end
|
||||
:padding-bottom 10}
|
||||
[react/view (style/collapse-button)
|
||||
[icons/icon :main-icons/dropdown
|
||||
{:color colors/white}]]]]])
|
||||
[react/touchable-highlight {:on-press #(swap! collapsed? not)
|
||||
:style {:align-self :center :margin 5}}
|
||||
[react/view (style/collapse-button)
|
||||
[icons/icon :main-icons/dropdown-up
|
||||
{:color colors/white}]]]))]]]]))))
|
||||
|
||||
(defmethod ->message constants/content-type-text
|
||||
[message {:keys [on-long-press modal] :as reaction-picker}]
|
||||
@@ -484,33 +511,37 @@
|
||||
(defmethod ->message constants/content-type-emoji
|
||||
[{:keys [content current-public-key outgoing public? pinned in-popover? message-pin-enabled] :as message} {:keys [on-long-press modal]
|
||||
:as reaction-picker}]
|
||||
(let [response-to (:response-to content)]
|
||||
[message-content-wrapper message
|
||||
[react/touchable-highlight (when-not modal
|
||||
{:disabled in-popover?
|
||||
:on-press (fn []
|
||||
(react/dismiss-keyboard!))
|
||||
:delay-long-press 100
|
||||
:on-long-press (fn []
|
||||
(on-long-press
|
||||
(concat
|
||||
[{:on-press #(re-frame/dispatch [:chat.ui/reply-to-message message])
|
||||
:id :reply
|
||||
:label (i18n/label :t/message-reply)}
|
||||
{:on-press #(react/copy-to-clipboard (get content :text))
|
||||
:id :copy
|
||||
:label (i18n/label :t/sharing-copy-to-clipboard)}]
|
||||
(when message-pin-enabled [{:on-press #(pin-message message)
|
||||
:label (if pinned (i18n/label :t/unpin) (i18n/label :t/pin))}]))))})
|
||||
[react/view (style/message-view message)
|
||||
[react/view {:style (style/message-view-content)}
|
||||
[react/view {:style (style/style-message-text outgoing)}
|
||||
(when (and (seq response-to) (:quoted-message message))
|
||||
[quoted-message response-to (:quoted-message message) outgoing current-public-key public? pinned])
|
||||
[react/text {:style (style/emoji-message message)}
|
||||
(:text content)]]
|
||||
[message-timestamp message]]]]
|
||||
reaction-picker]))
|
||||
(let [response-to (:response-to content)
|
||||
show-timestamp? (reagent/atom false)]
|
||||
(fn [] [message-content-wrapper message
|
||||
[react/touchable-highlight (when-not modal
|
||||
{:disabled in-popover?
|
||||
:on-press (fn []
|
||||
(react/dismiss-keyboard!)
|
||||
(reset! show-timestamp? true))
|
||||
:delay-long-press 100
|
||||
:on-long-press (fn []
|
||||
(on-long-press
|
||||
(concat
|
||||
[{:on-press #(re-frame/dispatch [:chat.ui/reply-to-message message])
|
||||
:id :reply
|
||||
:label (i18n/label :t/message-reply)}
|
||||
{:on-press #(react/copy-to-clipboard (get content :text))
|
||||
:id :copy
|
||||
:label (i18n/label :t/sharing-copy-to-clipboard)}]
|
||||
(when message-pin-enabled [{:on-press #(pin-message message)
|
||||
:label (if pinned (i18n/label :t/unpin) (i18n/label :t/pin))}]))))})
|
||||
[react/view (style/message-view-wrapper outgoing)
|
||||
[message-timestamp message show-timestamp?]
|
||||
[react/view (style/message-view message)
|
||||
[react/view {:style (style/message-view-content)}
|
||||
[react/view {:style (style/style-message-text outgoing)}
|
||||
(when (and (seq response-to) (:quoted-message message))
|
||||
[quoted-message response-to (:quoted-message message) outgoing current-public-key public? pinned])
|
||||
[react/text {:style (style/emoji-message message)}
|
||||
(:text content)]]
|
||||
[message-status message]]]]]
|
||||
reaction-picker])))
|
||||
|
||||
(defmethod ->message constants/content-type-sticker
|
||||
[{:keys [content from outgoing in-popover?]
|
||||
@@ -556,14 +587,19 @@
|
||||
|
||||
(defmethod ->message constants/content-type-audio [message {:keys [on-long-press modal]
|
||||
:as reaction-picker}]
|
||||
[message-content-wrapper message
|
||||
[react/touchable-highlight (when-not modal
|
||||
{:on-long-press
|
||||
(fn [] (on-long-press []))})
|
||||
[react/view {:style (style/message-view message) :accessibility-label :audio-message}
|
||||
[react/view {:style (style/message-view-content)}
|
||||
[message.audio/message-content message [message-timestamp message false]]]]]
|
||||
reaction-picker])
|
||||
(let [show-timestamp? (reagent/atom false)]
|
||||
(fn [] [message-content-wrapper message
|
||||
[react/touchable-highlight (when-not modal
|
||||
{:on-long-press
|
||||
(fn [] (on-long-press []))
|
||||
:on-press (fn []
|
||||
(reset! show-timestamp? true))})
|
||||
[react/view (style/message-view-wrapper (:outgoing message))
|
||||
[message-timestamp message show-timestamp?]
|
||||
[react/view {:style (style/message-view message) :accessibility-label :audio-message}
|
||||
[react/view {:style (style/message-view-content)}
|
||||
[message.audio/message-content message] [message-status message]]]]]
|
||||
reaction-picker])))
|
||||
|
||||
(defmethod ->message :default [message]
|
||||
[message-content-wrapper message
|
||||
|
||||
@@ -4,11 +4,12 @@
|
||||
[status-im.ui.screens.chat.styles.photos :as style]
|
||||
[status-im.profile.db :as profile.db]
|
||||
[status-im.multiaccounts.core :as multiaccounts]
|
||||
[status-im.utils.image :as utils.image]))
|
||||
[status-im.utils.image :as utils.image]
|
||||
[quo.design-system.colors :as colors]))
|
||||
|
||||
(def memo-photo-rend
|
||||
(memoize
|
||||
(fn [photo-path size accessibility-label]
|
||||
(fn [photo-path size accessibility-label _]
|
||||
(let [identicon? (when photo-path (profile.db/base64-png? photo-path))]
|
||||
[react/view {:style (style/photo-container size)}
|
||||
[react/image {:source (utils.image/source photo-path)
|
||||
@@ -18,8 +19,9 @@
|
||||
(when identicon?
|
||||
[react/view {:style (style/photo-border size)}])]))))
|
||||
|
||||
;; "(colors/dark?)" is passed to memoized function to avoid previous themes cache
|
||||
(defn photo [photo-path {:keys [size accessibility-label]}]
|
||||
[memo-photo-rend photo-path size accessibility-label])
|
||||
[memo-photo-rend photo-path size accessibility-label (colors/dark?)])
|
||||
|
||||
;; We optionally pass identicon for perfomance reason, so it does not have to be calculated for each message
|
||||
(defn member-photo [pub-key identicon]
|
||||
|
||||
@@ -43,5 +43,5 @@
|
||||
:justify-content :space-between})
|
||||
|
||||
(defn timestamp [outgoing]
|
||||
(merge (message.style/message-timestamp-text outgoing)
|
||||
(merge (message.style/audio-message-timestamp-text outgoing)
|
||||
{:margin-left 40}))
|
||||
@@ -29,11 +29,33 @@
|
||||
(def message-timestamp
|
||||
{:font-size 10})
|
||||
|
||||
(defn message-timestamp-placeholder
|
||||
(defn message-status-placeholder
|
||||
[]
|
||||
(merge message-timestamp {:opacity 0 :color "rgba(0,0,0,0)"}))
|
||||
|
||||
(defn message-timestamp-text
|
||||
(defn message-timestamp-wrapper [{:keys [last-in-group? outgoing group-chat]}]
|
||||
{:justify-content :center
|
||||
(if outgoing :margin-right :margin-left) 12 ;; horizontal margin is only required at the adjust side of the message.
|
||||
:margin-top (if (and last-in-group?
|
||||
(or outgoing
|
||||
(not group-chat)))
|
||||
16
|
||||
0) ;; Add gap between message groups
|
||||
:opacity 0})
|
||||
|
||||
(defn message-timestamp-text []
|
||||
(merge message-timestamp
|
||||
{:color colors/gray
|
||||
:text-align :center}))
|
||||
|
||||
(defn message-status-text [outgoing]
|
||||
{:font-size 10
|
||||
:line-height 10
|
||||
:color (if outgoing
|
||||
colors/white-transparent-70-persist
|
||||
colors/gray)})
|
||||
|
||||
(defn audio-message-timestamp-text
|
||||
[outgoing]
|
||||
(merge message-timestamp
|
||||
{:line-height 10
|
||||
@@ -44,7 +66,7 @@
|
||||
(defn message-wrapper [{:keys [outgoing in-popover?]}]
|
||||
(if (and outgoing (not in-popover?))
|
||||
{:margin-left 96}
|
||||
{:margin-right 52}))
|
||||
{:margin-right 96}))
|
||||
|
||||
(defn message-author-wrapper
|
||||
[outgoing display-photo? in-popover?]
|
||||
@@ -156,10 +178,10 @@
|
||||
:padding-left 3})
|
||||
|
||||
(defn emoji-message
|
||||
[{:keys [incoming-group]}]
|
||||
[{:keys [incoming-group outgoing]}]
|
||||
{:font-size 28
|
||||
:line-height 34 ;TODO: Smaller crops the icon on the top
|
||||
:margin-right 12
|
||||
:margin-right (if outgoing 18 0) ;; Margin to display outgoing message status
|
||||
:margin-top (if incoming-group 4 0)})
|
||||
|
||||
(defn collapse-button []
|
||||
@@ -171,6 +193,10 @@
|
||||
:shadow-color (:shadow-01 @colors/theme)
|
||||
:shadow-offset {:width 0 :height 4}})
|
||||
|
||||
(defn message-view-wrapper [outgoing]
|
||||
{:align-self :flex-end
|
||||
:flex-direction (if outgoing :row :row-reverse)})
|
||||
|
||||
(defn message-view
|
||||
[{:keys [content-type outgoing group-chat last-in-group? mentioned pinned]}]
|
||||
(merge
|
||||
|
||||
@@ -243,7 +243,8 @@
|
||||
(defn render-fn [{:keys [outgoing type] :as message}
|
||||
idx
|
||||
_
|
||||
{:keys [group-chat public? current-public-key space-keeper chat-id show-input? message-pin-enabled edit-enabled in-pinned-view?]}]
|
||||
{:keys [group-chat public? community? current-public-key space-keeper
|
||||
chat-id show-input? message-pin-enabled edit-enabled in-pinned-view?]}]
|
||||
[react/view {:style (when (and platform/android? (not in-pinned-view?)) {:scaleY -1})}
|
||||
(if (= type :datemark)
|
||||
[message-datemark/chat-datemark (:value message)]
|
||||
@@ -255,6 +256,7 @@
|
||||
:incoming-group (and group-chat (not outgoing))
|
||||
:group-chat group-chat
|
||||
:public? public?
|
||||
:community? community?
|
||||
:current-public-key current-public-key
|
||||
:show-input? show-input?
|
||||
:message-pin-enabled message-pin-enabled
|
||||
@@ -285,6 +287,7 @@
|
||||
community-admin?))))]
|
||||
{:group-chat group-chat
|
||||
:public? public?
|
||||
:community? (not (nil? community-id))
|
||||
:current-public-key current-public-key
|
||||
:space-keeper space-keeper
|
||||
:chat-id chat-id
|
||||
@@ -295,7 +298,7 @@
|
||||
|
||||
(defn messages-view [{:keys [chat bottom-space pan-responder space-keeper show-input?]}]
|
||||
(let [{:keys [group-chat chat-id public? community-id admins]} chat
|
||||
messages @(re-frame/subscribe [:chats/chat-messages-stream chat-id])]
|
||||
messages @(re-frame/subscribe [:chats/raw-chat-messages-stream chat-id])]
|
||||
;;do not use anonymous functions for handlers
|
||||
[list/flat-list
|
||||
(merge
|
||||
@@ -343,8 +346,7 @@
|
||||
[toolbar-content/toolbar-content-view-inner chat-info]]))
|
||||
|
||||
(defn chat []
|
||||
(let [curr-chat-id (:chat-id @(re-frame/subscribe [:chats/current-chat-chat-view]))
|
||||
bottom-space (reagent/atom 0)
|
||||
(let [bottom-space (reagent/atom 0)
|
||||
panel-space (reagent/atom 52)
|
||||
active-panel (reagent/atom nil)
|
||||
position-y (animated/value 0)
|
||||
@@ -355,48 +357,44 @@
|
||||
space-keeper (get-space-keeper-ios bottom-space panel-space active-panel text-input-ref)
|
||||
set-active-panel (get-set-active-panel active-panel)
|
||||
on-close #(set-active-panel nil)]
|
||||
(reagent/create-class
|
||||
{:component-will-unmount #(re-frame/dispatch-sync [:close-chat curr-chat-id])
|
||||
:component-did-mount (fn [] (js/setTimeout #(re-frame/dispatch [:set :ignore-close-chat false]) 500))
|
||||
:reagent-render
|
||||
(fn []
|
||||
(let [{:keys [chat-id show-input? group-chat admins invitation-admin] :as chat}
|
||||
;;we want to react only on these fields, do not use full chat map here
|
||||
@(re-frame/subscribe [:chats/current-chat-chat-view])
|
||||
max-bottom-space (max @bottom-space @panel-space)]
|
||||
[:<>
|
||||
[connectivity/loading-indicator]
|
||||
(when chat-id
|
||||
(if group-chat
|
||||
[invitation-requests chat-id admins]
|
||||
[add-contact-bar chat-id]))
|
||||
;;MESSAGES LIST
|
||||
[messages-view {:chat chat
|
||||
:bottom-space max-bottom-space
|
||||
:pan-responder pan-responder
|
||||
:space-keeper space-keeper
|
||||
:show-input? show-input?}]
|
||||
(when (and group-chat invitation-admin)
|
||||
[accessory/view {:y position-y
|
||||
:on-update-inset on-update}
|
||||
[invitation-bar chat-id]])
|
||||
[components/autocomplete-mentions text-input-ref max-bottom-space]
|
||||
(when show-input?
|
||||
;; NOTE: this only accepts two children
|
||||
[accessory/view {:y position-y
|
||||
:pan-state pan-state
|
||||
:has-panel (boolean @active-panel)
|
||||
:on-close on-close
|
||||
:on-update-inset on-update}
|
||||
[react/view
|
||||
[edit/edit-message-auto-focus-wrapper text-input-ref]
|
||||
[reply/reply-message-auto-focus-wrapper text-input-ref]
|
||||
;; We set the key so we can force a re-render as
|
||||
;; it does not rely on ratom but just atoms
|
||||
^{:key (str @components/chat-input-key "chat-input")}
|
||||
[components/chat-toolbar
|
||||
{:chat-id chat-id
|
||||
:active-panel @active-panel
|
||||
:set-active-panel set-active-panel
|
||||
:text-input-ref text-input-ref}]]
|
||||
[bottom-sheet @active-panel]])]))})))
|
||||
(fn []
|
||||
(let [{:keys [chat-id show-input? group-chat admins invitation-admin] :as chat}
|
||||
;;we want to react only on these fields, do not use full chat map here
|
||||
@(re-frame/subscribe [:chats/current-chat-chat-view])
|
||||
max-bottom-space (max @bottom-space @panel-space)]
|
||||
[:<>
|
||||
[connectivity/loading-indicator]
|
||||
(when chat-id
|
||||
(if group-chat
|
||||
[invitation-requests chat-id admins]
|
||||
[add-contact-bar chat-id]))
|
||||
;;MESSAGES LIST
|
||||
[messages-view {:chat chat
|
||||
:bottom-space max-bottom-space
|
||||
:pan-responder pan-responder
|
||||
:space-keeper space-keeper
|
||||
:show-input? show-input?}]
|
||||
(when (and group-chat invitation-admin)
|
||||
[accessory/view {:y position-y
|
||||
:on-update-inset on-update}
|
||||
[invitation-bar chat-id]])
|
||||
[components/autocomplete-mentions text-input-ref max-bottom-space]
|
||||
(when show-input?
|
||||
;; NOTE: this only accepts two children
|
||||
[accessory/view {:y position-y
|
||||
:pan-state pan-state
|
||||
:has-panel (boolean @active-panel)
|
||||
:on-close on-close
|
||||
:on-update-inset on-update}
|
||||
[react/view
|
||||
[edit/edit-message-auto-focus-wrapper text-input-ref]
|
||||
[reply/reply-message-auto-focus-wrapper text-input-ref]
|
||||
;; We set the key so we can force a re-render as
|
||||
;; it does not rely on ratom but just atoms
|
||||
^{:key (str @components/chat-input-key "chat-input")}
|
||||
[components/chat-toolbar
|
||||
{:chat-id chat-id
|
||||
:active-panel @active-panel
|
||||
:set-active-panel set-active-panel
|
||||
:text-input-ref text-input-ref}]]
|
||||
[bottom-sheet @active-panel]])]))))
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
(fn []
|
||||
(let [current-chat (<sub [:chat-by-id chat-id])
|
||||
{:keys [chat-name color description community-id emoji]} current-chat
|
||||
{:keys [position]} (<sub [:chats/community-chat-by-id community-id chat-id])
|
||||
category (<sub [:chats/category-by-chat-id community-id chat-id])
|
||||
{:keys [admin]} (<sub [:communities/community community-id])
|
||||
pinned-messages (<sub [:chats/pinned chat-id])]
|
||||
@@ -27,7 +28,8 @@
|
||||
color
|
||||
emoji
|
||||
chat-id
|
||||
(:id category)])}])
|
||||
(:id category)
|
||||
position])}])
|
||||
:extended-header (profile-header/extended-header
|
||||
{:title chat-name
|
||||
:color color
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.ui.screens.chat.sheets :as sheets]
|
||||
[status-im.ui.components.accordion :as accordion]
|
||||
[clojure.string :as string]
|
||||
[status-im.ui.screens.communities.styles :as styles]))
|
||||
|
||||
(def request-cooldown-ms (* 60 1000))
|
||||
@@ -139,12 +138,6 @@
|
||||
:title (i18n/label :t/edit-chats)
|
||||
:accessibility-label :community-edit-chats
|
||||
:icon :main-icons/edit
|
||||
:on-press #(hide-sheet-and-dispatch [:open-modal :community-edit-chats {:community-id id}])}]
|
||||
[quo/list-item
|
||||
{:theme :accent
|
||||
:title (i18n/label :t/reorder-categories)
|
||||
:accessibility-label :community-reorder-categories
|
||||
:icon :main-icons/channel-category
|
||||
:on-press #(hide-sheet-and-dispatch
|
||||
[:open-modal :community-reorder-categories {:community-id id}])}]])]))
|
||||
|
||||
@@ -154,60 +147,42 @@
|
||||
:color :secondary}
|
||||
text]])
|
||||
|
||||
(defn community-chat-item [{:keys [chat-id] :as home-item} _ _ {:keys [from-chat]}]
|
||||
(defn community-chat-item [{:keys [chat-id] :as home-item} _ _ _]
|
||||
[inner-item/home-list-item
|
||||
;; We want communities to behave as public chats when it comes to
|
||||
;; unread indicator
|
||||
(assoc home-item :public? true)
|
||||
{:on-press (fn []
|
||||
(re-frame/dispatch [:dismiss-keyboard])
|
||||
(re-frame/dispatch [:chat.ui/navigate-to-chat chat-id (not from-chat)])
|
||||
(re-frame/dispatch [:chat.ui/navigate-to-chat chat-id])
|
||||
(re-frame/dispatch [:search/home-filter-changed nil])
|
||||
(re-frame/dispatch [:accept-all-activity-center-notifications-from-chat chat-id]))
|
||||
:on-long-press #(re-frame/dispatch [:bottom-sheet/show-sheet
|
||||
{:content (fn []
|
||||
[sheets/actions home-item])}])}])
|
||||
|
||||
(defn categories-accordion [community-id chats categories edit data]
|
||||
(defn categories-accordion [community-id chats categories data]
|
||||
[:<>
|
||||
(for [{:keys [name id state]} (vals categories)]
|
||||
(for [{:keys [name id state]} categories]
|
||||
^{:key (str "cat" name id)}
|
||||
[:<>
|
||||
[accordion/section
|
||||
{:on-open #(>evt [::communities/store-category-state community-id id true])
|
||||
:on-close #(>evt [::communities/store-category-state community-id id false])
|
||||
:default state
|
||||
:opened edit
|
||||
:disabled edit
|
||||
:title [rn/view styles/category-item
|
||||
(if edit
|
||||
[rn/touchable-opacity {:on-press #(>evt [:delete-community-category community-id id])}
|
||||
[icons/icon :main-icons/delete-circle {:no-color true}]]
|
||||
[icons/icon :main-icons/channel-category {:color colors/gray}])
|
||||
[icons/icon :main-icons/channel-category {:color colors/gray}]
|
||||
[rn/text {:style {:font-size 17 :margin-left 10 :color colors/black}} name]]
|
||||
:content [rn/view
|
||||
:content [:<>
|
||||
(for [chat (get chats id)]
|
||||
(if edit
|
||||
^{:key (str "chat" chat id)}
|
||||
[rn/view styles/category-item
|
||||
[rn/touchable-opacity {:on-press #(>evt [:remove-chat-from-community-category
|
||||
community-id
|
||||
(string/replace (:chat-id chat) community-id "")
|
||||
(:categoryID chat)])}
|
||||
[icons/icon :main-icons/delete-circle {:no-color true}]]
|
||||
[rn/view {:flex 1}
|
||||
[inner-item/home-list-item
|
||||
(assoc chat :public? true)]]]
|
||||
^{:key (str "chat" chat id)}
|
||||
[community-chat-item chat nil nil data]))]}]
|
||||
^{:key (str "chat" chat id)}
|
||||
[community-chat-item chat nil nil data])]}]
|
||||
[quo/separator]])])
|
||||
|
||||
(defn community-chat-list [community-id categories edit from-chat]
|
||||
(let [chats (<sub [:chats/categories-by-community-id community-id])]
|
||||
(defn community-chat-list [community-id categories from-chat]
|
||||
(let [chats (<sub [:chats/sorted-categories-by-community-id community-id])]
|
||||
(if (and (empty? categories) (empty? chats))
|
||||
(if edit
|
||||
[blank-page (i18n/label :t/welcome-community-blank-message-edit-chats)]
|
||||
[blank-page (i18n/label :t/welcome-community-blank-message)])
|
||||
[blank-page (i18n/label :t/welcome-community-blank-message)]
|
||||
[list/flat-list
|
||||
{:key-fn :chat-id
|
||||
:content-container-style {:padding-bottom 8}
|
||||
@@ -215,7 +190,7 @@
|
||||
:data (get chats "")
|
||||
:render-data {:from-chat from-chat}
|
||||
:render-fn community-chat-item
|
||||
:header [categories-accordion community-id chats categories edit {:from-chat from-chat}]
|
||||
:header [categories-accordion community-id chats categories {:from-chat from-chat}]
|
||||
:footer [rn/view {:height 68}]}])))
|
||||
|
||||
(defn channel-preview-item [{:keys [id name]}]
|
||||
@@ -267,23 +242,6 @@
|
||||
[components.react/small-loading-indicator]
|
||||
(i18n/label :t/fetch-community))]]]))
|
||||
|
||||
(defn community-edit []
|
||||
(let [{:keys [community-id]} (<sub [:get-screen-params])]
|
||||
(fn []
|
||||
(let [{:keys [id name images members permissions color]} (<sub [:communities/community community-id])
|
||||
categories (<sub [:communities/sorted-categories community-id])]
|
||||
[:<>
|
||||
[topbar/topbar
|
||||
{:modal? true
|
||||
:content [toolbar-content
|
||||
id
|
||||
name
|
||||
color
|
||||
images
|
||||
(not= (:access permissions) constants/community-no-membership-access)
|
||||
(count members)]}]
|
||||
[community-chat-list id categories true false]]))))
|
||||
|
||||
(defn community []
|
||||
(let [{:keys [community-id from-chat]} (<sub [:get-screen-params])]
|
||||
(fn []
|
||||
|
||||
@@ -65,4 +65,4 @@
|
||||
@category-name
|
||||
(vec @selected-items)]
|
||||
3000)}
|
||||
(i18n/label :t/create)]}]]))))
|
||||
(i18n/label :t/create)]}]]))))
|
||||
|
||||
@@ -1,60 +1,176 @@
|
||||
(ns status-im.ui.screens.communities.reorder-categories
|
||||
(:require [quo.core :as quo]
|
||||
[clojure.walk :as walk]
|
||||
[quo.react-native :as rn]
|
||||
[reagent.core :as reagent]
|
||||
[clojure.string :as string]
|
||||
[clojure.set :as clojure.set]
|
||||
[status-im.i18n.i18n :as i18n]
|
||||
[status-im.utils.utils :as utils]
|
||||
[status-im.constants :as constants]
|
||||
[quo.design-system.colors :as colors]
|
||||
[status-im.ui.components.react :as react]
|
||||
[status-im.utils.platform :as platform]
|
||||
[status-im.ui.components.topbar :as topbar]
|
||||
[status-im.communities.core :as communities]
|
||||
[status-im.utils.handlers :refer [>evt <sub]]
|
||||
[status-im.ui.components.icons.icons :as icons]
|
||||
[status-im.ui.screens.communities.styles :as styles]
|
||||
[status-im.ui.screens.communities.community :as community]))
|
||||
[status-im.ui.screens.communities.community :as community]
|
||||
[status-im.ui.screens.home.views.inner-item :as inner-item]))
|
||||
|
||||
(defn category-change-positon [community-id key up? position]
|
||||
(let [new-position (if up? (dec position) (inc position))]
|
||||
(>evt [::communities/reorder-community-category community-id key new-position])))
|
||||
(def collapse-chats? (reagent/atom false))
|
||||
(def data (reagent/atom []))
|
||||
|
||||
(defn category-item-button [community-id up? disabled? key position]
|
||||
(let [[margin-right icon] (if up?
|
||||
[10 :main-icons/dropdown-up]
|
||||
[25 :main-icons/dropdown])]
|
||||
[react/touchable-opacity {:disabled disabled?
|
||||
:on-press #(category-change-positon
|
||||
community-id key up? position)}
|
||||
[rn/view {:style (styles/reorder-categories-button margin-right)}
|
||||
[icons/icon icon {:color colors/black}]]]))
|
||||
(defn show-delete-chat-confirmation [community-id chat-id]
|
||||
(utils/show-confirmation
|
||||
{:title (i18n/label :t/delete-confirmation)
|
||||
:content (i18n/label :t/delete-chat-confirmation)
|
||||
:confirm-button-text (i18n/label :t/delete)
|
||||
:on-accept #(>evt [:delete-community-chat community-id chat-id])}))
|
||||
|
||||
(defn category-item [community-id count {:keys [key name position]}]
|
||||
(let [up-disabled? (= position 0)
|
||||
down-disabled? (= position (dec count))]
|
||||
(defn show-delete-catgory-confirmation [community-id category-id]
|
||||
(utils/show-confirmation
|
||||
{:title (i18n/label :t/delete-confirmation)
|
||||
:content (i18n/label :t/delete-category-confirmation)
|
||||
:confirm-button-text (i18n/label :t/delete)
|
||||
:on-accept #(>evt [:delete-community-category community-id category-id])}))
|
||||
|
||||
(defn chat-item
|
||||
[{:keys [id community-id] :as home-item} is-active? drag]
|
||||
(let [chat-id (string/replace id community-id "")
|
||||
background-color (if is-active? colors/gray-lighter colors/white)
|
||||
home-item (clojure.set/rename-keys home-item {:id :chat-id})]
|
||||
[rn/view {:accessibility-label :chat-item
|
||||
:style (merge styles/category-item
|
||||
{:background-color background-color})}
|
||||
[rn/touchable-opacity
|
||||
{:accessibility-label :delete-community-chat
|
||||
:on-press #(show-delete-chat-confirmation community-id chat-id)}
|
||||
[icons/icon :main-icons/delete-circle {:no-color true}]]
|
||||
[rn/view {:flex 1}
|
||||
[inner-item/home-list-item (assoc home-item :edit? true) {:active-opacity 1}]]
|
||||
[rn/touchable-opacity {:on-long-press drag
|
||||
:delay-long-press 100
|
||||
:accessibility-label :chat-drag-handle
|
||||
:style {:padding 20}}
|
||||
[icons/icon :main-icons/reorder-handle {:no-color true :width 18 :height 12}]]]))
|
||||
|
||||
(defn category-item
|
||||
[{:keys [id name community-id]} is-active? drag]
|
||||
(let [background-color (if is-active? colors/gray-lighter colors/white)
|
||||
category-none? (string/blank? id)]
|
||||
[:<>
|
||||
[rn/view {:style styles/reorder-categories-item}
|
||||
[icons/icon :main-icons/channel-category {:color colors/gray}]
|
||||
[rn/text {:style (styles/reorder-categories-text)} name]
|
||||
[category-item-button community-id true up-disabled? key position]
|
||||
[category-item-button community-id false down-disabled? key position]]
|
||||
[quo/separator]]))
|
||||
[quo/separator]
|
||||
[rn/view {:accessibility-label :category-item
|
||||
:style (merge styles/category-item
|
||||
{:background-color background-color})}
|
||||
(if category-none?
|
||||
[icons/icon :main-icons/channel-category {:color colors/gray}]
|
||||
[rn/touchable-opacity
|
||||
{:accessibility-label :delete-category-button
|
||||
:on-press #(show-delete-catgory-confirmation community-id id)}
|
||||
[icons/icon :main-icons/delete-circle {:no-color true}]])
|
||||
[rn/view {:flex 1}
|
||||
[rn/text {:style {:font-size 17 :margin-left 10 :color colors/black}} name]]
|
||||
(when (and (not category-none?) @collapse-chats?)
|
||||
[rn/touchable-opacity {:accessibility-label :category-drag-handle
|
||||
:on-long-press drag
|
||||
:delay-long-press 100
|
||||
:style {:padding 20}}
|
||||
[icons/icon :main-icons/reorder-handle {:no-color true :width 18 :height 12}]])]]))
|
||||
|
||||
(defn categories-view [community-id categories count]
|
||||
[rn/view {:accessibility-label :reorder-categories-list}
|
||||
(for [category-vector categories]
|
||||
(let [category (clojure.set/rename-keys (get category-vector 1) {:id :key})]
|
||||
[category-item community-id count category]))])
|
||||
(defn render-fn
|
||||
[{:keys [chat-type] :as item} _ _ _ is-active? drag]
|
||||
(if (= chat-type constants/community-chat-type)
|
||||
[chat-item item is-active? drag]
|
||||
[category-item item is-active? drag]))
|
||||
|
||||
(defn calculate-chat-new-position-and-category
|
||||
[to second-call? old-category going-up?]
|
||||
(let [{:keys [id chat-type categoryID position]} (get @data to)
|
||||
[new-category new-position]
|
||||
(if going-up?
|
||||
(if (= chat-type constants/community-chat-type)
|
||||
[categoryID (if second-call? (inc position) position)]
|
||||
(if second-call? [id 0]
|
||||
(calculate-chat-new-position-and-category (dec to) true old-category true)))
|
||||
(if (= chat-type constants/community-chat-type)
|
||||
(if (= categoryID old-category)
|
||||
[categoryID position]
|
||||
[categoryID (inc position)]) [id 0]))]
|
||||
[new-category new-position]))
|
||||
|
||||
(defn update-local-atom [data-js]
|
||||
(reset! data data-js)
|
||||
(reagent/flush))
|
||||
|
||||
(defn on-drag-end-chat [from to data-js]
|
||||
(let [{:keys [id community-id categoryID position]} (get @data from)
|
||||
[new-category new-position] (calculate-chat-new-position-and-category
|
||||
to false categoryID (> from to))
|
||||
chat-id (string/replace id community-id "")]
|
||||
(when-not (and (= new-position position) (= new-category categoryID))
|
||||
(update-local-atom data-js)
|
||||
(>evt [::communities/reorder-community-category-chat
|
||||
community-id new-category chat-id new-position]))))
|
||||
|
||||
(defn on-drag-end-category [from to data-js]
|
||||
(let [{:keys [id community-id position]} (get @data from)]
|
||||
(when (and (< to (count @data)) (not= position to) (not= id ""))
|
||||
(update-local-atom data-js)
|
||||
(>evt [::communities/reorder-community-category community-id id to]))))
|
||||
|
||||
(defn on-drag-end-fn [from to data-js]
|
||||
(if @collapse-chats?
|
||||
(on-drag-end-category from to data-js)
|
||||
(when-not (= to 0) (on-drag-end-chat from to data-js))))
|
||||
|
||||
(defn reset-data [categories chats]
|
||||
(reset! data (if @collapse-chats? categories ;; If chats are collapsed then only show categories
|
||||
(walk/postwalk-replace ;; else, categories and chats
|
||||
{:chat-id :id}
|
||||
(reduce (fn [acc category]
|
||||
(-> acc
|
||||
(conj category)
|
||||
(into (get chats (:id category))))) [] categories)))))
|
||||
|
||||
(defn draggable-list []
|
||||
[rn/draggable-flat-list
|
||||
{:key-fn :id
|
||||
:data @data
|
||||
:render-fn render-fn
|
||||
:autoscroll-threshold (if platform/android? 150 250)
|
||||
:autoscroll-speed (if platform/android? 10 150) ;; TODO - Use same speed for both ios and android
|
||||
:container-style {:margin-bottom 108} ;; after bumping react native version to > 0.64
|
||||
:on-drag-end-fn on-drag-end-fn}])
|
||||
|
||||
(defn view []
|
||||
(let [{:keys [community-id]} (<sub [:get-screen-params])
|
||||
{:keys [id name images members permissions color]}
|
||||
(<sub [:communities/community community-id])
|
||||
categories (<sub [:communities/sorted-categories community-id])]
|
||||
sorted-categories (<sub [:communities/sorted-categories community-id])
|
||||
categories (if @collapse-chats? sorted-categories
|
||||
(conj sorted-categories
|
||||
{:id ""
|
||||
:position (count sorted-categories)
|
||||
:name (i18n/label :t/none)
|
||||
:community-id community-id}))
|
||||
chats (<sub [:chats/sorted-categories-by-community-id community-id])]
|
||||
(reset-data categories chats)
|
||||
[:<>
|
||||
[topbar/topbar
|
||||
{:modal? true
|
||||
:content [community/toolbar-content id name color images
|
||||
(not= (:access permissions) constants/community-no-membership-access)
|
||||
(count members)]}]
|
||||
(if (empty? categories)
|
||||
[community/blank-page (i18n/label :t/welcome-community-blank-message-categories)]
|
||||
[categories-view community-id categories (count categories)])]))
|
||||
(if (and (empty? sorted-categories) (empty? chats))
|
||||
[community/blank-page (i18n/label :t/welcome-community-blank-message-edit-chats)]
|
||||
[:<>
|
||||
[quo/list-item {:size :small
|
||||
:title (i18n/label :t/rearrange-categories)
|
||||
:active @collapse-chats?
|
||||
:accessory :switch
|
||||
:container-style {:padding-left 10}
|
||||
:on-press #(reset! collapse-chats? (not @collapse-chats?))}]
|
||||
[quo/separator]
|
||||
[draggable-list]])]))
|
||||
|
||||
@@ -11,7 +11,8 @@
|
||||
[status-im.ui.components.icons.icons :as icons]
|
||||
[status-im.ui.components.topbar :as topbar]
|
||||
[status-im.i18n.i18n :as i18n]
|
||||
[status-im.communities.core :as communities]))
|
||||
[status-im.communities.core :as communities]
|
||||
[quo.components.animated.pressable :as animation]))
|
||||
|
||||
(defn hide-sheet-and-dispatch [event]
|
||||
(>evt [:bottom-sheet/hide])
|
||||
@@ -19,11 +20,11 @@
|
||||
|
||||
(defn request-actions [community-id request-id]
|
||||
[react/view {:flex-direction :row}
|
||||
[react/touchable-highlight {:on-press #(re-frame/dispatch [:communities.ui/accept-request-to-join-pressed community-id request-id])}
|
||||
[animation/pressable {:on-press #(re-frame/dispatch [:communities.ui/accept-request-to-join-pressed community-id request-id])}
|
||||
[icons/icon :main-icons/checkmark-circle {:width 35
|
||||
:height 35
|
||||
:color colors/green}]]
|
||||
[react/touchable-highlight {:on-press #(re-frame/dispatch [:communities.ui/decline-request-to-join-pressed community-id request-id])}
|
||||
[animation/pressable {:on-press #(re-frame/dispatch [:communities.ui/decline-request-to-join-pressed community-id request-id])}
|
||||
[icons/icon :main-icons/cancel {:width 35
|
||||
:height 35
|
||||
:container-style {:margin-left 16}
|
||||
@@ -41,7 +42,8 @@
|
||||
:accessory (when can-manage-users?
|
||||
[request-actions community-id id])
|
||||
:icon [chat-icon/contact-icon-contacts-tab
|
||||
(multiaccounts/displayed-photo member)]}]))
|
||||
(multiaccounts/displayed-photo member)]
|
||||
:on-press #(re-frame/dispatch [:chat.ui/show-profile public-key])}]))
|
||||
|
||||
(defn requests-to-join []
|
||||
(let [{:keys [community-id]} (<sub [:get-screen-params])]
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
(let [{:keys [community-id chat]} (<sub [:get-screen-params])]
|
||||
(fn []
|
||||
(let [categories (<sub [:communities/sorted-categories community-id])
|
||||
chats (<sub [:chats/sorted-categories-by-community-id community-id])
|
||||
comm-chat (<sub [:chats/community-chat-by-id community-id (:chat-id chat)])
|
||||
_ (reset! selected-item (:categoryID comm-chat))]
|
||||
[:<>
|
||||
@@ -44,7 +45,7 @@
|
||||
:create-community-category
|
||||
{:community-id community-id}])
|
||||
:title (i18n/label :t/create-category)}]
|
||||
:data (conj (vec (vals categories)) {:name (i18n/label :t/none) :id ""})
|
||||
:data (conj categories {:name (i18n/label :t/none) :id ""})
|
||||
:render-fn render-fn}]]
|
||||
[toolbar/toolbar
|
||||
{:show-border? true
|
||||
@@ -54,6 +55,7 @@
|
||||
[::communities/change-category-confirmation-pressed
|
||||
community-id
|
||||
@selected-item
|
||||
comm-chat]
|
||||
(assoc comm-chat :position
|
||||
(count (get chats @selected-item)))] ;; Add as last item in new category
|
||||
3000)}
|
||||
(i18n/label :t/done)]}]]))))
|
||||
|
||||
@@ -1,34 +1,8 @@
|
||||
(ns status-im.ui.screens.communities.styles
|
||||
(:require [quo.design-system.colors :as colors]))
|
||||
(ns status-im.ui.screens.communities.styles)
|
||||
|
||||
(def category-item
|
||||
{:flex 1
|
||||
:flex-direction :row
|
||||
:align-items :center
|
||||
:height 52
|
||||
:margin-left 18})
|
||||
|
||||
(def reorder-categories-item
|
||||
{:accessibility-label :reorder-categories-item
|
||||
:flex-direction :row
|
||||
:height 60
|
||||
:align-items :center
|
||||
:margin-left 18})
|
||||
|
||||
(defn reorder-categories-text []
|
||||
{:font-size 17
|
||||
:margin-left 10
|
||||
:color (colors/get-color :text-01)
|
||||
:flex 1})
|
||||
|
||||
(defn reorder-categories-button [margin-right]
|
||||
{:accessibility-label :reorder-categories-button
|
||||
:width 30
|
||||
:height 30
|
||||
:border-radius 15
|
||||
:margin 10
|
||||
:margin-right margin-right
|
||||
:border-width 1
|
||||
:justify-content :center
|
||||
:align-items :center
|
||||
:border-color colors/black})
|
||||
:padding-left 18})
|
||||
|
||||
@@ -3,10 +3,12 @@
|
||||
(:require [status-im.ui.components.react :as react]
|
||||
[status-im.i18n.i18n :as i18n]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.utils.config :as config]
|
||||
[quo.core :as quo]
|
||||
[re-frame.core :as re-frame]))
|
||||
|
||||
(def titles {constants/one-day (i18n/label :t/one-day)
|
||||
(def titles {constants/two-mins (i18n/label :t/two-minutes)
|
||||
constants/one-day (i18n/label :t/one-day)
|
||||
constants/three-days (i18n/label :t/three-days)
|
||||
constants/one-week (i18n/label :t/one-week)
|
||||
constants/one-month (i18n/label :t/one-month)})
|
||||
@@ -21,6 +23,8 @@
|
||||
(views/defview default-sync-period-settings []
|
||||
(views/letsubs [{:keys [default-sync-period]} [:multiaccount]]
|
||||
[react/view {:margin-top 8}
|
||||
(when config/two-minutes-syncing?
|
||||
[radio-item constants/two-mins default-sync-period])
|
||||
[radio-item constants/one-day default-sync-period]
|
||||
[radio-item constants/three-days default-sync-period]
|
||||
[radio-item constants/one-week default-sync-period]
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
[reagent.core :as reagent]
|
||||
[status-im.i18n.i18n :as i18n]
|
||||
[status-im.react-native.resources :as resources]
|
||||
[status-im.communities.core :as communities]
|
||||
[status-im.ui.components.connectivity.view :as connectivity]
|
||||
[status-im.ui.components.icons.icons :as icons]
|
||||
[status-im.ui.components.list.views :as list]
|
||||
@@ -13,7 +12,6 @@
|
||||
[status-im.ui.screens.home.views.inner-item :as inner-item]
|
||||
[status-im.ui.screens.referrals.home-item :as referral-item]
|
||||
[quo.design-system.colors :as colors]
|
||||
[status-im.ui.screens.add-new.new-public-chat.view :as new-public-chat]
|
||||
[quo.core :as quo]
|
||||
[status-im.add-new.core :as new-chat]
|
||||
[status-im.ui.components.search-input.view :as search-input]
|
||||
@@ -24,7 +22,8 @@
|
||||
[status-im.ui.components.topbar :as topbar]
|
||||
[status-im.ui.components.plus-button :as components.plus-button]
|
||||
[status-im.ui.screens.chat.sheets :as sheets]
|
||||
[status-im.ui.components.tabbar.core :as tabbar])
|
||||
[status-im.ui.components.tabbar.core :as tabbar]
|
||||
["react-native-navigation" :refer (Navigation)])
|
||||
(:require-macros [status-im.utils.views :as views]))
|
||||
|
||||
(defn home-tooltip-view []
|
||||
@@ -40,30 +39,10 @@
|
||||
:accessibility-label :hide-home-button}
|
||||
[icons/icon :main-icons/close-circle {:color colors/gray}]]
|
||||
[react/i18n-text {:style styles/no-chats-text :key :chat-and-transact}]
|
||||
[invite/button]
|
||||
[react/view {:align-items :center :margin-bottom 16}
|
||||
[react/view {:style (styles/hr-wrapper)}]
|
||||
[react/i18n-text {:style (styles/or-text) :key :or}]]
|
||||
[react/i18n-text {:style {:margin-horizontal 16
|
||||
:text-align :center}
|
||||
:key :follow-your-interests}]
|
||||
[react/view {:flex-direction :row :flex-wrap :wrap :justify-content :center
|
||||
:margin-top 10
|
||||
:margin-bottom 18}
|
||||
(for [chat (new-public-chat/featured-public-chats)]
|
||||
^{:key chat}
|
||||
[new-public-chat/render-topic chat])]
|
||||
(when @(re-frame/subscribe [:communities/enabled?])
|
||||
[:<>
|
||||
[react/i18n-text {:style {:margin-horizontal 16
|
||||
:text-align :center}
|
||||
:key :join-a-community}]
|
||||
[react/view {:flex-direction :row :flex-wrap :wrap :justify-content :center
|
||||
:margin-top 10
|
||||
:margin-bottom 18}
|
||||
(for [{:keys [id] :as community} communities/featured]
|
||||
^{:key id}
|
||||
[communities.views/render-featured-community community])]])])
|
||||
[react/view {:align-items :center
|
||||
:margin-top 8
|
||||
:margin-bottom 12}
|
||||
[invite/button]]])
|
||||
|
||||
(defn welcome-blank-page []
|
||||
[react/view {:style {:flex 1 :flex-direction :row :align-items :center :justify-content :center}}
|
||||
@@ -199,13 +178,19 @@
|
||||
:accessibility-label :notifications-unread-badge}]])]))
|
||||
|
||||
(defn home []
|
||||
[react/keyboard-avoiding-view {:style {:flex 1}
|
||||
:ignore-offset true}
|
||||
[topbar/topbar {:title (i18n/label :t/chat)
|
||||
:navigation :none
|
||||
:right-component [react/view {:flex-direction :row :margin-right 16}
|
||||
[connectivity/connectivity-button]
|
||||
[notifications-button]]}]
|
||||
[chats-list]
|
||||
[plus-button]
|
||||
[tabbar/tabs-counts-subscriptions]])
|
||||
(reagent/create-class
|
||||
{:component-did-mount #(set! (.-navigationEventListener %) (.bindComponent (.events Navigation) % "home"))
|
||||
:componentWillAppear #(do (re-frame/dispatch-sync [:set :view-id :home])
|
||||
(re-frame/dispatch [:close-chat]))
|
||||
:reagent-render
|
||||
(fn []
|
||||
[react/keyboard-avoiding-view {:style {:flex 1}
|
||||
:ignore-offset true}
|
||||
[topbar/topbar {:title (i18n/label :t/chat)
|
||||
:navigation :none
|
||||
:right-component [react/view {:flex-direction :row :margin-right 16}
|
||||
[connectivity/connectivity-button]
|
||||
[notifications-button]]}]
|
||||
[chats-list]
|
||||
[plus-button]
|
||||
[tabbar/tabs-counts-subscriptions]])}))
|
||||
|
||||
@@ -149,13 +149,16 @@
|
||||
:else
|
||||
[icons/icon :main-icons/tiny-new-contact (icon-style)]))
|
||||
|
||||
(defn chat-item-title [chat-id muted group-chat chat-name]
|
||||
(defn chat-item-title [chat-id muted group-chat chat-name edit?]
|
||||
[quo/text {:weight :medium
|
||||
:color (when muted :secondary)
|
||||
:accessibility-label :chat-name-text
|
||||
:ellipsize-mode :tail
|
||||
:number-of-lines 1
|
||||
:style {:position :absolute :left 92 :top 10 :right 90}}
|
||||
:style {:position :absolute
|
||||
:left 92
|
||||
:top 10
|
||||
:right (if edit? 50 90)}}
|
||||
(if group-chat
|
||||
(utils/truncate-str chat-name 30)
|
||||
;; This looks a bit odd, but I would like only to subscribe
|
||||
@@ -164,7 +167,7 @@
|
||||
(first @(re-frame/subscribe [:contacts/contact-two-names-by-identity chat-id])))])
|
||||
|
||||
(defn home-list-item [home-item opts]
|
||||
(let [{:keys [chat-id chat-name color group-chat public? timestamp last-message muted emoji highlight]} home-item
|
||||
(let [{:keys [chat-id chat-name color group-chat public? timestamp last-message muted emoji highlight edit?]} home-item
|
||||
background-color (when highlight (colors/get-color :interactive-02))]
|
||||
[react/touchable-opacity (merge {:style {:height 64 :background-color background-color}} opts)
|
||||
[:<>
|
||||
@@ -178,13 +181,15 @@
|
||||
:default-chat-icon-text (if (string/blank? emoji)
|
||||
(chat-icon.styles/default-chat-icon-text 40)
|
||||
(chat-icon.styles/emoji-chat-icon-text 40))}]
|
||||
[chat-item-title chat-id muted group-chat chat-name]
|
||||
[react/text {:style styles/datetime-text
|
||||
:number-of-lines 1
|
||||
:accessibility-label :last-message-time-text}
|
||||
;;TODO (perf) move to event
|
||||
(memo-timestamp (if (pos? (:whisper-timestamp last-message))
|
||||
(:whisper-timestamp last-message)
|
||||
timestamp))]
|
||||
[message-content-text (select-keys last-message [:content :content-type :community-id]) true]
|
||||
[unviewed-indicator home-item]]]))
|
||||
[chat-item-title chat-id muted group-chat chat-name edit?]
|
||||
(when-not edit?
|
||||
[:<>
|
||||
[react/text {:style styles/datetime-text
|
||||
:number-of-lines 1
|
||||
:accessibility-label :last-message-time-text}
|
||||
;;TODO (perf) move to event
|
||||
(memo-timestamp (if (pos? (:whisper-timestamp last-message))
|
||||
(:whisper-timestamp last-message)
|
||||
timestamp))]
|
||||
[unviewed-indicator home-item]])
|
||||
[message-content-text (select-keys last-message [:content :content-type :community-id]) true]]]))
|
||||
|
||||
@@ -44,6 +44,17 @@
|
||||
[status-im.ui.screens.currency-settings.views :as currency-settings]
|
||||
[status-im.ui.screens.dapps-permissions.views :as dapps-permissions]
|
||||
[status-im.ui.screens.default-sync-period-settings.view :as default-sync-period-settings]
|
||||
[status-im.ui.screens.wallet.settings.views :as wallet-settings]
|
||||
[status-im.ui.screens.wallet.transactions.views :as wallet-transactions]
|
||||
[status-im.ui.screens.wallet.custom-tokens.views :as custom-tokens]
|
||||
[status-im.ui.screens.wallet.accounts.views :as wallet.accounts]
|
||||
[status-im.ui.screens.wallet.collectibles.views :as wallet.collectibles]
|
||||
[status-im.ui.screens.wallet.account.views :as wallet.account]
|
||||
[status-im.ui.screens.wallet.add-new.views :as add-account]
|
||||
[status-im.ui.screens.wallet.account-settings.views :as account-settings]
|
||||
[status-im.ui.screens.wallet.swap.views :as wallet.swap]
|
||||
[status-im.ui.screens.status.views :as status.views]
|
||||
[status-im.ui.screens.profile.user.views :as profile.user]
|
||||
[status-im.ui.screens.ens.views :as ens]
|
||||
[status-im.ui.screens.fleet-settings.views :as fleet-settings]
|
||||
[status-im.ui.screens.glossary.view :as glossary]
|
||||
@@ -91,7 +102,6 @@
|
||||
[status-im.ui.screens.profile.contact.views :as contact]
|
||||
[status-im.ui.screens.profile.group-chat.views :as profile.group-chat]
|
||||
[status-im.ui.screens.profile.seed.views :as profile.seed]
|
||||
[status-im.ui.screens.profile.user.views :as profile.user]
|
||||
[status-im.ui.screens.progress.views :as progress]
|
||||
[status-im.ui.screens.qr-scanner.views :as qr-scanner]
|
||||
[status-im.ui.screens.referrals.public-chat :as referrals.public-chat]
|
||||
@@ -99,7 +109,6 @@
|
||||
[status-im.ui.screens.reset-password.views :as reset-password]
|
||||
[status-im.ui.screens.rpc-usage-info :as rpc-usage-info]
|
||||
[status-im.ui.screens.status.new.views :as status.new]
|
||||
[status-im.ui.screens.status.views :as status.views]
|
||||
[status-im.ui.screens.stickers.views :as stickers]
|
||||
[status-im.ui.screens.sync-settings.views :as sync-settings]
|
||||
[status-im.ui.screens.terms-of-service.views :as terms-of-service]
|
||||
@@ -107,18 +116,10 @@
|
||||
:as
|
||||
edit-wakuv2-node]
|
||||
[status-im.ui.screens.wakuv2-settings.views :as wakuv2-settings]
|
||||
[status-im.ui.screens.wallet.account-settings.views :as account-settings]
|
||||
[status-im.ui.screens.wallet.account.views :as wallet.account]
|
||||
[status-im.ui.screens.wallet.accounts-manage.views :as accounts-manage]
|
||||
[status-im.ui.screens.wallet.accounts.views :as wallet.accounts]
|
||||
[status-im.ui.screens.wallet.add-new.views :as add-account]
|
||||
[status-im.ui.screens.wallet.buy-crypto.views :as wallet.buy-crypto]
|
||||
[status-im.ui.screens.wallet.collectibles.views :as wallet.collectibles]
|
||||
[status-im.ui.screens.wallet.custom-tokens.views :as custom-tokens]
|
||||
[status-im.ui.screens.wallet.recipient.views :as recipient]
|
||||
[status-im.ui.screens.wallet.send.views :as wallet.send]
|
||||
[status-im.ui.screens.wallet.settings.views :as wallet-settings]
|
||||
[status-im.ui.screens.wallet.transactions.views :as wallet-transactions]))
|
||||
[status-im.ui.screens.wallet.send.views :as wallet.send]))
|
||||
|
||||
(def components
|
||||
[{:name :chat-toolbar
|
||||
@@ -219,9 +220,10 @@
|
||||
|
||||
;Chat
|
||||
{:name :chat
|
||||
:options {:topBar {:title {:component {:name :chat-toolbar :id :chat-toolbar}
|
||||
:alignment :fill}
|
||||
:rightButtons (right-button-options :chat :more)}}
|
||||
:options {:popGesture false
|
||||
:topBar {:title {:component {:name :chat-toolbar :id :chat-toolbar}
|
||||
:alignment :fill}
|
||||
:rightButtons (right-button-options :chat :more)}}
|
||||
:right-handler chat/topbar-button
|
||||
:component chat/chat}
|
||||
|
||||
@@ -287,11 +289,6 @@
|
||||
;;TODO custom
|
||||
:options {:topBar {:visible false}}
|
||||
:component select-category/view}
|
||||
{:name :community-edit-chats
|
||||
;;TODO custom
|
||||
:insets {:bottom true}
|
||||
:options {:topBar {:visible false}}
|
||||
:component community/community-edit}
|
||||
{:name :community-reorder-categories
|
||||
:insets {:top false}
|
||||
:options {:topBar {:visible false}}
|
||||
@@ -399,6 +396,32 @@
|
||||
:options {:topBar {:title {:text (i18n/label :t/wallet-manage-accounts)}}}
|
||||
:component accounts-manage/manage}
|
||||
|
||||
{:name :token-swap
|
||||
;;TODO dynamic title
|
||||
:options {:topBar {:visible false}}
|
||||
:component wallet.swap/swap}
|
||||
|
||||
{:name :token-swap-advanced-nonce
|
||||
:options {:topBar {:title {:text (i18n/label :t/nonce)}}}
|
||||
:component wallet.swap/nonce-modal}
|
||||
|
||||
{:name :token-swap-advanced-approve-token
|
||||
:options {:topBar {:title {:text (i18n/label :t/approve-token)}}}
|
||||
:component wallet.swap/approve-token-modal}
|
||||
|
||||
{:name :token-swap-advanced-transaction-fee
|
||||
:options {:topBar {:title {:text (i18n/label :t/transaction-fee)}}}
|
||||
:component wallet.swap/transaction-fee-modal}
|
||||
|
||||
{:name :token-swap-advanced-swap-details
|
||||
:options {:topBar {:title {:text (i18n/label :t/swap-details)}}}
|
||||
:component wallet.swap/swap-details-modal}
|
||||
|
||||
{:name :swap-asset-selector
|
||||
;;TODO dynamic title
|
||||
:options {:topBar {:visible false}}
|
||||
:component wallet.swap/asset-selector}
|
||||
|
||||
;;MY STATUS
|
||||
|
||||
{:name :status
|
||||
@@ -707,8 +730,8 @@
|
||||
:options {:topBar {:visible false}}
|
||||
:component wallet.buy-crypto/website}
|
||||
|
||||
{:name :nft-details
|
||||
:insets {:bottom true}
|
||||
{:name :nft-details
|
||||
:insets {:bottom true}
|
||||
;;TODO dynamic title
|
||||
:options {:topBar {:visible false}}
|
||||
:component wallet.collectibles/nft-details-modal}
|
||||
|
||||
@@ -40,6 +40,8 @@
|
||||
:chevron true
|
||||
:accessory :text
|
||||
:accessory-text (cond
|
||||
(= default-sync-period constants/two-mins)
|
||||
(i18n/label :t/two-minutes)
|
||||
(= default-sync-period constants/one-day)
|
||||
(i18n/label :t/one-day)
|
||||
(= default-sync-period constants/three-days)
|
||||
|
||||
@@ -42,3 +42,19 @@
|
||||
:duration 200
|
||||
:easing (.-ease ^js animation/easing)
|
||||
:useNativeDriver true}))
|
||||
|
||||
(def round-action-button
|
||||
{:background-color colors/blue
|
||||
:height 44
|
||||
:flex 1
|
||||
:justify-content :center
|
||||
:align-items :center
|
||||
:width 44
|
||||
:border-radius 44})
|
||||
|
||||
(def top-actions
|
||||
{:flex 1
|
||||
:flex-direction :row
|
||||
:justify-content :space-between
|
||||
:width "60%"
|
||||
:align-self :center})
|
||||
|
||||
@@ -7,16 +7,17 @@
|
||||
[quo.design-system.colors :as colors]
|
||||
[status-im.ui.components.icons.icons :as icons]
|
||||
[quo.core :as quo]
|
||||
[quo.design-system.spacing :as spacing]
|
||||
[status-im.ui.components.react :as react]
|
||||
[status-im.ui.components.topbar :as topbar]
|
||||
[status-im.utils.config :as config]
|
||||
[status-im.ui.screens.wallet.account.styles :as styles]
|
||||
[status-im.ui.screens.wallet.accounts.sheets :as sheets]
|
||||
[status-im.ui.screens.wallet.accounts.views :as accounts]
|
||||
[status-im.ui.screens.wallet.buy-crypto.views :as buy-crypto]
|
||||
[status-im.ui.screens.wallet.transactions.views :as history]
|
||||
[status-im.ui.components.tabs :as tabs]
|
||||
[status-im.ui.screens.wallet.collectibles.views :as collectibles.views])
|
||||
[status-im.ui.screens.wallet.collectibles.views :as collectibles.views]
|
||||
[status-im.ui.screens.wallet.buy-crypto.views :as buy-crypto])
|
||||
(:require-macros [status-im.utils.views :as views]))
|
||||
|
||||
(def state (reagent/atom {:tab :assets}))
|
||||
@@ -102,7 +103,6 @@
|
||||
currency [:wallet/currency]
|
||||
opensea-enabled? [:opensea-enabled?]
|
||||
collectible-collection [:wallet/collectible-collection address]
|
||||
mainnet? [:mainnet?]
|
||||
ethereum-network? [:ethereum-network?]]
|
||||
(let [{:keys [tab]} @state]
|
||||
[react/view {:flex 1}
|
||||
@@ -111,11 +111,10 @@
|
||||
(when ethereum-network?
|
||||
[tabs/tab-title state :nft (i18n/label :t/wallet-collectibles) (= tab :nft)])
|
||||
[tabs/tab-title state :history (i18n/label :t/history) (= tab :history)]]
|
||||
[quo/separator {:style {:margin-top -8}}]
|
||||
(cond
|
||||
(= tab :assets)
|
||||
[:<>
|
||||
(when mainnet?
|
||||
[buy-crypto/banner])
|
||||
(for [item tokens]
|
||||
^{:key (:name item)}
|
||||
[accounts/render-asset item nil nil (:code currency)])]
|
||||
@@ -181,10 +180,31 @@
|
||||
(styles/bottom-send-recv-buttons-lower anim-y button-group-height)
|
||||
#(reset! to-show false))))))))
|
||||
|
||||
(defn round-action-button [{:keys [icon title on-press]}]
|
||||
[react/view {:style {:flex 1
|
||||
:align-items :center
|
||||
:margin-vertical (:large spacing/spacing)}}
|
||||
[react/touchable-opacity {:style styles/round-action-button
|
||||
:on-press on-press}
|
||||
(icons/icon icon {:color colors/white})]
|
||||
[quo/text {:color :secondary
|
||||
:size :small
|
||||
:style {:margin-top (:tiny spacing/spacing)}}
|
||||
title]])
|
||||
|
||||
(defn top-actions []
|
||||
[react/view {:style styles/top-actions}
|
||||
[round-action-button {:icon :main-icons/add
|
||||
:title (i18n/label :t/buy-crypto)
|
||||
:on-press #(re-frame/dispatch [:buy-crypto.ui/open-screen])}]
|
||||
[round-action-button {:icon :main-icons/change
|
||||
:title (i18n/label :t/swap)
|
||||
:on-press #(re-frame/dispatch [:open-modal :token-swap])}]])
|
||||
|
||||
(views/defview account []
|
||||
(views/letsubs [{:keys [name address] :as account} [:multiaccount/current-account]
|
||||
fetching-error [:wallet/fetching-error]]
|
||||
(let [anim-y (animation/create-value button-group-height)
|
||||
(let [anim-y (animation/create-value button-group-height)
|
||||
scroll-y (animation/create-value 0)]
|
||||
(anim-listener anim-y scroll-y)
|
||||
[:<>
|
||||
@@ -206,9 +226,9 @@
|
||||
@accounts/updates-counter
|
||||
@(re-frame/subscribe [:wallet/refreshing-history?])))}
|
||||
(when fetching-error
|
||||
[react/view {:style {:flex 1
|
||||
[react/view {:style {:flex 1
|
||||
:align-items :center
|
||||
:margin 8}}
|
||||
:margin 8}}
|
||||
[icons/icon
|
||||
:main-icons/warning
|
||||
{:color :red
|
||||
@@ -233,5 +253,8 @@
|
||||
[react/scroll-view {:horizontal true}
|
||||
[react/view {:flex-direction :row :padding-top 8 :padding-bottom 12}
|
||||
[account-card account]]]]
|
||||
(if config/swap-enabled?
|
||||
[top-actions]
|
||||
[buy-crypto/banner])
|
||||
[assets-and-collections address]]
|
||||
[bottom-send-recv-buttons account anim-y]])))
|
||||
|
||||
@@ -0,0 +1,433 @@
|
||||
(ns status-im.ui.screens.wallet.swap.views
|
||||
(:require [quo.core :as quo]
|
||||
[quo.design-system.colors :as colors]
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.ethereum.tokens :as tokens]
|
||||
[status-im.i18n.i18n :as i18n]
|
||||
[status-im.ui.components.chat-icon.screen :as chat-icon]
|
||||
[status-im.ui.components.icons.icons :as icons]
|
||||
[status-im.ui.components.keyboard-avoid-presentation
|
||||
:as
|
||||
kb-presentation]
|
||||
[status-im.ui.components.react :as react]
|
||||
[status-im.ui.components.search-input.view :as search-input]
|
||||
[status-im.ui.components.slider :as slider]
|
||||
[status-im.wallet.swap.core :as wallet.swap]
|
||||
[status-im.ui.components.toolbar :as toolbar]
|
||||
[status-im.ui.components.topbar :as topbar]
|
||||
[status-im.ui.screens.wallet.components.views :as wallet.components]
|
||||
[status-im.utils.handlers :refer [<sub]]
|
||||
[status-im.wallet.utils :as wallet.utils]
|
||||
[clojure.string :as str]))
|
||||
|
||||
(defn render-asset [{{:keys
|
||||
[icon decimals amount color value]
|
||||
:as token} :token
|
||||
currency :currency
|
||||
on-press :on-press}]
|
||||
[quo/list-item
|
||||
{:title [quo/text {:weight :medium}
|
||||
[quo/text {:weight :inherit}
|
||||
(str (if amount
|
||||
(wallet.utils/format-amount amount decimals)
|
||||
"...")
|
||||
" ")]
|
||||
[quo/text {:color :secondary
|
||||
:weight :inherit}
|
||||
(wallet.utils/display-symbol token)]]
|
||||
:on-press on-press
|
||||
:subtitle (str (if value value "...") " " currency)
|
||||
:accessibility-label
|
||||
(str (:symbol token) "-asset-value")
|
||||
:icon (if icon
|
||||
[wallet.components/token-icon icon]
|
||||
[chat-icon/custom-icon-view-list (:name token) color])}])
|
||||
|
||||
(defn asset-selector []
|
||||
(let [{:keys [address]} (<sub [:multiaccount/current-account])
|
||||
{:keys [tokens]} (<sub [:wallet/visible-assets-with-values address])
|
||||
source? (<sub [:wallet/modal-selecting-source-token?])
|
||||
currency (<sub [:wallet/currency])]
|
||||
[:<>
|
||||
[topbar/topbar
|
||||
{:title (if source?
|
||||
(i18n/label :t/select-token-to-swap)
|
||||
(i18n/label :t/select-token-to-receive))
|
||||
:modal? true}]
|
||||
|
||||
[search-input/search-input
|
||||
{:search-active? true}]
|
||||
|
||||
[react/scroll-view
|
||||
(for [token tokens]
|
||||
^{:key (:name token)}
|
||||
[render-asset {:token token
|
||||
:on-press #(re-frame/dispatch
|
||||
[(if source?
|
||||
::wallet.swap/set-from-token
|
||||
::wallet.swap/set-to-token)
|
||||
(:symbol token)])
|
||||
:currency (:code currency)}])]]))
|
||||
|
||||
(defn pill-button [{:keys [on-press label margin-left]}]
|
||||
[react/touchable-opacity {:on-press on-press
|
||||
:style {:background-color colors/blue-light
|
||||
:padding-horizontal 12
|
||||
:padding-vertical 2
|
||||
:border-radius 24
|
||||
:margin-left (or margin-left 8)}}
|
||||
[quo/text {:color :link
|
||||
:weight :medium} label]])
|
||||
|
||||
(defn token-display
|
||||
"Show token and act as an anchor to open selector."
|
||||
[{:keys [token source?]}]
|
||||
(let [token-icon-source (-> token :icon :source)]
|
||||
[react/touchable-highlight
|
||||
{:on-press #(re-frame/dispatch [::wallet.swap/open-asset-selector-modal source?])}
|
||||
[react/view {:style {:flex-direction :row
|
||||
:align-items :center
|
||||
:border-width 1
|
||||
:border-color colors/gray-lighter
|
||||
:border-radius 8
|
||||
:margin-left 16
|
||||
:padding-horizontal 8
|
||||
:padding-vertical 2}
|
||||
:accessibility-label
|
||||
:choose-asset-button}
|
||||
[quo/text {:style {:margin-right 8}}
|
||||
(-> token :symbol name)]
|
||||
[react/image {:source (if (fn? token-icon-source)
|
||||
(token-icon-source)
|
||||
token-icon-source)}]]]))
|
||||
|
||||
(defn token-input
|
||||
"Component to get the amount and type of tokens"
|
||||
[{:keys [amount error label token max-from source?]}]
|
||||
(let [window-width (<sub [:dimensions/window-width])]
|
||||
[react/view {:style {:justify-content :space-between
|
||||
:flex-direction :row
|
||||
:align-items :center}}
|
||||
[react/view {:flex 2}
|
||||
[react/view {:flex-direction :row
|
||||
:align-items :center}
|
||||
[quo/text label]
|
||||
(when max-from [pill-button {:on-press #()
|
||||
:label "Max 0.043"}])]
|
||||
[react/text-input
|
||||
{:style {:font-size 38
|
||||
:max-width (- (* (/ window-width 4) 3) 106)
|
||||
:color (if error colors/red colors/black)}
|
||||
:keyboard-type :decimal-pad
|
||||
:auto-capitalize :words
|
||||
:accessibility-label :amount-input
|
||||
:default-value amount
|
||||
:editable true
|
||||
:auto-focus true
|
||||
:on-change-text #(re-frame/dispatch [(when source?
|
||||
::wallet.swap/set-from-token-amount)
|
||||
%])
|
||||
:placeholder "0.0"}]]
|
||||
[token-display {:token token
|
||||
:source? source?}]]))
|
||||
|
||||
(defn separator-with-icon []
|
||||
[react/view
|
||||
{:margin-vertical 8}
|
||||
[quo/separator]
|
||||
[react/touchable-opacity
|
||||
{:on-press #(re-frame/dispatch [::wallet.swap/switch-from-token-with-to])}
|
||||
[react/view {:style {:background-color colors/gray-lighter
|
||||
:width 40
|
||||
:height 40
|
||||
:border-radius 40
|
||||
:border-width 4
|
||||
:border-color colors/white
|
||||
:margin-top -20
|
||||
:margin-bottom -20
|
||||
:align-self :center
|
||||
:align-items :center
|
||||
:justify-content :center}}
|
||||
[react/image {:source (icons/icon-source :main-icons/change)
|
||||
:style {:tint-color colors/gray
|
||||
:transform [{:rotate "90deg"}]}}]]]])
|
||||
|
||||
(defn floating-card [{:keys [icon title body on-press]}]
|
||||
[react/view {:style {:border-width 1
|
||||
:padding 2 ;; need a padding because border breaks otherwise
|
||||
:border-radius 12
|
||||
:margin-top 12
|
||||
:border-color colors/gray-lighter}}
|
||||
[quo/list-item {:title title
|
||||
:subtitle body
|
||||
:active-background-enabled
|
||||
false
|
||||
:on-press on-press
|
||||
:theme :main
|
||||
:chevron true
|
||||
:icon [react/view {:style {:background-color colors/blue-light
|
||||
:padding 8
|
||||
:border-radius 4}}
|
||||
(icons/icon icon {:color :dark})]}]])
|
||||
|
||||
(defn card-body-row [key value primary?]
|
||||
[react/view {:flex-direction :row}
|
||||
[quo/text {:color (when-not primary? :secondary)} key]
|
||||
[quo/text {:style {:margin-right 4}
|
||||
:color (when-not primary? :secondary)} ":"]
|
||||
[quo/text {:ellipsize-mode :middle
|
||||
:number-of-lines 1
|
||||
:style {:width "50%"}
|
||||
:color (when-not primary? :secondary)
|
||||
:weight :semi-bold} value]])
|
||||
|
||||
(defn transaction-fee-card [{:keys [gas-amount price-limit tip-limit gas-in-eth gas-in-usd]}]
|
||||
[floating-card {:title (i18n/label :t/transaction-fee)
|
||||
:icon :main-icons/gas
|
||||
:on-press #(re-frame/dispatch [:open-modal :token-swap-advanced-transaction-fee])
|
||||
:body [react/view
|
||||
[card-body-row (i18n/label :t/gas-amount-limit) gas-amount]
|
||||
[card-body-row (i18n/label :t/per-gas-price-limit) price-limit]
|
||||
[card-body-row (i18n/label :t/per-gas-tip-limit) tip-limit]
|
||||
[card-body-row (i18n/label :t/total-gas)
|
||||
(str gas-in-eth " • $" gas-in-usd)
|
||||
true]]}])
|
||||
|
||||
(defn swap-details-card [{:keys [slippage price-impact]}]
|
||||
[floating-card {:title (i18n/label :t/swap-details)
|
||||
:icon :main-icons/change
|
||||
:on-press #(re-frame/dispatch [:open-modal :token-swap-advanced-swap-details])
|
||||
:body [react/view
|
||||
[card-body-row (i18n/label :t/slippage) (str slippage " %")]
|
||||
[card-body-row (i18n/label :t/price-impact) (str price-impact " %")]]}])
|
||||
|
||||
(defn nonce-card [{:keys [nonce]}]
|
||||
[floating-card {:title (i18n/label :t/nonce)
|
||||
:icon :main-icons/channel
|
||||
:on-press #(re-frame/dispatch [:open-modal :token-swap-advanced-nonce])
|
||||
:body [react/view
|
||||
[card-body-row (i18n/label :t/nonce) nonce]]}])
|
||||
|
||||
(defn approve-token-card [{:keys [token contract-address approve-limit]}]
|
||||
[floating-card {:title (i18n/label :t/approve)
|
||||
:icon :main-icons/check
|
||||
:on-press #(re-frame/dispatch [:open-modal :token-swap-advanced-approve-token])
|
||||
:body [react/view
|
||||
[card-body-row (i18n/label :t/token) token]
|
||||
[card-body-row (i18n/label :t/contract-address) contract-address]
|
||||
[card-body-row (i18n/label :t/approve-limit) approve-limit]]}])
|
||||
|
||||
(defn advanced-input [{:keys [label label-help value on-change after]}]
|
||||
[react/view {:style {:padding-horizontal 16
|
||||
:margin-bottom 16}}
|
||||
[react/view {:style {:flex-direction :row
|
||||
:justify-content :space-between}}
|
||||
[quo/text {} label]
|
||||
label-help]
|
||||
|
||||
[quo/text-input {:default-value (str value)
|
||||
:show-cancel false
|
||||
:style {:margin-top 12
|
||||
:border-radius 8}
|
||||
:after {:component after}
|
||||
:on-change-text on-change}]])
|
||||
|
||||
(defn help-label-kv [{:keys [key value]}]
|
||||
[react/view {:style {:flex-direction :row}}
|
||||
[quo/text {:color :secondary} key]
|
||||
[quo/text {:color :secondary
|
||||
:style {:margin-right 4}} ":"]
|
||||
[quo/text {:color :secondary} value]])
|
||||
|
||||
(defn nonce-modal []
|
||||
(let [last-txn-nonce 22
|
||||
nonce 23]
|
||||
[kb-presentation/keyboard-avoiding-view {:style {:flex 1
|
||||
:margin-top 16}
|
||||
:ignore-offset true}
|
||||
[advanced-input {:label (i18n/label :t/nonce)
|
||||
:label-help [help-label-kv {:key (i18n/label :t/last-transaction)
|
||||
:value last-txn-nonce}]
|
||||
:value nonce
|
||||
:on-change #()
|
||||
:on-save #()}]
|
||||
[toolbar/toolbar
|
||||
{:show-border? true
|
||||
:left [quo/button {:type :secondary}
|
||||
(i18n/label :t/cancel)]
|
||||
:right [quo/button {:theme :accent}
|
||||
(i18n/label :t/save)]}]]))
|
||||
|
||||
(defn approve-token-modal []
|
||||
[quo/text "modal"])
|
||||
|
||||
(defn transaction-fee-modal []
|
||||
(let [gas-amount-limit 21000
|
||||
gas-amount 21000
|
||||
per-gas-price-limit 7.3
|
||||
current-avg-per-gas-price-limit 7.3
|
||||
per-gas-tip-limit 150
|
||||
current-avg-per-gas-tip-limit 150]
|
||||
[kb-presentation/keyboard-avoiding-view {:style {:flex 1
|
||||
:margin-top 16}
|
||||
:ignore-offset true}
|
||||
[react/view {:flex 1}
|
||||
[advanced-input {:label (i18n/label :t/gas-amount-limit)
|
||||
:label-help [help-label-kv {:key (i18n/label :t/limit)
|
||||
:value gas-amount-limit}]
|
||||
:value gas-amount
|
||||
:after [quo/text {:color :secondary} (i18n/label :t/gwei)]
|
||||
:on-change #()
|
||||
:on-save #()}]
|
||||
|
||||
[advanced-input {:label (i18n/label :t/per-gas-price-limit)
|
||||
:label-help [help-label-kv {:key (i18n/label :t/current-average)
|
||||
:value current-avg-per-gas-price-limit}]
|
||||
:value per-gas-price-limit
|
||||
:after [quo/text {:color :secondary} (i18n/label :t/gwei)]
|
||||
:on-change #()
|
||||
:on-save #()}]
|
||||
|
||||
[advanced-input {:label (i18n/label :t/per-gas-price-limit)
|
||||
:label-help [help-label-kv {:key (i18n/label :t/current-average)
|
||||
:value current-avg-per-gas-tip-limit}]
|
||||
:value per-gas-tip-limit
|
||||
:after [quo/text {:color :secondary} (i18n/label :t/gwei)]
|
||||
:on-change #()
|
||||
:on-save #()}]
|
||||
|
||||
[quo/list-item {:title (i18n/label :t/maximum-fee)
|
||||
:text-size :base
|
||||
:title-text-weight :regular
|
||||
:accessory :text
|
||||
:accessory-text [quo/text "0.3 ETH"]
|
||||
:container-style {:margin-top 16}}]
|
||||
[quo/text {:color :secondary
|
||||
:style {:padding-horizontal 16}}
|
||||
(i18n/label :t/maximum-fee-desc)]]
|
||||
[toolbar/toolbar
|
||||
{:show-border? true
|
||||
:left [quo/button {:type :secondary}
|
||||
(i18n/label :t/cancel)]
|
||||
:right [quo/button {:theme :accent}
|
||||
(i18n/label :t/save)]}]]))
|
||||
|
||||
(defn swap-details-modal []
|
||||
(let [slippage-limit 20
|
||||
slippage 0.5
|
||||
price-impact 4]
|
||||
[kb-presentation/keyboard-avoiding-view {:style {:flex 1
|
||||
:margin-top 16}
|
||||
:ignore-offset true}
|
||||
[react/view {:flex 1}
|
||||
[advanced-input {:label (str (i18n/label :t/slippage) " %")
|
||||
:label-help [help-label-kv {:key (i18n/label :t/limit)
|
||||
:value (str slippage-limit "%")}]
|
||||
:value slippage
|
||||
:on-change #()
|
||||
:on-save #()}]
|
||||
|
||||
[quo/list-item {:title (i18n/label :t/price-impact)
|
||||
:text-size :base
|
||||
:title-text-weight :regular
|
||||
:accessory :text
|
||||
:accessory-text (str price-impact "%")
|
||||
:container-style {:margin-top 16}}]
|
||||
[quo/text {:color :secondary
|
||||
:style {:padding-horizontal 16}}
|
||||
(i18n/label :t/price-impact-desc)]]
|
||||
[toolbar/toolbar
|
||||
{:show-border? true
|
||||
:left [quo/button {:type :secondary}
|
||||
(i18n/label :t/cancel)]
|
||||
:right [quo/button {:theme :accent}
|
||||
(i18n/label :t/save)]}]]))
|
||||
|
||||
(defn advanced-settings []
|
||||
[react/view {:style {:flex 1
|
||||
:padding-horizontal 16}}
|
||||
[react/view {:align-self :flex-start}
|
||||
[pill-button {:label (i18n/label :t/switch-to-simple-interface)
|
||||
:margin-left 0
|
||||
:on-press #(re-frame/dispatch [::wallet.swap/set-advanced-mode false])}]]
|
||||
[transaction-fee-card {:gas-amount 21000
|
||||
:price-limit 74
|
||||
:tip-limit 21
|
||||
:gas-in-eth 0.0031
|
||||
:gas-in-usd 34.28}]
|
||||
[swap-details-card {:slippage 0.5
|
||||
:price-impact 4}]
|
||||
[approve-token-card {:token "USDC"
|
||||
:contract-address "0x9f8f72aa9304c8b593d555f12ef6589cc3a579a2"
|
||||
:approve-limit "unlimited"}]
|
||||
[nonce-card {:nonce 22}]])
|
||||
|
||||
(defn swap []
|
||||
(let [{:keys [name]}
|
||||
(<sub [:multiaccount/current-account])
|
||||
all-tokens (<sub [:wallet/all-tokens])
|
||||
from-symbol (<sub [:wallet/swap-from-token])
|
||||
to-symbol (<sub [:wallet/swap-to-token])
|
||||
advanced-mode? (<sub [:wallet/swap-advanced-mode?])
|
||||
amount "0.02"
|
||||
from-token (tokens/symbol->token all-tokens (or from-symbol :DGX))
|
||||
to-token (tokens/symbol->token all-tokens (or to-symbol :SNT))]
|
||||
|
||||
[kb-presentation/keyboard-avoiding-view {:style (merge
|
||||
{:flex 1})
|
||||
:ignore-offset true}
|
||||
[topbar/topbar
|
||||
{:title name
|
||||
:subtitle (str/upper-case (i18n/label :t/powered-by-paraswap))
|
||||
:modal? true}]
|
||||
|
||||
[react/view (merge {:padding-horizontal 16
|
||||
:margin-vertical 32}
|
||||
(when-not advanced-mode?
|
||||
{:flex 1}))
|
||||
[token-input {:amount amount
|
||||
:error nil
|
||||
:label (i18n/label :t/amount)
|
||||
:token from-token
|
||||
:source? true
|
||||
:max-from 67.28}]
|
||||
|
||||
[separator-with-icon]
|
||||
|
||||
[token-input {:amount "0.01"
|
||||
:error nil
|
||||
:label (i18n/label :t/minimum-received)
|
||||
:source? false
|
||||
:token to-token}]]
|
||||
|
||||
(when-not advanced-mode?
|
||||
[react/view {:style {:flex-direction :row
|
||||
:justify-content :space-between
|
||||
:padding-horizontal 16
|
||||
:align-items :center}}
|
||||
[react/view {:style {:flex-direction :row}}
|
||||
[quo/text {} (i18n/label :t/priority)]
|
||||
[pill-button {:label (i18n/label :t/advanced)
|
||||
:on-press #(re-frame/dispatch [::wallet.swap/set-advanced-mode true])}]]
|
||||
|
||||
[quo/text {:color :secondary} "0.0034 ETH/ $ 8.09"]])
|
||||
|
||||
(comment
|
||||
(re-frame/dispatch [::wallet.swap/set-advanced-mode false]))
|
||||
|
||||
(when-not advanced-mode?
|
||||
[react/view {:style {:padding-horizontal 16}}
|
||||
[slider/animated-slider
|
||||
{:minimum-value 0
|
||||
:maximum-value 100
|
||||
:style {:margin-vertical 8}}]])
|
||||
|
||||
(when advanced-mode?
|
||||
[quo/text "here"]
|
||||
[advanced-settings])
|
||||
|
||||
[toolbar/toolbar
|
||||
{:show-border? true
|
||||
:right [quo/button {:theme :accent}
|
||||
(i18n/label :t/swap)]}]]))
|
||||
|
||||
@@ -52,6 +52,8 @@
|
||||
(def delete-message-enabled? (enabled? (get-config :DELETE_MESSAGE_ENABLED "0")))
|
||||
(def collectibles-enabled? (enabled? (get-config :COLLECTIBLES_ENABLED "1")))
|
||||
(def test-stateofus? (enabled? (get-config :TEST_STATEOFUS "0")))
|
||||
(def two-minutes-syncing? (enabled? (get-config :TWO_MINUTES_SYNCING "0")))
|
||||
(def swap-enabled? (enabled? (get-config :SWAP_ENABLED "0")))
|
||||
|
||||
;; CONFIG VALUES
|
||||
(def log-level
|
||||
@@ -110,12 +112,6 @@
|
||||
:DataDir "/ethereum/xdai_rpc"
|
||||
:UpstreamConfig {:Enabled true
|
||||
:URL "https://dai.poa.network"}}}
|
||||
{:id "poa_rpc",
|
||||
:name "POA Network",
|
||||
:config {:NetworkId (ethereum/chain-keyword->chain-id :poa)
|
||||
:DataDir "/ethereum/poa_rpc"
|
||||
:UpstreamConfig {:Enabled true
|
||||
:URL "https://core.poa.network"}}}
|
||||
{:id "bsc_rpc",
|
||||
:chain-explorer-link "https://bscscan.com/address/",
|
||||
:name "BSC Network",
|
||||
|
||||
@@ -51,11 +51,14 @@
|
||||
(swap! handlers/handler-nesting-level inc))
|
||||
(let [[first-arg & rest-args] args
|
||||
initial-fxs? (map? first-arg)
|
||||
fx-fns (if initial-fxs? rest-args args)]
|
||||
(clojure.core/reduce (fn [fxs fx-fn]
|
||||
(let [updated-cofx (update-db cofx fxs)]
|
||||
(if fx-fn
|
||||
(safe-merge fxs (fx-fn updated-cofx))
|
||||
fxs)))
|
||||
(if initial-fxs? first-arg {:db db})
|
||||
fx-fns)))
|
||||
fx-fns (if initial-fxs? rest-args args)
|
||||
res
|
||||
(clojure.core/reduce (fn [fxs fx-fn]
|
||||
(let [updated-cofx (update-db cofx fxs)]
|
||||
(if fx-fn
|
||||
(safe-merge fxs (fx-fn updated-cofx))
|
||||
fxs)))
|
||||
(if initial-fxs? first-arg {:db db})
|
||||
fx-fns)]
|
||||
(swap! handlers/handler-nesting-level dec)
|
||||
res))
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
(defn- format-price-resp [resp mainnet?]
|
||||
;;NOTE(this check is to allow value conversion for sidechains with native currencies listed on cryptocompare
|
||||
;; under a symbol different than display symbol. Specific use case xDAI and POA.
|
||||
;; under a symbol different than display symbol. Specific use case xDAI.
|
||||
(if mainnet?
|
||||
(when-let [RAW (:RAW (types/json->clj resp))]
|
||||
(into {} (for [[from entries] RAW]
|
||||
|
||||
@@ -72,7 +72,7 @@
|
||||
(fx/defn handle-community-chat [cofx {:keys [chat-id]}]
|
||||
(log/info "universal-links: handling community chat" chat-id)
|
||||
{:dispatch-n [[:accept-all-activity-center-notifications-from-chat chat-id]
|
||||
[:chat.ui/navigate-to-chat chat-id true]]})
|
||||
[:chat.ui/navigate-to-chat chat-id]]})
|
||||
|
||||
(fx/defn handle-public-chat [cofx {:keys [topic]}]
|
||||
(log/info "universal-links: handling public chat" topic)
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
(ns status-im.wallet.swap.core
|
||||
(:require [status-im.utils.fx :as fx]
|
||||
[re-frame.db :as re-frame.db]
|
||||
[status-im.navigation :as navigation]))
|
||||
|
||||
(fx/defn open-asset-selector-modal
|
||||
"source? true signinfies we are selecting the source asset. false implies selection of sink asset"
|
||||
{:events [::open-asset-selector-modal]}
|
||||
[{:keys [db]} source?]
|
||||
(fx/merge {:db (assoc db :wallet/modal-selecting-source-token? source?)}
|
||||
(navigation/open-modal :swap-asset-selector {})))
|
||||
|
||||
(fx/defn set-from-token
|
||||
{:events [::set-from-token]}
|
||||
[{:keys [db]} from-symbol]
|
||||
(fx/merge {:db (assoc db :wallet/swap-from-token from-symbol)}
|
||||
(navigation/navigate-back)))
|
||||
|
||||
(fx/defn set-to-token
|
||||
{:events [::set-to-token]}
|
||||
[{:keys [db]} to-symbol]
|
||||
(fx/merge {:db (assoc db :wallet/swap-to-token to-symbol)}
|
||||
(navigation/navigate-back)))
|
||||
|
||||
(fx/defn set-from-token-amount
|
||||
[{:keys [db]} from-amount]
|
||||
{:db (assoc db :wallet/swap-from-token-amount from-amount)})
|
||||
|
||||
(fx/defn set-max-from-token-amount
|
||||
[{:keys [db]} _]
|
||||
{:db (assoc db :wallet/swap-from-token-amount 0)})
|
||||
|
||||
(fx/defn switch-from-token-with-to
|
||||
{:events [::switch-from-token-with-to]}
|
||||
[{:keys [db]}]
|
||||
{:db (assoc db
|
||||
:wallet/swap-from-token (:wallet/swap-to-token db)
|
||||
:wallet/swap-to-token (:wallet/swap-from-token db))})
|
||||
|
||||
(fx/defn set-advanced-mode
|
||||
{:events [::set-advanced-mode]}
|
||||
[{:keys [db]} mode]
|
||||
{:db (assoc db :wallet/swap-advanced-mode? mode)})
|
||||
|
||||
(comment
|
||||
(->> re-frame.db/app-db
|
||||
deref
|
||||
:wallet/all-tokens
|
||||
vals
|
||||
(map #(str (:name %) "-" (:symbol %)))))
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"_comment": "Instead use: scripts/update-status-go.sh <rev>",
|
||||
"owner": "status-im",
|
||||
"repo": "status-go",
|
||||
"version": "v0.91.12",
|
||||
"commit-sha1": "f60cf5cd47c9f50f1bfb8e01aa5f49802d5220c5",
|
||||
"src-sha256": "10dwxrav77v7xvbzy9camacdflsvpyjnwry638jhgrd4i32x745f"
|
||||
"version": "feat/node-config",
|
||||
"commit-sha1": "3daf1ea073fe1aa636a9d301a8e2a04acd7adbca",
|
||||
"src-sha256": "1vc70av6jvsch12hyr32hsnh5yqsaavmhy32d20zx3nfb3kxgv12"
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[pytest]
|
||||
norecursedirs = .git views
|
||||
addopts = -s -v --tb=line --junitxml=result.xml
|
||||
addopts = -s -v --tb=line --junitxml=result.xml --dist loadgroup -n 5
|
||||
junit_family=legacy
|
||||
markers =
|
||||
critical: TCs by priority
|
||||
|
||||
@@ -17,7 +17,7 @@ future==0.18.2
|
||||
flaky==3.7.0
|
||||
idna==2.10
|
||||
kiwisolver==1.3.1
|
||||
lxml==4.6.2
|
||||
lxml==4.6.5
|
||||
matplotlib==3.3.3
|
||||
multidict==5.0.2
|
||||
namedlist==1.8
|
||||
@@ -30,9 +30,9 @@ pycryptodome==3.9.9
|
||||
pyethash==0.1.27
|
||||
pyparsing==2.4.7
|
||||
pysha3==1.0.2
|
||||
pytest==6.1.2
|
||||
pytest==6.2.0
|
||||
pytest-forked==1.3.0
|
||||
pytest-xdist==2.2.0
|
||||
pytest-xdist==2.5.0
|
||||
python-dateutil==2.8.1
|
||||
pytz==2020.4
|
||||
PyYAML==5.4
|
||||
@@ -42,11 +42,11 @@ rlp==1.2.0
|
||||
sauceclient==1.0.0
|
||||
scrypt==0.8.17
|
||||
selenium==3.14.1
|
||||
six==1.10.0
|
||||
six==1.11.0
|
||||
urllib3==1.26.3
|
||||
yarl==1.6.3
|
||||
zbarlight==3.0
|
||||
docker==4.4.0
|
||||
influxdb==5.3.1
|
||||
web3
|
||||
imagehash
|
||||
web3==5.25.0
|
||||
imagehash
|
||||
@@ -97,10 +97,11 @@ class TestrailReport(BaseTestReport):
|
||||
|
||||
def get_regression_cases(self):
|
||||
test_cases = dict()
|
||||
test_cases['critical'] = 734
|
||||
test_cases['high'] = 735
|
||||
test_cases['critical'] = 730
|
||||
test_cases['medium'] = 736
|
||||
test_cases['upgrade'] = 881
|
||||
test_cases['public_chat'] = 50654
|
||||
test_cases['one_to_one_chat'] = 50655
|
||||
case_ids = list()
|
||||
for arg in argv:
|
||||
if "run_testrail_ids" in arg:
|
||||
@@ -108,7 +109,7 @@ class TestrailReport(BaseTestReport):
|
||||
case_ids = value.split(',')
|
||||
if len(case_ids) == 0:
|
||||
if 'critical or high' in argv:
|
||||
for case in self.get_cases([test_cases['critical'], test_cases['high']]):
|
||||
for case in self.get_cases([test_cases['critical'], test_cases['public_chat'], test_cases['one_to_one_chat']]):
|
||||
case_ids.append(case['id'])
|
||||
elif 'upgrade' in argv and 'not upgrade' not in argv:
|
||||
for case in self.get_cases([test_cases['upgrade']]):
|
||||
|
||||
@@ -96,7 +96,7 @@ class TestCreateAccount(SingleDeviceTestCase):
|
||||
sign_in.get_started_button.click()
|
||||
if sign_in.generate_key_button.is_element_displayed():
|
||||
self.errors.append("Agree with ToS is not mandatory to proceed onboarding!")
|
||||
sign_in.accept_tos_checkbox.click()
|
||||
sign_in.accept_tos_checkbox.enable()
|
||||
sign_in.get_started_button.click_until_presence_of_element(sign_in.generate_key_button)
|
||||
sign_in.generate_key_button.click()
|
||||
from views.sign_in_view import MultiAccountButton
|
||||
@@ -141,7 +141,7 @@ class TestCreateAccount(SingleDeviceTestCase):
|
||||
@marks.high
|
||||
def test_pass_phrase_validation(self):
|
||||
sign_in = SignInView(self.driver)
|
||||
sign_in.accept_tos_checkbox.click()
|
||||
sign_in.accept_tos_checkbox.enable()
|
||||
sign_in.get_started_button.click_until_presence_of_element(sign_in.access_key_button)
|
||||
sign_in.access_key_button.click()
|
||||
validations = [
|
||||
@@ -219,7 +219,7 @@ class TestCreateAccount(SingleDeviceTestCase):
|
||||
@marks.medium
|
||||
def test_create_account_short_and_mismatch_password(self):
|
||||
sign_in = SignInView(self.driver)
|
||||
sign_in.accept_tos_checkbox.click()
|
||||
sign_in.accept_tos_checkbox.enable()
|
||||
sign_in.get_started_button.click()
|
||||
sign_in.generate_key_button.click()
|
||||
sign_in.next_button.click()
|
||||
|
||||
@@ -61,7 +61,7 @@ class TestCreateAccount(SingleDeviceTestCase):
|
||||
sign_in.confirm_button.click()
|
||||
keycard = sign_in.move_and_reset_button.click()
|
||||
keycard.begin_setup_button.click()
|
||||
keycard.connect_card_button.click()
|
||||
keycard.connect_card_button.wait_and_click()
|
||||
keycard.enter_default_pin()
|
||||
keycard.enter_default_pin()
|
||||
if not sign_in.element_by_translation_id("migration-successful").is_element_displayed(30):
|
||||
@@ -126,7 +126,7 @@ class TestCreateAccount(SingleDeviceTestCase):
|
||||
sign_in.migration_password_input.set_value(common_password)
|
||||
sign_in.confirm_button.click()
|
||||
keycard.begin_setup_button.click()
|
||||
keycard.connect_card_button.click()
|
||||
keycard.connect_card_button.wait_and_click()
|
||||
keycard.enter_default_pin()
|
||||
keycard.enter_default_pin()
|
||||
if not sign_in.element_by_translation_id("migration-successful").is_element_displayed(30):
|
||||
@@ -179,7 +179,7 @@ class TestCreateAccount(SingleDeviceTestCase):
|
||||
sign_in = SignInView(self.driver)
|
||||
|
||||
sign_in.just_fyi('Cancel on PIN code setup stage')
|
||||
sign_in.accept_tos_checkbox.click()
|
||||
sign_in.accept_tos_checkbox.enable()
|
||||
sign_in.get_started_button.click()
|
||||
sign_in.generate_key_button.click()
|
||||
username = sign_in.first_username_on_choose_chat_name.text
|
||||
@@ -187,7 +187,7 @@ class TestCreateAccount(SingleDeviceTestCase):
|
||||
keycard_flow = sign_in.keycard_storage_button.click()
|
||||
keycard_flow.next_button.click()
|
||||
keycard_flow.begin_setup_button.click()
|
||||
keycard_flow.connect_card_button.click()
|
||||
keycard_flow.connect_card_button.wait_and_click()
|
||||
keycard_flow.enter_another_pin()
|
||||
keycard_flow.cancel_button.click()
|
||||
|
||||
@@ -232,7 +232,7 @@ class TestCreateAccount(SingleDeviceTestCase):
|
||||
@marks.flaky
|
||||
def test_keycard_interruption_access_key_onboarding_flow(self):
|
||||
sign_in = SignInView(self.driver)
|
||||
sign_in.accept_tos_checkbox.click()
|
||||
sign_in.accept_tos_checkbox.enable()
|
||||
sign_in.get_started_button.click()
|
||||
|
||||
sign_in.access_key_button.click()
|
||||
@@ -246,7 +246,7 @@ class TestCreateAccount(SingleDeviceTestCase):
|
||||
sign_in.just_fyi('Cancel on PIN code setup stage')
|
||||
keycard_flow.next_button.click()
|
||||
keycard_flow.begin_setup_button.click()
|
||||
keycard_flow.connect_card_button.click()
|
||||
keycard_flow.connect_card_button.wait_and_click()
|
||||
keycard_flow.enter_another_pin()
|
||||
keycard_flow.cancel_button.click()
|
||||
|
||||
@@ -277,7 +277,7 @@ class TestCreateAccount(SingleDeviceTestCase):
|
||||
recovered_user = transaction_senders['A']
|
||||
|
||||
sign_in.just_fyi('Recover multiaccount')
|
||||
sign_in.accept_tos_checkbox.click()
|
||||
sign_in.accept_tos_checkbox.enable()
|
||||
sign_in.get_started_button.click_until_presence_of_element(sign_in.access_key_button)
|
||||
sign_in.access_key_button.click()
|
||||
sign_in.recover_with_keycard_button.click()
|
||||
@@ -324,7 +324,7 @@ class TestCreateAccount(SingleDeviceTestCase):
|
||||
sign_in.toggle_airplane_mode()
|
||||
|
||||
sign_in.just_fyi('Recover multiaccount offline')
|
||||
sign_in.accept_tos_checkbox.click()
|
||||
sign_in.accept_tos_checkbox.enable()
|
||||
sign_in.get_started_button.click_until_presence_of_element(sign_in.access_key_button)
|
||||
sign_in.access_key_button.click()
|
||||
sign_in.recover_with_keycard_button.click()
|
||||
@@ -673,7 +673,7 @@ class TestKeycardCreateMultiaccountMultipleDevice(MultipleDeviceTestCase):
|
||||
device_1, device_2 = SignInView(self.drivers[0]), SignInView(self.drivers[1])
|
||||
|
||||
device_1.just_fyi("Create keycard account and save seed phrase")
|
||||
device_1.accept_tos_checkbox.click()
|
||||
device_1.accept_tos_checkbox.enable()
|
||||
device_1.get_started_button.click()
|
||||
device_1.generate_key_button.click_until_presence_of_element(device_1.next_button)
|
||||
device_1.next_button.click_until_absense_of_element(device_1.element_by_translation_id("intro-wizard-title2"))
|
||||
|
||||
@@ -754,9 +754,9 @@ class TestProfileMultipleDevice(MultipleDeviceTestCase):
|
||||
profile_1.just_fyi('Check profile image updated in group chat invite')
|
||||
home_1.get_back_to_home_view()
|
||||
new_group_chat = 'new_gr'
|
||||
home_1.create_group_chat(user_names_to_add=[default_username_2], group_chat_name=new_group_chat)
|
||||
home_2.click_system_back_button()
|
||||
home_2.open_notification_bar()
|
||||
home_1.create_group_chat(user_names_to_add=[default_username_2], group_chat_name=new_group_chat)
|
||||
|
||||
invite = group_chat_2.pn_invited_to_group_chat(default_username_1, new_group_chat)
|
||||
home_2.get_pn(invite).wait_for_visibility_of_element(30)
|
||||
@@ -1036,7 +1036,7 @@ class TestProfileMultipleDevice(MultipleDeviceTestCase):
|
||||
profile_1.mail_server_button.click()
|
||||
profile_1.use_history_node_button.click()
|
||||
profile_1.home_button.click(desired_view='chat')
|
||||
if not public_chat_1.chat_element_by_text(message).is_element_displayed(30):
|
||||
if not public_chat_1.chat_element_by_text(message).is_element_displayed(60):
|
||||
self.errors.append('History was not fetched after enabling use_history_node')
|
||||
self.errors.verify_no_errors()
|
||||
|
||||
@@ -1219,7 +1219,7 @@ class TestProfileMultipleDevice(MultipleDeviceTestCase):
|
||||
|
||||
@marks.testrail_id(695856)
|
||||
@marks.medium
|
||||
@marks.flaky
|
||||
#@marks.flaky
|
||||
def test_pair_devices_sync_photo_community_group_chats(self):
|
||||
self.create_drivers(2)
|
||||
device_1, device_2 = SignInView(self.drivers[0]), SignInView(self.drivers[1])
|
||||
@@ -1287,6 +1287,7 @@ class TestProfileMultipleDevice(MultipleDeviceTestCase):
|
||||
if not channel_2.chat_element_by_text(message_after_sync).is_element_displayed(30):
|
||||
self.errors.append("Message sent to community channel after sync is not shown!")
|
||||
[channel.back_button.click() for channel in (channel_1, channel_2)]
|
||||
[home.get_chat(comm_before_sync_name, community=True).click() for home in (home_1, home_2)]
|
||||
comm_before_1.add_channel(channel_after_sync)
|
||||
if not comm_before_2.get_chat(channel_after_sync).is_element_displayed(30):
|
||||
self.errors.append("New added channel after sync is not shown!")
|
||||
@@ -1295,12 +1296,12 @@ class TestProfileMultipleDevice(MultipleDeviceTestCase):
|
||||
[home.home_button.double_click() for home in (home_1, home_2)]
|
||||
home_1.get_chat(comm_before_sync_name, community=True).click()
|
||||
comm_before_1.leave_community()
|
||||
if not home_2.get_chat(comm_before_sync_name).is_element_disappeared(30):
|
||||
if not home_2.element_by_text_part(comm_before_sync_name).is_element_disappeared(30):
|
||||
self.errors.append("Leaving community was not synced!")
|
||||
|
||||
device_1.just_fyi("Adding new community and check it will be synced")
|
||||
home_1.create_community(comm_after_sync_name)
|
||||
if not home_2.get_chat(comm_after_sync_name, community=True).is_element_displayed(30):
|
||||
if not home_2.element_by_text(comm_after_sync_name).is_element_displayed(30):
|
||||
self.errors.append('Added community was not appeared after initial sync')
|
||||
|
||||
# TODO: skip until #11558 (rechecked 23.11.21, valid)
|
||||
|
||||
@@ -168,7 +168,10 @@ class TestWalletManagement(SingleDeviceTestCase):
|
||||
self.errors.append('%s asset is not shown in wallet after relogin' % asset)
|
||||
|
||||
sign_in.just_fyi("Deselecting asset")
|
||||
wallet.select_asset(asset)
|
||||
wallet.multiaccount_more_options.click()
|
||||
wallet.manage_assets_button.click()
|
||||
wallet.asset_checkbox_by_name(asset).click()
|
||||
wallet.cross_icon.click()
|
||||
if wallet.asset_by_name(asset).is_element_displayed():
|
||||
self.errors.append('%s asset is shown in wallet but was deselected' % asset)
|
||||
self.errors.verify_no_errors()
|
||||
|
||||
@@ -616,7 +616,6 @@ class TestChatManagementMultipleDevice(MultipleDeviceTestCase):
|
||||
device_1.just_fyi('check that new messages from blocked user are not delivered')
|
||||
self.drivers[0].launch_app()
|
||||
device_1.sign_in()
|
||||
home_1.join_public_chat(chat_name)
|
||||
for message in message_before_block_2, message_after_block_2:
|
||||
if chat_public_1.chat_element_by_text(message).is_element_displayed():
|
||||
self.errors.append(
|
||||
@@ -697,7 +696,6 @@ class TestChatManagementMultipleDevice(MultipleDeviceTestCase):
|
||||
|
||||
if public_chat_after_block_1.chat_element_by_text(message_after_block_2).is_element_displayed():
|
||||
self.errors.append("Message from blocked user '%s' is received" % device_2.driver.number)
|
||||
public_chat_after_block_1.get_back_to_home_view()
|
||||
if home_1.notifications_unread_badge.is_element_displayed():
|
||||
device_1.driver.fail("Unread badge is shown after receiving new message from blocked user")
|
||||
if blocked_chat_user.is_element_displayed():
|
||||
@@ -719,6 +717,7 @@ class TestChatManagementMultipleDevice(MultipleDeviceTestCase):
|
||||
device_1.click_system_home_button()
|
||||
self.drivers[0].launch_app()
|
||||
device_1.sign_in()
|
||||
public_chat_after_block_1.home_button.double_click()
|
||||
if home_1.notifications_unread_badge.is_element_displayed():
|
||||
device_1.driver.fail("Unread badge is shown after after fetching new messages from offline")
|
||||
if blocked_chat_user.is_element_displayed():
|
||||
@@ -1019,7 +1018,7 @@ class TestChatManagementMultipleDevice(MultipleDeviceTestCase):
|
||||
public_1.chat_message_input.send_keys('@')
|
||||
if (chat_1.search_user_in_mention_suggestion_list(ens_nickname_value).is_element_displayed() or
|
||||
chat_1.search_user_in_mention_suggestion_list(sender['username']).is_element_displayed()):
|
||||
self.errors.append('Blcoked user is available in mention suggestion list')
|
||||
self.errors.append('Blocked user is available in mention suggestion list')
|
||||
|
||||
self.errors.verify_no_errors()
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ class TestCommandsMultipleDevices(MultipleDeviceTestCase):
|
||||
@marks.critical
|
||||
@marks.transaction
|
||||
def test_send_eth_in_1_1_chat_transaction_push(self):
|
||||
sender = transaction_senders['A']
|
||||
sender = transaction_senders['B']
|
||||
self.create_drivers(2)
|
||||
device_1, device_2 = SignInView(self.drivers[0]), SignInView(self.drivers[1])
|
||||
home_1 = device_1.recover_access(passphrase=sender['passphrase'], enable_notifications=True)
|
||||
@@ -45,7 +45,7 @@ class TestCommandsMultipleDevices(MultipleDeviceTestCase):
|
||||
|
||||
chat_2 = home_2.get_chat(sender['username']).click()
|
||||
receiver_message = chat_2.get_incoming_transaction(account_name)
|
||||
timestamp_sender = sender_message.timestamp_message.text
|
||||
timestamp_sender = sender_message.timestamp_command_message.text
|
||||
if not receiver_message.is_element_displayed():
|
||||
self.drivers[0].fail('No message about incoming transaction in 1-1 chat is shown for receiver')
|
||||
receiver_message.transaction_status.wait_for_element_text(receiver_message.address_requested)
|
||||
@@ -68,7 +68,7 @@ class TestCommandsMultipleDevices(MultipleDeviceTestCase):
|
||||
send_bottom_sheet = sender_message.sign_and_send.click()
|
||||
send_bottom_sheet.next_button.click()
|
||||
send_bottom_sheet.sign_transaction()
|
||||
updated_timestamp_sender = sender_message.timestamp_message.text
|
||||
updated_timestamp_sender = sender_message.timestamp_command_message.text
|
||||
if updated_timestamp_sender == timestamp_sender:
|
||||
self.errors.append("Timestamp of message is not updated after signing transaction")
|
||||
chat_1.wallet_button.click()
|
||||
|
||||
@@ -35,17 +35,16 @@ class TestGroupChatMultipleDevice(MultipleDeviceTestCase):
|
||||
home_1.add_contact(key_2)
|
||||
home_1.get_back_to_home_view()
|
||||
home_2.put_app_to_background()
|
||||
|
||||
home_2.open_notification_bar()
|
||||
chat_1 = home_1.create_group_chat([username_2], chat_name)
|
||||
|
||||
home_2.just_fyi('check that PN invite to group chat is received and after tap you are redirected to group chat')
|
||||
home_2.open_notification_bar()
|
||||
pns = [chat_1.pn_invited_to_group_chat(username_1, chat_name),
|
||||
chat_1.pn_wants_you_to_join_to_group_chat(username_1, chat_name)]
|
||||
for pn in pns:
|
||||
if not home_2.get_pn(pn).is_element_displayed(30):
|
||||
self.errors.append('%s is not shown after invite to group chat' % pn)
|
||||
group_invite_pn = home_2.get_pn(pns[1])
|
||||
group_invite_pn = home_2.get_pn(pns[0])
|
||||
|
||||
if not group_invite_pn.group_chat_icon.is_element_displayed(30):
|
||||
self.errors.append('No icon is shown for PN for group invite')
|
||||
@@ -255,9 +254,9 @@ class TestGroupChatMultipleDevice(MultipleDeviceTestCase):
|
||||
chat.changed_group_name_system_message(device_1_username, new_chat_name)).is_element_displayed():
|
||||
self.errors.append('Message about changing chat name is not shown')
|
||||
|
||||
device_2.just_fyi('Check that you can navigate to renamed chat')
|
||||
device_2.just_fyi('Check that you can see renamed chat')
|
||||
device_2_chat.back_button.click()
|
||||
home_2.get_chat(new_chat_name).click()
|
||||
home_2.get_chat(new_chat_name).wait_for_visibility_of_element(60)
|
||||
|
||||
self.errors.verify_no_errors()
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ class TestCommandsMultipleDevices(MultipleDeviceTestCase):
|
||||
|
||||
chat_2 = home_2.get_chat(sender['username']).click()
|
||||
receiver_message = chat_2.get_incoming_transaction()
|
||||
timestamp_sender = sender_message.timestamp_message.text
|
||||
timestamp_sender = sender_message.timestamp_command_message.text
|
||||
if not receiver_message.is_element_displayed():
|
||||
self.drivers[0].fail('No message about incoming transaction in 1-1 chat is shown for receiver')
|
||||
receiver_message.transaction_status.wait_for_element_text(receiver_message.address_requested)
|
||||
@@ -63,7 +63,7 @@ class TestCommandsMultipleDevices(MultipleDeviceTestCase):
|
||||
send_message = sender_message.sign_and_send.click()
|
||||
send_message.next_button.click()
|
||||
send_message.sign_transaction(keycard=True)
|
||||
updated_timestamp_sender = sender_message.timestamp_message.text
|
||||
updated_timestamp_sender = sender_message.timestamp_command_message.text
|
||||
if updated_timestamp_sender == timestamp_sender:
|
||||
self.errors.append("Timestamp of message is not updated after signing transaction")
|
||||
|
||||
|
||||
@@ -109,8 +109,7 @@ class TestMessagesOneToOneChatMultiple(MultipleDeviceTestCase):
|
||||
|
||||
home_1.just_fyi('go back online and check that 1-1 chat will be fetched')
|
||||
home_1.toggle_airplane_mode()
|
||||
chat_element = home_1.get_chat(username_2)
|
||||
chat_element.wait_for_visibility_of_element(30)
|
||||
chat_element = home_1.get_chat(username_2, wait_time=60)
|
||||
chat_1 = chat_element.click()
|
||||
chat_1.chat_element_by_text(message_1).wait_for_visibility_of_element(2)
|
||||
|
||||
@@ -162,13 +161,14 @@ class TestMessagesOneToOneChatMultiple(MultipleDeviceTestCase):
|
||||
if device_2_chat.user_name_text.text != default_username_1:
|
||||
self.errors.append("Default username '%s' is not shown in one-to-one chat" % default_username_1)
|
||||
|
||||
profile_1.just_fyi("Check timestamps for sender and receiver")
|
||||
for chat in device_1_chat, device_2_chat:
|
||||
chat.verify_message_is_under_today_text(timestamp_message, self.errors)
|
||||
timestamp = chat.chat_element_by_text(timestamp_message).timestamp_message.text
|
||||
if timestamp not in sent_time_variants:
|
||||
self.errors.append(
|
||||
"Timestamp is not shown, expected '%s', in fact '%s'" % (sent_time_variants.join(","), timestamp))
|
||||
# TODO: disabled until https://github.com/status-im/status-react/issues/12936 fix
|
||||
# profile_1.just_fyi("Check timestamps for sender and receiver")
|
||||
# for chat in device_1_chat, device_2_chat:
|
||||
# chat.verify_message_is_under_today_text(timestamp_message, self.errors)
|
||||
# timestamp = chat.chat_element_by_text(timestamp_message).timestamp_message.text
|
||||
# if timestamp not in sent_time_variants:
|
||||
# self.errors.append(
|
||||
# "Timestamp is not shown, expected '%s', in fact '%s'" % (sent_time_variants.join(","), timestamp))
|
||||
|
||||
device_2_home.just_fyi("Add user to contact and verify his default username")
|
||||
device_2_chat.add_to_contacts.click()
|
||||
@@ -208,7 +208,7 @@ class TestMessagesOneToOneChatMultiple(MultipleDeviceTestCase):
|
||||
message_before_edit, message_after_edit = "Message BEFORE edit 1", "Message AFTER edit 2"
|
||||
public_chat_1.send_message(message_before_edit)
|
||||
public_chat_1.edit_message_in_chat(message_before_edit, message_after_edit)
|
||||
if not public_chat_1.element_by_text_part("⌫ Edited").is_element_displayed():
|
||||
if not public_chat_1.element_by_text_part("⌫ Edited").is_element_displayed(60):
|
||||
self.errors.append('No mark in message bubble about this message was edited')
|
||||
|
||||
device_2.just_fyi(
|
||||
@@ -223,9 +223,9 @@ class TestMessagesOneToOneChatMultiple(MultipleDeviceTestCase):
|
||||
if not home_1.element_by_text_part(message_after_edit_1_1).is_element_present():
|
||||
self.errors.append('UNedited message version displayed on preview')
|
||||
chat_private_1 = device_1_one_to_one_chat_element.click()
|
||||
if not home_1.element_by_text_part(message_after_edit_1_1).is_element_present():
|
||||
if not home_1.element_by_text_part(message_after_edit_1_1).is_element_present(30):
|
||||
self.errors.append('No edited message in 1-1 chat displayed')
|
||||
if not home_1.element_by_text_part("⌫ Edited").is_element_present():
|
||||
if not home_1.element_by_text_part("⌫ Edited").is_element_present(30):
|
||||
self.errors.append('No mark in message bubble about this message was edited on receiver side')
|
||||
|
||||
device_2.just_fyi("Verify Device1 can not edit and delete received message from Device2")
|
||||
@@ -238,10 +238,10 @@ class TestMessagesOneToOneChatMultiple(MultipleDeviceTestCase):
|
||||
device_2.just_fyi("Delete message and check it is not shown in chat preview on home")
|
||||
chat_private_2.delete_message_in_chat(message_after_edit_1_1)
|
||||
for chat in (chat_private_2, chat_private_1):
|
||||
if chat.chat_element_by_text(message_after_edit_1_1).is_element_displayed():
|
||||
if chat.chat_element_by_text(message_after_edit_1_1).is_element_displayed(30):
|
||||
self.errors.append("Deleted message is shown in chat view for 1-1 chat")
|
||||
chat_private_1.home_button.double_click()
|
||||
if home_1.element_by_text(message_after_edit_1_1).is_element_displayed():
|
||||
if home_1.element_by_text(message_after_edit_1_1).is_element_displayed(30):
|
||||
self.errors.append("Deleted message is shown on chat element on home screen")
|
||||
|
||||
device_2.just_fyi("Send one more message and check that PN will be deleted with message deletion")
|
||||
@@ -258,13 +258,13 @@ class TestMessagesOneToOneChatMultiple(MultipleDeviceTestCase):
|
||||
chat_private_2.just_fyi("Check for that edited message is shown for Device 2 and delete message in public chat")
|
||||
[home.home_button.double_click() for home in (home_1, home_2)]
|
||||
public_chat_1, public_chat_2 = home_1.get_chat('#%s' % chat_name).click(), home_2.join_public_chat(chat_name)
|
||||
if not public_chat_2.element_by_text_part("⌫ Edited").is_element_displayed():
|
||||
if not public_chat_2.element_by_text_part("⌫ Edited").is_element_displayed(60):
|
||||
self.errors.append('No mark in message bubble about this message was edited')
|
||||
if not public_chat_2.element_by_text_part(message_after_edit).is_element_displayed():
|
||||
if not public_chat_2.element_by_text_part(message_after_edit).is_element_displayed(60):
|
||||
self.errors.append('Message is not edited.')
|
||||
public_chat_1.delete_message_in_chat(message_after_edit)
|
||||
for chat in (public_chat_1, public_chat_2):
|
||||
if chat.chat_element_by_text(message_after_edit).is_element_displayed():
|
||||
if chat.chat_element_by_text(message_after_edit).is_element_displayed(30):
|
||||
self.errors.append("Deleted message is shown in chat view for public chat")
|
||||
|
||||
self.errors.verify_no_errors()
|
||||
@@ -883,7 +883,7 @@ class TestMessagesOneToOneChatSingle(SingleDeviceTestCase):
|
||||
chat.send_message_button.click()
|
||||
|
||||
message_bubble = chat.chat_element_by_text(formatted_message[message])
|
||||
message_bubble.timestamp_message.long_press_element()
|
||||
message_bubble.sent_status_checkmark.long_press_element()
|
||||
chat.element_by_text('Copy').click()
|
||||
|
||||
message_input.paste_text_from_clipboard()
|
||||
@@ -964,13 +964,10 @@ class TestMessagesOneToOneChatSingle(SingleDeviceTestCase):
|
||||
self.errors.append('"%s" is not show in chat preview on home screen!' % message)
|
||||
home.get_chat('@%s' % ens).click()
|
||||
|
||||
home.just_fyi('Check redirect to user profile on mention by ENS tap')
|
||||
chat.chat_element_by_text(message).click()
|
||||
if not chat.profile_block_contact.is_element_displayed():
|
||||
self.errors.append('No redirect to user profile after tapping on message with mention (ENS) in 1-1 chat')
|
||||
|
||||
home.just_fyi('Set nickname and mention user by nickname in 1-1 chat')
|
||||
russian_nickname = 'МОЙ дорогой ДРУх'
|
||||
chat.chat_options.click()
|
||||
chat.view_profile_button.click()
|
||||
chat.set_nickname(russian_nickname)
|
||||
chat.select_mention_from_suggestion_list(russian_nickname + ' @' + ens)
|
||||
|
||||
|
||||
@@ -1,117 +1,125 @@
|
||||
import emoji
|
||||
import random
|
||||
from dateutil import parser
|
||||
from tests import marks
|
||||
from tests.base_test_case import MultipleDeviceTestCase, SingleDeviceTestCase
|
||||
from views.sign_in_view import SignInView
|
||||
from datetime import timedelta
|
||||
from time import sleep
|
||||
|
||||
import emoji
|
||||
import pytest
|
||||
from dateutil import parser
|
||||
|
||||
class TestPublicChatMultipleDevice(MultipleDeviceTestCase):
|
||||
from tests import marks
|
||||
from tests.base_test_case import MultipleDeviceTestCase, SingleDeviceTestCase, create_shared_drivers, \
|
||||
MultipleSharedDeviceTestCase
|
||||
from views.sign_in_view import SignInView
|
||||
|
||||
|
||||
@pytest.mark.xdist_group(name="public_chat")
|
||||
class TestPublicChatMultipleDeviceMerged(MultipleSharedDeviceTestCase):
|
||||
|
||||
@classmethod
|
||||
def setup_class(cls):
|
||||
cls.drivers, cls.loop = create_shared_drivers(2)
|
||||
device_1, device_2 = SignInView(cls.drivers[0]), SignInView(cls.drivers[1])
|
||||
cls.home_1, cls.home_2 = device_1.create_user(), device_2.create_user()
|
||||
profile_1 = cls.home_1.profile_button.click()
|
||||
cls.username_1 = profile_1.default_username_text.text
|
||||
profile_1.home_button.click()
|
||||
cls.home_2.home_button.click()
|
||||
cls.public_chat_name = cls.home_1.get_random_chat_name()
|
||||
cls.chat_1, cls.chat_2 = cls.home_1.join_public_chat(cls.public_chat_name), cls.home_2.join_public_chat(cls.public_chat_name)
|
||||
|
||||
@marks.testrail_id(5313)
|
||||
@marks.critical
|
||||
def test_public_chat_messaging_emojis_timestamps(self):
|
||||
self.create_drivers(2)
|
||||
device_1, device_2 = SignInView(self.drivers[0]), SignInView(self.drivers[1])
|
||||
home_1, home_2 = device_1.create_user(), device_2.create_user()
|
||||
profile_1 = home_1.profile_button.click()
|
||||
default_username_1 = profile_1.default_username_text.text
|
||||
profile_1.home_button.click()
|
||||
home_2.home_button.click()
|
||||
def test_public_chat_text_timestamps_while_on_different_tab(self):
|
||||
message = 'hello'
|
||||
self.chat_2.dapp_tab_button.click()
|
||||
self.chat_1.send_message(message)
|
||||
sent_time_variants = self.chat_1.convert_device_time_to_chat_timestamp()
|
||||
timestamp = self.chat_1.chat_element_by_text(message).timestamp_on_tap
|
||||
if timestamp not in sent_time_variants:
|
||||
self.errors.append("Timestamp is not shown, expected: '%s', in fact: '%s'" % (sent_time_variants.join(','), timestamp))
|
||||
self.chat_2.home_button.click(desired_view='chat')
|
||||
for chat in self.chat_1, self.chat_2:
|
||||
chat.verify_message_is_under_today_text(message, self.errors)
|
||||
if self.chat_2.chat_element_by_text(message).username.text != self.username_1:
|
||||
self.errors.append("Default username '%s' is not shown next to the received message" % self.username_1)
|
||||
self.errors.verify_no_errors()
|
||||
|
||||
home_1.just_fyi("Check preselected chats, redirect to status chat")
|
||||
home_1.plus_button.click_until_presence_of_element(home_1.join_public_chat_button)
|
||||
home_1.join_public_chat_button.click()
|
||||
preselected_chats = ['#status', '#chitchat', '#defi', '#crypto', '#markets', '#dap-ps']
|
||||
for chat in preselected_chats:
|
||||
if not home_1.element_by_text(chat).is_element_displayed():
|
||||
self.errors.append("'%s' text is not in the list of preselected chats" % chat)
|
||||
home_1.element_by_text(preselected_chats[0]).click()
|
||||
status_chat = home_1.get_chat_view()
|
||||
if not status_chat.user_name_text != preselected_chats[0]:
|
||||
self.errors.append('No redirect to chat if tap on #status chat')
|
||||
status_chat.home_button.click()
|
||||
|
||||
public_chat_name = home_1.get_random_chat_name()
|
||||
chat_1, chat_2 = home_1.join_public_chat(public_chat_name), home_2.join_public_chat(public_chat_name)
|
||||
|
||||
home_1.just_fyi("Check sending text messages, emojis, usernames and timestamps on messages")
|
||||
@marks.testrail_id(700719)
|
||||
@marks.critical
|
||||
def test_public_emoji(self):
|
||||
emoji_name = random.choice(list(emoji.EMOJI_UNICODE))
|
||||
emoji_unicode = emoji.EMOJI_UNICODE[emoji_name]
|
||||
message, emoji_message = 'hello', emoji.emojize(emoji_name)
|
||||
chat_1.send_message(message)
|
||||
|
||||
sent_time_variants = chat_1.convert_device_time_to_chat_timestamp()
|
||||
for chat in chat_1, chat_2:
|
||||
chat.verify_message_is_under_today_text(message, self.errors)
|
||||
timestamp = chat.chat_element_by_text(message).timestamp_message.text
|
||||
if timestamp not in sent_time_variants:
|
||||
self.errors.append(
|
||||
"Timestamp is not shown, expected '%s', in fact '%s'" % (sent_time_variants.join(','), timestamp))
|
||||
if chat_2.chat_element_by_text(message).username.text != default_username_1:
|
||||
self.errors.append("Default username '%s' is not shown next to the received message" % default_username_1)
|
||||
|
||||
chat_1.send_message(emoji_message)
|
||||
for chat in chat_1, chat_2:
|
||||
if not chat.chat_element_by_text(emoji_unicode).is_element_displayed():
|
||||
emoji_message = emoji.emojize(emoji_name)
|
||||
self.chat_1.send_message(emoji_message)
|
||||
for chat in self.chat_1, self.chat_2:
|
||||
if not chat.chat_element_by_text(emoji_unicode).is_element_displayed(30):
|
||||
self.errors.append('Message with emoji was not sent or received in public chat')
|
||||
|
||||
self.chat_1.just_fyi("Can copy and paste emojis")
|
||||
self.chat_1.element_by_text_part(emoji_unicode).long_press_element()
|
||||
self.chat_1.element_by_text('Copy').click()
|
||||
self.chat_1.chat_message_input.paste_text_from_clipboard()
|
||||
if self.chat_1.chat_message_input.text != emoji_unicode:
|
||||
self.errors.append('Emoji message was not copied')
|
||||
|
||||
self.chat_1.just_fyi("Can reply to emojis")
|
||||
self.chat_2.quote_message(emoji_unicode)
|
||||
message_text = 'test message'
|
||||
self.chat_2.chat_message_input.send_keys(message_text)
|
||||
self.chat_2.send_message_button.click()
|
||||
chat_element_1 = self.chat_1.chat_element_by_text(message_text)
|
||||
if not chat_element_1.is_element_displayed(sec=10) or chat_element_1.replied_message_text != emoji_unicode:
|
||||
self.errors.append('Reply message was not received by the sender')
|
||||
self.errors.verify_no_errors()
|
||||
|
||||
@marks.testrail_id(5360)
|
||||
@marks.critical
|
||||
def test_unread_messages_counter_public_chat(self):
|
||||
self.create_drivers(2)
|
||||
driver_2 = self.drivers[1]
|
||||
home_1, home_2 = SignInView(self.drivers[0]).create_user(), SignInView(self.drivers[1]).create_user()
|
||||
profile_1 = home_1.profile_button.click()
|
||||
username_1 = profile_1.default_username_text.text
|
||||
profile_1.home_button.click()
|
||||
|
||||
chat_name = home_1.get_random_chat_name()
|
||||
chat_1, chat_2 = home_1.join_public_chat(chat_name), home_2.join_public_chat(chat_name)
|
||||
chat_1.send_message('пиу')
|
||||
chat_1.home_button.click()
|
||||
message, message_2 = 'test message', 'test message2'
|
||||
chat_2.send_message(message)
|
||||
|
||||
home_1.just_fyi(
|
||||
"Check unread message indicator on home, on chat element and that it is not shown after reading messages")
|
||||
if not home_1.home_button.public_unread_messages.is_element_displayed():
|
||||
def test_public_unread_messages_counter(self):
|
||||
self.chat_1.send_message('пиу')
|
||||
home_1 = self.chat_1.home_button.click()
|
||||
message = 'test message'
|
||||
self.chat_2.send_message(message)
|
||||
if not self.chat_1.home_button.public_unread_messages.is_element_displayed():
|
||||
self.errors.append('New messages public chat badge is not shown on Home button')
|
||||
chat_element = home_1.get_chat('#' + chat_name)
|
||||
chat_element = home_1.get_chat('#' + self.public_chat_name)
|
||||
if not chat_element.new_messages_public_chat.is_element_displayed():
|
||||
self.errors.append('New messages counter is not shown in public chat')
|
||||
self.errors.verify_no_errors()
|
||||
|
||||
home_1.just_fyi("Check unread message counter when mentioned in public chat")
|
||||
chat_2 = home_2.get_chat_view()
|
||||
chat_2.select_mention_from_suggestion_list(username_1, username_1[:2])
|
||||
chat_2.send_message_button.click()
|
||||
@marks.testrail_id(700718)
|
||||
@marks.critical
|
||||
def test_public_unread_messages_counter_for_mentions_relogin(self):
|
||||
message = 'test message2'
|
||||
[chat.home_button.double_click() for chat in (self.chat_1, self.chat_2)]
|
||||
chat_element = self.home_1.get_chat('#' + self.public_chat_name)
|
||||
self.home_2.get_chat('#' + self.public_chat_name).click()
|
||||
self.chat_2.select_mention_from_suggestion_list(self.username_1, self.username_1[:2])
|
||||
self.chat_2.send_message_button.click()
|
||||
chat_element.new_messages_counter.wait_for_element(30)
|
||||
chat_element.new_messages_counter.wait_for_element_text("1", 60)
|
||||
|
||||
chat_element.click()
|
||||
home_1.home_button.double_click()
|
||||
|
||||
if home_1.home_button.public_unread_messages.is_element_displayed():
|
||||
self.home_1.home_button.double_click()
|
||||
if self.home_1.home_button.public_unread_messages.is_element_displayed():
|
||||
self.errors.append('New messages public chat badge is shown on Home button')
|
||||
if chat_element.new_messages_public_chat.is_element_displayed():
|
||||
self.errors.append('Unread messages badge is shown in public chat while there are no unread messages')
|
||||
[home.get_chat('#' + chat_name).click() for home in (home_1, home_2)]
|
||||
chat_1.send_message(message_2)
|
||||
chat_2.chat_element_by_text(message_2).wait_for_element(20)
|
||||
[home.get_chat('#' + self.public_chat_name).click() for home in (self.home_1, self.home_2)]
|
||||
self.chat_1.send_message(message)
|
||||
self.chat_2.chat_element_by_text(message).wait_for_element(20)
|
||||
|
||||
home_2.just_fyi("Check that unread message indicator is not reappeared after relogin")
|
||||
self.chat_2.just_fyi("Check that unread messages counter doesn't reappear after relogin")
|
||||
driver_2 = self.drivers[1]
|
||||
driver_2.close_app()
|
||||
driver_2.launch_app()
|
||||
SignInView(driver_2).sign_in()
|
||||
chat_element = home_2.get_chat('#' + chat_name)
|
||||
chat_element = self.home_2.get_chat('#' + self.public_chat_name)
|
||||
if chat_element.new_messages_public_chat.is_element_displayed():
|
||||
self.errors.append('New messages counter is shown after relogin')
|
||||
self.drivers[0].fail('New messages counter is shown after relogin')
|
||||
self.errors.verify_no_errors()
|
||||
|
||||
|
||||
class TestPublicChatMultipleDevice(MultipleDeviceTestCase):
|
||||
|
||||
@marks.testrail_id(6270)
|
||||
@marks.medium
|
||||
def test_mark_all_messages_as_read_public_chat(self):
|
||||
@@ -141,45 +149,6 @@ class TestPublicChatMultipleDevice(MultipleDeviceTestCase):
|
||||
|
||||
self.errors.verify_no_errors()
|
||||
|
||||
@marks.testrail_id(6275)
|
||||
@marks.medium
|
||||
def test_receive_message_while_in_different_tab_and_emoji_messages_long_press(self):
|
||||
self.create_drivers(2)
|
||||
device_1, device_2 = SignInView(self.drivers[0]), SignInView(self.drivers[1])
|
||||
home_1, home_2 = device_1.create_user(), device_2.create_user()
|
||||
public_chat_name = home_1.get_random_chat_name()
|
||||
chat_1, chat_2 = home_1.join_public_chat(public_chat_name), home_2.join_public_chat(public_chat_name)
|
||||
|
||||
device_2.just_fyi("Switch to different tab out from chat")
|
||||
device_2.dapp_tab_button.click()
|
||||
emoji_name = random.choice(list(emoji.EMOJI_UNICODE))
|
||||
emoji_unicode = emoji.EMOJI_UNICODE[emoji_name]
|
||||
chat_1.chat_message_input.send_keys(emoji.emojize(emoji_name))
|
||||
chat_1.send_message_button.click()
|
||||
|
||||
device_1.just_fyi("Long press emoji message actions")
|
||||
chat_1.element_by_text_part(emoji_unicode).long_press_element()
|
||||
chat_1.element_by_text('Copy').click()
|
||||
chat_1.chat_message_input.paste_text_from_clipboard()
|
||||
if chat_1.chat_message_input.text != emoji_unicode:
|
||||
self.errors.append('Emoji message was not copied')
|
||||
|
||||
home_2.home_button.click(desired_view='chat')
|
||||
chat_element_2 = chat_2.element_by_text_part(emoji_unicode)
|
||||
if not chat_element_2.is_element_displayed(sec=10):
|
||||
self.errors.append('Message with emoji was not received in public chat by the recipient')
|
||||
|
||||
chat_2.quote_message(emoji_unicode)
|
||||
message_text = 'test message'
|
||||
chat_2.chat_message_input.send_keys(message_text)
|
||||
chat_2.send_message_button.click()
|
||||
|
||||
chat_element_1 = chat_1.chat_element_by_text(message_text)
|
||||
if not chat_element_1.is_element_displayed(sec=10) or chat_element_1.replied_message_text != emoji_unicode:
|
||||
self.errors.append('Reply message was not received by the sender')
|
||||
|
||||
self.errors.verify_no_errors()
|
||||
|
||||
@marks.testrail_id(6342)
|
||||
@marks.medium
|
||||
def test_different_status_in_timeline(self):
|
||||
|
||||
@@ -290,8 +290,6 @@ class TestBrowsing(SingleDeviceTestCase):
|
||||
urls = {
|
||||
'https://cdn.dribbble.com/users/45534/screenshots/3142450/logo_dribbble.png':
|
||||
'url1.png',
|
||||
'https://thebitcoinpub-91d3.kxcdn.com/uploads/default/original/2X/d/db97611b41a96cb7642b06636b82c0800678b140.jpg':
|
||||
'url2.png',
|
||||
'https://steemitimages.com/DQmYEjeBuAKVRa3b3ZqwLicSHaPUm7WFtQqohGaZdA9ghjx/images%20(4).jpeg':
|
||||
'url3.png'
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user