Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
106eb2acfd | ||
|
|
7948582e46 | ||
|
|
6c5242b3e0 | ||
|
|
60d6a5c3cc | ||
|
|
049822b5bb | ||
|
|
02c7460a24 | ||
|
|
10c6bf7156 | ||
|
|
d0d7310e82 | ||
|
|
219dd7cb46 | ||
|
|
9da0559b15 | ||
|
|
aa7db8b883 | ||
|
|
a06c5fdc02 | ||
|
|
2a515a82ce | ||
|
|
69294b196f | ||
|
|
58606dc87c | ||
|
|
bccf0f8d11 | ||
|
|
aab62dd19e | ||
|
|
fa9645d6dd | ||
|
|
614b03d701 |
+3
-6
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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",
|
||||
|
||||
@@ -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!`.
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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]})))
|
||||
|
||||
@@ -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]}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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]})))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
[]
|
||||
|
||||
@@ -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]}]
|
||||
|
||||
@@ -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])}])]))
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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)])
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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}}]))
|
||||
@@ -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))})]))
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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)})
|
||||
|
||||
@@ -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]]))
|
||||
|
||||
@@ -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}))
|
||||
|
||||
@@ -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])
|
||||
|
||||
@@ -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))}
|
||||
|
||||
@@ -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))]])]))
|
||||
|
||||
@@ -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)
|
||||
|
||||
+99
-1
@@ -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 %)}]})))
|
||||
|
||||
@@ -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)}]])))
|
||||
@@ -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
Reference in New Issue
Block a user