Compare commits

..
Author SHA1 Message Date
Shivek Khurana 106eb2acfd 📼 Rive animation demo working 2024-03-18 16:21:36 +00:00
Icaro MottaandCristian Lungu 7948582e46 Account selection: Implement features related to editing shared addresses (#19177)
* Fix schema error

* Implement feature to edit shared addresses

* fix: show tokens when sharing all future addresses toggled

* fix: eligibility not checked when toggling all addresses

* Revert "fix: show tokens when sharing all future addresses toggled"

This reverts commit 8443a3432e.

* fix: don't fetch balances on mount if toggled share all

---------

Co-authored-by: Cristian Lungu <lungucristian95@gmail.com>
2024-03-18 17:07:15 +02:00
Parvesh Monu 6c5242b3e0 fix bio-metric login (#19293) 2024-03-18 19:50:10 +05:30
Lungu Cristian 60d6a5c3cc Fix pinned messages context tag style (#19245)
* fix: pinned messages context tag style

Signed-off-by: Cristian Lungu <lungucristian95@gmail.com>

* formatting

Signed-off-by: Cristian Lungu <lungucristian95@gmail.com>

---------

Signed-off-by: Cristian Lungu <lungucristian95@gmail.com>
2024-03-18 12:34:46 +02:00
suchsoon 049822b5bb chore: remove repetitive words (#19189)
Signed-off-by: suchsoon <silverjadebeauty@gmail.com>
2024-03-18 11:10:50 +01:00
Lungu Cristian 02c7460a24 Fix chat navigation buttons when scrolling to top (#19097)
* fix: change nav buttons to :photo when scrolled to top

Signed-off-by: Cristian Lungu <lungucristian95@gmail.com>

* fix: renamed to use-messages-scrolled-to-threshold

Signed-off-by: Cristian Lungu <lungucristian95@gmail.com>

* fix: nav buttons are shown without flicker on mount

Signed-off-by: Cristian Lungu <lungucristian95@gmail.com>

---------

Signed-off-by: Cristian Lungu <lungucristian95@gmail.com>
2024-03-18 12:05:36 +02:00
Mohamed Javid 10c6bf7156 [Fix] Chain down toast shown for chains unrelated to current network (#19155)
This commit fixes chain down toast shown for chains unrelated to the current network.

Signed-off-by: Mohamed Javid <19339952+smohamedjavid@users.noreply.github.com>
2024-03-16 16:29:16 +05:30
Jamie Caprani d0d7310e82 feat(wallet): add ability to remove wallet account (#19121) 2024-03-15 14:20:28 -07:00
Jamie Caprani 219dd7cb46 chore(quo): add profile - collectibles list item component (#19125) 2024-03-15 13:58:04 -07:00
Parvesh Monu 9da0559b15 fix keycard crash (#19275) 2024-03-15 19:17:55 +05:30
Shivek Khurana aa7db8b883 💾 🗂️ [17653] wallet implement UI for save address bottom sheet (#19079)
* 🚧 Save address UI reached teenage years

* 🚧 Save point

* 📑 Use bottom sheet effect properly

* 📝 Can't get title input to work

* 🎨 Design in place

* 🗺️ Add address box and trigger for network prefs

* 💅 Pixel perfect UI and hide save address button

*  Upgrade to screen tech

* 🤚 Undo changes made to color picker during rebase

* 🧰 Fix screens I broke during rebase

* ❄️ Fix json indent

* ⚒️ Implement PR feedback

* ⛏️ Remove unrelated translations

* 🖼️ Remove container to fix margin issue

- Use rn/use-callback instead of defined functions

* 😶‍🌫️ Hide save address button

* 🔨 Fix lint

*  Remove bottom sheet screen updates

*  Remove empty lines between elements
2024-03-15 10:54:04 +00:00
Brian Sztamfater a06c5fdc02 fix: view-id not updating when navigating inside modals (#19163) 2024-03-14 13:56:30 -03:00
BalogunofAfrica 2a515a82ce fix: polish new chat (#19054) 2024-03-14 17:30:23 +01:00
flexsurfer 69294b196f Display discord bridged posts #19233 (#19248) 2024-03-14 13:46:00 +01:00
BalogunofAfrica 58606dc87c fix: handle limit event (#19066) 2024-03-14 13:13:29 +01:00
Parvesh Monu bccf0f8d11 re add progress root and popover overlay (#19241) 2024-03-14 16:48:08 +05:30
Lungu Cristian aab62dd19e Fix channel-action component (#19031)
* feat: added separate channel-action component & fixed pressed color

* feat: added channel-action preview screen

* fix: moved channel-action/s into separate dirs

* fix: channel-action style prop

* fix: renamed color prop to customization-color

* fix: small button width should be fixed

* fix: removed temp file

* style: formatting
2024-03-14 11:56:47 +02:00
Alexander fa9645d6dd Partial handlers update (re-frame/reg-event-fx instead of rf/defn) (#19005)
* Handlers update (re-frame/reg-event-fx instead of rf/defn)

* Fixes

* Fixes

* Fixes
2024-03-14 10:24:37 +01:00
yqrashawn 614b03d701 fix: duplicate sub key :communities/fetching-community (#18890) 2024-03-14 09:50:06 +08:00
139 changed files with 6141 additions and 6570 deletions
+3 -6
View File
@@ -1,9 +1,6 @@
module.exports = {
presets: [
"@babel/preset-env"
// 'module:metro-react-native-babel-preset'
],
/*plugins: ['react-native-reanimated/plugin', '@babel/plugin-transform-named-capturing-groups-regex'],
presets: ['module:metro-react-native-babel-preset'],
plugins: ['react-native-reanimated/plugin', '@babel/plugin-transform-named-capturing-groups-regex'],
env: {
test: {
presets: [
@@ -18,5 +15,5 @@ module.exports = {
],
],
},
},*/
},
};
+1 -1
View File
@@ -5,7 +5,7 @@ require Pod::Executable.execute_command('node', ['-p',
{paths: [process.argv[1]]},
)', __dir__]).strip
platform :ios, min_ios_version_supported
platform :ios, '15.0'
prepare_react_native_project!
linkage = ENV['USE_FRAMEWORKS']
+12 -2
View File
@@ -466,6 +466,10 @@ PODS:
- React-CoreModules
- React-RCTImage
- React-RCTText
- rive-react-native (6.2.0):
- React-Core
- RiveRuntime (= 5.5.1)
- RiveRuntime (5.5.1)
- RNCAsyncStorage (1.19.3):
- React-Core
- RNCClipboard (1.2.2):
@@ -586,6 +590,7 @@ DEPENDENCIES:
- "ReactNativeAudioToolkit (from `../node_modules/@react-native-community/audio-toolkit`)"
- ReactNativeCameraKit (from `../node_modules/react-native-camera-kit`)
- ReactNativeNavigation (from `../node_modules/react-native-navigation`)
- rive-react-native (from `../node_modules/rive-react-native`)
- "RNCAsyncStorage (from `../node_modules/@react-native-async-storage/async-storage`)"
- "RNCClipboard (from `../node_modules/@react-native-community/clipboard`)"
- "RNCMaskedView (from `../node_modules/@react-native-community/masked-view`)"
@@ -612,6 +617,7 @@ SPEC REPOS:
- fmt
- HMSegmentedControl
- libwebp
- RiveRuntime
- SDWebImage
- SDWebImageWebPCoder
- SocketRocket
@@ -745,6 +751,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native-camera-kit"
ReactNativeNavigation:
:path: "../node_modules/react-native-navigation"
rive-react-native:
:path: "../node_modules/rive-react-native"
RNCAsyncStorage:
:path: "../node_modules/@react-native-async-storage/async-storage"
RNCClipboard:
@@ -800,7 +808,7 @@ SPEC CHECKSUMS:
FBLazyVector: 71803c074f6325f10b5ec891c443b6bbabef0ca7
FBReactNativeSpec: 448e08a759d29a96e15725ae532445bf4343567c
fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9
glog: cf171f517b828fdde711287b723e348da1ea0fc3
glog: 553c84c5d721b0d5eee45abc0e1045eff08d0363
HMSegmentedControl: 34c1f54d822d8308e7b24f5d901ec674dfa31352
Keycard: ac6df4d91525c3c82635ac24d4ddd9a80aca5fc8
libwebp: f62cb61d0a484ba548448a4bd52aabf150ff6eef
@@ -860,6 +868,8 @@ SPEC CHECKSUMS:
ReactNativeAudioToolkit: de9610f323e855ac6574be8c99621f3d57c5df06
ReactNativeCameraKit: d95d3e19c514526a234d9f93c6db7e7f10eef9ea
ReactNativeNavigation: 2651d0bc1479e9df0789b077ae93320dc2c9b73b
rive-react-native: 82eb809ebec7ab5059982dc1a2b6097c74d722ea
RiveRuntime: b57830ff73f406f3b4022f457b16690535ca4d05
RNCAsyncStorage: c913ede1fa163a71cea118ed4670bbaaa4b511bb
RNCClipboard: 8148e21ac347c51fd6cd4b683389094c216bb543
RNCMaskedView: 71fc32d971f03b7f03d6ab6b86b730c4ee64f5b6
@@ -884,6 +894,6 @@ SPEC CHECKSUMS:
TOCropViewController: edfd4f25713d56905ad1e0b9f5be3fbe0f59c863
Yoga: 86fed2e4d425ee4c6eab3813ba1791101ee153c6
PODFILE CHECKSUM: 3f98ce893757dfa17e609ef7cd24fa41635b73a6
PODFILE CHECKSUM: 5fb780ad69423bc07ecf2830edc197c35b030433
COCOAPODS: 1.12.0
+57
View File
@@ -346,6 +346,7 @@
00E356EB1AD99517003FC87E /* Frameworks */,
00E356EC1AD99517003FC87E /* Resources */,
D737FA0B0E9D346092C626FB /* [CP] Copy Pods Resources */,
E12C2C68160526186D75A66F /* [CP] Embed Pods Frameworks */,
);
buildRules = (
);
@@ -369,6 +370,7 @@
20B6B6891D92C42700CC5C6A /* Embed Frameworks */,
E3914A731DF919ED00EBB515 /* Run Script */,
28606042DA81A750949525E4 /* [CP] Copy Pods Resources */,
39DDA8A9A8650A8882274315 /* [CP] Embed Pods Frameworks */,
);
buildRules = (
);
@@ -391,6 +393,7 @@
3AAD2AD624A3A60E0075D594 /* Embed Frameworks */,
3AAD2AD724A3A60E0075D594 /* Run Script */,
BB1D92AA7446228787D6925C /* [CP] Copy Pods Resources */,
BC3725905F2B61D1D2349AC3 /* [CP] Embed Pods Frameworks */,
);
buildRules = (
);
@@ -566,6 +569,24 @@
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Status-StatusIm/Pods-Status-StatusIm-resources.sh\"\n";
showEnvVarsInLog = 0;
};
39DDA8A9A8650A8882274315 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Status-StatusIm/Pods-Status-StatusIm-frameworks.sh",
"${PODS_XCFRAMEWORKS_BUILD_DIR}/RiveRuntime/RiveRuntime.framework/RiveRuntime",
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RiveRuntime.framework",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Status-StatusIm/Pods-Status-StatusIm-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
3AAD2AD524A3A60E0075D594 /* Bundle React Native code and images */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
@@ -638,6 +659,24 @@
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Status-StatusImPR/Pods-Status-StatusImPR-resources.sh\"\n";
showEnvVarsInLog = 0;
};
BC3725905F2B61D1D2349AC3 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Status-StatusImPR/Pods-Status-StatusImPR-frameworks.sh",
"${PODS_XCFRAMEWORKS_BUILD_DIR}/RiveRuntime/RiveRuntime.framework/RiveRuntime",
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RiveRuntime.framework",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Status-StatusImPR/Pods-Status-StatusImPR-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
BDAFF7E8D7D1C97E92C1F9B0 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
@@ -704,6 +743,24 @@
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Status-StatusIm-StatusImTests/Pods-Status-StatusIm-StatusImTests-resources.sh\"\n";
showEnvVarsInLog = 0;
};
E12C2C68160526186D75A66F /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Status-StatusIm-StatusImTests/Pods-Status-StatusIm-StatusImTests-frameworks.sh",
"${PODS_XCFRAMEWORKS_BUILD_DIR}/RiveRuntime/RiveRuntime.framework/RiveRuntime",
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RiveRuntime.framework",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Status-StatusIm-StatusImTests/Pods-Status-StatusIm-StatusImTests-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
E3914A731DF919ED00EBB515 /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 8;
+1 -1
View File
@@ -69,6 +69,7 @@
"react-native-transparent-video": "git+https://github.com/status-im/react-native-transparent-video.git#refs/tags/0.1.1",
"react-native-webview": "13.6.3",
"react-syntax-highlighter": "^15.5.0",
"rive-react-native": "^6.2.0",
"rn-emoji-keyboard": "0.7.0",
"tdigest": "^0.1.1"
},
@@ -78,7 +79,6 @@
"@babel/helper-builder-react-jsx": "^7.20.0",
"@babel/plugin-transform-block-scoping": "^7.20.0",
"@babel/preset-env": "^7.20.0",
"@babel/preset-es2015": "^7.0.0-beta.53",
"@babel/preset-react": "^7.18.6",
"@babel/register": "7.0.0",
"@jest/globals": "^25.1.0",
-1
View File
@@ -46,7 +46,6 @@
;; To match the folder created by Nix build of JSBundle.
:output-dir "result"
:init-fn status-im.core/init
:build-hooks [(status-im.setup.build-hooks.worklets/transform-output)]
;; When false, the Shadow-CLJS watcher won't automatically refresh
;; the target files (a.k.a hot reload). When false, you can manually
;; reload by calling `shadow.cljs.devtools.api/watch-compile-all!`.
+16 -1
View File
@@ -1,4 +1,5 @@
import { withTiming, runOnJS } from 'react-native-reanimated';
import { useAnimatedReaction, withTiming, runOnJS } from 'react-native-reanimated';
import { useState } from "react"
export function messagesListOnScroll(distanceFromListTop, chatListScrollY, callback) {
return function (event) {
@@ -12,3 +13,17 @@ export function messagesListOnScroll(distanceFromListTop, chatListScrollY, callb
runOnJS(callback)(layoutHeight, newDistance);
};
}
export function useMessagesScrolledToThreshold(distanceFromListTop, threshold) {
const [scrolledToThreshold, setScrolledToThreshold] = useState(false)
useAnimatedReaction(function () {
return distanceFromListTop.value <= threshold;
}, function (current) {
if(current !== scrolledToThreshold) {
runOnJS(setScrolledToThreshold)(current)
}
}, [scrolledToThreshold])
return scrolledToThreshold
}
@@ -19,6 +19,13 @@ export function navigationHeaderPosition(distanceFromListTop, isAllLoaded, topBa
});
}
export function navigationButtonsCompleteOpacity(isCalculationComplete) {
return useDerivedValue(function () {
'worklet'
return isCalculationComplete.value ? withTiming(1) : 0
})
}
export function interpolateNavigationViewOpacity(props) {
return useDerivedValue(function () {
'worklet';
+9 -9
View File
@@ -15,6 +15,7 @@
[native-module.core :as native-module]
[re-frame.core :as re-frame]
[react-native.platform :as platform]
[status-im.common.json-rpc.events :as json-rpc]
[status-im.common.universal-links :as links]
[status-im.constants :as constants]
[status-im.contexts.chat.events :as chat.events]
@@ -654,12 +655,11 @@
stored-bookmarks)]
{:db (assoc db :bookmarks/bookmarks bookmarks)}))
(rf/defn initialize-browser
[_]
{:json-rpc/call
[{:method "wakuext_getBrowsers"
:on-success #(re-frame/dispatch [::initialize-browsers %])}
{:method "browsers_getBookmarks"
:on-success #(re-frame/dispatch [::initialize-bookmarks %])}
{:method "permissions_getDappPermissions"
:on-success #(re-frame/dispatch [::initialize-dapp-permissions %])}]})
(re-frame/reg-fx :browser/initialize-browser
(fn []
(json-rpc/call {:method "wakuext_getBrowsers"
:on-success [::initialize-browsers]})
(json-rpc/call {:method "browsers_getBookmarks"
:on-success [::initialize-bookmarks]})
(json-rpc/call {:method "permissions_getDappPermissions"
:on-success [::initialize-dapp-permissions]})))
+6 -8
View File
@@ -4,7 +4,6 @@
[legacy.status-im.bottom-sheet.events :as bottom-sheet]
legacy.status-im.communities.e2e
[re-frame.core :as re-frame]
[status-im.contexts.shell.activity-center.events :as activity-center]
[status-im.navigation.events :as navigation]
[taoensso.timbre :as log]
[utils.re-frame :as rf]))
@@ -84,13 +83,12 @@
(navigation/navigate-back)
(handle-response response-js)))
(rf/defn member-banned
{:events [::member-banned]}
[cofx response-js]
(rf/merge cofx
(bottom-sheet/hide-bottom-sheet-old)
(handle-response response-js)
(activity-center/notifications-fetch-unread-count)))
(re-frame/reg-event-fx ::member-banned
(fn [{:keys [db]} [response-js]]
{:db (assoc db :bottom-sheet/show? false)
:fx [[:dismiss-bottom-sheet-overlay-old]
[:sanitize-messages-and-process-response response-js]
[:activity-center.notifications/fetch-unread-count]]}))
(rf/defn member-ban
{:events [::member-ban]}
+10 -11
View File
@@ -6,7 +6,6 @@
[re-frame.core :as re-frame]
[status-im.contexts.chat.contacts.events :as contacts-store]
[status-im.contexts.chat.messenger.messages.list.events :as message-list]
[status-im.contexts.shell.activity-center.events :as activity-center]
[status-im.navigation.events :as navigation]
[utils.re-frame :as rf]))
@@ -45,16 +44,16 @@
(apply
rf/merge
cofx
{:db (->
db
(update :chats dissoc public-key)
(update :chats-home-list disj public-key)
(assoc-in [:contacts/contacts public-key
:added?]
false))
:dispatch [:shell/close-switcher-card public-key]
:effects/push-notifications-clear-message-notifications [public-key]}
(activity-center/notifications-fetch-unread-count)
{:db (->
db
(update :chats dissoc public-key)
(update :chats-home-list disj public-key)
(assoc-in [:contacts/contacts public-key
:added?]
false))
:fx [[:activity-center.notifications/fetch-unread-count]
[:effects/push-notifications-clear-message-notifications [public-key]]
[:dispatch [:shell/close-switcher-card public-key]]]}
fxs)))
(rf/defn block-contact
@@ -44,6 +44,7 @@
:line-count nil
:links nil
:text nil}
:bridge-message nil
:outgoing false}
:message nil
:reply-message {:quoted-message nil
@@ -61,6 +62,7 @@
:line-count nil
:links nil
:text nil}
:bridge-message nil
:outgoing false}}
(-> raw-notification
store/<-rpc
+10 -9
View File
@@ -3,9 +3,10 @@
[clojure.set :as set]
[legacy.status-im.data-store.messages :as messages]
[legacy.status-im.utils.deprecated-types :as types]
[re-frame.core :as re-frame]
[status-im.common.json-rpc.events :as json-rpc]
[status-im.constants :as constants]
[taoensso.timbre :as log]
[utils.re-frame :as rf]))
[taoensso.timbre :as log]))
(defn rpc->type
[{:keys [chat-type name] :as chat}]
@@ -117,10 +118,10 @@
rpc->type
unmarshal-members))
(rf/defn fetch-chats-preview
[_ {:keys [on-success]}]
{:json-rpc/call [{:method "wakuext_chatsPreview"
:params []
:js-response true
:on-success #(on-success ^js %)
:on-error #(log/error "failed to fetch chats" 0 -1 %)}]})
(re-frame/reg-fx :fetch-chats-preview
(fn [{:keys [on-success]}]
(json-rpc/call {:method "wakuext_chatsPreview"
:params []
:js-response true
:on-success #(on-success ^js %)
:on-error #(log/error "failed to fetch chats" 0 -1 %)})))
@@ -82,7 +82,13 @@
:albumImagesCount :album-images-count
:displayName :display-name
:linkPreviews :link-previews
:statusLinkPreviews :status-link-previews})
:statusLinkPreviews :status-link-previews
:bridgeMessage :bridge-message})
(update :bridge-message
set/rename-keys
{:bridgeName :bridge-name
:userName :user-name
:userAvatar :user-avatar})
(update :link-previews #(map <-link-preview-rpc %))
(update :status-link-previews #(map <-status-link-previews-rpc %))
(update :quoted-message
@@ -21,6 +21,7 @@
:image nil
:response-to "a"
:links nil}
:bridge-message nil
:whisper-timestamp 1
:contact-verification-state 1
:contact-request-state 2
@@ -2,6 +2,8 @@
(:require
[clojure.set :as set]
[clojure.walk :as walk]
[re-frame.core :as re-frame]
[status-im.common.json-rpc.events :as json-rpc]
[taoensso.timbre :as log]
[utils.re-frame :as rf]))
@@ -32,11 +34,11 @@
:on-success #()
:on-error #()}]})
(rf/defn fetch-switcher-cards-rpc
[_]
{:json-rpc/call [{:method "wakuext_switcherCards"
:params []
:on-success #(rf/dispatch
[:shell/switcher-cards-loaded
(:switcherCards ^js %)])
:on-error #(log/error "Failed to fetch switcher cards" %)}]})
(re-frame/reg-fx :switcher-cards/fetch
(fn []
(json-rpc/call {:method "wakuext_switcherCards"
:params []
:on-success #(rf/dispatch
[:shell/switcher-cards-loaded
(:switcherCards ^js %)])
:on-error #(log/error "Failed to fetch switcher cards" %)})))
@@ -2,8 +2,8 @@
(:require
[clojure.set :as set]
[re-frame.core :as re-frame]
[taoensso.timbre :as log]
[utils.re-frame :as rf]))
[status-im.common.json-rpc.events :as json-rpc]
[taoensso.timbre :as log]))
(defn <-rpc
[visibility-status-update]
@@ -18,13 +18,13 @@
{:current-user-status :current-user-visibility-status})
(update :current-user-visibility-status <-rpc)))
(rf/defn fetch-visibility-status-updates-rpc
[_]
{:json-rpc/call [{:method "wakuext_statusUpdates"
:params []
:on-success #(re-frame/dispatch
[:visibility-status-updates/visibility-status-updates-loaded
(:statusUpdates ^js %)])
:on-error #(log/error
"failed to fetch visibility-status-updates"
%)}]})
(re-frame/reg-fx :visibility-status-updates/fetch
(fn []
(json-rpc/call {:method "wakuext_statusUpdates"
:params []
:on-success #(re-frame/dispatch
[:visibility-status-updates/visibility-status-updates-loaded
(:statusUpdates ^js %)])
:on-error #(log/error
"failed to fetch visibility-status-updates"
%)})))
@@ -239,7 +239,7 @@
(rf/defn tx-history-end-reached
[{:keys [db] :as cofx} address]
(let [syncing-allowed? (utils.mobile-sync/syncing-allowed? cofx)]
(let [syncing-allowed? (utils.mobile-sync/syncing-allowed? db)]
{:db (assoc-in db
[:wallet-legacy :fetching address :all-fetched?]
(if syncing-allowed?
@@ -327,7 +327,7 @@
{:chain-tokens (:wallet-legacy/all-tokens db)
:addresses [address]
:before-block min-known-block
:fetch-more? (utils.mobile-sync/syncing-allowed? cofx)
:fetch-more? (utils.mobile-sync/syncing-allowed? db)
;; Transfers are requested before and including `min-known-block` because there is no
;; guarantee that all transfers from that block are shown already. To make sure that we fetch
;; the whole `default-transfers-limit` of transfers the number of transfers already received
+5
View File
@@ -8,11 +8,16 @@
legacy.status-im.chat.models.loading
legacy.status-im.contact.block
legacy.status-im.currency.core
legacy.status-im.data-store.chats
legacy.status-im.data-store.switcher-cards
legacy.status-im.data-store.visibility-status-updates
legacy.status-im.fleet.core
legacy.status-im.group-chats.core
[legacy.status-im.keycard.core :as keycard]
legacy.status-im.log-level.core
legacy.status-im.mailserver.constants
[legacy.status-im.mailserver.core :as mailserver]
legacy.status-im.mobile-sync-settings.core
legacy.status-im.multiaccounts.login.core
legacy.status-im.multiaccounts.logout.core
[legacy.status-im.multiaccounts.model :as multiaccounts.model]
+12 -15
View File
@@ -6,9 +6,9 @@
[legacy.status-im.data-store.invitations :as data-store.invitations]
[oops.core :as oops]
[re-frame.core :as re-frame]
[status-im.common.json-rpc.events :as json-rpc]
[status-im.constants :as constants]
[status-im.contexts.chat.events :as chat.events]
[status-im.contexts.shell.activity-center.events :as activity-center]
[status-im.navigation.events :as navigation]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
@@ -19,15 +19,13 @@
(when (get-in cofx [:db :chats chat-id])
(chat.events/pop-to-root-and-navigate-to-chat cofx chat-id nil)))
(rf/defn handle-chat-removed
{:events [:chat-removed]}
[cofx response chat-id]
(rf/merge cofx
{:db (dissoc (:db cofx) :current-chat-id)
:dispatch-n [[:shell/close-switcher-card chat-id]
[:sanitize-messages-and-process-response response]
[:pop-to-root :shell-stack]]}
(activity-center/notifications-fetch-unread-count)))
(re-frame/reg-event-fx :chat-removed
(fn [{:keys [db]} [response chat-id]]
{:db (dissoc db :current-chat-id)
:fx [[:dispatch [:shell/close-switcher-card chat-id]]
[:dispatch [:sanitize-messages-and-process-response response]]
[:dispatch [:pop-to-root :shell-stack]]
[:activity-center.notifications/fetch-unread-count]]}))
(rf/defn handle-chat-update
{:events [:chat-updated]}
@@ -264,8 +262,7 @@
{}
invitations))})
(rf/defn get-group-chat-invitations
[_]
{:json-rpc/call
[{:method "wakuext_getGroupChatInvitations"
:on-success #(re-frame/dispatch [::initialize-invitations %])}]})
(re-frame/reg-fx :group-chats/get-group-chat-invitations
(fn []
(json-rpc/call {:method "wakuext_getGroupChatInvitations"
:on-success [::initialize-invitations]})))
+26 -17
View File
@@ -5,6 +5,7 @@
[legacy.status-im.node.core :as node]
[legacy.status-im.utils.mobile-sync :as mobile-network-utils]
[re-frame.core :as re-frame]
[status-im.common.json-rpc.events :as json-rpc]
[status-im.navigation.events :as navigation]
[taoensso.timbre :as log]
[utils.i18n :as i18n]
@@ -61,7 +62,7 @@
(dissoc :mailserver/current-request :mailserver/fetching-gaps-in-progress))})
(defn fetch-use-mailservers?
[{:keys [db]}]
[db]
(get-in db [:profile/profile :use-mailservers?]))
(defonce showing-connection-error-popup? (atom false))
@@ -117,24 +118,32 @@
[{:keys [db] :as cofx}]
{:db (dissoc db :mailserver/current-request)})
(defn needs-to-fetch-historic-messages?
[db]
(and
(:messenger/started? db)
(mobile-network-utils/syncing-allowed? db)
(fetch-use-mailservers? db)
(not (:mailserver/current-request db))))
(rf/defn process-next-messages-request
{:events [::request-messages]}
[{:keys [db now] :as cofx}]
(when (and
(:messenger/started? db)
(mobile-network-utils/syncing-allowed? cofx)
(fetch-use-mailservers? cofx)
(not (:mailserver/current-request db)))
{:db (assoc db :mailserver/current-request true)
:json-rpc/call [{:method "wakuext_requestAllHistoricMessagesWithRetries"
:params [false]
:js-response true
:on-success #(do
(log/info "fetched historical messages")
(re-frame/dispatch [::request-success %]))
:on-error #(do
(log/error "failed retrieve historical messages" %)
(re-frame/dispatch [::request-error]))}]}))
[{:keys [db]}]
(when (needs-to-fetch-historic-messages? db)
{:db (assoc db :mailserver/current-request true)
:mailserver/request-all-historic-messages nil}))
(re-frame/reg-fx :mailserver/request-all-historic-messages
(fn []
(json-rpc/call {:method "wakuext_requestAllHistoricMessagesWithRetries"
:params [false]
:js-response true
:on-success #(do
(log/info "fetched historical messages")
(re-frame/dispatch [::request-success %]))
:on-error #(do
(log/error "failed retrieve historical messages" %)
(re-frame/dispatch [::request-error]))})))
(rf/defn handle-mailserver-changed
[{:keys [db] :as cofx} ms]
@@ -5,7 +5,7 @@
[legacy.status-im.multiaccounts.model :as multiaccounts.model]
[legacy.status-im.multiaccounts.update.core :as multiaccounts.update]
[legacy.status-im.utils.mobile-sync :as utils]
[status-im.contexts.chat.home.add-new-contact.events :as add-new-contact]
[re-frame.core :as re-frame]
[status-im.navigation.events :as navigation]
[taoensso.timbre :as log]
[utils.re-frame :as rf]))
@@ -18,27 +18,24 @@
(or (nil? remember-choice?)
remember-choice?))}))
(rf/defn on-network-status-change
[{:keys [db] :as cofx}]
(let [initialized? (get db :network-status/initialized?)
logged-in? (multiaccounts.model/logged-in? db)
{:keys [remember-syncing-choice?]} (:profile/profile db)]
(apply
rf/merge
cofx
{:db (assoc db :network-status/initialized? true)}
(cond
;; NOTE(rasom): When we log into account on-network-status-change is
;; dispatched, but that doesn't mean there was a status change, thus
;; no reason to restart wallet.
(and logged-in? initialized?)
[(mailserver/process-next-messages-request)
(bottom-sheet/hide-bottom-sheet-old)
#(add-new-contact/set-new-identity-reconnected %)]
logged-in?
[(mailserver/process-next-messages-request)
(bottom-sheet/hide-bottom-sheet-old)]))))
(re-frame/reg-event-fx :mobile-network/on-network-status-change
(fn [{:keys [db]}]
(let [previously-initialized? (get db :network-status/initialized?)
logged-in? (multiaccounts.model/logged-in? db)
fetch-historic-messages? (mailserver/needs-to-fetch-historic-messages? db)]
(if logged-in?
{:db (cond-> (-> db
(assoc :network-status/initialized? true)
(assoc :bottom-sheet/show? false))
fetch-historic-messages?
(assoc :mailserver/current-request true))
:fx [(when fetch-historic-messages?
[:mailserver/request-all-historic-messages])
[:dismiss-bottom-sheet-overlay-old]
(when previously-initialized?
(let [new-identity-input (get-in db [:contacts/new-identity :input])]
[:dispatch [:contacts/set-new-identity {:input new-identity-input}]]))]}
{:db (assoc db :network-status/initialized? true)}))))
(defn apply-settings
([sync?] (apply-settings sync? :default))
@@ -28,7 +28,8 @@
[{:keys [db] :as cofx} {:keys [auth-method logout?]}]
(let [key-uid (get-in db [:profile/profile :key-uid])]
(rf/merge cofx
{:effects.shell/reset-state nil
{:set-root :progress
:effects.shell/reset-state nil
:hide-popover nil
::logout nil
:profile.settings/webview-debug-changed false
+4 -5
View File
@@ -1,7 +1,6 @@
(ns legacy.status-im.network.net-info
(:require
["@react-native-community/netinfo" :default net-info]
[legacy.status-im.mobile-sync-settings.core :as mobile-network]
[native-module.core :as native-module]
[re-frame.core :as re-frame]
[taoensso.timbre :as log]
@@ -13,11 +12,11 @@
{:db (assoc db :network-status (if is-connected? :online :offline))}))
(rf/defn change-network-type
[{:keys [db] :as cofx} old-network-type network-type expensive?]
[{:keys [db] :as cofx} network-type expensive?]
(rf/merge cofx
{:db (assoc db :network/type network-type)
:network/notify-status-go [network-type expensive?]}
(mobile-network/on-network-status-change)))
:network/notify-status-go [network-type expensive?]
:dispatch [:mobile-network/on-network-status-change]}))
(rf/defn handle-network-info-change
{:events [::network-info-changed]}
@@ -37,7 +36,7 @@
(when-not status-changed?
(change-network-status isConnected))
(when-not type-changed?
(change-network-type old-network-type type (:is-connection-expensive details))))))
(change-network-type type (:is-connection-expensive details))))))
(defn add-net-info-listener
[]
+16
View File
@@ -2,6 +2,7 @@
(:require
[legacy.status-im.utils.utils :as utils]
[re-frame.core :as re-frame]
[status-im.common.json-rpc.events :as json-rpc]
[status-im.constants :as constants]
[utils.ethereum.chain :as chain]
[utils.re-frame :as rf]))
@@ -22,6 +23,21 @@
:params [(chain/chain-id db) id]
:on-success #()}]}))
(re-frame/reg-fx :stickers/load-packs
(fn [chain-id]
(json-rpc/call {:method "stickers_market"
:params [chain-id]
:on-success [:stickers/stickers-market-success]})
(json-rpc/call {:method "stickers_installed"
:params []
:on-success [:stickers/stickers-installed-success]})
(json-rpc/call {:method "stickers_pending"
:params []
:on-success [:stickers/stickers-pending-success]})
(json-rpc/call {:method "stickers_recent"
:params []
:on-success [:stickers/stickers-recent-success]})))
(rf/defn load-packs
{:events [:stickers/load-packs]}
[{:keys [db]}]
+1 -1
View File
@@ -61,7 +61,7 @@
(re-frame/reg-sub
:mailserver/use-status-nodes?
(fn [db _]
(boolean (mailserver/fetch-use-mailservers? {:db db}))))
(boolean (mailserver/fetch-use-mailservers? db))))
(re-frame/reg-sub
:mailserver.edit/validation-errors
@@ -21,7 +21,7 @@
{:active (= value id)
:accessory :radio
:title (get titles id)
:on-press #(re-frame/dispatch [:profile.settings/update-value :default-sync-period id])}])
:on-press #(re-frame/dispatch [:profile.settings/profile-update :default-sync-period id])}])
(views/defview default-sync-period-settings
[]
@@ -111,7 +111,7 @@
:subtitle (i18n/label :t/webview-camera-permission-requests-subtitle)
:subtitle-max-lines 2
:on-press #(re-frame/dispatch
[:profile.settings/update-value
[:profile.settings/profile-update
:webview-allow-permission-requests?
((complement boolean) webview-allow-permission-requests?)])}])
[separator]
@@ -169,8 +169,7 @@
{:active (= value id)
:accessory :radio
:title (get titles id)
:on-press #(re-frame/dispatch [:profile.settings/update-value :profile-pictures-visibility
id])}])
:on-press #(re-frame/dispatch [:profile.settings/profile-update :profile-pictures-visibility id])}])
(views/defview profile-pic
[]
@@ -51,4 +51,4 @@
:icon :main-icons/delete
:theme :accent
:title (i18n/label :t/profile-pic-remove)
:on-press #(re-frame/dispatch [:profile.settings/delete-profile-picture nil])}])]))
:on-press #(re-frame/dispatch [:profile.settings/delete-profile-picture])}])]))
+5 -5
View File
@@ -10,6 +10,7 @@
[re-frame.core :as re-frame]
[react-native.mail :as react-native-mail]
[react-native.platform :as platform]
[status-im.common.json-rpc.events :as json-rpc]
[status-im.common.log :as log]
[status-im.config :as config]
[utils.datetime :as datetime]
@@ -31,11 +32,10 @@
[{:keys [db]} node-version]
{:db (assoc db :web3-node-version node-version)})
(rf/defn initialize-web3-client-version
{:events [:logging/initialize-web3-client-version]}
[_]
{:json-rpc/call [{:method "web3_clientVersion"
:on-success #(re-frame/dispatch [:logging/store-web3-client-version %])}]})
(re-frame/reg-fx :logging/initialize-web3-client-version
(fn []
(json-rpc/call {:method "web3_clientVersion"
:on-success [:logging/store-web3-client-version]})))
(defn extract-url-components
[address]
+1 -1
View File
@@ -5,7 +5,7 @@
(= network-type "cellular"))
(defn syncing-allowed?
[{:keys [db]}]
[db]
(let [network (:network/type db)
{:keys [syncing-on-mobile-network?]} (:profile/profile db)]
(or (= network "wifi")
@@ -2,10 +2,17 @@
(:require
[quo.foundations.colors :as colors]))
(defn- get-dimensions
[size]
(case size
:size-24 24
:size-20 20
nil))
(defn collection-avatar
[theme]
{:width 24
:height 24
[theme size]
{:width (get-dimensions size)
:height (get-dimensions size)
:border-width 1
:border-color (colors/theme-colors colors/neutral-80-opa-10 colors/white-opa-10 theme)
:border-radius 6})
@@ -9,10 +9,10 @@
:image - collection image
:theme - keyword -> :light/:dark"
[{:keys [image theme]}]
[{:keys [image theme size] :or {size :size-24}}]
[fast-image/fast-image
{:accessibility-label :collection-avatar
:source image
:style (style/collection-avatar theme)}])
:style (style/collection-avatar theme size)}])
(def view (quo.theme/with-theme view-internal))
@@ -0,0 +1,23 @@
(ns quo.components.community.channel-action.style
(:require
[quo.foundations.colors :as colors]))
(defn channel-action-container
[{:keys [big? disabled?]}]
(cond-> {}
disabled? (assoc :opacity 0.3)
big? (assoc :flex-grow 1)
(not big?) (assoc :width 104)))
(defn channel-action
[{:keys [color pressed? theme]}]
{:height 102
:padding 12
:border-radius 16
:background-color (colors/resolve-color color theme (if pressed? 20 10))
:justify-content :space-between})
(def channel-action-row
{:flex-direction :row
:justify-content :space-between
:align-items :center})
@@ -0,0 +1,39 @@
(ns quo.components.community.channel-action.view
(:require
[quo.components.community.channel-action.style :as style]
[quo.components.counter.counter.view :as counter]
[quo.components.icon :as icons]
[quo.components.markdown.text :as text]
[quo.theme]
[react-native.core :as rn]))
(defn view
[{:keys [big? customization-color label counter-value icon on-press accessibility-label disabled?]}]
(let [theme (quo.theme/use-theme-value)
[pressed? set-pressed] (rn/use-state false)
on-press-in (rn/use-callback #(set-pressed true))
on-press-out (rn/use-callback #(set-pressed false))]
[rn/view
{:style (style/channel-action-container
{:big? big?
:disabled? disabled?})}
[rn/pressable
(cond-> {:style (style/channel-action
{:big? big?
:color customization-color
:pressed? pressed?
:theme theme
:disabled? disabled?})
:accessibility-label accessibility-label}
(not disabled?) (assoc :on-press on-press
:on-press-in on-press-in
:on-press-out on-press-out))
[rn/view {:style style/channel-action-row}
[icons/icon icon]
(when counter-value
[counter/view {:type :secondary} counter-value])]
[text/text
{:size :paragraph-1
:weight :medium
:number-of-lines 2}
label]]]))
@@ -1,32 +0,0 @@
(ns quo.components.community.channel-actions
(:require
[quo.components.community.style :as style]
[quo.components.counter.counter.view :as counter]
[quo.components.icon :as icons]
[quo.components.markdown.text :as text]
[react-native.core :as rn]))
(defn channel-action
[{:keys [big? color label counter-value icon on-press accessibility-label]}]
[rn/touchable-opacity
{:on-press on-press
:style (style/channel-action-touch big?)
:accessibility-label accessibility-label}
[rn/view {:style (style/channel-action color)}
[rn/view {:style style/channel-action-row}
[icons/icon icon]
(when counter-value
[counter/view {:type :secondary} counter-value])]
[text/text {:size :paragraph-1 :weight :medium :number-of-lines 2} label]]])
(defn channel-actions
[{:keys [container-style actions]}]
[rn/view {:style (assoc container-style :flex-direction :row)}
(map-indexed
(fn [index action]
^{:key index}
[:<>
[channel-action action]
(when (not= action (last actions))
[rn/view {:width 16}])])
actions)])
@@ -0,0 +1,16 @@
(ns quo.components.community.channel-actions.view
(:require
[quo.components.community.channel-action.view :as channel-action]
[react-native.core :as rn]))
(defn view
[{:keys [container-style actions]}]
[rn/view {:style (assoc container-style :flex-direction :row)}
(map-indexed
(fn [index action]
^{:key index}
[:<>
[channel-action/view action]
(when (not= action (last actions))
[rn/view {:width 16}])])
actions)])
-18
View File
@@ -133,24 +133,6 @@
colors/neutral-80
theme)})
(defn channel-action-touch
[big?]
{:flex 1
:max-width (if big? 216 104)})
(defn channel-action
[color]
{:padding 12
:height 102
:border-radius 16
:background-color (colors/custom-color color 50 10)
:justify-content :space-between})
(def channel-action-row
{:flex-direction :row
:justify-content :space-between
:align-items :center})
(defn loading-card
[width theme]
(merge
@@ -11,6 +11,7 @@
[:catn
[:props
[:map {:closed true}
[:container-style {:optional true} [:maybe :map]]
[:value {:optional true} [:maybe [:or :string :int]]]
[:status {:optional true} [:maybe :keyword]]
[:size {:optional true} [:maybe [:enum :size-32 :size-24]]]
@@ -19,7 +20,7 @@
:any])
(defn- view-internal
[{:keys [value accessibility-label]
[{:keys [value accessibility-label container-style]
:as props}]
(let [default-props {:status :default
:size :size-32}
@@ -27,7 +28,7 @@
[rn/view
{:accessible true
:accessibility-label (or accessibility-label :collectible-counter)
:style (style/container props)}
:style (merge (style/container props) container-style)}
[text/text
{:weight :medium
:size (style/get-text-size props)
@@ -59,4 +59,15 @@
:button-one-label "Request to join"}])
(h/is-truthy (h/get-by-text "Eligible to join as"))
(h/is-truthy (h/get-by-text "Admin"))
(h/is-truthy (h/get-by-text "Request to join")))
(h/test "render with top description with custom text & 1 action"
(render [bottom-actions/view
{:description :top
:role :admin
:actions :one-action
:description-top-text "You'll be an"
:button-one-label "Request to join"}])
(h/is-truthy (h/get-by-text "You'll be an"))
(h/is-truthy (h/get-by-text "Admin"))
(h/is-truthy (h/get-by-text "Request to join"))))
@@ -19,6 +19,7 @@
[:actions [:maybe [:enum :one-action :two-actions]]]
[:description {:optional true} [:maybe [:enum :top :bottom :top-error]]]
[:description-text {:optional true} [:maybe :string]]
[:description-top-text {:optional true} [:maybe :string]]
[:error-message {:optional true} [:maybe :string]]
[:role {:optional true} [:maybe [:enum :admin :member :token-master :owner]]]
[:button-one-label {:optional true} [:maybe :string]]
@@ -38,8 +39,8 @@
:owner :i/crown})
(defn- view-internal
[{:keys [actions description description-text error-message role button-one-label button-two-label
blur? button-one-props button-two-props theme scroll? container-style]}]
[{:keys [actions description description-text description-top-text error-message role button-one-label
button-two-label blur? button-one-props button-two-props theme scroll? container-style]}]
[rn/view
{:style (merge (style/container scroll? blur? theme) container-style)}
(when (= description :top-error)
@@ -54,12 +55,11 @@
error-message]])
(when (and (= description :top) role)
[rn/view
{:style style/description-top}
[rn/view {:style style/description-top}
[text/text
{:size :paragraph-2
:style (style/description-top-text scroll? blur? theme)}
(i18n/label :t/eligible-to-join-as)]
(or description-top-text (i18n/label :t/eligible-to-join-as))]
[context-tag/view
{:type :icon
:size 24
@@ -76,12 +76,12 @@
:blur? overflow-label blur?}
items preview list items (only 4 items is required for preview)
"
[{:keys [type size number blur?]} items]
[{:keys [type size number blur? container-style]} items]
(let [size-key (if (contains? properties/sizes size) size :size-24)
number (or number (count items))
border-type (properties/border-type type)
margin-left (get-in properties/sizes [size-key :margin-left])]
[rn/view {:style {:flex-direction :row}}
[rn/view {:style (assoc container-style :flex-direction :row)}
(for [index (range (if (> number 4) 3 number))]
^{:key (str index number)}
[list-item
+4 -3
View File
@@ -18,9 +18,9 @@
:align-items :center})
(defn action-icon
[{:keys [type on-press on-check disabled? checked?]} theme]
[{:keys [type on-press on-check disabled? checked?]} customization-color theme]
[rn/touchable-opacity
{:on-press (when on-press on-press)}
{:on-press on-press}
(case type
:options
[icons/icon :i/options
@@ -30,6 +30,7 @@
[selectors/view
{:type :checkbox
:checked? checked?
:customization-color customization-color
:accessibility-label :user-list-toggle-check
:disabled? disabled?
:on-change (when on-check on-check)}]
@@ -68,4 +69,4 @@
:style {:color (colors/theme-colors colors/neutral-50 colors/neutral-40)}}
short-chat-key])]
(when accessory
[action-icon accessory theme])]])
[action-icon accessory customization-color theme])]])
@@ -0,0 +1,116 @@
(ns quo.components.profile.collectible-list-item.component-spec
(:require
[quo.components.profile.collectible-list-item.view :as collectible-list-item]
[test-helpers.component :as h]))
(h/describe "Profile/ collectible list item tests"
(h/describe "type card"
(h/test "Renders default and on press fires"
(let [on-press (h/mock-fn)]
(h/render-with-theme-provider
[collectible-list-item/view
{:type :card
:on-press on-press}])
(h/fire-event :press (h/get-by-label-text :collectible-list-item))
(h/was-called on-press)))
(h/test "Renders loading and on press fires"
(let [on-press (h/mock-fn)]
(h/render-with-theme-provider
[collectible-list-item/view
{:type :card
:status :loading
:on-press on-press}])
(h/fire-event :press (h/get-by-label-text :collectible-list-item))
(h/was-not-called on-press)
(h/is-truthy (h/get-by-label-text :gradient-overlay))))
(h/test "Renders counter"
(h/render-with-theme-provider
[collectible-list-item/view
{:type :card
:counter "x500"}])
(h/is-truthy (h/get-by-text "x500")))
(h/test "Renders counter and collectible name"
(h/render-with-theme-provider
[collectible-list-item/view
{:type :card
:collectible-name "Doodle #6822"
:counter "x500"}])
(h/is-truthy (h/get-by-text "x500"))
(h/is-truthy (h/get-by-text "Doodle #6822")))
(h/test "Renders status cant-fetch"
(h/render-with-theme-provider
[collectible-list-item/view
{:type :card
:status :cant-fetch}])
(h/is-truthy (h/get-by-translation-text :t/cant-fetch-info)))
(h/test "Renders status unsupported"
(h/render-with-theme-provider
[collectible-list-item/view
{:type :card
:status :unsupported}])
(h/is-truthy (h/get-by-translation-text :t/unsupported-file)))
(h/test "Renders status unsupported and counter"
(h/render-with-theme-provider
[collectible-list-item/view
{:type :card
:status :unsupported
:counter "x500"}])
(h/is-truthy (h/get-by-text "x500"))
(h/is-truthy (h/get-by-translation-text :t/unsupported-file))))
(h/describe "type image"
(h/test "Renders default and on press fires"
(let [on-press (h/mock-fn)]
(h/render-with-theme-provider
[collectible-list-item/view
{:type :image
:on-press on-press}])
(h/fire-event :press (h/get-by-label-text :collectible-list-item))
(h/was-called on-press)))
(h/test "Renders loading and on press fires"
(let [on-press (h/mock-fn)]
(h/render-with-theme-provider
[collectible-list-item/view
{:type :image
:status :loading
:on-press on-press}])
(h/fire-event :press (h/get-by-label-text :collectible-list-item))
(h/was-not-called on-press)
(h/is-truthy (h/get-by-label-text :gradient-overlay))))
(h/test "Renders counter"
(h/render-with-theme-provider
[collectible-list-item/view
{:type :image
:counter "x500"}])
(h/is-truthy (h/get-by-text "x500")))
(h/test "Renders status cant-fetch"
(h/render-with-theme-provider
[collectible-list-item/view
{:type :image
:status :cant-fetch}])
(h/is-truthy (h/get-by-translation-text :t/cant-fetch-info)))
(h/test "Renders status unsupported"
(h/render-with-theme-provider
[collectible-list-item/view
{:type :image
:status :unsupported}])
(h/is-truthy (h/get-by-translation-text :t/unsupported-file)))
(h/test "Renders status unsupported and counter"
(h/render-with-theme-provider
[collectible-list-item/view
{:type :image
:status :unsupported
:counter "x500"}])
(h/get-by-text "x500")
(h/is-truthy (h/get-by-translation-text :t/unsupported-file)))))
@@ -0,0 +1,90 @@
(ns quo.components.profile.collectible-list-item.style
(:require [quo.foundations.colors :as colors]
[quo.foundations.shadows :as shadows]))
(def container-border-radius 12)
(def card-image-padding-vertical 3)
(def card-image-padding-horizontal 3)
(defn fallback
[{:keys [theme]}]
{:background-color (colors/theme-colors colors/neutral-2_5 colors/neutral-90 theme)
:border-style :dashed
:border-color (colors/theme-colors colors/neutral-20 colors/neutral-80 theme)
:border-width 1
:border-radius container-border-radius
:width "100%"
:aspect-ratio 1
:align-items :center
:justify-content :center})
(def collectible-counter
{:position :absolute
:top 12
:right 12})
(def avatar
{:position :absolute
:bottom 12
:left 12})
(def container
{:flex 1})
(defn card-view-container
[theme]
(merge
{:background-color (colors/theme-colors colors/white colors/neutral-95 theme)
:padding-top card-image-padding-vertical
:padding-left card-image-padding-horizontal
:padding-right card-image-padding-horizontal
:padding-bottom card-image-padding-vertical
:border-radius 14
:border-width 1
:border-color (colors/theme-colors colors/neutral-10 colors/neutral-80 theme)}
(shadows/get 2)))
(def image
{:width "100%"
:flex 1
:border-radius container-border-radius})
(def card-details-container
{:flex-direction :row
:height 27
:margin-top 3
:margin-bottom 2
:align-items :center
:padding-left 8
:padding-right 0
:padding-top 4})
(def card-detail-text
{:flex 1})
(def image-view-container
{:aspect-ratio 1
:border-radius container-border-radius})
(defn loading-square
[theme]
{:height 20
:width 20
:border-radius 6
:align-self :center
:background-color (colors/theme-colors colors/neutral-5 colors/neutral-90 theme)})
(defn loading-message
[theme]
{:height 14
:width 72
:margin-left 8
:border-radius 6
:align-self :center
:background-color (colors/theme-colors colors/neutral-5 colors/neutral-90 theme)})
(defn loading-image
[theme]
{:flex 1
:border-radius container-border-radius
:background-color (colors/theme-colors colors/white-70-blur colors/neutral-95-opa-70-blur theme)})
@@ -0,0 +1,195 @@
(ns quo.components.profile.collectible-list-item.view
(:require
[quo.components.avatars.collection-avatar.view :as collection-avatar]
[quo.components.counter.collectible-counter.view :as collectible-counter]
[quo.components.icon :as icon]
[quo.components.list-items.preview-list.view :as preview-list]
[quo.components.markdown.text :as quo]
[quo.components.profile.collectible-list-item.style :as style]
[quo.foundations.colors :as colors]
[quo.foundations.gradients :as gradients]
[quo.theme]
[react-native.core :as rn]
[schema.core :as schema]
[utils.i18n :as i18n]))
(defn- fallback-view
[{:keys [label theme type]}]
[rn/view
{:style (style/fallback {:type type
:theme theme})}
[rn/view
[icon/icon :i/sad {:color (colors/theme-colors colors/neutral-40 colors/neutral-50 theme)}]]
[rn/view {:style {:height 4}}]
[quo/text
{:size :paragraph-2
:style {:color (colors/theme-colors colors/neutral-40 colors/neutral-50 theme)}}
label]])
(defn- loading-square
[theme]
[rn/view {:style (style/loading-square theme)}])
(defn- loading-message
[theme]
[rn/view {:style (style/loading-message theme)}])
(defn- loading-image
[{:keys [theme gradient-color-index]}]
[gradients/view
{:theme theme
:container-style (style/loading-image theme)
:color-index gradient-color-index}])
(defn- card-details
[{:keys [status community? avatar-image-src collectible-name theme]}]
[rn/view {:style style/card-details-container}
(cond (= :cant-fetch status)
[quo/text
{:size :paragraph-1
:weight :medium
:style {:color (colors/theme-colors colors/neutral-50 colors/neutral-40 theme)}}
(i18n/label :t/unknown)]
(= :loading status)
[rn/view {:style {:flex-direction :row}}
[loading-square theme]
[loading-message theme]]
community?
[:<>
[preview-list/view
{:type :communities
:size :size-20}
[avatar-image-src]]
[rn/view {:style {:width 8}}]
[quo/text
{:size :paragraph-1
:weight :semi-bold
:style style/card-detail-text}
collectible-name]]
:else
[:<>
[collection-avatar/view
{:size :size-20
:image avatar-image-src}]
[rn/view {:style {:width 8}}]
[quo/text
{:size :paragraph-1
:weight :semi-bold
:ellipsize-mode :tail
:number-of-lines 1
:style style/card-detail-text}
collectible-name]])])
(defn- card-view
[{:keys [avatar-image-src collectible-name community? counter
gradient-color-index image-src status type]}]
(let [theme (quo.theme/use-theme-value)]
[rn/view {:style (style/card-view-container theme)}
[rn/view {:style {:aspect-ratio 1}}
(cond
(= :loading status)
[loading-image
{:theme theme
:gradient-color-index gradient-color-index}]
(= status :unsupported)
[fallback-view
{:theme theme
:type type
:label (i18n/label :t/unsupported-file)}]
(= status :cant-fetch)
[fallback-view
{:theme theme
:type type
:label (i18n/label :t/cant-fetch-info)}]
:else
[rn/view {:style {:aspect-ratio 1}}
[rn/image
{:style style/image
:source image-src}]])]
(when (and (not= status :loading) (not= status :cant-fetch) counter)
[collectible-counter/view
{:container-style style/collectible-counter
:size :size-24
:value counter}])
[card-details
{:status status
:community? community?
:avatar-image-src avatar-image-src
:collectible-name collectible-name
:theme theme}]]))
(defn- image-view
[{:keys [avatar-image-src community? counter
gradient-color-index image-src status]}]
(let [theme (quo.theme/use-theme-value)]
[rn/view {:style style/image-view-container}
(cond
(= :loading status)
[loading-image
{:theme theme
:gradient-color-index gradient-color-index}]
(= status :unsupported)
[fallback-view
{:theme theme
:type type
:label (i18n/label :t/unsupported-file)}]
(= status :cant-fetch)
[fallback-view
{:theme theme
:type type
:label (i18n/label :t/cant-fetch-info)}]
:else [rn/view {:style {:aspect-ratio 1}}
[rn/image
{:style style/image
:source image-src}]])
(when (and (not= status :loading) (not= status :cant-fetch) counter)
[collectible-counter/view
{:container-style style/collectible-counter
:size :size-24
:value counter}])
(when (and (not= status :loading) (not= status :cant-fetch) community?)
[preview-list/view
{:container-style style/avatar
:type :communities
:size :size-24}
[avatar-image-src]])]))
(defn- view-internal
[{:keys [container-style type on-press status]
:as props}]
[rn/pressable
{:on-press (when-not (= status :loading) on-press)
:accessibility-label :collectible-list-item
:style (merge container-style style/container)}
(if (= type :card)
[card-view props]
[image-view props])])
(def ?schema
[:=>
[:catn
[:props
[:map {:closed true}
[:avatar-image-src {:optional true} [:maybe :schema.common/image-source]]
[:collectible-name {:optional true} [:maybe string?]]
[:community? {:optional true} [:maybe boolean?]]
[:counter {:optional true} [:maybe string?]]
[:gradient-color-index {:optional true}
[:maybe [:enum :gradient-1 :gradient-2 :gradient-3 :gradient-4 :gradient-5]]]
[:image-src {:optional true} [:maybe :schema.common/image-source]]
[:on-press {:optional true} [:maybe fn?]]
[:status {:optional true} [:maybe [:enum :default :loading :cant-fetch :unsupported]]]
[:type [:enum :card :image]]]]]
:any])
(def view (schema/instrument #'view-internal ?schema))
@@ -8,6 +8,7 @@
[:enum :default :multiuser :group :channel :community :token :network :multinetwork :account
:collectible :address :icon :audio]]]
[:customization-color {:optional true} [:maybe :schema.common/customization-color]]
[:container-style {:optional true} [:maybe :map]]
[:theme :schema.common/theme]
[:blur? {:optional true} [:maybe :boolean]]
[:state {:optional true} [:maybe [:enum :selected :default]]]])
@@ -38,6 +39,7 @@
(def ^:private ?channel
[:map
[:community-name {:optional true} [:maybe :string]]
[:community-logo {:optional true} [:maybe :schema.common/image-source]]
[:channel-name {:optional true} [:maybe :string]]])
(def ^:private ?community
@@ -36,6 +36,7 @@
(colors/custom-color customization-color 60)
theme)]
(cond-> {:padding 2
:padding-right 8
:flex-direction :row
:align-items :center
:height size
+65 -64
View File
@@ -12,6 +12,7 @@
[quo.foundations.colors :as colors]
[quo.theme :as quo.theme]
[react-native.core :as rn]
[react-native.fast-image :as fast-image]
[schema.core :as schema]))
(defn- tag-skeleton
@@ -30,7 +31,7 @@
(let [text-size (if (= size 24) :paragraph-2 :paragraph-1)
icon-size (if (= size 24) 16 20)]
[rn/view {:style (style/tag-container size)}
[rn/image {:style (style/circle-logo size) :source community-logo}]
[fast-image/fast-image {:style (style/circle-logo size) :source community-logo}]
[rn/view {:style (style/tag-spacing size)}
[text/text
{:style (style/text theme)
@@ -82,81 +83,81 @@
type :default
state :default}
:as props}]
[rn/view
{:style (merge (style/container {:theme theme
:type type
:size size
:state state
:blur? blur?
:customization-color customization-color})
container-style)
:accessibility-label :context-tag}
(case type
:default
[tag-skeleton {:theme theme :size size :text full-name}
[user-avatar/user-avatar
{:full-name full-name
:profile-picture profile-picture
:size (if (= size 24) :xxs 28)
:status-indicator? false
:ring? false
:customization-color customization-color}]]
[rn/view {:style (merge {:align-items :flex-start} container-style)}
[rn/view
{:style (style/container {:theme theme
:type type
:size size
:state state
:blur? blur?
:customization-color customization-color})
:accessibility-label :context-tag}
(case type
:default
[tag-skeleton {:theme theme :size size :text full-name}
[user-avatar/user-avatar
{:full-name full-name
:profile-picture profile-picture
:size (if (= size 24) :xxs 28)
:status-indicator? false
:ring? false
:customization-color customization-color}]]
:multiuser
[preview-list/view {:type :user :size :size-20}
users]
:multiuser
[preview-list/view {:type :user :size :size-20}
users]
:multinetwork
[preview-list/view {:type :network :size :size-20}
networks]
:multinetwork
[preview-list/view {:type :network :size :size-20}
networks]
:audio
[tag-skeleton {:theme theme :text (str duration)}
[rn/view {:style (style/audio-tag-icon-container customization-color theme)}
[icons/icon :i/play {:color style/audio-tag-icon-color :size 12}]]]
:audio
[tag-skeleton {:theme theme :text (str duration)}
[rn/view {:style (style/audio-tag-icon-container customization-color theme)}
[icons/icon :i/play {:color style/audio-tag-icon-color :size 12}]]]
:group
[tag-skeleton {:theme theme :size size :text group-name}
[group-avatar/view
{:icon-name :i/members
:size (if (= size 24) :size-20 :size-28)
:customization-color (colors/custom-color customization-color 50)}]]
:group
[tag-skeleton {:theme theme :size size :text group-name}
[group-avatar/view
{:icon-name :i/members
:size (if (= size 24) :size-20 :size-28)
:customization-color (colors/custom-color customization-color 50)}]]
(:channel :community)
[communities-tag (assoc props :channel? (= type :channel))]
(:channel :community)
[communities-tag (assoc props :channel? (= type :channel))]
:token
[tag-skeleton {:theme theme :size size :text (str amount " " token)}
[token/view
{:style (style/token-logo size)
:token token
:size (if (= size 24) :size-20 :size-28)}]]
:token
[tag-skeleton {:theme theme :size size :text (str amount " " token)}
[token/view
{:style (style/token-logo size)
:token token
:size (if (= size 24) :size-20 :size-28)}]]
:network
[tag-skeleton {:theme theme :size size :text network-name}
[rn/image {:style (style/circle-logo size) :source network-logo}]]
:network
[tag-skeleton {:theme theme :size size :text network-name}
[rn/image {:style (style/circle-logo size) :source network-logo}]]
:collectible
[tag-skeleton
{:theme theme
:size size
:text (str collectible-name " #" collectible-number)}
[rn/image {:style (style/rounded-logo size) :source collectible}]]
:collectible
[tag-skeleton
{:theme theme
:size size
:text (str collectible-name " #" collectible-number)}
[rn/image {:style (style/rounded-logo size) :source collectible}]]
:account
[tag-skeleton {:theme theme :size size :text account-name}
[account-avatar/view
{:customization-color customization-color
:emoji emoji
:size (if (= size 24) 20 28)}]]
:account
[tag-skeleton {:theme theme :size size :text account-name}
[account-avatar/view
{:customization-color customization-color
:emoji emoji
:size (if (= size 24) 20 28)}]]
:address
[address-tag props]
:address
[address-tag props]
:icon
[icon-tag props]
:icon
[icon-tag props]
nil)])
nil)]])
(def view
(quo.theme/with-theme
+7 -3
View File
@@ -29,7 +29,8 @@
quo.components.common.notification-dot.view
quo.components.common.separator.view
quo.components.community.banner.view
quo.components.community.channel-actions
quo.components.community.channel-action.view
quo.components.community.channel-actions.view
quo.components.community.community-card-view
quo.components.community.community-list-view
quo.components.community.community-stat.view
@@ -55,7 +56,7 @@
quo.components.dropdowns.network-dropdown.view
quo.components.empty-state.empty-state.view
quo.components.gradient.gradient-cover.view
[quo.components.graph.interactive-graph.view :as interactive-graph]
quo.components.graph.interactive-graph.view
quo.components.graph.wallet-graph.view
quo.components.header
quo.components.icon
@@ -109,6 +110,7 @@
quo.components.onboarding.small-option-card.view
quo.components.overlay.view
quo.components.password.tips.view
quo.components.profile.collectible-list-item.view
quo.components.profile.collectible.view
quo.components.profile.link-card.view
quo.components.profile.profile-card.view
@@ -229,7 +231,8 @@
(def discover-card quo.components.community.banner.view/view)
(def community-icon quo.components.community.icon/community-icon)
(def token-requirement-list quo.components.community.token-gating/token-requirement-list)
(def channel-actions quo.components.community.channel-actions/channel-actions)
(def channel-action quo.components.community.channel-action.view/view)
(def channel-actions quo.components.community.channel-actions.view/view)
;;;; Counter
(def collectible-counter quo.components.counter.collectible-counter.view/view)
@@ -350,6 +353,7 @@
;;;; Profile
(def collectible quo.components.profile.collectible.view/collectible)
(def collectible-list-item quo.components.profile.collectible-list-item.view/view)
(def link-card quo.components.profile.link-card.view/view)
(def profile-card quo.components.profile.profile-card.view/profile-card)
(def select-profile quo.components.profile.select-profile.view/view)
+1
View File
@@ -63,6 +63,7 @@
quo.components.numbered-keyboard.keyboard-key.component-spec
quo.components.onboarding.small-option-card.component-spec
quo.components.password.tips.component-spec
quo.components.profile.collectible-list-item.component-spec
quo.components.profile.link-card.component-spec
quo.components.profile.select-profile.component-spec
quo.components.profile.showcase-nav.component-spec
+34
View File
@@ -0,0 +1,34 @@
(ns quo.foundations.gradients
(:require
[quo.foundations.colors :as colors]
[quo.theme]
[react-native.linear-gradient :as linear-gradient]))
(defn- gradient-colors
[index theme]
(case index
:gradient-1 [(colors/resolve-color :yellow theme)
(colors/resolve-color :sky theme)
(colors/resolve-color :purple theme)]
:gradient-2 [(colors/resolve-color :orange theme)
(colors/resolve-color :purple theme)
(colors/resolve-color :blue theme)]
:gradient-3 [(colors/resolve-color :blue theme)
(colors/resolve-color :magenta theme)
(colors/resolve-color :yellow theme)]
:gradient-4 [(colors/resolve-color :army theme)
(colors/resolve-color :orange theme)
(colors/resolve-color :blue theme)]
[(colors/resolve-color :purple theme)
(colors/resolve-color :army theme)
(colors/resolve-color :yellow theme)]))
(defn view
[{:keys [color-index container-style] :or {color-index 1}}]
(let [theme (quo.theme/use-theme-value)]
[linear-gradient/linear-gradient
{:style (merge {:border-radius 16} container-style)
:accessibility-label :gradient-overlay
:colors (gradient-colors color-index theme)
:start {:x 0 :y 0}
:end {:x 0 :y 1}}]))
+27 -6
View File
@@ -95,13 +95,34 @@
(into [{:title title :header? true}] data))
sections))
(defn- find-sticky-indices
[data]
(->> data
(map-indexed (fn [index item] (when (:header? item) index)))
(remove nil?)
(vec)))
(defn- is-last-item-in-section
[data index]
(let [next-item (nth data (inc index) nil)]
(or (nil? next-item) (:header? next-item))))
(defn section-list
[{:keys [sections render-section-header-fn render-fn] :as props}]
[{:keys [sections sticky-section-headers-enabled render-section-header-fn render-section-footer-fn
render-fn]
:or {sticky-section-headers-enabled true}
:as props}]
(let [data (flatten-sections sections)]
[flat-list
(merge props
{:data data
:render-fn (fn [p1 p2 p3 p4]
(if (:header? p1)
[render-section-header-fn p1 p2 p3 p4]
[render-fn p1 p2 p3 p4]))})]))
{:data data
:render-fn (fn [p1 p2 p3 p4]
[:<>
(if (:header? p1)
[render-section-header-fn p1 p2 p3 p4]
[render-fn p1 p2 p3 p4])
(when (and render-section-footer-fn
(is-last-item-in-section data p2))
[render-section-footer-fn p1 p2 p3 p4])])
:sticky-header-indices (when sticky-section-headers-enabled
(find-sticky-indices data))})]))
+1 -4
View File
@@ -20,8 +20,7 @@
LinearTransition
enableLayoutAnimations
useAnimatedScrollHandler
runOnJS)
:as reanimated*]
runOnJS)]
["react-native-redash" :refer (withPause)]
[react-native.flat-list :as rn-flat-list]
[react-native.utils :as rn.utils]
@@ -108,8 +107,6 @@
(when (and anim (some? v))
(set! (.-value anim) v)))
(def interpolate* reanimated*/interpolate)
(defn interpolate
([shared-value input-range output-range]
(interpolate shared-value input-range output-range nil))
+9 -1
View File
@@ -5,6 +5,14 @@
(def ^:private ?cofx
[:map])
(def ^:private ?event
[:and
[:vector {:min 1} :any]
[:catn
[:event-id keyword?]
[:event-args [:* :any]]]])
(defn register-schemas
[]
(registry/register ::cofx ?cofx))
(registry/register ::cofx ?cofx)
(registry/register ::event ?event))
+7 -3
View File
@@ -1,5 +1,9 @@
(ns status-im.common.contact-list.style)
(ns status-im.common.contact-list.style
(:require [quo.foundations.colors :as colors]))
(def contacts-section-footer
{:height 8})
(defn contacts-section-header
[first-item?]
{:padding-top (if first-item? 0 8)})
[theme]
{:background-color (colors/theme-colors colors/white colors/neutral-95 theme)})
+9 -3
View File
@@ -1,10 +1,16 @@
(ns status-im.common.contact-list.view
(:require
[quo.core :as quo]
[quo.theme]
[react-native.core :as rn]
[status-im.common.contact-list.style :as style]))
(defn contacts-section-footer
[]
[rn/view style/contacts-section-footer])
(defn contacts-section-header
[{:keys [title index]}]
[rn/view (style/contacts-section-header (= index 0))
[quo/divider-label title]])
[{:keys [title]}]
(let [theme (quo.theme/use-theme-value)]
[rn/view (style/contacts-section-header theme)
[quo/divider-label title]]))
-8
View File
@@ -4,9 +4,7 @@
[clojure.string :as string]
[native-module.core :as native-module]
[re-frame.core :as re-frame]
[status-im.config :as config]
[taoensso.timbre :as log]
[utils.re-frame :as rf]
[utils.transforms :as transforms]))
(def logs-queue (atom #queue []))
@@ -52,9 +50,3 @@
:logs/set-level
(fn [level]
(setup level)))
(rf/defn set-log-level
[{:keys [db]} log-level]
(let [log-level (or log-level config/log-level)]
{:db (assoc-in db [:profile/profile :log-level] log-level)
:logs/set-level log-level}))
+24 -57
View File
@@ -1,36 +1,31 @@
(ns ^:workletize status-im.common.scalable-avatar.view
(ns status-im.common.scalable-avatar.view
(:require [quo.core :as quo]
[react-native.reanimated :as reanimated]
;;[status-im.common.scalable-avatar.style :as style]
[status-im.contexts.profile.settings.header.style :as style]))
[status-im.common.scalable-avatar.style :as style]))
(def scroll-animation-input-range [0 50])
(def header-extrapolation-option
{:extrapolateLeft "clamp"
:extrapolateRight "clamp"})
(defn f-avatar
[{:keys [scroll-y full-name online? profile-picture customization-color]}]
(let [avatar-total-size 88
border-height 4
translation-to-bottom (fn [scale inverse-scale]
(js* "'worklet'")
(let [current-avatar-size (* avatar-total-size (- 1 scale))
current-center (/ current-avatar-size 2)]
(* current-center inverse-scale)))
transform (reanimated/use-animated-style
(fn []
(js* "'worklet'")
(let [scale (reanimated/interpolate*
(.-value scroll-y)
#js [0 48]
#js [1 0.4]
"clamp")
inverse-scale (/ 1 scale)
translation (translation-to-bottom scale inverse-scale)
bottom (* border-height inverse-scale (- 1 scale))]
#js
{:transform #js
[#js {:scale scale}
#js {:translateX (- translation)}
#js {:translateY (- translation bottom)}]})))
theme (quo.theme/get-theme)]
[reanimated/view {:style [transform (style/avatar-container theme)]}
[{:keys [scroll-y full-name online? profile-picture customization-color border-color]}]
(let [image-scale-animation (reanimated/interpolate scroll-y
scroll-animation-input-range
[1 0.4]
header-extrapolation-option)
image-top-margin-animation (reanimated/interpolate scroll-y
scroll-animation-input-range
[0 20]
header-extrapolation-option)
image-side-margin-animation (reanimated/interpolate scroll-y
scroll-animation-input-range
[-4 -20]
header-extrapolation-option)]
[reanimated/view
{:style (style/wrapper {:scale image-scale-animation
:margin-top image-top-margin-animation
:margin image-side-margin-animation
:border-color border-color})}
[quo/user-avatar
{:full-name full-name
:online? online?
@@ -40,34 +35,6 @@
:customization-color customization-color
:size :big}]]))
#_(defn f-avatar
[{:keys [scroll-y full-name online? profile-picture customization-color border-color]}]
(let [image-scale-animation (reanimated/interpolate scroll-y
scroll-animation-input-range
[1 0.4]
header-extrapolation-option)
image-top-margin-animation (reanimated/interpolate scroll-y
scroll-animation-input-range
[0 20]
header-extrapolation-option)
image-side-margin-animation (reanimated/interpolate scroll-y
scroll-animation-input-range
[-4 -20]
header-extrapolation-option)]
[reanimated/view
{:style (style/wrapper {:scale image-scale-animation
:margin-top image-top-margin-animation
:margin image-side-margin-animation
:border-color border-color})}
[quo/user-avatar
{:full-name full-name
:online? online?
:profile-picture profile-picture
:status-indicator? true
:ring? true
:customization-color customization-color
:size :big}]]))
(defn view
[props]
[:f> f-avatar props])
+3 -2
View File
@@ -7,7 +7,6 @@
[status-im.contexts.chat.messenger.messages.link-preview.events :as link-preview]
[status-im.contexts.chat.messenger.messages.transport.events :as messages.transport]
[status-im.contexts.communities.discover.events]
[status-im.contexts.profile.login.events :as profile.login]
[status-im.contexts.profile.push-notifications.local.events :as local-notifications]
[taoensso.timbre :as log]
[utils.re-frame :as rf]
@@ -37,7 +36,9 @@
^js event-js (.-event data)
type (.-type data)]
(case type
"node.login" (profile.login/login-node-signal cofx (transforms/js->clj event-js))
"node.login" {:fx [[:dispatch
[:profile.login/login-node-signal
(transforms/js->clj event-js)]]]}
"backup.performed" {:db (assoc-in db
[:profile/profile :last-backup]
(.-lastBackup event-js))}
+7
View File
@@ -19,6 +19,7 @@
(def ^:const content-type-system-message-mutual-event-sent 15)
(def ^:const content-type-system-message-mutual-event-accepted 16)
(def ^:const content-type-system-message-mutual-event-removed 17)
(def ^:const content-type-bridge-message 18)
;; Not implemented in status-go, only used for testing/ui work
(def ^:const content-type-gif 100)
@@ -428,6 +429,12 @@
(def ^:const mainnet-chain-ids
#{ethereum-mainnet-chain-id arbitrum-mainnet-chain-id optimism-mainnet-chain-id})
(def ^:const goerli-chain-ids
#{ethereum-goerli-chain-id arbitrum-goerli-chain-id optimism-goerli-chain-id})
(def ^:const sepolia-chain-ids
#{ethereum-sepolia-chain-id arbitrum-sepolia-chain-id optimism-sepolia-chain-id})
(def ^:const mainnet-short-name "eth")
(def ^:const optimism-short-name "opt")
(def ^:const arbitrum-short-name "arb1")
@@ -1,6 +1,8 @@
(ns status-im.contexts.chat.contacts.events
(:require
[oops.core :as oops]
[re-frame.core :as re-frame]
[status-im.common.json-rpc.events :as json-rpc]
[status-im.constants :as constants]
[taoensso.timbre :as log]
[utils.i18n :as i18n]
@@ -64,18 +66,21 @@
(when (> (count events) 1)
{:dispatch-n events}))))
(rf/defn initialize-contacts
[_]
{:json-rpc/call [{:method "wakuext_contacts"
:params []
:js-response true
:on-success #(rf/dispatch [:contacts/contacts-loaded (map <-rpc-js %)])
:on-error #(log/error "failed to fetch contacts" %)}]})
(re-frame/reg-event-fx :contacts/contacts-loaded
(fn [{:keys [db]} [loaded-contacts]]
(let [contacts (->> loaded-contacts
(map <-rpc-js)
(mapv (fn [{:keys [public-key] :as contact}] [public-key contact]))
(into {}))]
{:db (assoc db :contacts/contacts contacts)})))
(rf/defn contacts-loaded
{:events [:contacts/contacts-loaded]}
[{:keys [db]} contacts]
{:db (assoc db :contacts/contacts (into {} (map #(vector (:public-key %) %) contacts)))})
(re-frame/reg-fx :contacts/initialize-contacts
(fn []
(json-rpc/call {:method "wakuext_contacts"
:params []
:js-response true
:on-success [:contacts/contacts-loaded]
:on-error #(log/error "failed to fetch contacts" %)})))
(defn send-contact-request
[{:keys [db]} [id message]]
@@ -62,6 +62,7 @@
:sticky-section-headers-enabled false
:sections (rf/sub [:contacts/grouped-by-first-letter])
:render-section-header-fn contact-list/contacts-section-header
:render-section-footer-fn contact-list/contacts-section-footer
:content-container-style {:padding-bottom 20}
:render-data {:group group}
:render-fn add-member-contact-item-render}]
@@ -186,9 +186,3 @@
{:db (dissoc db :contacts/new-identity)})
(re-frame/reg-event-fx :contacts/clear-new-identity clear-new-identity)
(defn set-new-identity-reconnected
[{:keys [db]}]
(let [input (get-in db [:contacts/new-identity :input])]
(re-frame/dispatch [:contacts/set-new-identity {:input input}])))
@@ -1,5 +1,6 @@
(ns status-im.contexts.chat.home.new-chat.styles
(:require
[quo.foundations.colors :as colors]
[react-native.safe-area :as safe-area]))
(def contact-selection-heading
@@ -9,11 +10,16 @@
:margin-top 24
:margin-bottom 16})
(def chat-button
{:position :absolute
:bottom (+ 12 (safe-area/get-bottom))
:left 20
:right 20})
(defn chat-button-container
[theme]
{:position :absolute
:bottom 0
:padding-bottom 33
:background-color (colors/theme-colors colors/white-opa-70 colors/neutral-95-opa-70 theme)
:padding-top 12
:padding-horizontal 20
:left 0
:right 0})
(defn no-contacts
[]
@@ -2,7 +2,7 @@
(:require
[quo.core :as quo]
[quo.foundations.colors :as colors]
[quo.theme :as quo.theme]
[quo.theme]
[re-frame.core :as re-frame]
[react-native.core :as rn]
[react-native.gesture :as gesture]
@@ -49,27 +49,54 @@
(rf/dispatch [:open-modal :new-contact]))}
(i18n/label :t/add-a-contact)]]))
(defn contact-item-render
[_]
(fn [{:keys [public-key] :as item}]
(let [user-selected? (rf/sub [:is-contact-selected? public-key])
on-toggle #(if user-selected?
(re-frame/dispatch [:deselect-contact public-key])
(re-frame/dispatch [:select-contact public-key]))]
[contact-list-item/contact-list-item
{:on-press on-toggle
:allow-multiple-presses? true
:accessory {:type :checkbox
:checked? user-selected?
:on-check on-toggle}}
item])))
(def ^:private contacts-selection-limit (dec constants/max-group-chat-participants))
(defn- view-internal
[{:keys [scroll-enabled? on-scroll close theme]}]
(let [contacts (rf/sub [:contacts/sorted-and-grouped-by-first-letter])
(defn- toggle-selection
[public-key user-selected?]
(let [selected-contacts-count (rf/sub [:selected-contacts-count])]
(if user-selected?
(re-frame/dispatch [:deselect-contact public-key])
(if (= contacts-selection-limit
selected-contacts-count)
(do
(rf/dispatch
[:toasts/upsert
{:id :remove-nickname
:type :negative
:text (i18n/label :t/new-group-limit
{:max-contacts
contacts-selection-limit})}])
true)
(re-frame/dispatch [:select-contact public-key])))))
(defn contact-item-render
[{:keys [public-key] :as item} set-has-error]
(let [user-selected? (rf/sub [:is-contact-selected? public-key])
on-toggle (fn []
(-> public-key
(toggle-selection user-selected?)
boolean
set-has-error))]
[contact-list-item/contact-list-item
{:on-press on-toggle
:allow-multiple-presses? true
:accessory {:type :checkbox
:checked? user-selected?
:on-check on-toggle}}
item]))
(defn view
[{:keys [scroll-enabled? on-scroll close]}]
(let [theme (quo.theme/use-theme-value)
contacts (rf/sub [:contacts/sorted-and-grouped-by-first-letter])
selected-contacts-count (rf/sub [:selected-contacts-count])
selected-contacts (rf/sub [:group/selected-contacts])
customization-color (rf/sub [:profile/customization-color])
one-contact-selected? (= selected-contacts-count 1)
[has-error? set-has-error] (rn/use-state false)
render-fn (rn/use-callback (fn [item]
(contact-item-render item set-has-error))
[set-has-error])
contacts-selected? (pos? selected-contacts-count)
{:keys [primary-name public-key]} (when one-contact-selected?
(rf/sub [:contacts/contact-by-identity
@@ -86,38 +113,42 @@
{:weight :semi-bold
:size :heading-1
:style {:color (colors/theme-colors colors/neutral-100 colors/white theme)}}
(i18n/label :t/new-chat)]
(if (or (not contacts-selected?) one-contact-selected?)
(i18n/label :t/new-chat)
(i18n/label :t/new-group-chat))]
(when (seq contacts)
[quo/text
{:size :paragraph-2
:weight :regular
:style {:margin-bottom 2
:color (colors/theme-colors colors/neutral-40 colors/neutral-50 theme)}}
:color (if has-error?
(colors/theme-colors colors/danger-50 colors/danger-60 theme)
(colors/theme-colors colors/neutral-40 colors/neutral-50 theme))}}
(i18n/label :t/selected-count-from-max
{:selected selected-contacts-count
:max constants/max-group-chat-participants})])]]
:max contacts-selection-limit})])]]
(if (empty? contacts)
[no-contacts-view {:theme theme}]
[gesture/section-list
{:key-fn :title
:sticky-section-headers-enabled false
:sections (rf/sub [:contacts/filtered-active-sections])
:render-section-header-fn contact-list/contacts-section-header
:content-container-style {:padding-bottom 70}
:render-fn contact-item-render
:scroll-enabled @scroll-enabled?
:on-scroll on-scroll}])
{:key-fn :title
:sections (rf/sub [:contacts/filtered-active-sections])
:render-section-header-fn contact-list/contacts-section-header
:render-section-footer-fn contact-list/contacts-section-footer
:content-container-style {:padding-bottom 70}
:render-fn render-fn
:scroll-enabled @scroll-enabled?
:on-scroll on-scroll}])
(when contacts-selected?
[quo/button
{:type :primary
:accessibility-label :next-button
:container-style style/chat-button
:on-press (fn []
(if one-contact-selected?
(rf/dispatch [:chat.ui/start-chat public-key])
(rf/dispatch [:navigate-to :new-group])))}
(if one-contact-selected?
(i18n/label :t/chat-with {:selected-user primary-name})
(i18n/label :t/setup-group-chat))])]))
(def view (quo.theme/with-theme view-internal))
[rn/view
{:style (style/chat-button-container theme)}
[quo/button
{:type :primary
:customization-color customization-color
:accessibility-label :next-button
:on-press (fn []
(if one-contact-selected?
(rf/dispatch [:chat.ui/start-chat public-key])
(rf/dispatch [:navigate-to :new-group])))}
(if one-contact-selected?
(i18n/label :t/chat-with {:selected-user primary-name})
(i18n/label :t/setup-group-chat))]])]))
+40 -45
View File
@@ -106,6 +106,7 @@
:sections items
:sticky-section-headers-enabled false
:render-section-header-fn contact-list/contacts-section-header
:render-section-footer-fn contact-list/contacts-section-footer
:render-fn (fn [data]
(contact-item-render data theme))
:scroll-event-throttle 8
@@ -126,48 +127,42 @@
:title (i18n/label :t/invite-friends-to-status)
:description (i18n/label :t/share-invite-link)}})
(defn- f-view-internal
[{:keys [theme]}]
(let [scroll-ref (atom nil)
set-scroll-ref #(reset! scroll-ref %)]
(fn []
(let [{:keys [universal-profile-url]} (rf/sub [:profile/profile])
customization-color (rf/sub [:profile/customization-color])
pending-contact-requests (rf/sub [:activity-center/pending-contact-requests])
selected-tab (or (rf/sub [:messages-home/selected-tab]) :tab/recent)
scroll-shared-value (reanimated/use-shared-value 0)]
[:<>
(if (= selected-tab :tab/contacts)
[contacts
{:pending-contact-requests pending-contact-requests
:set-scroll-ref set-scroll-ref
:scroll-shared-value scroll-shared-value
:theme theme}]
[chats
{:selected-tab selected-tab
:set-scroll-ref set-scroll-ref
:scroll-shared-value scroll-shared-value
:theme theme}])
[:f> common.banner/animated-banner
{:content (banner-data universal-profile-url)
:customization-color customization-color
:scroll-ref scroll-ref
:tabs [{:id :tab/recent
:label (i18n/label :t/recent)
:accessibility-label :tab-recent}
{:id :tab/groups
:label (i18n/label :t/groups)
:accessibility-label :tab-groups}
{:id :tab/contacts
:label (i18n/label :t/contacts)
:accessibility-label :tab-contacts
:notification-dot? (pos? (count pending-contact-requests))}]
:selected-tab selected-tab
:on-tab-change (fn [tab] (rf/dispatch [:messages-home/select-tab tab]))
:scroll-shared-value scroll-shared-value}]]))))
(defn- internal-chats-home-view
[params]
[:f> f-view-internal params])
(def view (quo.theme/with-theme internal-chats-home-view))
(defn view
[]
(let [theme (quo.theme/use-theme-value)
scroll-ref (rn/use-ref-atom nil)
set-scroll-ref (rn/use-callback #(reset! scroll-ref %))
{:keys [universal-profile-url]} (rf/sub [:profile/profile])
customization-color (rf/sub [:profile/customization-color])
pending-contact-requests (rf/sub [:activity-center/pending-contact-requests])
selected-tab (or (rf/sub [:messages-home/selected-tab]) :tab/recent)
scroll-shared-value (reanimated/use-shared-value 0)]
[:<>
(if (= selected-tab :tab/contacts)
[contacts
{:pending-contact-requests pending-contact-requests
:set-scroll-ref set-scroll-ref
:scroll-shared-value scroll-shared-value
:theme theme}]
[chats
{:selected-tab selected-tab
:set-scroll-ref set-scroll-ref
:scroll-shared-value scroll-shared-value
:theme theme}])
[common.banner/animated-banner
{:content (banner-data universal-profile-url)
:customization-color customization-color
:scroll-ref scroll-ref
:tabs [{:id :tab/recent
:label (i18n/label :t/recent)
:accessibility-label :tab-recent}
{:id :tab/groups
:label (i18n/label :t/groups)
:accessibility-label :tab-groups}
{:id :tab/contacts
:label (i18n/label :t/contacts)
:accessibility-label :tab-contacts
:notification-dot? (pos? (count pending-contact-requests))}]
:selected-tab selected-tab
:on-tab-change (fn [tab] (rf/dispatch [:messages-home/select-tab tab]))
:scroll-shared-value scroll-shared-value}]]))
@@ -1,6 +1,5 @@
(ns status-im.contexts.chat.messenger.menus.pinned-messages.style
(:require
[quo.foundations.colors :as colors]
[react-native.platform :as platform]))
(defn heading
@@ -8,29 +7,8 @@
{:padding-horizontal 20
:margin-bottom (when-not community? 12)})
(defn heading-container
[]
{:flex-direction :row
:background-color (colors/theme-colors colors/neutral-10 colors/neutral-80)
:border-radius 20
:align-items :center
:align-self :flex-start
:margin-horizontal 20
:padding 4
:margin-top 8
:margin-bottom 16})
(defn heading-text
[]
{:margin-left 6
:margin-right 4
:color (colors/theme-colors colors/neutral-60 colors/neutral-20)})
(defn chat-name-text
[]
{:margin-left 4
:margin-right 8
:color (colors/theme-colors colors/neutral-60 colors/neutral-20)})
(def community-tag-container
{:margin-horizontal 20 :margin-top 4 :margin-bottom 12})
(def no-pinned-messages-container
{:justify-content :center
@@ -38,22 +16,5 @@
:margin 12
:margin-bottom (when platform/android? 12)})
(def no-pinned-messages-icon
{:width 80
:height 80
:justify-content :center
:align-items :center
:border-width 1})
(def no-pinned-messages-content
{:margin-top 12})
(def no-pinned-messages-title
{:text-align :center})
(def no-pinned-messages-text
{:text-align :center
:margin-top 2})
(def list-footer
{:height (when platform/android? 12)})
@@ -1,10 +1,8 @@
(ns status-im.contexts.chat.messenger.menus.pinned-messages.view
(:require
[quo.core :as quo]
[quo.foundations.colors :as colors]
[quo.theme]
[react-native.core :as rn]
[react-native.fast-image :as fast-image]
[react-native.gesture :as gesture]
[status-im.common.resources :as resources]
[status-im.contexts.chat.messenger.menus.pinned-messages.style :as style]
@@ -52,20 +50,13 @@
:style (style/heading community)}
(i18n/label :t/pinned-messages)]
(when community
[rn/view {:style (style/heading-container)}
[fast-image/fast-image
{:source (community-avatar community-images)
:style {:width 20
:height 20
:border-radius 20}}]
[rn/text {:style (style/heading-text)} (:name community)]
[quo/icon
:i/chevron-right
{:color (colors/theme-colors colors/neutral-60 colors/neutral-30)
:size 12}]
[rn/text
{:style (style/chat-name-text)}
(str "# " (:chat-name current-chat))]])]
[quo/context-tag
{:type :channel
:size 24
:container-style style/community-tag-container
:community-logo (community-avatar community-images)
:community-name (:name community)
:channel-name (:chat-name current-chat)}])]
(if (pos? (count pinned))
[rn/flat-list
{:data pinned
@@ -1,10 +1,12 @@
(ns status-im.contexts.chat.messenger.messages.content.view
(:require
[clojure.string :as string]
[legacy.status-im.ui.screens.chat.message.legacy-view :as old-message]
[quo.core :as quo]
[quo.foundations.colors :as colors]
[quo.theme :as quo.theme]
[react-native.core :as rn]
[react-native.fast-image :as fast-image]
[react-native.gesture :as gesture]
[react-native.platform :as platform]
[reagent.core :as reagent]
@@ -113,6 +115,34 @@
constants/content-type-system-message-mutual-event-sent
[system-message-contact-request message-data :contact-request])))
(defn bridge-message-content
[{:keys [bridge-message timestamp]}]
(let [{:keys [user-avatar user-name
bridge-name content]} bridge-message
user-name (when (string? user-name)
(-> user-name
(string/replace "<b>" "")
(string/replace "</b>" "")))]
[rn/view
{:style {:flex-direction :row
:padding-horizontal 12
:padding-top 4}}
[fast-image/fast-image
{:source {:uri user-avatar}
:style {:width 32
:margin-top 4
:border-radius 16
:height 32}}]
[rn/view {:margin-left 8 :flex 1}
[quo/author
{:primary-name (str user-name)
:short-chat-key (str "Bridged from " bridge-name)
:time-str (datetime/timestamp->time timestamp)}]
[quo/text
{:size :paragraph-1
:style {:line-height 22.75}}
content]]]))
(declare on-long-press)
(defn- user-message-content-internal
@@ -284,6 +314,9 @@
keyboard-shown?))
context]
(= content-type constants/content-type-bridge-message)
[bridge-message-content message-data]
:else
[user-message-content
{:message-data message-data
@@ -1,79 +1,65 @@
(ns status-im.contexts.chat.messenger.messages.link-preview.events
(:require
[camel-snake-kebab.core :as csk]
[status-im.contexts.profile.settings.events :as profile.settings.events]
[taoensso.timbre :as log]
[utils.collection]
[utils.re-frame :as rf]))
(:require [camel-snake-kebab.core :as csk]
[status-im.common.json-rpc.events :as json-rpc]
[taoensso.timbre :as log]
[utils.collection]
[utils.re-frame :as rf]))
(defn community-link
[id]
(str "https://status.app/c#" id))
(rf/defn cache-link-preview-data
{:events [:chat.ui/cache-link-preview-data]}
[{{:profile/keys [profile]} :db :as cofx} site data]
(let [link-previews-cache (get profile :link-previews-cache {})]
(profile.settings.events/optimistic-profile-update
cofx
:link-previews-cache
(assoc link-previews-cache site (utils.collection/map-keys csk/->kebab-case-keyword data)))))
(rf/reg-event-fx :chat.ui/cache-link-preview-data
(fn [{:keys [db]} [site data]]
(let [{:profile/keys [profile]} db
link-previews-cache (-> profile
(get :link-previews-cache {})
(assoc site
(utils.collection/map-keys csk/->kebab-case-keyword
data)))]
{:db (assoc-in db [:profile/profile :link-previews-cache] link-previews-cache)})))
(rf/defn load-link-preview-data
{:events [:chat.ui/load-link-preview-data]}
[{{:profile/keys [profile] :as db} :db} link]
(let [{:keys [error] :as cache-data} (get-in profile [:link-previews-cache link])]
(if (or (not cache-data) error)
{:json-rpc/call [{:method "wakuext_getLinkPreviewData"
:params [link]
:on-success #(rf/dispatch [:chat.ui/cache-link-preview-data link %])
:on-error #(rf/dispatch [:chat.ui/cache-link-preview-data link
{:error (str "Can't get preview data for " link)}])}]}
{:db db})))
(rf/reg-event-fx :chat.ui/load-link-preview-data
(fn [{{:profile/keys [profile]} :db} [link]]
(let [{:keys [error] :as cache-data} (get-in profile [:link-previews-cache link])]
(when (or (not cache-data) error)
{:fx [[:json-rpc/call
[{:method "wakuext_getLinkPreviewData"
:params [link]
:on-success [:chat.ui/cache-link-preview-data link]
:on-error [:chat.ui/cache-link-preview-data link
{:error (str "Can't get preview data for " link)}]}]]]}))))
(rf/defn should-suggest-link-preview
{:events [:chat.ui/should-suggest-link-preview]}
[{:keys [db] :as cofx} enabled?]
(profile.settings.events/profile-update
cofx
:link-preview-request-enabled
(boolean enabled?)
{}))
(rf/reg-event-fx :chat.ui/should-suggest-link-preview
(fn [_ [enabled?]]
{:fx [[:dispatch
[:profile.settings/profile-update :link-preview-request-enabled (boolean enabled?)]]]}))
(rf/defn save-link-preview-whitelist
{:events [:chat.ui/link-preview-whitelist-received]}
[{:keys [db]} whitelist]
{:db (assoc db :link-previews-whitelist whitelist)})
(rf/reg-event-fx :chat.ui/link-preview-whitelist-received
(fn [{:keys [db]} [whitelist]]
{:db (assoc db :link-previews-whitelist whitelist)}))
(rf/defn request-link-preview-whitelist
[_]
{:json-rpc/call [{:method "wakuext_getLinkPreviewWhitelist"
:params []
:on-success #(rf/dispatch [:chat.ui/link-preview-whitelist-received %])
:on-error #(log/error "Failed to get link preview whitelist")}]})
(rf/reg-fx :chat.ui/request-link-preview-whitelist
(fn []
(json-rpc/call {:method "wakuext_getLinkPreviewWhitelist"
:params []
:on-success [:chat.ui/link-preview-whitelist-received]
:on-error #(log/error "Failed to get link preview whitelist")})))
(defn cache-community-preview-data
[{:keys [id] :as community}]
(rf/dispatch [:chat.ui/cache-link-preview-data (community-link id) community]))
(rf/defn enable
{:events [:chat.ui/enable-link-previews]}
[{{:profile/keys [profile]} :db :as cofx} site enabled?]
(profile.settings.events/profile-update
cofx
:link-previews-enabled-sites
(if enabled?
(conj (get profile :link-previews-enabled-sites #{}) site)
(disj (get profile :link-previews-enabled-sites #{}) site))
{}))
(rf/reg-event-fx :chat.ui/enable-link-previews
(fn [{{:profile/keys [profile]} :db} [site enabled?]]
(let [enabled-sites (if enabled?
(conj (get profile :link-previews-enabled-sites #{}) site)
(disj (get profile :link-previews-enabled-sites #{}) site))]
{:fx [[:dispatch [:profile.settings/profile-update :link-previews-enabled-sites enabled-sites]]]})))
(rf/defn enable-all
{:events [:chat.ui/enable-all-link-previews]}
[cofx link-previews-whitelist enabled?]
(profile.settings.events/profile-update
cofx
:link-previews-enabled-sites
(if enabled?
(into #{} (map :title link-previews-whitelist))
#{})
{}))
(rf/reg-event-fx :chat.ui/enable-all-link-previews
(fn [_ [link-previews-whitelist enabled?]]
(let [enabled-sites (if enabled?
(into #{} (map :title link-previews-whitelist))
#{})]
{:fx [[:dispatch [:profile.settings/profile-update :link-previews-enabled-sites enabled-sites]]]})))
@@ -47,8 +47,8 @@
(defn list-on-end-reached
[distance-from-list-top]
;; FIXME: that's a bit of a hack but we need to update `distance-from-list-top` once the new messages
;; are fetched in order for the header to work properly
;; FIXME: that's a bit of a hack but we need to update `distance-from-list-top` once the new
;; messages are fetched in order for the header to work properly
(let [on-loaded (fn [n]
(reanimated/set-shared-value distance-from-list-top
(+ (reanimated/get-shared-value distance-from-list-top)
@@ -147,7 +147,7 @@
:actions [{:accessibility-label :action-button-pinned
:big? true
:label (or latest-pin-text (i18n/label :t/no-pinned-messages))
:color cover-bg-color
:customization-color cover-bg-color
:icon :i/pin
:counter-value pins-count
:on-press (fn []
@@ -157,7 +157,7 @@
:label (i18n/label (if muted
unmute-chat-label
mute-chat-label))
:color cover-bg-color
:customization-color cover-bg-color
:icon (if muted? :i/activity-center :i/muted)
:on-press (fn []
(if muted?
@@ -32,6 +32,12 @@
:height top-bar-height
:align-items :center})
(defn button-animation-container
[opacity-value]
(reanimated/apply-animations-to-style
{:opacity opacity-value}
{}))
;;;; Content
(defn header-content-container
@@ -15,6 +15,7 @@
[status-im.contexts.chat.messenger.messages.pin.banner.view :as pin.banner]
[utils.i18n :as i18n]
[utils.re-frame :as rf]
[utils.worklets.chat.messenger.messages :as messages.worklets]
[utils.worklets.chat.messenger.navigation :as worklets]))
(defn f-header-content-container
@@ -103,15 +104,22 @@
:banner-opacity banner-opacity
:top-offset navigation-view-height}]]))
(defn f-view
(defn view
[{:keys [distance-from-list-top chat-screen-layout-calculations-complete?]}]
(let [{:keys [chat-id chat-type] :as chat} (rf/sub [:chats/current-chat-chat-view])
all-loaded? (reanimated/use-shared-value false)
all-loaded-sub (rf/sub [:chats/all-loaded? chat-id])
top-insets (safe-area/get-top)
top-bar-height messages.constants/top-bar-height
navigation-view-height (+ top-bar-height top-insets)]
(reanimated/set-shared-value all-loaded? all-loaded-sub)
navigation-view-height (+ top-bar-height top-insets)
navigation-buttons-opacity (worklets/navigation-buttons-complete-opacity
chat-screen-layout-calculations-complete?)
reached-threshold? (messages.worklets/use-messages-scrolled-to-threshold
distance-from-list-top
top-bar-height)
button-background (if reached-threshold? :photo :blur)]
(rn/use-effect (fn [] (reanimated/set-shared-value all-loaded? all-loaded-sub))
[all-loaded-sub])
[rn/view
{:style (style/navigation-view navigation-view-height messages.constants/pinned-banner-height)}
[:f> f-animated-background-and-pinned-banner
@@ -120,27 +128,29 @@
:distance-from-list-top distance-from-list-top
:all-loaded? all-loaded?}]
[rn/view {:style (style/header-container top-insets top-bar-height)}
[quo/button
{:icon-only? true
:type :grey
:background :blur
:size 32
:accessibility-label :back-button
:on-press #(rf/dispatch [:navigate-back])}
(if (= chat-type constants/community-chat-type) :i/arrow-left :i/close)]
[reanimated/view {:style (style/button-animation-container navigation-buttons-opacity)}
[quo/button
{:icon-only? true
:type :grey
:background button-background
:size 32
:accessibility-label :back-button
:on-press #(rf/dispatch [:navigate-back])}
(if (= chat-type constants/community-chat-type) :i/arrow-left :i/close)]]
[:f> f-header-content-container
{:chat chat
:distance-from-list-top distance-from-list-top
:all-loaded? all-loaded?
:chat-screen-layout-calculations-complete? chat-screen-layout-calculations-complete?}]
[quo/button
{:icon-only? true
:type :grey
:background :blur
:size 32
:accessibility-label :options-button
:on-press (fn []
(rf/dispatch [:dismiss-keyboard])
(rf/dispatch [:show-bottom-sheet
{:content (fn [] [actions/chat-actions chat true])}]))}
:i/options]]]))
[reanimated/view {:style (style/button-animation-container navigation-buttons-opacity)}
[quo/button
{:icon-only? true
:type :grey
:background button-background
:size 32
:accessibility-label :options-button
:on-press (fn []
(rf/dispatch [:dismiss-keyboard])
(rf/dispatch [:show-bottom-sheet
{:content (fn [] [actions/chat-actions chat true])}]))}
:i/options]]]]))
@@ -24,7 +24,7 @@
[rn/keyboard-avoiding-view
{:style style/keyboard-avoiding-container
:keyboard-vertical-offset (- (:bottom insets))}
[:f> messages.navigation/f-view
[messages.navigation/view
{:distance-from-list-top distance-from-list-top
:chat-screen-layout-calculations-complete? chat-screen-layout-calculations-complete?}]
[:f> list.view/f-messages-list-content
@@ -0,0 +1,102 @@
(ns status-im.contexts.communities.actions.accounts-selection.effects
(:require
[promesa.core :as p]
[schema.core :as schema]
[status-im.common.json-rpc.events :as rpc]
[utils.re-frame :as rf]))
(defn- generate-requests-for-signing
[pub-key community-id addresses-to-reveal]
(p/create
(fn [p-resolve p-reject]
(rpc/call
{:method :wakuext_generateJoiningCommunityRequestsForSigning
:params [pub-key community-id addresses-to-reveal]
:on-success p-resolve
:on-error #(p-reject (str "failed to generate requests for signing\n" %))}))))
(defn- sign-data
[sign-params password]
(p/create
(fn [p-resolve p-reject]
(rpc/call
{:method :wakuext_signData
:params [(map #(assoc % :password password) sign-params)]
:on-success p-resolve
:on-error #(p-reject (str "failed to sign data\n" %))}))))
(defn- edit-shared-addresses-for-community
[community-id signatures addresses-to-reveal airdrop-address]
(p/create
(fn [p-resolve p-reject]
(rpc/call
{:method :wakuext_editSharedAddressesForCommunity
:params [{:communityId community-id
:signatures signatures
:addressesToReveal addresses-to-reveal
:airdropAddress airdrop-address}]
:js-response true
:on-success p-resolve
:on-error p-reject}))))
(defn- request-to-join
[community-id signatures addresses-to-reveal airdrop-address]
(p/create
(fn [p-resolve p-reject]
(rpc/call
{:method :wakuext_requestToJoinCommunity
:params [{:communityId community-id
:signatures signatures
:addressesToReveal addresses-to-reveal
:airdropAddress airdrop-address}]
:js-response true
:on-success p-resolve
:on-error p-reject}))))
(defn- run-callback-or-event
[callback-or-event result]
(cond (fn? callback-or-event)
(callback-or-event result)
(vector? callback-or-event)
(rf/dispatch (conj callback-or-event result))))
(defn- sign-and-call-endpoint
[{:keys [community-id password pub-key
addresses-to-reveal airdrop-address
on-success on-error
callback]}]
(-> (p/let [sign-params (generate-requests-for-signing pub-key community-id addresses-to-reveal)
signatures (sign-data sign-params password)
result (callback community-id
signatures
addresses-to-reveal
airdrop-address)]
(run-callback-or-event on-success result))
(p/catch #(run-callback-or-event on-error %))))
(schema/=> sign-and-call-endpoint
[:=>
[:cat
[:map {:closed true}
[:community-id string?]
[:password string?]
[:pub-key string?]
[:addresses-to-reveal
[:or [:set string?]
[:sequential string?]]]
[:airdrop-address string?]
[:on-success [:or fn? :schema.re-frame/event]]
[:on-error [:or fn? :schema.re-frame/event]]
[:callback fn?]]]
:any])
(rf/reg-fx :effects.community/edit-shared-addresses
(fn [opts]
(sign-and-call-endpoint
(assoc opts :callback edit-shared-addresses-for-community))))
(rf/reg-fx :effects.community/request-to-join
(fn [opts]
(sign-and-call-endpoint
(assoc opts :callback request-to-join))))
@@ -0,0 +1,103 @@
(ns status-im.contexts.communities.actions.accounts-selection.events
(:require
status-im.contexts.communities.actions.accounts-selection.effects
[status-im.contexts.communities.utils :as utils]
[taoensso.timbre :as log]
[utils.re-frame :as rf]))
(defn initialize-permission-addresses
[{:keys [db]} [community-id]]
(let [{:keys [joined]} (get-in db [:communities community-id])
pending-requests (get-in db [:communities/my-pending-requests-to-join community-id])
init-using-revealed-accounts? (or joined (seq pending-requests))]
{:fx [(if init-using-revealed-accounts?
[:dispatch
[:communities/get-revealed-accounts community-id
[:communities/do-init-permission-addresses community-id]]]
[:dispatch [:communities/do-init-permission-addresses community-id]])]}))
(rf/reg-event-fx :communities/initialize-permission-addresses initialize-permission-addresses)
(defn do-init-permission-addresses
[{:keys [db]} [community-id revealed-accounts]]
(let [wallet-accounts (utils/sorted-non-watch-only-accounts db)
addresses-to-reveal (if (seq revealed-accounts)
(set (keys revealed-accounts))
;; Reveal all addresses as fallback.
(set (map :address wallet-accounts)))
;; When there are no revealed addresses, such as when joining a
;; community, use first address for airdrops.
airdrop-address (or (->> revealed-accounts
vals
(filter :airdrop-address?)
first
:address)
(->> wallet-accounts
first
:address))]
{:db (-> db
;; Set to false by default while we don't persist the user's choice
;; in status-go, otherwise whenever the view is mounted, the choice
;; of selected addresses won't be respected.
(assoc-in [:communities/selected-share-all-addresses community-id] false)
(assoc-in [:communities/all-addresses-to-reveal community-id] addresses-to-reveal)
(assoc-in [:communities/all-airdrop-addresses community-id] airdrop-address))
:fx [[:dispatch
[:communities/check-permissions-to-join-community
community-id addresses-to-reveal :based-on-client-selection]]
;; Pre-fetch permissions check so that when first opening the
;; Addresses for Permissions screen the highest permission role is
;; already available and no incorrect information flashes on screen.
[:dispatch
[:communities/check-permissions-to-join-during-selection community-id
addresses-to-reveal]]]}))
(rf/reg-event-fx :communities/do-init-permission-addresses do-init-permission-addresses)
(defn edit-shared-addresses
"This event will effectively persist the choice of addresses and airdrop address
in status-go. It can either take addresses to share AND an airdrop address, or
just addresses to share OR an airdrop address. This is because when the user
is selecting an airdrop address, we must submit to status-go the current
choice of addresses to share, and vice-versa. If we omit addresses to share,
status-go will default to all available."
[{:keys [db]} [{:keys [community-id password on-success addresses airdrop-address]}]]
(let [pub-key (get-in db [:profile/profile :public-key])
wallet-accounts (utils/sorted-non-watch-only-accounts db)
addresses-to-reveal (if (seq addresses)
(set addresses)
(get-in db [:communities/all-addresses-to-reveal community-id]))
new-airdrop-address (if (contains? addresses-to-reveal airdrop-address)
airdrop-address
(->> wallet-accounts
(filter #(contains? addresses-to-reveal (:address %)))
first
:address))]
{:fx [[:effects.community/edit-shared-addresses
{:community-id community-id
:password password
:pub-key pub-key
:addresses-to-reveal addresses-to-reveal
:airdrop-address new-airdrop-address
:on-success (fn []
(when (fn? on-success)
(on-success addresses-to-reveal new-airdrop-address))
(rf/dispatch [:communities/edit-shared-addresses-success
community-id addresses-to-reveal airdrop-address]))
:on-error [:communities/edit-shared-addresses-failure community-id]}]]}))
(rf/reg-event-fx :communities/edit-shared-addresses edit-shared-addresses)
(rf/reg-event-fx :communities/edit-shared-addresses-success
(fn [_ [community-id addresses-to-reveal airdrop-address]]
{:fx [[:dispatch [:communities/set-airdrop-address community-id airdrop-address]]
[:dispatch [:communities/set-addresses-to-reveal community-id addresses-to-reveal]]]}))
(rf/reg-event-fx :communities/edit-shared-addresses-failure
(fn [{:keys [db]} [community-id error]]
(log/error "failed to edit shared addresses"
{:event :communities/edit-shared-addresses
:community-id community-id
:error error})
{:db (assoc-in db [:password-authentication :error] error)}))
@@ -0,0 +1,169 @@
(ns status-im.contexts.communities.actions.accounts-selection.events-test
(:require [cljs.test :refer [deftest is testing]]
matcher-combinators.test
[status-im.contexts.communities.actions.accounts-selection.events :as sut]))
(def community-id "0x99")
(def password "password")
(def wallet-accounts
{"0xA" {:address "0xA"
:watch-only? true
:position 2
:color :red
:emoji "🦇"}
"0xB" {:address "0xB"
:position 0
:color :blue
:emoji "🐈"}
"0xC" {:address "0xC"
:position 1
:color :orange
:emoji "🛏️"}})
(def permissioned-accounts
[{:address "0xB"
:position 0
:color :blue
:emoji "🐈"
:airdrop-address? true
:reveal? true}
{:address "0xC"
:position 1
:color :orange
:emoji "🛏️"
:airdrop-address? false
:reveal? false}])
(deftest initialize-permission-addresses-test
(testing "fetches revealed accounts when pending and not joined"
(let [cofx {:db {:communities {community-id {:joined false}}
:communities/my-pending-requests-to-join {community-id [:anything]}}}]
(is (match?
{:fx [[:dispatch
[:communities/get-revealed-accounts community-id
[:communities/do-init-permission-addresses community-id]]]]}
(sut/initialize-permission-addresses cofx [community-id])))))
(testing "fetches revealed accounts when not pending and joined"
(let [cofx {:db {:communities {community-id {:joined true}}
:communities/my-pending-requests-to-join {}}}]
(is (match?
{:fx [[:dispatch
[:communities/get-revealed-accounts community-id
[:communities/do-init-permission-addresses community-id]]]]}
(sut/initialize-permission-addresses cofx [community-id])))))
(testing "does not fetch revealed accounts when not pending and not joined"
(let [cofx {:db {:communities {community-id {:joined false}}
:communities/my-pending-requests-to-join {}}}]
(is (match?
{:fx [[:dispatch [:communities/do-init-permission-addresses community-id]]]}
(sut/initialize-permission-addresses cofx [community-id]))))))
(deftest do-init-permission-addresses-test
(testing "uses already revealed accounts to initialize shareable accounts"
(let [cofx {:db {:wallet {:accounts wallet-accounts}}}
revealed-accounts {"0xC" {:address "0xC"
:airdrop-address? true
:position 1}}
airdrop-address "0xC"
addresses-to-reveal #{"0xC"}]
(is
(match?
{:db (-> (:db cofx)
(assoc-in [:communities/selected-share-all-addresses community-id] false)
(assoc-in [:communities/all-addresses-to-reveal community-id] addresses-to-reveal)
(assoc-in [:communities/all-airdrop-addresses community-id] airdrop-address))
:fx [[:dispatch
[:communities/check-permissions-to-join-community
community-id addresses-to-reveal :based-on-client-selection]]
;; Pre-fetch permissions check so that when first opening the
;; Addresses for Permissions screen the highest permission role is
;; already available and no incorrect information flashes on screen.
[:dispatch
[:communities/check-permissions-to-join-during-selection community-id
addresses-to-reveal]]]}
(sut/do-init-permission-addresses cofx [community-id revealed-accounts])))))
;; Expect to mark all addresses to be revealed and first one to receive
;; airdrops when no addresses were previously revealed.
(testing "handles case where there are no previously revealed addresses"
(let [cofx {:db {:wallet {:accounts wallet-accounts}}}
addresses-to-reveal #{"0xB" "0xC"}
revealed-accounts []]
(is
(match?
{:db (-> (:db cofx)
(assoc-in [:communities/selected-share-all-addresses community-id] false)
(assoc-in [:communities/all-addresses-to-reveal community-id] addresses-to-reveal))
:fx [[:dispatch
[:communities/check-permissions-to-join-community
community-id addresses-to-reveal :based-on-client-selection]]
[:dispatch
[:communities/check-permissions-to-join-during-selection community-id
addresses-to-reveal]]]}
(sut/do-init-permission-addresses cofx [community-id revealed-accounts]))))))
(deftest edit-shared-addresses-test
(testing
"when airdrop address is passed, but addresses to reveal is not, then
fallback to all wallet addresses"
(let [pub-key "abcdef"
revealed-addresses #{"0xB" "0xC"}
cofx {:db {:profile/profile {:public-key pub-key}
:communities/all-addresses-to-reveal {community-id revealed-addresses}}}
airdrop-address "0xB"
actual
(sut/edit-shared-addresses
cofx
[{:community-id community-id
:password password
:airdrop-address airdrop-address
:on-success (fn [new-addresses-to-reveal]
(is (match? revealed-addresses new-addresses-to-reveal)))}])
on-success-wrapper (-> actual :fx first second :on-success)]
(is (match?
{:fx [[:effects.community/edit-shared-addresses
{:community-id community-id
:password password
:pub-key pub-key
:addresses-to-reveal revealed-addresses
:airdrop-address airdrop-address
:on-success fn?
:on-error [:communities/edit-shared-addresses-failure community-id]}]]}
actual))
(on-success-wrapper)))
(testing "when addresses to reveal are passed, but airdrop address is not"
(let [pub-key "abcdef"
cofx {:db {:profile/profile {:public-key pub-key}
:wallet {:accounts wallet-accounts}
:communities/all-addresses-to-reveal {community-id #{"0xB" "0xC"}}}}
actual (sut/edit-shared-addresses
cofx
[{:community-id community-id
:password password
:addresses ["0xC"]
:on-success (fn [new-addresses-to-reveal new-airdrop-address]
(is (= #{"0xC"} new-addresses-to-reveal))
(is (= "0xC" new-airdrop-address)))}])
on-success-wrapper
(-> actual :fx first second :on-success)]
(is (match?
{:fx [[:effects.community/edit-shared-addresses
{:community-id community-id
:password password
:pub-key pub-key
:addresses-to-reveal #{"0xC"}
:airdrop-address "0xC"
:on-success fn?
:on-error [:communities/edit-shared-addresses-failure community-id]}]]}
actual))
(on-success-wrapper))))
@@ -14,83 +14,110 @@
(defn view
[]
(let [{id :community-id} (rf/sub [:get-screen-params])
show-addresses-for-permissions (fn []
(rf/dispatch [:show-bottom-sheet
{:community-id id
:content addresses-for-permissions/view}]))
show-airdrop-addresses (fn []
(rf/dispatch [:show-bottom-sheet
{:community-id id
:content airdrop-addresses/view}]))
navigate-back #(rf/dispatch [:navigate-back])
join-and-go-back (fn []
(rf/dispatch [:password-authentication/show
{:content (fn [] [password-authentication/view])}
{:label (i18n/label :t/join-open-community)
:on-press
#(rf/dispatch
[:communities/request-to-join-with-addresses
{:community-id id :password %}])}])
(navigate-back))]
(fn []
(let [{:keys [name color images]} (rf/sub [:communities/community id])
airdrop-account (rf/sub [:communities/airdrop-account id])
selected-accounts (rf/sub [:communities/selected-permission-accounts id])
{:keys [highest-permission-role]} (rf/sub [:community/token-gated-overview id])
highest-role-text (i18n/label (communities.utils/role->translation-key
highest-permission-role
:t/member))]
[rn/safe-area-view {:style style/container}
[quo/page-nav
{:text-align :left
:icon-name :i/close
:on-press navigate-back
:accessibility-label :back-button}]
[quo/page-top
{:title (i18n/label :t/request-to-join)
:description :context-tag
:context-tag {:type :community
:size 24
:community-logo (get-in images [:thumbnail :uri])
:community-name name}}]
[gesture/scroll-view
[:<>
[quo/text
{:style style/section-title
:accessibility-label :community-rules-title
:weight :semi-bold
:size :paragraph-1}
(i18n/label :t/address-to-share)]
[quo/category
{:list-type :settings
:data [{:title (i18n/label :t/join-as-a {:role highest-role-text})
:on-press show-addresses-for-permissions
:description :text
:action :arrow
:label :preview
:label-props {:type :accounts
:data selected-accounts}
:description-props {:text (i18n/label :t/all-addresses)}}
{:title (i18n/label :t/for-airdrops)
:on-press show-airdrop-addresses
:description :text
:action :arrow
:label :preview
:label-props {:type :accounts
:data [airdrop-account]}
:description-props {:text (:name airdrop-account)}}]}]
[quo/text
{:style style/section-title
:accessibility-label :community-rules-title
:weight :semi-bold
:size :paragraph-1}
(i18n/label :t/community-rules)]
[community-rules/view id]]]
[rn/view {:style (style/bottom-actions)}
[quo/slide-button
{:size :size-48
:track-text (i18n/label :t/slide-to-request-to-join)
:track-icon :i/face-id
:customization-color color
:on-complete join-and-go-back}]]]))))
(let [{id :community-id} (rf/sub [:get-screen-params])
{:keys [name color images joined]} (rf/sub [:communities/community id])
airdrop-account (rf/sub [:communities/airdrop-account id])
revealed-accounts (rf/sub [:communities/accounts-to-reveal id])
{:keys [highest-permission-role]} (rf/sub [:community/token-gated-overview id])
highest-role-text (i18n/label (communities.utils/role->translation-key
highest-permission-role
:t/member))
can-edit-addresses? (rf/sub [:communities/can-edit-shared-addresses? id])
navigate-back (rn/use-callback #(rf/dispatch [:navigate-back]))
show-addresses-for-permissions
(rn/use-callback
(fn []
(if can-edit-addresses?
(rf/dispatch [:open-modal :addresses-for-permissions {:community-id id}])
(rf/dispatch [:show-bottom-sheet
{:community-id id
:content (fn [] [addresses-for-permissions/view])}])))
[can-edit-addresses?])
show-airdrop-addresses
(rn/use-callback
(fn []
(if can-edit-addresses?
(rf/dispatch [:open-modal :address-for-airdrop {:community-id id}])
(rf/dispatch [:show-bottom-sheet
{:community-id id
:content (fn [] [airdrop-addresses/view])}])))
[can-edit-addresses?])
confirm-choices
(rn/use-callback
(fn []
(rf/dispatch
[:password-authentication/show
{:content (fn [] [password-authentication/view])}
{:label (i18n/label :t/join-open-community)
:on-press (fn [password]
(rf/dispatch [:communities/request-to-join-with-addresses
{:community-id id :password password}]))}])
(navigate-back)))]
(rn/use-mount
(fn []
(rf/dispatch [:communities/initialize-permission-addresses id])))
[rn/safe-area-view {:style style/container}
[quo/page-nav
{:text-align :left
:icon-name :i/close
:on-press navigate-back
:accessibility-label :back-button}]
[quo/page-top
{:title (if can-edit-addresses?
(i18n/label :t/edit-shared-addresses)
(i18n/label :t/request-to-join))
:description :context-tag
:context-tag {:type :community
:size 24
:community-logo (get-in images [:thumbnail :uri])
:community-name name}}]
[gesture/scroll-view
[:<>
(when-not can-edit-addresses?
[quo/text
{:style style/section-title
:accessibility-label :community-rules-title
:weight :semi-bold
:size :paragraph-1}
(i18n/label :t/address-to-share)])
[quo/category
{:list-type :settings
:data [{:title (if joined
(i18n/label :t/you-are-a-role {:role highest-role-text})
(i18n/label :t/join-as-a {:role highest-role-text}))
:on-press show-addresses-for-permissions
:description :text
:action :arrow
:label :preview
:label-props {:type :accounts
:data revealed-accounts}
:description-props {:text (i18n/label :t/all-addresses)}}
{:title (i18n/label :t/for-airdrops)
:on-press show-airdrop-addresses
:description :text
:action :arrow
:label :preview
:label-props {:type :accounts
:data [airdrop-account]}
:description-props {:text (:name airdrop-account)}}]}]
(when-not can-edit-addresses?
[quo/text
{:style style/section-title
:accessibility-label :community-rules-title
:weight :semi-bold
:size :paragraph-1}
(i18n/label :t/community-rules)])
(when-not can-edit-addresses?
[community-rules/view id])]]
(when-not can-edit-addresses?
[rn/view {:style (style/bottom-actions)}
[quo/slide-button
{:size :size-48
:track-text (i18n/label :t/slide-to-request-to-join)
:track-icon :i/face-id
:customization-color color
:on-complete confirm-choices}]])]))
@@ -1,6 +1,7 @@
(ns status-im.contexts.communities.actions.addresses-for-permissions.events
(:require
[schema.core :as schema]
[status-im.contexts.communities.utils :as utils]
[taoensso.timbre :as log]
[utils.re-frame :as rf]))
@@ -56,3 +57,97 @@
map?])
(rf/reg-event-fx :communities/get-permissioned-balances-success get-permissioned-balances-success)
(rf/reg-event-fx :communities/addresses-for-permissions-cancel-request
(fn [_ [request-id]]
{:fx [[:dispatch [:communities/cancel-request-to-join request-id]]
[:dispatch [:pop-to-root :shell-stack]]
[:dispatch [:hide-bottom-sheet]]]}))
(rf/reg-event-fx :communities/addresses-for-permissions-leave
(fn [_ [community-id]]
{:fx [[:dispatch [:communities/leave community-id]]
[:dispatch [:hide-bottom-sheet]]
[:dispatch [:dismiss-modal :addresses-for-permissions]]
[:dispatch [:pop-to-root :shell-stack]]]}))
(defn check-permissions-to-join-for-selection
[{:keys [db]} [community-id addresses]]
(if (empty? addresses)
;; When there are no addresses we can't just check permissions, otherwise
;; status-go will consider all possible addresses and the user will see the
;; incorrect highest permission role.
{:db (update db :communities/permissions-checks-for-selection dissoc community-id)}
(let [{:keys [checking?]} (get-in db [:communities/permissions-checks-for-selection community-id])]
(when-not checking?
{:db (assoc-in db [:communities/permissions-checks-for-selection community-id :checking?] true)
:fx [[:json-rpc/call
[{:method :wakuext_checkPermissionsToJoinCommunity
:params [{:communityId community-id :addresses addresses}]
:on-success [:communities/check-permissions-to-join-during-selection-success
community-id]
:on-error [:communities/check-permissions-to-join-during-selection-failure
community-id addresses]}]]]}))))
;; This event should be used to check permissions temporarily because it won't
;; mutate the state `:communities/permissions-check` (used by many other
;; screens).
(rf/reg-event-fx :communities/check-permissions-to-join-during-selection
check-permissions-to-join-for-selection)
(rf/reg-event-fx :communities/check-permissions-to-join-during-selection-success
(fn [{:keys [db]} [community-id result]]
{:db (assoc-in db
[:communities/permissions-checks-for-selection community-id]
{:checking? false
:based-on-client-selection? true
:check result})}))
(rf/reg-event-fx :communities/check-permissions-to-join-during-selection-failure
(fn [_ [community-id addresses error]]
(log/error "failed to check permissions for currently selected addresses"
{:event :communities/check-permissions-to-join-during-selection
:community-id community-id
:addresses addresses
:error error})))
(defn set-permissioned-accounts
[{:keys [db]} [community-id addresses-to-reveal]]
(let [addresses-to-reveal (set addresses-to-reveal)
wallet-accounts (utils/sorted-non-watch-only-accounts db)
current-airdrop-address (get-in db [:communities/all-airdrop-addresses community-id])
new-airdrop-address (if (contains? addresses-to-reveal current-airdrop-address)
current-airdrop-address
(->> wallet-accounts
(filter #(contains? addresses-to-reveal (:address %)))
first
:address))]
{:db (-> db
(assoc-in [:communities/all-addresses-to-reveal community-id] addresses-to-reveal)
(assoc-in [:communities/all-airdrop-addresses community-id] new-airdrop-address))
:fx [[:dispatch
[:communities/check-permissions-to-join-community
community-id addresses-to-reveal :based-on-client-selection]]
[:dispatch [:hide-bottom-sheet]]]}))
(rf/reg-event-fx :communities/set-addresses-to-reveal set-permissioned-accounts)
(defn set-share-all-addresses
[{:keys [db]} [community-id new-value]]
(let [current-addresses (get-in db [:communities/all-addresses-to-reveal community-id])
addresses-to-reveal (if new-value
(->> (utils/sorted-non-watch-only-accounts db)
(map :address)
set)
current-addresses)]
{:db (-> db
(assoc-in [:communities/selected-share-all-addresses community-id] new-value)
(assoc-in [:communities/all-addresses-to-reveal community-id] addresses-to-reveal))
;; We should check permissions again because the flag is being enabled and
;; different addresses will be revealed.
:fx [(when new-value
[:dispatch
[:communities/check-permissions-to-join-during-selection
community-id addresses-to-reveal]])]}))
(rf/reg-event-fx :communities/set-share-all-addresses set-share-all-addresses)
@@ -1,6 +1,6 @@
(ns status-im.contexts.communities.actions.addresses-for-permissions.events-test
(:require
[cljs.test :refer [deftest is]]
[cljs.test :refer [deftest is testing]]
[status-im.contexts.communities.actions.addresses-for-permissions.events :as sut]))
(def community-id "0x1")
@@ -13,3 +13,101 @@
:on-success [:communities/get-permissioned-balances-success community-id]
:on-error fn?}]]]}
(sut/get-permissioned-balances cofx [community-id])))))
(deftest set-permissioned-accounts-test
(testing "new accounts contain the current airdrop address"
(let [cofx {:db {:communities/all-addresses-to-reveal
{community-id #{"0xA" "0xB"}}}}
addresses-to-reveal ["0xA"]
expected-addresses-to-reveal (set addresses-to-reveal)]
(is (match?
{:db {:communities/all-addresses-to-reveal
{community-id expected-addresses-to-reveal}}
:fx [[:dispatch
[:communities/check-permissions-to-join-community
community-id expected-addresses-to-reveal :based-on-client-selection]]
[:dispatch [:hide-bottom-sheet]]]}
(sut/set-permissioned-accounts cofx [community-id addresses-to-reveal])))))
(testing "new accounts do not contain the current airdrop address"
(let [cofx
{:db {:communities/all-addresses-to-reveal {community-id #{"0xA" "0xB" "0xC"}}
:communities/all-airdrop-addresses {community-id "0xB"}
:wallet {:accounts {"0xB" {:address "0xB" :position 0}
"0xA" {:address "0xA" :position 1}
"0xC" {:address "0xC" :position 2}}}}}
addresses-to-reveal ["0xA" "0xC"]]
(is (match?
{:db {:communities/all-addresses-to-reveal
{community-id (set addresses-to-reveal)}
:communities/all-airdrop-addresses
{community-id "0xA"}}
:fx [[:dispatch
[:communities/check-permissions-to-join-community
community-id (set addresses-to-reveal) :based-on-client-selection]]
[:dispatch [:hide-bottom-sheet]]]}
(sut/set-permissioned-accounts cofx [community-id addresses-to-reveal]))))))
(deftest set-share-all-addresses-test
(testing "sets flag from false -> true will mark all addresses to be revealed"
(let [cofx {:db
{:wallet
{:accounts {"0xB" {:address "0xB" :position 0}
"0xA" {:address "0xA" :position 1}
"0xC" {:address "0xC" :position 2}}}
:communities/all-addresses-to-reveal {community-id #{"0xA"}}
:communities/selected-share-all-addresses {community-id false}}}
addresses-to-reveal #{"0xA" "0xB" "0xC"}]
(is (match?
{:db {:communities/selected-share-all-addresses {community-id true}
:communities/all-addresses-to-reveal
{community-id addresses-to-reveal}}
:fx [[:dispatch
[:communities/check-permissions-to-join-during-selection
community-id addresses-to-reveal]]]}
(sut/set-share-all-addresses cofx [community-id true])))))
(testing "sets flag from true -> false will not change addresses to be revealed"
(let [cofx {:db {:communities/all-addresses-to-reveal {community-id #{"0xA"}}}}]
(is (match?
{:db {:communities/selected-share-all-addresses {community-id false}
:communities/all-addresses-to-reveal {community-id #{"0xA"}}}
:fx [nil]}
(sut/set-share-all-addresses cofx [community-id false]))))))
(deftest check-permissions-to-join-for-selection-test
(testing "when no addresses are passed don't check permissions"
(let [addresses []
cofx {:db {:foo :bar
:communities/permissions-checks-for-selection
{"0xC" :another-check
community-id :some-check}}}]
(is (match?
{:db {:foo :bar
:communities/permissions-checks-for-selection {"0xC" :another-check}}}
(sut/check-permissions-to-join-for-selection cofx [community-id addresses])))))
(testing "when there are addresses to check permissions and not currently checking"
(let [addresses ["0xA"]
cofx {:db {:communities/permissions-checks-for-selection
{"other-comm-id" {}
community-id {:checking? false}}}}]
(is (match?
{:db {:communities/permissions-checks-for-selection
{"other-comm-id" {}
community-id {:checking? true}}}
:fx [[:json-rpc/call
[{:method :wakuext_checkPermissionsToJoinCommunity
:params [{:communityId community-id :addresses addresses}]
:on-success [:communities/check-permissions-to-join-during-selection-success
community-id]
:on-error [:communities/check-permissions-to-join-during-selection-failure
community-id addresses]}]]]}
(sut/check-permissions-to-join-for-selection cofx [community-id addresses])))))
(testing "when there are addresses to check permissions, but currently checking, then skip the check"
(let [addresses ["0xA"]
cofx {:db {:communities/permissions-checks-for-selection
{"other-comm-id" {}
community-id {:checking? true}}}}]
(is (nil? (sut/check-permissions-to-join-for-selection cofx [community-id addresses]))))))
@@ -0,0 +1,6 @@
(ns status-im.contexts.communities.actions.addresses-for-permissions.style)
(def drawer-body
{:padding-top 4
:padding-horizontal 20
:padding-bottom 12})
@@ -1,11 +1,16 @@
(ns status-im.contexts.communities.actions.addresses-for-permissions.view
(:require [quo.core :as quo]
[react-native.gesture :as gesture]
[status-im.common.not-implemented :as not-implemented]
[status-im.constants :as constants]
[utils.i18n :as i18n]
[utils.money :as money]
[utils.re-frame :as rf]))
(:require
[clojure.string :as string]
[quo.core :as quo]
[react-native.core :as rn]
[react-native.gesture :as gesture]
[status-im.common.not-implemented :as not-implemented]
[status-im.common.password-authentication.view :as password-authentication]
[status-im.constants :as constants]
[status-im.contexts.communities.actions.addresses-for-permissions.style :as style]
[utils.i18n :as i18n]
[utils.money :as money]
[utils.re-frame :as rf]))
(defn- role-keyword
[role]
@@ -36,96 +41,316 @@
:token (:symbol balance)
:token-img-src (images-by-symbol sym)))))
(defn- cancel-join-request-drawer
[community-id]
(let [{:keys [name logo color]} (rf/sub [:communities/for-context-tag community-id])
request-id (rf/sub [:communities/my-pending-request-to-join community-id])]
[:<>
[quo/drawer-top
{:type :context-tag
:context-tag-type :community
:title (i18n/label :t/cancel-request?)
:community-name name
:community-logo logo
:customization-color color}]
[rn/view {:style style/drawer-body}
[quo/text (i18n/label :t/pending-join-request-farewell)]]
[quo/bottom-actions
{:actions :two-actions
:button-one-label (i18n/label :t/confirm-and-cancel)
:button-one-props {:customization-color color
:on-press
(fn []
(rf/dispatch [:communities/addresses-for-permissions-cancel-request
request-id]))}
:button-two-label (i18n/label :t/cancel)
:button-two-props {:type :grey
:on-press #(rf/dispatch [:hide-bottom-sheet])}}]]))
(defn- confirm-discard-drawer
[community-id]
(let [{:keys [name logo color]} (rf/sub [:communities/for-context-tag community-id])]
[:<>
[quo/drawer-top
{:type :context-tag
:context-tag-type :community
:title (i18n/label :t/discard-changes?)
:community-name name
:community-logo logo
:customization-color color}]
[rn/view {:style style/drawer-body}
[quo/text (i18n/label :t/all-changes-will-be-discarded)]]
[quo/bottom-actions
{:actions :two-actions
:button-one-label (i18n/label :t/discard)
:button-one-props {:customization-color color
:on-press
(fn []
(rf/dispatch [:dismiss-modal :addresses-for-permissions])
(rf/dispatch [:hide-bottom-sheet]))}
:button-two-label (i18n/label :t/cancel)
:button-two-props {:type :grey
:on-press #(rf/dispatch [:hide-bottom-sheet])}}]]))
(defn- leave-community-drawer
[community-id outro-message]
(let [{:keys [name logo color]} (rf/sub [:communities/for-context-tag community-id])]
[:<>
[quo/drawer-top
{:type :context-tag
:context-tag-type :community
:title (i18n/label :t/leave-community?)
:community-name name
:community-logo logo
:customization-color color}]
[rn/view {:style style/drawer-body}
[quo/text
(if (string/blank? outro-message)
(i18n/label :t/leave-community-farewell)
outro-message)]]
[quo/bottom-actions
{:actions :two-actions
:button-one-label (i18n/label :t/confirm-and-leave)
:button-one-props {:customization-color color
:on-press
#(rf/dispatch [:communities/addresses-for-permissions-leave community-id])}
:button-two-label (i18n/label :t/cancel)
:button-two-props {:type :grey
:on-press #(rf/dispatch [:hide-bottom-sheet])}}]]))
(defn- account-item
[{:keys [color address name emoji]} _ _
{:keys [selected-addresses community-id share-all-addresses? community-color]}]
[{:keys [customization-color address name emoji]} _ _
[addresses-to-reveal set-addresses-to-reveal community-id community-color share-all-addresses?]]
(let [balances (rf/sub [:communities/permissioned-balances-by-address community-id address])
images-by-symbol (rf/sub [:communities/token-images-by-symbol community-id])]
images-by-symbol (rf/sub [:communities/token-images-by-symbol community-id])
checked? (contains? addresses-to-reveal address)
toggle-address (fn []
(let [new-addresses (if checked?
(disj addresses-to-reveal address)
(conj addresses-to-reveal address))]
(set-addresses-to-reveal new-addresses)))]
[quo/account-permissions
{:account {:name name
:address address
:emoji emoji
:customization-color color}
:token-details (balances->components-props balances images-by-symbol)
:checked? (contains? selected-addresses address)
:customization-color customization-color}
:token-details (when-not share-all-addresses?
(balances->components-props balances images-by-symbol))
:checked? checked?
:disabled? share-all-addresses?
:on-change #(rf/dispatch [:communities/toggle-selected-permission-address
address community-id])
:on-change toggle-address
:container-style {:margin-bottom 8}
:customization-color community-color}]))
(defn- page-top
[{:keys [community-id identical-choices? can-edit-addresses?]}]
(let [{:keys [name logo color]} (rf/sub [:communities/for-context-tag community-id])
confirm-discard-changes (rn/use-callback
(fn []
(if identical-choices?
(rf/dispatch [:dismiss-modal :addresses-for-permissions])
(rf/dispatch [:show-bottom-sheet
{:content (fn [] [confirm-discard-drawer
community-id])}])))
[identical-choices?])]
[:<>
(when can-edit-addresses?
[quo/page-nav
{:type :no-title
:icon-name :i/arrow-left
:on-press confirm-discard-changes}])
(if can-edit-addresses?
[quo/page-top
{:title (i18n/label :t/addresses-for-permissions)
:title-accessibility-label :title-label
:description :context-tag
:context-tag {:type :community
:community-logo logo
:community-name name}}]
[quo/drawer-top
{:type :context-tag
:title (i18n/label :t/addresses-for-permissions)
:context-tag-type :community
:community-name name
:button-icon :i/info
:button-type :grey
:on-button-press not-implemented/alert
:community-logo logo
:customization-color color}])]))
(defn view
[]
(let [{id :community-id} (rf/sub [:get-screen-params])
toggle-share-all-addresses #(rf/dispatch [:communities/toggle-share-all-addresses id])
update-previous-addresses (fn []
(rf/dispatch [:communities/update-previous-permission-addresses id])
(rf/dispatch [:hide-bottom-sheet]))
reset-selected-addresses (fn []
(rf/dispatch [:communities/reset-selected-permission-addresses id])
(rf/dispatch [:hide-bottom-sheet]))]
(rf/dispatch [:communities/get-permissioned-balances id])
(fn []
(let [{:keys [name color images]} (rf/sub [:communities/community id])
{:keys [checking?
highest-permission-role]} (rf/sub [:community/token-gated-overview id])
accounts (rf/sub [:wallet/accounts-without-watched-accounts])
selected-addresses (rf/sub [:communities/selected-permission-addresses id])
share-all-addresses? (rf/sub [:communities/share-all-addresses? id])
unsaved-address-changes? (rf/sub [:communities/unsaved-address-changes? id])]
[:<>
[quo/drawer-top
{:type :context-tag
:title (i18n/label :t/addresses-for-permissions)
:context-tag-type :community
:community-name name
:button-icon :i/info
:button-type :grey
:on-button-press not-implemented/alert
:community-logo (get-in images [:thumbnail :uri])
:customization-color color}]
(let [{id :community-id} (rf/sub [:get-screen-params])
{:keys [color joined] outro-message :outroMessage} (rf/sub [:communities/community id])
[gesture/flat-list
{:render-fn account-item
:render-data {:selected-addresses selected-addresses
:community-id id
:share-all-addresses? share-all-addresses?
:community-color color}
:header [quo/category
{:list-type :settings
:data [{:title
(i18n/label
:t/share-all-current-and-future-addresses)
:action :selector
:action-props
{:on-change toggle-share-all-addresses
:customization-color color
:checked? share-all-addresses?}}]
:container-style {:padding-bottom 16 :padding-horizontal 0}}]
:content-container-style {:padding-horizontal 20}
:key-fn :address
:data accounts}]
highest-role (rf/sub [:communities/highest-role-for-selection id])
[unmodified-role _] (rn/use-state highest-role)
[quo/bottom-actions
{:actions :two-actions
:button-one-label (i18n/label :t/confirm-changes)
:button-one-props {:customization-color color
:disabled? (or checking?
(empty? selected-addresses)
(not highest-permission-role)
(not unsaved-address-changes?))
:on-press update-previous-addresses}
:button-two-label (i18n/label :t/cancel)
:button-two-props {:type :grey
:on-press reset-selected-addresses}
:description (if (or (empty? selected-addresses)
(not highest-permission-role))
:top-error
:top)
:role (when-not checking? (role-keyword highest-permission-role))
:error-message (cond
(empty? selected-addresses)
(i18n/label :t/no-addresses-selected)
can-edit-addresses? (rf/sub [:communities/can-edit-shared-addresses? id])
pending? (boolean (rf/sub [:communities/my-pending-request-to-join id]))
(not highest-permission-role)
(i18n/label :t/addresses-dont-contain-tokens-needed))}]]))))
wallet-accounts (rf/sub [:wallet/accounts-without-watched-accounts])
unmodified-addresses-to-reveal (rf/sub [:communities/addresses-to-reveal id])
[addresses-to-reveal set-addresses-to-reveal] (rn/use-state unmodified-addresses-to-reveal)
unmodified-flag-share-all-addresses (rf/sub [:communities/share-all-addresses? id])
[flag-share-all-addresses
set-flag-share-all-addresses] (rn/use-state unmodified-flag-share-all-addresses)
identical-choices? (and (= unmodified-addresses-to-reveal addresses-to-reveal)
(= unmodified-flag-share-all-addresses flag-share-all-addresses))
toggle-flag-share-all-addresses
(fn []
(let [new-value (not flag-share-all-addresses)]
(set-flag-share-all-addresses new-value)
(when new-value
(set-addresses-to-reveal (set (map :address wallet-accounts))))))
cancel-join-request
(rn/use-callback
(fn []
(rf/dispatch [:show-bottom-sheet
{:content (fn [] [cancel-join-request-drawer id])}])))
leave-community
(rn/use-callback
(fn []
(rf/dispatch [:show-bottom-sheet
{:content (fn [] [leave-community-drawer id outro-message])}]))
[outro-message])
cancel-selection
(fn []
(rf/dispatch [:communities/check-permissions-to-join-community
id
unmodified-addresses-to-reveal
:based-on-client-selection])
(rf/dispatch [:hide-bottom-sheet]))
confirm-changes
(fn []
(if can-edit-addresses?
(rf/dispatch
[:password-authentication/show
{:content (fn [] [password-authentication/view])}
{:label (i18n/label :t/enter-password)
:on-press (fn [password]
(rf/dispatch
[:communities/edit-shared-addresses
{:community-id id
:password password
:addresses addresses-to-reveal
:on-success (fn []
(rf/dispatch [:dismiss-modal :addresses-for-permissions])
(rf/dispatch [:hide-bottom-sheet]))}]))}])
(do
(rf/dispatch [:communities/set-share-all-addresses id flag-share-all-addresses])
(rf/dispatch [:communities/set-addresses-to-reveal id addresses-to-reveal]))))]
(rn/use-mount
(fn []
(when-not flag-share-all-addresses
(rf/dispatch [:communities/get-permissioned-balances id]))))
(rn/use-effect
(fn []
(rf/dispatch [:communities/check-permissions-to-join-during-selection id addresses-to-reveal]))
[id addresses-to-reveal])
[:<>
[page-top
{:community-id id
:identical-choices? identical-choices?
:can-edit-addresses? can-edit-addresses?}]
[gesture/flat-list
{:render-fn account-item
:render-data [addresses-to-reveal
set-addresses-to-reveal
id
color
flag-share-all-addresses]
:header [quo/category
{:list-type :settings
:data [{:title
(i18n/label
:t/share-all-current-and-future-addresses)
:action :selector
:action-props
{:on-change toggle-flag-share-all-addresses
:customization-color color
:checked? flag-share-all-addresses}}]
:container-style {:padding-bottom 16 :padding-horizontal 0}}]
:content-container-style {:padding-horizontal 20}
:key-fn :address
:data wallet-accounts}]
[quo/bottom-actions
(cond-> {:role (role-keyword highest-role)
:description (if highest-role
:top
:top-error)
:button-one-props {:customization-color color
:on-press confirm-changes
:disabled? (or (empty? addresses-to-reveal)
(not highest-role)
identical-choices?)}}
can-edit-addresses?
(->
(assoc :actions :one-action
:button-one-label (cond
(and pending? (not highest-role))
(i18n/label :t/cancel-request)
(and joined (not highest-role))
(i18n/label :t/leave-community)
:else
(i18n/label :t/confirm-changes))
:description-top-text (cond
(and pending? highest-role)
(i18n/label :t/eligible-to-join-as)
(and joined (= highest-role unmodified-role))
(i18n/label :t/you-are-a)
(and joined (not= highest-role unmodified-role))
(i18n/label :t/you-will-be-a))
:error-message (cond
(and pending? (not highest-role))
(i18n/label :t/community-join-requirements-not-met)
(and joined (not highest-role))
(i18n/label :t/membership-requirements-not-met)))
(update :button-one-props
merge
(cond (and pending? (not highest-role))
{:type :danger
:disabled? false
:on-press cancel-join-request}
(and joined (not highest-role))
{:type :danger
:disabled? false
:on-press leave-community})))
(not can-edit-addresses?)
(assoc :actions :two-actions
:button-one-label (i18n/label :t/confirm-changes)
:button-two-label (i18n/label :t/cancel)
:button-two-props {:type :grey
:on-press cancel-selection}
:error-message (cond
(empty? addresses-to-reveal)
(i18n/label :t/no-addresses-selected)
(not highest-role)
(i18n/label :t/addresses-dont-contain-tokens-needed))))]]))
@@ -0,0 +1,9 @@
(ns status-im.contexts.communities.actions.airdrop-addresses.events
(:require
[utils.re-frame :as rf]))
(defn set-airdrop-address
[{:keys [db]} [community-id airdrop-address]]
{:db (assoc-in db [:communities/all-airdrop-addresses community-id] airdrop-address)})
(rf/reg-event-fx :communities/set-airdrop-address set-airdrop-address)
@@ -0,0 +1,18 @@
(ns status-im.contexts.communities.actions.airdrop-addresses.events-test
(:require
[cljs.test :refer [deftest is testing]]
[status-im.contexts.communities.actions.airdrop-addresses.events :as sut]))
(def community-id "community-id")
(deftest set-airdrop-address-test
(testing "updates all reveal? flags"
(let [new-airdrop-address "0xA"
cofx {:db {:communities/all-airdrop-addresses
{"another-community" "0xF"
community-id "0xB"}}}]
(is (match?
(assoc-in cofx
[:db :communities/all-airdrop-addresses community-id]
new-airdrop-address)
(sut/set-airdrop-address cofx [community-id new-airdrop-address]))))))
@@ -1,41 +1,81 @@
(ns status-im.contexts.communities.actions.airdrop-addresses.view
(:require
[quo.core :as quo]
[react-native.core :as rn]
[react-native.gesture :as gesture]
[status-im.common.not-implemented :as not-implemented]
[status-im.common.password-authentication.view :as password-authentication]
[status-im.contexts.communities.actions.airdrop-addresses.style :as style]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(defn- render-item
[item _ _ [airdrop-address community-id]]
[quo/account-item
{:account-props item
:state (when (= airdrop-address (:address item)) :selected)
:on-press (fn []
(rf/dispatch [:communities/set-airdrop-address (:address item) community-id])
(rf/dispatch [:hide-bottom-sheet]))
:emoji (:emoji item)}])
(defn- account-item
[{:keys [address emoji] :as account}
_ _
[community-id airdrop-address can-edit-addresses?]]
(let [airdrop-address? (= address airdrop-address)
on-press
(when-not airdrop-address?
(fn []
(if can-edit-addresses?
(rf/dispatch
[:password-authentication/show
{:content (fn [] [password-authentication/view])}
{:label (i18n/label :t/enter-password)
:on-press (fn [password]
(rf/dispatch
[:communities/edit-shared-addresses
{:community-id community-id
:password password
:airdrop-address address
:on-success (fn []
(rf/dispatch [:dismiss-modal :address-for-airdrop])
(rf/dispatch [:hide-bottom-sheet]))}]))}])
(do
(rf/dispatch [:communities/set-airdrop-address community-id address])
(rf/dispatch [:hide-bottom-sheet])))))]
[quo/account-item
{:account-props account
:emoji emoji
:state (if airdrop-address? :selected :default)
:on-press on-press}]))
(defn view
[]
(let [{id :community-id} (rf/sub [:get-screen-params])
{:keys [name images color]} (rf/sub [:communities/community id])
selected-accounts (rf/sub [:communities/selected-permission-accounts id])
airdrop-address (rf/sub [:communities/airdrop-address id])]
(let [{id :community-id} (rf/sub [:get-screen-params])
{:keys [name logo color]} (rf/sub [:communities/for-context-tag id])
accounts (rf/sub [:communities/accounts-to-reveal id])
airdrop-address (rf/sub [:communities/airdrop-address id])
can-edit-addresses? (rf/sub [:communities/can-edit-shared-addresses? id])
go-back (rn/use-callback #(rf/dispatch [:dismiss-modal :address-for-airdrop]))]
[:<>
[quo/drawer-top
{:type :context-tag
:context-tag-type :community
:title (i18n/label :t/airdrop-addresses)
:community-name name
:button-icon :i/info
:on-button-press not-implemented/alert
:community-logo (get-in images [:thumbnail :uri])
:customization-color color}]
(when can-edit-addresses?
[quo/page-nav
{:type :no-title
:icon-name :i/arrow-left
:on-press go-back}])
(if can-edit-addresses?
[quo/page-top
{:title (i18n/label :t/airdrop-addresses)
:title-accessibility-label :title-label
:description :context-tag
:context-tag {:type :community
:community-logo logo
:community-name name}}]
[quo/drawer-top
{:type :context-tag
:context-tag-type :community
:title (i18n/label :t/airdrop-addresses)
:community-name name
:button-icon :i/info
:on-button-press not-implemented/alert
:community-logo logo
:customization-color color}])
[gesture/flat-list
{:data selected-accounts
:render-fn render-item
:render-data [airdrop-address id]
{:data accounts
:render-fn account-item
:render-data [id airdrop-address can-edit-addresses?]
:content-container-style style/account-list-container
:key-fn :address}]]))
@@ -7,6 +7,7 @@
[status-im.contexts.communities.actions.leave.view :as leave-menu]
[status-im.contexts.communities.actions.see-rules.view :as see-rules]
[status-im.contexts.communities.actions.token-gating.view :as token-gating]
[status-im.feature-flags :as ff]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
@@ -41,6 +42,15 @@
{:content (fn [] [token-gating/token-requirements id])}])
:label (i18n/label :t/view-token-gating)})
(defn edit-shared-addresses
[id]
{:icon :i/wallet
:right-icon :i/chevron-right
:accessibility-label :edit-shared-addresses
:on-press (fn []
(rf/dispatch [:open-modal :community-account-selection {:community-id id}]))
:label (i18n/label :t/edit-shared-addresses)})
(defn mark-as-read
[id]
{:icon :i/up-to-date
@@ -119,28 +129,33 @@
request-id])}])})
(defn not-joined-options
[id token-gated?]
[id token-gated? pending?]
[[(when-not token-gated? (view-members id))
(when-not token-gated? (view-rules id))
(invite-contacts id)
(when token-gated? (view-token-gating id))
(when (and pending? (ff/enabled? ::ff/community.edit-account-selection))
(edit-shared-addresses id))
(show-qr id)
(share-community id)]])
(defn join-request-sent-options
[id token-gated? request-id]
[(conj (first (not-joined-options id token-gated?))
[(conj (first (not-joined-options id token-gated? request-id))
(assoc (cancel-request-to-join id request-id) :add-divider? true))])
(defn banned-options
[id token-gated?]
(not-joined-options id token-gated?))
(let [pending? false]
(not-joined-options id token-gated? pending?)))
(defn joined-options
[id token-gated? muted? muted-till]
[[(view-members id)
(view-rules id)
(when token-gated? (view-token-gating id))
(when (ff/enabled? ::ff/community.edit-account-selection)
(edit-shared-addresses id))
(mark-as-read id)
(mute-community id muted? muted-till)
(community-notification-settings id)
@@ -171,7 +186,7 @@
joined (joined-options id token-permissions muted muted-till)
request-id (join-request-sent-options id token-permissions request-id)
banList (banned-options id token-permissions)
:else (not-joined-options id token-permissions))))
:else (not-joined-options id token-permissions request-id))))
(defn community-options-bottom-sheet
[id]
@@ -29,10 +29,11 @@
{:type :positive
:text (i18n/label :t/left-community {:community community-name})}]]
[:dispatch [:activity-center.notifications/fetch-unread-count]]
[:dispatch [:hide-bottom-sheet]]
[:dispatch [:navigate-back]]]})))
(rf/reg-event-fx :communities/leave
(fn [{:keys [db]} [community-id]]
(fn [{:keys [db]} [community-id on-success]]
(let [community-chat-ids (map #(str community-id %)
(keys (get-in db [:communities community-id :chats])))]
{:effects/push-notifications-clear-message-notifications community-chat-ids
@@ -41,5 +42,8 @@
[{:method "wakuext_leaveCommunity"
:params [community-id]
:js-response true
:on-success #(rf/dispatch [:communities/left %])
:on-success (fn [^js response]
(when (fn? on-success)
(on-success))
(rf/dispatch [:communities/left response]))
:on-error #(log/error "failed to leave community" community-id %)}]})))
+26 -115
View File
@@ -9,10 +9,11 @@
[schema.core :as schema]
[status-im.constants :as constants]
[status-im.contexts.chat.messenger.messages.link-preview.events :as link-preview.events]
status-im.contexts.communities.actions.accounts-selection.events
status-im.contexts.communities.actions.addresses-for-permissions.events
status-im.contexts.communities.actions.airdrop-addresses.events
status-im.contexts.communities.actions.community-options.events
status-im.contexts.communities.actions.leave.events
[status-im.contexts.communities.utils :as utils]
[status-im.navigation.events :as navigation]
[taoensso.timbre :as log]
[utils.i18n :as i18n]
@@ -29,13 +30,10 @@
{:db (assoc-in db
[:communities id]
(assoc community :last-opened-at (max last-opened-at previous-last-opened-at)))
:fx [[:dispatch [:communities/initialize-permission-addresses id]]
(when (not joined)
:fx [(when (not joined)
[:dispatch [:chat.ui/spectate-community id]])
(when (nil? token-permissions-check)
[:dispatch [:communities/check-permissions-to-join-community id]])
(when joined
[:dispatch [:communities/get-revealed-accounts id]])]}))))
[:dispatch [:communities/check-permissions-to-join-community id]])]}))))
(rf/reg-event-fx :communities/handle-community handle-community)
@@ -157,97 +155,6 @@
:on-success #(rf/dispatch [:communities/fetched-collapsed-categories-success %])
:on-error #(log/error "failed to fetch collapsed community categories" %)}]}))
(defn initialize-permission-addresses
[{:keys [db]} [community-id]]
(when community-id
(let [accounts (utils/sorted-non-watch-only-accounts db)
addresses (set (map :address accounts))]
{:db (update-in db
[:communities community-id]
assoc
:previous-share-all-addresses? true
:share-all-addresses? true
:previous-permission-addresses addresses
:selected-permission-addresses addresses
:airdrop-address (:address (first accounts)))})))
(rf/reg-event-fx :communities/initialize-permission-addresses
initialize-permission-addresses)
(defn update-previous-permission-addresses
[{:keys [db]} [community-id]]
(when community-id
(let [accounts (utils/sorted-non-watch-only-accounts db)
selected-permission-addresses (get-in db
[:communities community-id
:selected-permission-addresses])
selected-accounts (filter #(contains? selected-permission-addresses (:address %))
accounts)
current-airdrop-address (get-in db [:communities community-id :airdrop-address])
share-all-addresses? (get-in db [:communities community-id :share-all-addresses?])]
{:db (update-in db
[:communities community-id]
assoc
:previous-share-all-addresses? share-all-addresses?
:previous-permission-addresses selected-permission-addresses
:airdrop-address (if (contains? selected-permission-addresses
current-airdrop-address)
current-airdrop-address
(:address (first selected-accounts))))})))
(rf/reg-event-fx :communities/update-previous-permission-addresses
update-previous-permission-addresses)
(defn toggle-selected-permission-address
[{:keys [db]} [address community-id]]
(let [selected-permission-addresses
(get-in db [:communities community-id :selected-permission-addresses])
updated-selected-permission-addresses
(if (contains? selected-permission-addresses address)
(disj selected-permission-addresses address)
(conj selected-permission-addresses address))]
{:db (assoc-in db
[:communities community-id :selected-permission-addresses]
updated-selected-permission-addresses)
:fx [(when community-id
[:dispatch
[:communities/check-permissions-to-join-community community-id
updated-selected-permission-addresses :based-on-client-selection]])]}))
(rf/reg-event-fx :communities/toggle-selected-permission-address
toggle-selected-permission-address)
(defn toggle-share-all-addresses
[{:keys [db]} [community-id]]
(let [share-all-addresses? (get-in db [:communities community-id :share-all-addresses?])
next-share-all-addresses? (not share-all-addresses?)
accounts (utils/sorted-non-watch-only-accounts db)
addresses (set (map :address accounts))]
{:db (update-in db
[:communities community-id]
assoc
:share-all-addresses? next-share-all-addresses?
:selected-permission-addresses addresses)
:fx [(when (and community-id next-share-all-addresses?)
[:dispatch
[:communities/check-permissions-to-join-community community-id
addresses :based-on-client-selection]])]}))
(rf/reg-event-fx :communities/toggle-share-all-addresses
toggle-share-all-addresses)
(rf/reg-event-fx :communities/reset-selected-permission-addresses
(fn [{:keys [db]} [community-id]]
(when community-id
{:db (update-in db
[:communities community-id]
assoc
:selected-permission-addresses
(get-in db [:communities community-id :previous-permission-addresses])
:share-all-addresses?
(get-in db [:communities community-id :previous-share-all-addresses?]))
:fx [[:dispatch [:communities/check-permissions-to-join-community community-id]]]})))
(rf/reg-event-fx :communities/get-community-channel-share-data
(fn [_ [chat-id on-success]]
(let [{:keys [community-id channel-id]} (data-store.chats/decode-chat-id chat-id)]
@@ -286,14 +193,10 @@
:url %}])]
{:fx [[:dispatch [:communities/get-community-channel-share-data chat-id on-success]]]})))
(rf/reg-event-fx :communities/set-airdrop-address
(fn [{:keys [db]} [address community-id]]
{:db (assoc-in db [:communities community-id :airdrop-address] address)}))
(defn community-fetched
[{:keys [db]} [community-id community]]
(when community
{:db (update db :communities/fetching-community dissoc community-id)
{:db (update db :communities/fetching-communities dissoc community-id)
:fx [[:dispatch [:communities/handle-community community]]
[:dispatch [:communities/update-last-opened-at community-id]]
[:dispatch
@@ -304,14 +207,14 @@
(defn community-failed-to-fetch
[{:keys [db]} [community-id]]
{:db (update db :communities/fetching-community dissoc community-id)})
{:db (update db :communities/fetching-communities dissoc community-id)})
(rf/reg-event-fx :chat.ui/community-failed-to-fetch community-failed-to-fetch)
(defn fetch-community
[{:keys [db]} [{:keys [community-id update-last-opened-at?]}]]
(when (and community-id (not (get-in db [:communities/fetching-community community-id])))
{:db (assoc-in db [:communities/fetching-community community-id] true)
(when (and community-id (not (get-in db [:communities/fetching-communities community-id])))
{:db (assoc-in db [:communities/fetching-communities community-id] true)
:json-rpc/call [{:method "wakuext_fetchCommunity"
:params [{:CommunityKey community-id
:TryDatabase true
@@ -398,7 +301,7 @@
:community-id community-id})}})
(rf/reg-event-fx :communities/navigate-to-community-overview
(fn [cofx [deserialized-key]]
(fn [{:keys [db] :as cofx} [deserialized-key]]
(if (string/starts-with? deserialized-key constants/serialization-key)
(navigate-to-serialized-community cofx deserialized-key)
(rf/merge
@@ -407,7 +310,9 @@
[:communities/fetch-community
{:community-id deserialized-key
:update-last-opened-at? true}]]
[:dispatch [:navigate-to :community-overview deserialized-key]]]}
[:dispatch [:navigate-to :community-overview deserialized-key]]
(when (get-in db [:communities deserialized-key :joined])
[:dispatch [:activity-center.notifications/dismiss-community-overview deserialized-key]])]}
(navigation/pop-to-root :shell-stack)))))
(rf/reg-event-fx :communities/navigate-to-community-chat
@@ -423,16 +328,17 @@
[:dispatch [:chat/navigate-to-chat chat-id]])]})))
(defn get-revealed-accounts
[{:keys [db]} [community-id]]
[{:keys [db]} [community-id on-success]]
(let [{:keys [joined fetching-revealed-accounts]
:as community} (get-in db [:communities community-id])]
(when (and community joined (not fetching-revealed-accounts))
:as community} (get-in db [:communities community-id])
pending? (get-in db [:communities/my-pending-requests-to-join community-id])]
(when (and community (or pending? joined) (not fetching-revealed-accounts))
{:db (assoc-in db [:communities community-id :fetching-revealed-accounts] true)
:json-rpc/call
[{:method "wakuext_getRevealedAccounts"
:params [community-id (get-in db [:profile/profile :public-key])]
:js-response true
:on-success [:communities/get-revealed-accounts-success community-id]
:on-success [:communities/get-revealed-accounts-success community-id on-success]
:on-error (fn [err]
(log/error {:message "failed to fetch revealed accounts"
:community-id community-id
@@ -446,19 +352,22 @@
[:catn
[:cofx :schema.re-frame/cofx]
[:args
[:schema [:catn [:community-id [:? :string]]]]]]
[:schema
[:catn
[:community-id [:? :string]]
[:on-success [:? :schema.re-frame/event]]]]]]
[:maybe
[:map
[:db map?]
[:json-rpc/call :schema.common/rpc-call]]]])
(rf/reg-event-fx :communities/get-revealed-accounts-success
(fn [{:keys [db]} [community-id revealed-accounts-js]]
(fn [{:keys [db]} [community-id on-success revealed-accounts-js]]
(when-let [community (get-in db [:communities community-id])]
(let [revealed-accounts
(reduce
(fn [acc {:keys [address] :as revealed-account}]
(assoc acc address (dissoc revealed-account :address)))
(assoc acc address revealed-account))
{}
(data-store.communities/<-revealed-accounts-rpc revealed-accounts-js))
@@ -466,7 +375,9 @@
(-> community
(assoc :revealed-accounts revealed-accounts)
(dissoc :fetching-revealed-accounts))]
{:db (assoc-in db [:communities community-id] community-with-revealed-accounts)}))))
{:db (assoc-in db [:communities community-id] community-with-revealed-accounts)
:fx [(when (vector? on-success)
[:dispatch (conj on-success revealed-accounts)])]}))))
(rf/reg-event-fx :communities/get-revealed-accounts-failed
(fn [{:keys [db]} [community-id]]
@@ -7,104 +7,11 @@
(def community-id "community-id")
(deftest initialize-permission-addresses-test
(let [initial-db {:db {:wallet {:accounts {"0x1" {:address "0x1"
:position 0}
"0x2" {:address "0x2"
:position 1}}}}}
expected-db {:db (update-in (:db initial-db)
[:communities community-id]
assoc
:share-all-addresses? true
:previous-share-all-addresses? true
:previous-permission-addresses #{"0x1" "0x2"}
:selected-permission-addresses #{"0x1" "0x2"}
:airdrop-address "0x1")}]
(is (match? expected-db (events/initialize-permission-addresses initial-db [community-id])))))
(deftest toggle-selected-permission-address-test
(let [initial-db {:db {:communities {community-id {:selected-permission-addresses #{"0x1" "0x2"}}}}}]
(is (match? {:db {:communities {community-id {:selected-permission-addresses #{"0x1"}}}}}
(events/toggle-selected-permission-address initial-db ["0x2" community-id])))
(is (match? {:db {:communities {community-id {:selected-permission-addresses #{"0x1" "0x2" "0x3"}}}}}
(events/toggle-selected-permission-address initial-db ["0x3" community-id])))))
(deftest update-previous-permission-addresses-test
(let [wallet {:accounts {"0x1" {:address "0x1"
:position 0}
"0x2" {:address "0x2"
:position 1}
"0x3" {:address "0x3"
:position 2}}}]
(let [initial-db {:db {:wallet wallet
:communities {community-id {:previous-permission-addresses #{"0x1" "0x2"}
:selected-permission-addresses #{"0x1" "0x2"
"0x3"}
:share-all-addresses? true
:previous-share-all-addresses? false
:airdrop-address "0x1"}}}}
expected-db {:db {:wallet wallet
:communities {community-id {:previous-permission-addresses #{"0x1" "0x2"
"0x3"}
:selected-permission-addresses #{"0x1" "0x2"
"0x3"}
:share-all-addresses? true
:previous-share-all-addresses? true
:airdrop-address "0x1"}}}}]
(is
(match? expected-db
(events/update-previous-permission-addresses initial-db [community-id]))))
(let [initial-db {:db {:wallet wallet
:communities {community-id {:previous-permission-addresses #{"0x1" "0x2"}
:selected-permission-addresses #{"0x2" "0x3"}
:airdrop-address "0x1"}}}}
expected-db {:db {:wallet wallet
:communities {community-id {:previous-permission-addresses #{"0x2" "0x3"}
:selected-permission-addresses #{"0x2" "0x3"}
:airdrop-address "0x2"}}}}]
(is
(match? expected-db
(events/update-previous-permission-addresses initial-db [community-id]))))))
(deftest toggle-share-all-addresses-test
(let [initial-db {:db {:wallet {:accounts {"0x1" {:address "0x1"
:position 0}
"0x2" {:address "0x2"
:position 1}}}
:communities {community-id {:share-all-addresses? true
:previous-share-all-addresses? true
:previous-permission-addresses #{"0x1" "0x2"}
:selected-permission-addresses #{"0x1" "0x2"}
:airdrop-address "0x1"}}}}
expected-db (update-in initial-db
[:db :communities community-id]
assoc
:previous-share-all-addresses? true
:share-all-addresses?
false)]
(is (match? expected-db (events/toggle-share-all-addresses initial-db [community-id]))))
(let [initial-db {:db {:wallet {:accounts {"0x1" {:address "0x1"
:position 0}
"0x2" {:address "0x2"
:position 1}}}
:communities {community-id {:share-all-addresses? false
:previous-share-all-addresses? false
:previous-permission-addresses #{"0x1"}
:selected-permission-addresses #{"0x1"}
:airdrop-address "0x1"}}}}
expected-db (update-in initial-db
[:db :communities community-id]
assoc
:selected-permission-addresses #{"0x1" "0x2"}
:previous-share-all-addresses? false
:share-all-addresses? true)]
(is (match? expected-db (events/toggle-share-all-addresses initial-db [community-id])))))
(deftest fetch-community
(testing "with community id"
(testing "update fetching indicator in db"
(is (match?
{:db {:communities/fetching-community {community-id true}}}
{:db {:communities/fetching-communities {community-id true}}}
(events/fetch-community {} [{:community-id community-id}]))))
(testing "call the fetch community rpc method with correct community id"
(is (match?
@@ -124,21 +31,21 @@
(testing "remove community id from fetching indicator in db"
(is (match?
nil
(get-in (events/community-failed-to-fetch {:db {:communities/fetching-community
(get-in (events/community-failed-to-fetch {:db {:communities/fetching-communities
{community-id true}}}
[community-id])
[:db :communities/fetching-community community-id]))))))
[:db :communities/fetching-communities community-id]))))))
(deftest community-fetched
(with-redefs [link-preview.events/community-link (fn [id] (str "community-link+" id))]
(testing "given a community"
(let [cofx {:db {:communities/fetching-community {community-id true}}}
(let [cofx {:db {:communities/fetching-communities {community-id true}}}
arg [community-id {:id community-id}]]
(testing "remove community id from fetching indicator in db"
(is (match?
nil
(get-in (events/community-fetched cofx arg)
[:db :communities/fetching-community community-id]))))
[:db :communities/fetching-communities community-id]))))
(testing "dispatch fxs"
(is (match?
{:fx [[:dispatch [:communities/handle-community {:id community-id}]]
@@ -148,7 +55,7 @@
{:id community-id}]]]}
(events/community-fetched cofx arg))))))
(testing "given a joined community"
(let [cofx {:db {:communities/fetching-community {community-id true}}}
(let [cofx {:db {:communities/fetching-communities {community-id true}}}
arg [community-id {:id community-id :joined true}]]
(testing "dispatch fxs, do not spectate community"
(is (match?
@@ -159,7 +66,7 @@
{:id community-id}]]]}
(events/community-fetched cofx arg))))))
(testing "given a token-gated community"
(let [cofx {:db {:communities/fetching-community {community-id true}}}
(let [cofx {:db {:communities/fetching-communities {community-id true}}}
arg [community-id {:id community-id :tokenPermissions [1]}]]
(testing "dispatch fxs, do not spectate community"
(is (match?
@@ -243,12 +150,14 @@
(is (match?
nil
(events/get-revealed-accounts {:db {:communities {community-id community}}} [community-id]))))
(testing "given a already :fetching-revealed-accounts community"
(is (match?
nil
(events/get-revealed-accounts
{:db {:communities {community-id (assoc community :fetching-revealed-accounts true)}}}
[community-id]))))
(testing "given joined community"
(let [community (assoc community :joined true)
db {:communities {community-id community}
@@ -258,7 +167,26 @@
(:db effects)))
(is (match? {:method "wakuext_getRevealedAccounts"
:params [community-id "profile-public-key"]}
(-> effects :json-rpc/call first (select-keys [:method :params]))))))))
(-> effects :json-rpc/call first (select-keys [:method :params]))))))
(testing "given there is a pending request"
(let [pub-key "profile-public-key"
community (assoc community :joined false)
db {:communities {community-id community}
:profile/profile {:public-key pub-key}
:communities/my-pending-requests-to-join {community-id [:anything]}}
on-success [:some-event-id]
actual (events/get-revealed-accounts {:db db} [community-id on-success])
expected {:db (assoc-in db
[:communities community-id :fetching-revealed-accounts]
true)
:json-rpc/call [{:method "wakuext_getRevealedAccounts"
:params [community-id pub-key]
:js-response true
:on-success [:communities/get-revealed-accounts-success
community-id on-success]
:on-error fn?}]}]
(is (match? expected actual))))))
(deftest handle-community
(let [community {:id community-id :clock 2}]
@@ -267,24 +195,22 @@
(is (match? community-id
(-> effects :db :communities (get community-id) :id)))
(is (match?
[[:dispatch [:communities/initialize-permission-addresses community-id]]
[:dispatch [:chat.ui/spectate-community community-id]]
[[:dispatch [:chat.ui/spectate-community community-id]]
[:dispatch [:communities/check-permissions-to-join-community community-id]]]
(filter some? (:fx effects))))))
(testing "given a joined community"
(let [community (assoc community :joined true)
effects (events/handle-community {} [community])]
(is (match?
[[:dispatch [:communities/initialize-permission-addresses community-id]]
[:dispatch [:communities/check-permissions-to-join-community community-id]]
[:dispatch [:communities/get-revealed-accounts community-id]]]
[[:dispatch [:communities/check-permissions-to-join-community community-id]]]
(filter some? (:fx effects))))))
(testing "given a community with token-permissions-check"
(let [community (assoc community :token-permissions-check :fake-token-permissions-check)
effects (events/handle-community {} [community])]
(is (match?
[[:dispatch [:communities/initialize-permission-addresses community-id]]
[:dispatch [:chat.ui/spectate-community community-id]]]
[[:dispatch [:chat.ui/spectate-community community-id]]]
(filter some? (:fx effects))))))
(testing "given a community with lower clock"
(let [effects (events/handle-community {:db {:communities {community-id {:clock 3}}}} [community])]
@@ -4,8 +4,6 @@
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(rf/reg-event-fx :communities/check-permissions-to-join-community-success
(fn [{:keys [db]} [community-id based-on-client-selection? result]]
(let [token-permissions-check (cond-> result
@@ -118,41 +116,19 @@
:category-id category-id
:collapse? collapse?})}]}))
(defn request-to-join-with-signatures-and-addresses
[{:keys [db]} [community-id signatures]]
(let [{:keys [airdrop-address selected-permission-addresses]} (get-in db [:communities community-id])]
{:fx [[:json-rpc/call
[{:method "wakuext_requestToJoinCommunity"
:params [{:communityId community-id
:signatures signatures
:addressesToReveal selected-permission-addresses
:airdropAddress airdrop-address}]
:js-response true
:on-success [:communities/requested-to-join]
:on-error [:communities/requested-to-join-error community-id]}]]]}))
(rf/reg-event-fx :communities/request-to-join-with-signatures-and-addresses
request-to-join-with-signatures-and-addresses)
(defn sign-data-with-addresses
[_ [community-id password sign-params]]
{:fx [[:json-rpc/call
[{:method "wakuext_signData"
:params [(map #(assoc % :password password) sign-params)]
:on-success [:communities/request-to-join-with-signatures-and-addresses community-id]
:on-error [:communities/requested-to-join-error community-id]}]]]})
(rf/reg-event-fx :communities/sign-data-with-addresses sign-data-with-addresses)
(defn request-to-join-with-addresses
[{:keys [db]}
[{:keys [community-id password]}]]
(let [pub-key (get-in db [:profile/profile :public-key])
addresses-to-reveal (get-in db [:communities community-id :selected-permission-addresses])]
{:fx [[:json-rpc/call
[{:method "wakuext_generateJoiningCommunityRequestsForSigning"
:params [pub-key community-id addresses-to-reveal]
:on-success [:communities/sign-data-with-addresses community-id password]
:on-error [:communities/requested-to-join-error community-id]}]]]}))
addresses-to-reveal (get-in db [:communities/all-addresses-to-reveal community-id])
airdrop-address (get-in db [:communities/all-airdrop-addresses community-id])]
{:fx [[:effects.community/request-to-join
{:community-id community-id
:password password
:pub-key pub-key
:addresses-to-reveal addresses-to-reveal
:airdrop-address airdrop-address
:on-success [:communities/requested-to-join]
:on-error [:communities/requested-to-join-error community-id]}]]}))
(rf/reg-event-fx :communities/request-to-join-with-addresses request-to-join-with-addresses)
@@ -21,6 +21,13 @@
:align-items :center
:margin-top 20})
(def fetching-placeholder
{:align-items :center
:justify-content :center
:flex 1})
(def fetching-text {:color :red})
(def blur-channel-header
{:position :absolute
:top 100
@@ -7,6 +7,7 @@
[react-native.core :as rn]
[reagent.core :as reagent]
[status-im.common.home.actions.view :as actions]
[status-im.common.not-implemented :as not-implemented]
[status-im.common.scroll-page.style :as scroll-page.style]
[status-im.common.scroll-page.view :as scroll-page]
[status-im.config :as config]
@@ -119,7 +120,7 @@
[id color]
[quo/button
{:on-press (if config/community-accounts-selection-enabled?
#(rf/dispatch [:open-modal :community-account-selection
#(rf/dispatch [:open-modal :community-account-selection-sheet
{:community-id id}])
#(rf/dispatch [:open-modal :community-requests-to-join {:id id}]))
:accessibility-label :show-request-to-join-screen-button
@@ -167,7 +168,7 @@
:padding? true}]
[quo/button
{:on-press (if config/community-accounts-selection-enabled?
#(rf/dispatch [:open-modal :community-account-selection
#(rf/dispatch [:open-modal :community-account-selection-sheet
{:community-id id}])
#(rf/dispatch [:open-modal :community-requests-to-join {:id id}]))
:accessibility-label :join-community-button
@@ -177,7 +178,6 @@
:icon-left (if can-request-access? :i/unlocked :i/locked)}
(i18n/label :t/join-open-community)]])))
(defn- join-community
[{:keys [id joined permissions role-permissions? can-join?] :as community}]
(let [pending? (rf/sub [:communities/my-pending-request-to-join id])
@@ -366,14 +366,28 @@
;; might have been removed.
on-first-channel-height-changed}]]))))
(defn- community-fetching-placeholder
[id]
(let [fetching? (rf/sub [:communities/fetching-community id])]
[rn/view
{:style style/fetching-placeholder
:accessibility-label (if fetching?
:fetching-community-overview
:failed-to-fetch-community-overview)}
[not-implemented/not-implemented
[rn/text
{:style style/fetching-text}
(if fetching?
"Fetching community..."
"Failed to fetch community")]]]))
(defn- community-card-page-view
[id]
(let [{:keys [id joined name images]
(let [{:keys [joined name images]
:as community} (rf/sub [:communities/community id])]
(when community
(when joined
(rf/dispatch [:activity-center.notifications/dismiss-community-overview id]))
[community-scroll-page id joined name images])))
(if community
[community-scroll-page id joined name images]
[community-fetching-placeholder id])))
(defn view
[id]
@@ -1,6 +1,5 @@
(ns status-im.contexts.onboarding.new-to-status.view
(:require
[legacy.status-im.keycard.recovery :as keycard]
[quo.core :as quo]
re-frame.db
[react-native.core :as rn]
@@ -53,7 +52,7 @@
:title (i18n/label :t/use-keycard)
:subtitle (i18n/label :t/use-keycard-subtitle)
:image (resources/get-image :use-keycard)
:on-press #(rf/dispatch [::keycard/recover-with-keycard-pressed])}]]]))
:on-press #(js/alert "TODO: to be implemented")}]]]))
(defn getting-started-doc
[]
@@ -7,7 +7,11 @@
[status-im.contexts.preview.quo.preview :as preview]))
(def descriptor
[{:key :image
[{:key :size
:type :select
:options [{:key :size-24}
{:key :size-20}]}
{:key :image
:type :select
:options [{:key (resources/get-mock-image :bored-ape)
:value "Bored ape"}
@@ -0,0 +1,31 @@
(ns status-im.contexts.preview.quo.community.channel-action
(:require [quo.core :as quo]
[reagent.core :as reagent]
[status-im.contexts.preview.quo.preview :as preview]))
(def descriptor
[{:key :label
:type :text}
{:key :big?
:type :boolean}
{:key :counter-value
:type :number}
{:key :icon
:type :select
:options [{:key :i/muted}
{:key :i/pin}]}
(preview/customization-color-option)
{:key :disabled?
:type :boolean}])
(defn view
[]
(let [state (reagent/atom {:label "Action"
:icon :i/muted
:customization-color :blue
:counter-value nil
:disabled? false
:big? true})]
(fn []
[preview/preview-container {:state state :descriptor descriptor}
[quo/channel-action @state]])))
@@ -8,21 +8,40 @@
[]
[preview/preview-container
[quo/channel-actions
{:actions [{:big? true
:label "Pinned Messages"
:color :blue
:icon :i/pin
:counter-value 0}]}]
{:actions [{:big? true
:label "Pinned Messages"
:customization-color :blue
:icon :i/pin
:counter-value 0}]}]
[rn/view {:height 50}]
[quo/channel-actions
{:actions [{:label "Pinned Messages" :color :blue :icon :i/pin :counter-value 5}
{:label "Mute chat" :color :blue :icon :i/muted}]}]
{:actions [{:label "Pinned Messages"
:customization-color :blue
:icon :i/pin
:counter-value 5}
{:label "Mute chat"
:customization-color :blue
:icon :i/muted}]}]
[rn/view {:height 50}]
[quo/channel-actions
{:actions [{:big? true :label "Pinned Messages" :color :blue :icon :i/pin :counter-value 5}
{:label "Mute chat" :color :blue :icon :i/muted}]}]
{:actions
[{:big? true
:label "Pinned Messages"
:customization-color :blue
:icon :i/pin
:counter-value 5}
{:label "Mute chat"
:customization-color :blue
:icon :i/muted}]}]
[rn/view {:height 50}]
[quo/channel-actions
{:actions [{:label "Pinned Messages" :color :blue :icon :i/pin :counter-value 5}
{:label "Mute chat" :color :blue :icon :i/muted}
{:label "Something else" :color :blue :icon :i/placeholder}]}]])
{:actions [{:label "Pinned Messages"
:customization-color :blue
:icon :i/pin
:counter-value 5}
{:label "Mute chat"
:customization-color :blue
:icon :i/muted}
{:label "Something else"
:customization-color :blue
:icon :i/placeholder}]}]])
@@ -63,6 +63,10 @@
{:key :admin}
{:key :member}]})
(def description-top-descriptor
{:key :description-top-text
:type :text})
(def description-descriptor
{:key :description-text
:type :text})
@@ -73,28 +77,32 @@
(defn view
[]
(let [state (reagent/atom {:actions :two-actions
:description :bottom
:description-text description
:error-message "Error message"
:button-one-label button-one
:button-two-label button-two
:button-one-props {:on-press (button-press 1)
:type :primary}
:button-two-props {:on-press (button-press 2)
:type :grey}
:blur? false
:role :owner
:scroll? false})]
(let [state (reagent/atom {:actions :two-actions
:description :bottom
:description-text description
:description-top-text "Eligible to join as"
:error-message "Error message"
:button-one-label button-one
:button-two-label button-two
:button-one-props {:on-press (button-press 1)
:type :primary}
:button-two-props {:on-press (button-press 2)
:type :grey}
:blur? false
:role :owner
:scroll? false})]
(fn []
[preview/preview-container
{:state state
:descriptor (merge descriptor
(case (:description @state)
:top role-descriptor
:bottom description-descriptor
:top-error error-descriptor
nil))
:descriptor (cond-> descriptor
(= (:description @state) :top)
(conj role-descriptor description-top-descriptor)
(= (:description @state) :bottom)
(conj description-descriptor)
(= (:description @state) :top-error)
(conj error-descriptor))
:blur? (:blur? @state)
:show-blur-background? true
:blur-dark-only? true
@@ -0,0 +1,28 @@
(ns status-im.contexts.preview.quo.foundations.gradients
(:require [quo.foundations.gradients :as quo.gradients]
[reagent.core :as reagent]
[status-im.contexts.preview.quo.preview :as preview]))
(def ^:private descriptor
[{:key :color-index
:type :select
:options [{:key :gradient-1}
{:key :gradient-2}
{:key :gradient-3}
{:key :gradient-4}
{:key :gradient-5}]}])
(defn view
[]
(let [state (reagent/atom {:color-index 1})]
(fn []
[preview/preview-container
{:state state
:descriptor descriptor
:blur? (:blur? @state)
:show-blur-background? (:blur? @state)}
[quo.gradients/view
{:container-style {:align-self :center
:height 200
:width 200}
:color-index (:color-index @state)}]])))
+23 -2
View File
@@ -33,6 +33,8 @@
[status-im.contexts.preview.quo.colors.color :as color]
[status-im.contexts.preview.quo.colors.color-picker :as color-picker]
[status-im.contexts.preview.quo.common :as common]
[status-im.contexts.preview.quo.community.channel-action :as
channel-action]
[status-im.contexts.preview.quo.community.channel-actions :as
channel-actions]
[status-im.contexts.preview.quo.community.community-card-view :as
@@ -66,6 +68,7 @@
[status-im.contexts.preview.quo.dropdowns.network-dropdown :as
network-dropdown]
[status-im.contexts.preview.quo.empty-state.empty-state :as empty-state]
[status-im.contexts.preview.quo.foundations.gradients :as gradients]
[status-im.contexts.preview.quo.foundations.shadows :as shadows]
[status-im.contexts.preview.quo.gradient.gradient-cover :as gradient-cover]
[status-im.contexts.preview.quo.graph.interactive-graph :as
@@ -131,6 +134,7 @@
small-option-card]
[status-im.contexts.preview.quo.password.tips :as tips]
[status-im.contexts.preview.quo.profile.collectible :as collectible]
[status-im.contexts.preview.quo.profile.collectible-list-item :as collectible-list-item]
[status-im.contexts.preview.quo.profile.link-card :as link-card]
[status-im.contexts.preview.quo.profile.profile-card :as profile-card]
[status-im.contexts.preview.quo.profile.select-profile :as select-profile]
@@ -199,7 +203,9 @@
[utils.re-frame :as rf]))
(def screens-categories
{:foundations [{:name :shadows
{:foundations [{:name :gradients
:component gradients/view}
{:name :shadows
:component shadows/view}]
:animated-list [{:name :animated-header-list
:component animated-header-list/mock-screen}]
@@ -260,6 +266,9 @@
{:name :token-gating
:options {:insets {:bottom? true}}
:component token-gating/view}
{:name :channel-action
:options {:insets {:bottom? true}}
:component channel-action/view}
{:name :channel-actions
:options {:insets {:bottom? true}}
:component channel-actions/view}]
@@ -409,6 +418,8 @@
:component tips/view}]
:profile [{:name :collectible
:component collectible/view}
{:name :collectible-list-item
:component collectible-list-item/view}
{:name :link-card
:component link-card/view}
{:name :profile-card
@@ -542,10 +553,20 @@
[]
[:<>
[common/navigation-bar {:title "Quo components preview"}]
[:> Rive
{ ;; :url "https://public.rive.app/community/runtime-files/2195-4346-avatar-pack-use-case.riv"
;; :stateMachineName "avatar"
;; :artboardName "Avatar 1"
:url "https://public.rive.app/community/runtime-files/5965-11570-viking-strike.riv"
:stateMachineName "State Machine 1"
:artboardName "Sword Swing"
:style {:width 400 :height 400}}
]
[rn/scroll-view {:style (style/main)}
(for [category (sort screens-categories)]
^{:key (first category)}
[category-view category])]])
[category-view category])]
])
(def screens
(->> screens-categories

Some files were not shown because too many files have changed in this diff Show More