Compare commits

...
Author SHA1 Message Date
yqrashawn 24da99fe45 test: ios Associated Domains Entitlement WIP 2024-03-22 14:49:58 +08:00
Ulises Manuel ad42882c5b Increase debounce timing for fetching routes (#19100) 2024-03-21 11:15:36 -06:00
Jamie Caprani ee35fd52f6 chore(quo): add profile/extended collectible component (#19297) 2024-03-21 08:54:14 -07:00
Andrea Maria Piana fba363d9ea Bump version to 2.27 2024-03-21 15:24:08 +00:00
Alexander 51541f7f0a Fix for "Jump to" button overlapping Logout button on the Profile screen (#19318)
* Fix for "Jump to" button overlapping Logout button on the Profile screen

* Fix for offsets

* Code style

* Fixes
2024-03-21 15:05:49 +01:00
Flavio FraschettiandAjay Sivan 1e37765197 18638- [Communities] Implement Permissions Drawer (#18988)
* Community Permissions Sheet

* Request to join screen: join as role

---------

Co-authored-by: Ajay Sivan <ajayesivan@gmail.com>
2024-03-21 06:18:50 -07:00
Flavio Fraschetti 90913500b4 Fraschetti - Add tests for wallet_getWalletToken (#19210)
- Add tests for wallet_getWalletToken 
- Remove get-main-account 
- Add get-default-address function
- Adapt constants/fixtures for recovered account
2024-03-21 09:29:12 -03:00
yqrashawn 6d74d0396e fix: show pubkey in add contact input when available (#19187) 2024-03-21 19:19:55 +08:00
Ajay Sivan fd24a80904 fix: Long community name not split into two lines (#19223) 2024-03-20 21:28:16 -07:00
Yevheniia Berdnyk ab53450ba8 e2e: changed build name and added wait for session id 2024-03-21 02:16:20 +02:00
Andrea Maria Piana 813d96df10 fix can post
https://github.com/status-im/status-go/compare/f69ee075...894eb575
2024-03-20 22:17:06 +00:00
Brian Sztamfater 6363756c09 fix: unresponsive add watched address screen when entering a multi-chain address (#19185) 2024-03-20 13:58:23 -03:00
Parvesh Monu 5854a473f0 fix duplicate mention (#19203) 2024-03-20 21:31:57 +05:30
Ajay Sivan c2f0060a47 fix: Community admins will review request text is visible even after joining (#19218) 2024-03-20 08:49:24 -07:00
Ajay Sivan 0fdb599d93 fix: unable to swipe b/w activity center tabs (#19033) 2024-03-20 08:37:55 -07:00
Parvesh Monu ef5153f138 fix incorrect unread counter is displayed when a message is removed (#19217) 2024-03-20 20:26:57 +05:30
Brian Sztamfater 463e8a5eec feat: make bridging transactions work after sliding to confirm the transaction (#18986) 2024-03-20 10:07:02 -03:00
Sean Hagstrom 40e6c44b99 fix: revert removal of key in profile settings view (#19329) 2024-03-20 08:35:39 +00:00
Omar Basem fc801213ef Wallet: selecting keypair (#19070)
Wallet: selecting keypair (#19070)
2024-03-19 22:36:08 +04:00
9e5b8b5f9c [#19247] feat: migrate to new contact profile (#19246)
Co-authored-by: Yevheniia Berdnyk <ie.berdnyk@gmail.com>
Co-authored-by: Sean Hagstrom <sean@seanhagstrom.com>
2024-03-19 20:57:58 +03:00
Sean Hagstrom 772efa90d4 fix: reset profiles list translate-x while unmounting (#19315) 2024-03-19 17:41:43 +00:00
Parvesh Monu 8fb42d2503 Improve navigation code (#19274) 2024-03-19 22:12:30 +05:30
Lungu Cristian 2295b01bc9 Fix drawer message according to desings (#19056)
* fix: bottom-sheet's selected-item was not visible

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

* fix: drawer message spacings and removed emojis & identicon

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

* fix: bottom-sheet use-callback dependencies

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

* fix: added :profile/public-key sub

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

* test: added :profile/public-key sub test

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

* fix: spacings & added reactions to message drawer

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

---------

Signed-off-by: Cristian Lungu <lungucristian95@gmail.com>
2024-03-19 16:23:36 +02:00
codemaster 2ee7db9370 feat: add jump-to button in group-detail screen (#19134) 2024-03-19 07:06:06 -07:00
Ibrahem Khalil 27407b9cbb chore: Fix subs leak and fix schema error (#19321) 2024-03-19 14:14:15 +02:00
Flavio Fraschetti 01a881523f JC-Fraschetti/[Wallet] Add fixtures to recovered accounts and refactor wallet_getDerivedAddresses test (#19287)
* chore: fix contract test for wallet/create-derived-addresses and add asynchronous operations using Promesa library
2024-03-19 05:55:38 -03:00
codemaster 3b5afb5d60 feat: show pinned messages bottom sheet in channel home (#19105) 2024-03-18 12:28:47 -07:00
Omar Basem e5cee4b640 Wallet: Derivation Path screen (#19268)
Wallet: Derivation Path screen (#19268)
2024-03-18 20:44:16 +04:00
Icaro MottaandCristian Lungu 7948582e46 Account selection: Implement features related to editing shared addresses (#19177)
* Fix schema error

* Implement feature to edit shared addresses

* fix: show tokens when sharing all future addresses toggled

* fix: eligibility not checked when toggling all addresses

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

This reverts commit 8443a3432e.

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

---------

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

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

* formatting

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

---------

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

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

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

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

* fix: nav buttons are shown without flicker on mount

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

---------

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

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

* 🚧 Save point

* 📑 Use bottom sheet effect properly

* 📝 Can't get title input to work

* 🎨 Design in place

* 🗺️ Add address box and trigger for network prefs

* 💅 Pixel perfect UI and hide save address button

*  Upgrade to screen tech

* 🤚 Undo changes made to color picker during rebase

* 🧰 Fix screens I broke during rebase

* ❄️ Fix json indent

* ⚒️ Implement PR feedback

* ⛏️ Remove unrelated translations

* 🖼️ Remove container to fix margin issue

- Use rn/use-callback instead of defined functions

* 😶‍🌫️ Hide save address button

* 🔨 Fix lint

*  Remove bottom sheet screen updates

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

* feat: added channel-action preview screen

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

* fix: channel-action style prop

* fix: renamed color prop to customization-color

* fix: small button width should be fixed

* fix: removed temp file

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

* Fixes

* Fixes

* Fixes
2024-03-14 10:24:37 +01:00
yqrashawn 614b03d701 fix: duplicate sub key :communities/fetching-community (#18890) 2024-03-14 09:50:06 +08:00
222 changed files with 5289 additions and 2626 deletions
-1
View File
@@ -34,4 +34,3 @@ STICKERS_TEST_ENABLED=1
LOCAL_PAIRING_ENABLED=1
TEST_STATEOFUS=1
FAST_CREATE_COMMUNITY_ENABLED=1
FLAG_NEW_CONTACT_UI_ENABLED=0
+1 -1
View File
@@ -1 +1 @@
1.25.0
2.27.0
+2 -2
View File
@@ -5,8 +5,8 @@ pipeline {
agent { label 'linux' }
triggers {
// Nightly at 2am
cron 'H 2 * * *'
// Nightly at 0am
cron 'H 0 * * *'
}
parameters {
+17 -17
View File
@@ -1,21 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.developer.nfc.readersession.formats</key>
<array>
<string>NDEF</string>
<string>TAG</string>
</array>
<key>aps-environment</key>
<string>development</string>
<key>com.apple.developer.associated-domains</key>
<array>
<string>applinks:status.app</string>
</array>
<key>keychain-access-groups</key>
<array>
<string>$(AppIdentifierPrefix)im.status.ethereum.pr</string>
</array>
</dict>
<dict>
<key>com.apple.developer.nfc.readersession.formats</key>
<array>
<string>NDEF</string>
<string>TAG</string>
</array>
<key>aps-environment</key>
<string>development</string>
<key>com.apple.developer.associated-domains</key>
<array>
<string>applinks:yqrashawn.com?mode=developer</string>
</array>
<key>keychain-access-groups</key>
<array>
<string>$(AppIdentifierPrefix)im.status.ethereum.pr</string>
</array>
</dict>
</plist>
+20 -1
View File
@@ -1,4 +1,5 @@
import { withTiming, runOnJS } from 'react-native-reanimated';
import { useAnimatedReaction, withTiming, runOnJS } from 'react-native-reanimated';
import { useState } from 'react';
export function messagesListOnScroll(distanceFromListTop, chatListScrollY, callback) {
return function (event) {
@@ -12,3 +13,21 @@ export function messagesListOnScroll(distanceFromListTop, chatListScrollY, callb
runOnJS(callback)(layoutHeight, newDistance);
};
}
export function useMessagesScrolledToThreshold(distanceFromListTop, threshold) {
const [scrolledToThreshold, setScrolledToThreshold] = useState(false);
useAnimatedReaction(
function () {
return distanceFromListTop.value <= threshold;
},
function (current) {
if (current !== scrolledToThreshold) {
runOnJS(setScrolledToThreshold)(current);
}
},
[scrolledToThreshold],
);
return scrolledToThreshold;
}
@@ -19,6 +19,13 @@ export function navigationHeaderPosition(distanceFromListTop, isAllLoaded, topBa
});
}
export function navigationButtonsCompleteOpacity(isCalculationComplete) {
return useDerivedValue(function () {
'worklet';
return isCalculationComplete.value ? withTiming(1) : 0;
});
}
export function interpolateNavigationViewOpacity(props) {
return useDerivedValue(function () {
'worklet';
+9 -9
View File
@@ -15,6 +15,7 @@
[native-module.core :as native-module]
[re-frame.core :as re-frame]
[react-native.platform :as platform]
[status-im.common.json-rpc.events :as json-rpc]
[status-im.common.universal-links :as links]
[status-im.constants :as constants]
[status-im.contexts.chat.events :as chat.events]
@@ -654,12 +655,11 @@
stored-bookmarks)]
{:db (assoc db :bookmarks/bookmarks bookmarks)}))
(rf/defn initialize-browser
[_]
{:json-rpc/call
[{:method "wakuext_getBrowsers"
:on-success #(re-frame/dispatch [::initialize-browsers %])}
{:method "browsers_getBookmarks"
:on-success #(re-frame/dispatch [::initialize-bookmarks %])}
{:method "permissions_getDappPermissions"
:on-success #(re-frame/dispatch [::initialize-dapp-permissions %])}]})
(re-frame/reg-fx :browser/initialize-browser
(fn []
(json-rpc/call {:method "wakuext_getBrowsers"
:on-success [::initialize-browsers]})
(json-rpc/call {:method "browsers_getBookmarks"
:on-success [::initialize-bookmarks]})
(json-rpc/call {:method "permissions_getDappPermissions"
:on-success [::initialize-dapp-permissions]})))
@@ -4,7 +4,6 @@
[legacy.status-im.chat.models.loading :as chat.loading]
[legacy.status-im.data-store.messages :as data-store.messages]
[legacy.status-im.utils.deprecated-types :as types]
[re-frame.core :as re-frame]
[react-native.platform :as platform]
[status-im.contexts.chat.messenger.messages.delete-message.events :as delete-message]
[status-im.contexts.chat.messenger.messages.list.events :as message-list]
@@ -135,9 +134,7 @@
message-id (:messageId removed-message)]
(data-store.messages/mark-messages-seen chat-id
[message-id]
#(re-frame/dispatch
[:chat/decrease-unviewed-count
chat-id %3]))))
nil)))
removed-messages)
remove-messages-fx (fn [{:keys [db]}]
{:dispatch [:activity-center.notifications/fetch-unread-count]})]
+6 -8
View File
@@ -4,7 +4,6 @@
[legacy.status-im.bottom-sheet.events :as bottom-sheet]
legacy.status-im.communities.e2e
[re-frame.core :as re-frame]
[status-im.contexts.shell.activity-center.events :as activity-center]
[status-im.navigation.events :as navigation]
[taoensso.timbre :as log]
[utils.re-frame :as rf]))
@@ -84,13 +83,12 @@
(navigation/navigate-back)
(handle-response response-js)))
(rf/defn member-banned
{:events [::member-banned]}
[cofx response-js]
(rf/merge cofx
(bottom-sheet/hide-bottom-sheet-old)
(handle-response response-js)
(activity-center/notifications-fetch-unread-count)))
(re-frame/reg-event-fx ::member-banned
(fn [{:keys [db]} [response-js]]
{:db (assoc db :bottom-sheet/show? false)
:fx [[:dismiss-bottom-sheet-overlay-old]
[:sanitize-messages-and-process-response response-js]
[:activity-center.notifications/fetch-unread-count]]}))
(rf/defn member-ban
{:events [::member-ban]}
+17 -15
View File
@@ -6,7 +6,6 @@
[re-frame.core :as re-frame]
[status-im.contexts.chat.contacts.events :as contacts-store]
[status-im.contexts.chat.messenger.messages.list.events :as message-list]
[status-im.contexts.shell.activity-center.events :as activity-center]
[status-im.navigation.events :as navigation]
[utils.re-frame :as rf]))
@@ -45,21 +44,23 @@
(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
{:events [:contact.ui/block-contact-confirmed]}
[{:keys [db] :as cofx} public-key]
[{:keys [db] :as cofx} public-key
{:keys [handle-navigation?]
:or {handle-navigation? true}}]
(let [contact (-> (contact.db/public-key->contact
(:contacts/contacts db)
public-key)
@@ -76,9 +77,10 @@
(re-frame/dispatch [:sanitize-messages-and-process-response block-contact])
(re-frame/dispatch [:hide-popover])))
;; reset navigation to avoid going back to non existing one to one chat
(if from-one-to-one-chat?
(navigation/pop-to-root :shell-stack)
(navigation/navigate-back)))))
(when handle-navigation?
(if from-one-to-one-chat?
(navigation/pop-to-root :shell-stack)
(navigation/navigate-back))))))
(rf/defn contact-unblocked
{:events [:contacts/unblocked]}
@@ -44,6 +44,7 @@
:line-count nil
:links nil
:text nil}
:bridge-message nil
:outgoing false}
:message nil
:reply-message {:quoted-message nil
@@ -61,6 +62,7 @@
:line-count nil
:links nil
:text nil}
:bridge-message nil
:outgoing false}}
(-> raw-notification
store/<-rpc
+10 -9
View File
@@ -3,9 +3,10 @@
[clojure.set :as set]
[legacy.status-im.data-store.messages :as messages]
[legacy.status-im.utils.deprecated-types :as types]
[re-frame.core :as re-frame]
[status-im.common.json-rpc.events :as json-rpc]
[status-im.constants :as constants]
[taoensso.timbre :as log]
[utils.re-frame :as rf]))
[taoensso.timbre :as log]))
(defn rpc->type
[{:keys [chat-type name] :as chat}]
@@ -117,10 +118,10 @@
rpc->type
unmarshal-members))
(rf/defn fetch-chats-preview
[_ {:keys [on-success]}]
{:json-rpc/call [{:method "wakuext_chatsPreview"
:params []
:js-response true
:on-success #(on-success ^js %)
:on-error #(log/error "failed to fetch chats" 0 -1 %)}]})
(re-frame/reg-fx :fetch-chats-preview
(fn [{:keys [on-success]}]
(json-rpc/call {:method "wakuext_chatsPreview"
:params []
:js-response true
:on-success #(on-success ^js %)
:on-error #(log/error "failed to fetch chats" 0 -1 %)})))
@@ -28,8 +28,9 @@
(name k)
(-> v
(assoc :token-gated? (:tokenGated v)
:can-post? (:canPost v))
(dissoc :canPost :tokenGated)
:can-post? (:canPost v)
:can-view? (:canView v))
(dissoc :canPost :tokenGated :canView)
(update :members walk/stringify-keys))))
{}
chats))
@@ -82,7 +82,13 @@
:albumImagesCount :album-images-count
:displayName :display-name
:linkPreviews :link-previews
:statusLinkPreviews :status-link-previews})
:statusLinkPreviews :status-link-previews
:bridgeMessage :bridge-message})
(update :bridge-message
set/rename-keys
{:bridgeName :bridge-name
:userName :user-name
:userAvatar :user-avatar})
(update :link-previews #(map <-link-preview-rpc %))
(update :status-link-previews #(map <-status-link-previews-rpc %))
(update :quoted-message
@@ -21,6 +21,7 @@
:image nil
:response-to "a"
:links nil}
:bridge-message nil
:whisper-timestamp 1
:contact-verification-state 1
:contact-request-state 2
@@ -2,6 +2,8 @@
(:require
[clojure.set :as set]
[clojure.walk :as walk]
[re-frame.core :as re-frame]
[status-im.common.json-rpc.events :as json-rpc]
[taoensso.timbre :as log]
[utils.re-frame :as rf]))
@@ -32,11 +34,11 @@
:on-success #()
:on-error #()}]})
(rf/defn fetch-switcher-cards-rpc
[_]
{:json-rpc/call [{:method "wakuext_switcherCards"
:params []
:on-success #(rf/dispatch
[:shell/switcher-cards-loaded
(:switcherCards ^js %)])
:on-error #(log/error "Failed to fetch switcher cards" %)}]})
(re-frame/reg-fx :switcher-cards/fetch
(fn []
(json-rpc/call {:method "wakuext_switcherCards"
:params []
:on-success #(rf/dispatch
[:shell/switcher-cards-loaded
(:switcherCards ^js %)])
:on-error #(log/error "Failed to fetch switcher cards" %)})))
@@ -2,8 +2,8 @@
(:require
[clojure.set :as set]
[re-frame.core :as re-frame]
[taoensso.timbre :as log]
[utils.re-frame :as rf]))
[status-im.common.json-rpc.events :as json-rpc]
[taoensso.timbre :as log]))
(defn <-rpc
[visibility-status-update]
@@ -18,13 +18,13 @@
{:current-user-status :current-user-visibility-status})
(update :current-user-visibility-status <-rpc)))
(rf/defn fetch-visibility-status-updates-rpc
[_]
{:json-rpc/call [{:method "wakuext_statusUpdates"
:params []
:on-success #(re-frame/dispatch
[:visibility-status-updates/visibility-status-updates-loaded
(:statusUpdates ^js %)])
:on-error #(log/error
"failed to fetch visibility-status-updates"
%)}]})
(re-frame/reg-fx :visibility-status-updates/fetch
(fn []
(json-rpc/call {:method "wakuext_statusUpdates"
:params []
:on-success #(re-frame/dispatch
[:visibility-status-updates/visibility-status-updates-loaded
(:statusUpdates ^js %)])
:on-error #(log/error
"failed to fetch visibility-status-updates"
%)})))
@@ -239,7 +239,7 @@
(rf/defn tx-history-end-reached
[{:keys [db] :as cofx} address]
(let [syncing-allowed? (utils.mobile-sync/syncing-allowed? cofx)]
(let [syncing-allowed? (utils.mobile-sync/syncing-allowed? db)]
{:db (assoc-in db
[:wallet-legacy :fetching address :all-fetched?]
(if syncing-allowed?
@@ -327,7 +327,7 @@
{:chain-tokens (:wallet-legacy/all-tokens db)
:addresses [address]
:before-block min-known-block
:fetch-more? (utils.mobile-sync/syncing-allowed? cofx)
:fetch-more? (utils.mobile-sync/syncing-allowed? db)
;; Transfers are requested before and including `min-known-block` because there is no
;; guarantee that all transfers from that block are shown already. To make sure that we fetch
;; the whole `default-transfers-limit` of transfers the number of transfers already received
+5
View File
@@ -8,11 +8,16 @@
legacy.status-im.chat.models.loading
legacy.status-im.contact.block
legacy.status-im.currency.core
legacy.status-im.data-store.chats
legacy.status-im.data-store.switcher-cards
legacy.status-im.data-store.visibility-status-updates
legacy.status-im.fleet.core
legacy.status-im.group-chats.core
[legacy.status-im.keycard.core :as keycard]
legacy.status-im.log-level.core
legacy.status-im.mailserver.constants
[legacy.status-im.mailserver.core :as mailserver]
legacy.status-im.mobile-sync-settings.core
legacy.status-im.multiaccounts.login.core
legacy.status-im.multiaccounts.logout.core
[legacy.status-im.multiaccounts.model :as multiaccounts.model]
+12 -15
View File
@@ -6,9 +6,9 @@
[legacy.status-im.data-store.invitations :as data-store.invitations]
[oops.core :as oops]
[re-frame.core :as re-frame]
[status-im.common.json-rpc.events :as json-rpc]
[status-im.constants :as constants]
[status-im.contexts.chat.events :as chat.events]
[status-im.contexts.shell.activity-center.events :as activity-center]
[status-im.navigation.events :as navigation]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
@@ -19,15 +19,13 @@
(when (get-in cofx [:db :chats chat-id])
(chat.events/pop-to-root-and-navigate-to-chat cofx chat-id nil)))
(rf/defn handle-chat-removed
{:events [:chat-removed]}
[cofx response chat-id]
(rf/merge cofx
{:db (dissoc (:db cofx) :current-chat-id)
:dispatch-n [[:shell/close-switcher-card chat-id]
[:sanitize-messages-and-process-response response]
[:pop-to-root :shell-stack]]}
(activity-center/notifications-fetch-unread-count)))
(re-frame/reg-event-fx :chat-removed
(fn [{:keys [db]} [response chat-id]]
{:db (dissoc db :current-chat-id)
:fx [[:dispatch [:shell/close-switcher-card chat-id]]
[:dispatch [:sanitize-messages-and-process-response response]]
[:dispatch [:pop-to-root :shell-stack]]
[:activity-center.notifications/fetch-unread-count]]}))
(rf/defn handle-chat-update
{:events [:chat-updated]}
@@ -264,8 +262,7 @@
{}
invitations))})
(rf/defn get-group-chat-invitations
[_]
{:json-rpc/call
[{:method "wakuext_getGroupChatInvitations"
:on-success #(re-frame/dispatch [::initialize-invitations %])}]})
(re-frame/reg-fx :group-chats/get-group-chat-invitations
(fn []
(json-rpc/call {:method "wakuext_getGroupChatInvitations"
:on-success [::initialize-invitations]})))
+26 -17
View File
@@ -5,6 +5,7 @@
[legacy.status-im.node.core :as node]
[legacy.status-im.utils.mobile-sync :as mobile-network-utils]
[re-frame.core :as re-frame]
[status-im.common.json-rpc.events :as json-rpc]
[status-im.navigation.events :as navigation]
[taoensso.timbre :as log]
[utils.i18n :as i18n]
@@ -61,7 +62,7 @@
(dissoc :mailserver/current-request :mailserver/fetching-gaps-in-progress))})
(defn fetch-use-mailservers?
[{:keys [db]}]
[db]
(get-in db [:profile/profile :use-mailservers?]))
(defonce showing-connection-error-popup? (atom false))
@@ -117,24 +118,32 @@
[{:keys [db] :as cofx}]
{:db (dissoc db :mailserver/current-request)})
(defn needs-to-fetch-historic-messages?
[db]
(and
(:messenger/started? db)
(mobile-network-utils/syncing-allowed? db)
(fetch-use-mailservers? db)
(not (:mailserver/current-request db))))
(rf/defn process-next-messages-request
{:events [::request-messages]}
[{:keys [db now] :as cofx}]
(when (and
(:messenger/started? db)
(mobile-network-utils/syncing-allowed? cofx)
(fetch-use-mailservers? cofx)
(not (:mailserver/current-request db)))
{:db (assoc db :mailserver/current-request true)
:json-rpc/call [{:method "wakuext_requestAllHistoricMessagesWithRetries"
:params [false]
:js-response true
:on-success #(do
(log/info "fetched historical messages")
(re-frame/dispatch [::request-success %]))
:on-error #(do
(log/error "failed retrieve historical messages" %)
(re-frame/dispatch [::request-error]))}]}))
[{:keys [db]}]
(when (needs-to-fetch-historic-messages? db)
{:db (assoc db :mailserver/current-request true)
:mailserver/request-all-historic-messages nil}))
(re-frame/reg-fx :mailserver/request-all-historic-messages
(fn []
(json-rpc/call {:method "wakuext_requestAllHistoricMessagesWithRetries"
:params [false]
:js-response true
:on-success #(do
(log/info "fetched historical messages")
(re-frame/dispatch [::request-success %]))
:on-error #(do
(log/error "failed retrieve historical messages" %)
(re-frame/dispatch [::request-error]))})))
(rf/defn handle-mailserver-changed
[{:keys [db] :as cofx} ms]
@@ -5,7 +5,7 @@
[legacy.status-im.multiaccounts.model :as multiaccounts.model]
[legacy.status-im.multiaccounts.update.core :as multiaccounts.update]
[legacy.status-im.utils.mobile-sync :as utils]
[status-im.contexts.chat.home.add-new-contact.events :as add-new-contact]
[re-frame.core :as re-frame]
[status-im.navigation.events :as navigation]
[taoensso.timbre :as log]
[utils.re-frame :as rf]))
@@ -18,27 +18,24 @@
(or (nil? remember-choice?)
remember-choice?))}))
(rf/defn on-network-status-change
[{:keys [db] :as cofx}]
(let [initialized? (get db :network-status/initialized?)
logged-in? (multiaccounts.model/logged-in? db)
{:keys [remember-syncing-choice?]} (:profile/profile db)]
(apply
rf/merge
cofx
{:db (assoc db :network-status/initialized? true)}
(cond
;; NOTE(rasom): When we log into account on-network-status-change is
;; dispatched, but that doesn't mean there was a status change, thus
;; no reason to restart wallet.
(and logged-in? initialized?)
[(mailserver/process-next-messages-request)
(bottom-sheet/hide-bottom-sheet-old)
#(add-new-contact/set-new-identity-reconnected %)]
logged-in?
[(mailserver/process-next-messages-request)
(bottom-sheet/hide-bottom-sheet-old)]))))
(re-frame/reg-event-fx :mobile-network/on-network-status-change
(fn [{:keys [db]}]
(let [previously-initialized? (get db :network-status/initialized?)
logged-in? (multiaccounts.model/logged-in? db)
fetch-historic-messages? (mailserver/needs-to-fetch-historic-messages? db)]
(if logged-in?
{:db (cond-> (-> db
(assoc :network-status/initialized? true)
(assoc :bottom-sheet/show? false))
fetch-historic-messages?
(assoc :mailserver/current-request true))
:fx [(when fetch-historic-messages?
[:mailserver/request-all-historic-messages])
[:dismiss-bottom-sheet-overlay-old]
(when previously-initialized?
(let [new-identity-input (get-in db [:contacts/new-identity :input])]
[:dispatch [:contacts/set-new-identity {:input new-identity-input}]]))]}
{:db (assoc db :network-status/initialized? true)}))))
(defn apply-settings
([sync?] (apply-settings sync? :default))
@@ -28,7 +28,8 @@
[{:keys [db] :as cofx} {:keys [auth-method logout?]}]
(let [key-uid (get-in db [:profile/profile :key-uid])]
(rf/merge cofx
{:effects.shell/reset-state nil
{:set-root :progress
:effects.shell/reset-state nil
:hide-popover nil
::logout nil
:profile.settings/webview-debug-changed false
+4 -5
View File
@@ -1,7 +1,6 @@
(ns legacy.status-im.network.net-info
(:require
["@react-native-community/netinfo" :default net-info]
[legacy.status-im.mobile-sync-settings.core :as mobile-network]
[native-module.core :as native-module]
[re-frame.core :as re-frame]
[taoensso.timbre :as log]
@@ -13,11 +12,11 @@
{:db (assoc db :network-status (if is-connected? :online :offline))}))
(rf/defn change-network-type
[{:keys [db] :as cofx} old-network-type network-type expensive?]
[{:keys [db] :as cofx} network-type expensive?]
(rf/merge cofx
{:db (assoc db :network/type network-type)
:network/notify-status-go [network-type expensive?]}
(mobile-network/on-network-status-change)))
:network/notify-status-go [network-type expensive?]
:dispatch [:mobile-network/on-network-status-change]}))
(rf/defn handle-network-info-change
{:events [::network-info-changed]}
@@ -37,7 +36,7 @@
(when-not status-changed?
(change-network-status isConnected))
(when-not type-changed?
(change-network-type old-network-type type (:is-connection-expensive details))))))
(change-network-type type (:is-connection-expensive details))))))
(defn add-net-info-listener
[]
+16
View File
@@ -2,6 +2,7 @@
(:require
[legacy.status-im.utils.utils :as utils]
[re-frame.core :as re-frame]
[status-im.common.json-rpc.events :as json-rpc]
[status-im.constants :as constants]
[utils.ethereum.chain :as chain]
[utils.re-frame :as rf]))
@@ -22,6 +23,21 @@
:params [(chain/chain-id db) id]
:on-success #()}]}))
(re-frame/reg-fx :stickers/load-packs
(fn [chain-id]
(json-rpc/call {:method "stickers_market"
:params [chain-id]
:on-success [:stickers/stickers-market-success]})
(json-rpc/call {:method "stickers_installed"
:params []
:on-success [:stickers/stickers-installed-success]})
(json-rpc/call {:method "stickers_pending"
:params []
:on-success [:stickers/stickers-pending-success]})
(json-rpc/call {:method "stickers_recent"
:params []
:on-success [:stickers/stickers-recent-success]})))
(rf/defn load-packs
{:events [:stickers/load-packs]}
[{:keys [db]}]
+1 -1
View File
@@ -61,7 +61,7 @@
(re-frame/reg-sub
:mailserver/use-status-nodes?
(fn [db _]
(boolean (mailserver/fetch-use-mailservers? {:db db}))))
(boolean (mailserver/fetch-use-mailservers? db))))
(re-frame/reg-sub
:mailserver.edit/validation-errors
-1
View File
@@ -22,7 +22,6 @@
(reg-root-key-sub :peers-count :peers-count)
(reg-root-key-sub :peers-summary :peers-summary)
(reg-root-key-sub :web3-node-version :web3-node-version)
(reg-root-key-sub :alert-banners :alert-banners)
;;keycard
(reg-root-key-sub :keycard :keycard)
@@ -21,7 +21,7 @@
{:active (= value id)
:accessory :radio
:title (get titles id)
:on-press #(re-frame/dispatch [:profile.settings/update-value :default-sync-period id])}])
:on-press #(re-frame/dispatch [:profile.settings/profile-update :default-sync-period id])}])
(views/defview default-sync-period-settings
[]
@@ -111,7 +111,7 @@
:subtitle (i18n/label :t/webview-camera-permission-requests-subtitle)
:subtitle-max-lines 2
:on-press #(re-frame/dispatch
[:profile.settings/update-value
[:profile.settings/profile-update
:webview-allow-permission-requests?
((complement boolean) webview-allow-permission-requests?)])}])
[separator]
@@ -169,8 +169,7 @@
{:active (= value id)
:accessory :radio
:title (get titles id)
:on-press #(re-frame/dispatch [:profile.settings/update-value :profile-pictures-visibility
id])}])
:on-press #(re-frame/dispatch [:profile.settings/profile-update :profile-pictures-visibility id])}])
(views/defview profile-pic
[]
@@ -51,4 +51,4 @@
:icon :main-icons/delete
:theme :accent
:title (i18n/label :t/profile-pic-remove)
:on-press #(re-frame/dispatch [:profile.settings/delete-profile-picture nil])}])]))
:on-press #(re-frame/dispatch [:profile.settings/delete-profile-picture])}])]))
+5 -5
View File
@@ -10,6 +10,7 @@
[re-frame.core :as re-frame]
[react-native.mail :as react-native-mail]
[react-native.platform :as platform]
[status-im.common.json-rpc.events :as json-rpc]
[status-im.common.log :as log]
[status-im.config :as config]
[utils.datetime :as datetime]
@@ -31,11 +32,10 @@
[{:keys [db]} node-version]
{:db (assoc db :web3-node-version node-version)})
(rf/defn initialize-web3-client-version
{:events [:logging/initialize-web3-client-version]}
[_]
{:json-rpc/call [{:method "web3_clientVersion"
:on-success #(re-frame/dispatch [:logging/store-web3-client-version %])}]})
(re-frame/reg-fx :logging/initialize-web3-client-version
(fn []
(json-rpc/call {:method "web3_clientVersion"
:on-success [:logging/store-web3-client-version]})))
(defn extract-url-components
[address]
+1 -1
View File
@@ -5,7 +5,7 @@
(= network-type "cellular"))
(defn syncing-allowed?
[{:keys [db]}]
[db]
(let [network (:network/type db)
{:keys [syncing-on-mobile-network?]} (:profile/profile db)]
(or (= network "wifi")
@@ -2,10 +2,17 @@
(:require
[quo.foundations.colors :as colors]))
(defn- get-dimensions
[size]
(case size
:size-24 24
:size-20 20
nil))
(defn collection-avatar
[theme]
{:width 24
:height 24
[theme size]
{:width (get-dimensions size)
:height (get-dimensions size)
:border-width 1
:border-color (colors/theme-colors colors/neutral-80-opa-10 colors/white-opa-10 theme)
:border-radius 6})
@@ -9,10 +9,10 @@
:image - collection image
:theme - keyword -> :light/:dark"
[{:keys [image theme]}]
[{:keys [image theme size] :or {size :size-24}}]
[fast-image/fast-image
{:accessibility-label :collection-avatar
:source image
:style (style/collection-avatar theme)}])
:style (style/collection-avatar theme size)}])
(def view (quo.theme/with-theme view-internal))
@@ -0,0 +1,23 @@
(ns quo.components.community.channel-action.style
(:require
[quo.foundations.colors :as colors]))
(defn channel-action-container
[{:keys [big? disabled?]}]
(cond-> {}
disabled? (assoc :opacity 0.3)
big? (assoc :flex-grow 1)
(not big?) (assoc :width 104)))
(defn channel-action
[{:keys [color pressed? theme]}]
{:height 102
:padding 12
:border-radius 16
:background-color (colors/resolve-color color theme (if pressed? 20 10))
:justify-content :space-between})
(def channel-action-row
{:flex-direction :row
:justify-content :space-between
:align-items :center})
@@ -0,0 +1,39 @@
(ns quo.components.community.channel-action.view
(:require
[quo.components.community.channel-action.style :as style]
[quo.components.counter.counter.view :as counter]
[quo.components.icon :as icons]
[quo.components.markdown.text :as text]
[quo.theme]
[react-native.core :as rn]))
(defn view
[{:keys [big? customization-color label counter-value icon on-press accessibility-label disabled?]}]
(let [theme (quo.theme/use-theme-value)
[pressed? set-pressed] (rn/use-state false)
on-press-in (rn/use-callback #(set-pressed true))
on-press-out (rn/use-callback #(set-pressed false))]
[rn/view
{:style (style/channel-action-container
{:big? big?
:disabled? disabled?})}
[rn/pressable
(cond-> {:style (style/channel-action
{:big? big?
:color customization-color
:pressed? pressed?
:theme theme
:disabled? disabled?})
:accessibility-label accessibility-label}
(not disabled?) (assoc :on-press on-press
:on-press-in on-press-in
:on-press-out on-press-out))
[rn/view {:style style/channel-action-row}
[icons/icon icon]
(when counter-value
[counter/view {:type :secondary} counter-value])]
[text/text
{:size :paragraph-1
:weight :medium
:number-of-lines 2}
label]]]))
@@ -1,32 +0,0 @@
(ns quo.components.community.channel-actions
(:require
[quo.components.community.style :as style]
[quo.components.counter.counter.view :as counter]
[quo.components.icon :as icons]
[quo.components.markdown.text :as text]
[react-native.core :as rn]))
(defn channel-action
[{:keys [big? color label counter-value icon on-press accessibility-label]}]
[rn/touchable-opacity
{:on-press on-press
:style (style/channel-action-touch big?)
:accessibility-label accessibility-label}
[rn/view {:style (style/channel-action color)}
[rn/view {:style style/channel-action-row}
[icons/icon icon]
(when counter-value
[counter/view {:type :secondary} counter-value])]
[text/text {:size :paragraph-1 :weight :medium :number-of-lines 2} label]]])
(defn channel-actions
[{:keys [container-style actions]}]
[rn/view {:style (assoc container-style :flex-direction :row)}
(map-indexed
(fn [index action]
^{:key index}
[:<>
[channel-action action]
(when (not= action (last actions))
[rn/view {:width 16}])])
actions)])
@@ -0,0 +1,16 @@
(ns quo.components.community.channel-actions.view
(:require
[quo.components.community.channel-action.view :as channel-action]
[react-native.core :as rn]))
(defn view
[{:keys [container-style actions]}]
[rn/view {:style (assoc container-style :flex-direction :row)}
(map-indexed
(fn [index action]
^{:key index}
[:<>
[channel-action/view action]
(when (not= action (last actions))
[rn/view {:width 16}])])
actions)])
-18
View File
@@ -133,24 +133,6 @@
colors/neutral-80
theme)})
(defn channel-action-touch
[big?]
{:flex 1
:max-width (if big? 216 104)})
(defn channel-action
[color]
{:padding 12
:height 102
:border-radius 16
:background-color (colors/custom-color color 50 10)
:justify-content :space-between})
(def channel-action-row
{:flex-direction :row
:justify-content :space-between
:align-items :center})
(defn loading-card
[width theme]
(merge
@@ -11,6 +11,7 @@
[:catn
[:props
[:map {:closed true}
[:container-style {:optional true} [:maybe :map]]
[:value {:optional true} [:maybe [:or :string :int]]]
[:status {:optional true} [:maybe :keyword]]
[:size {:optional true} [:maybe [:enum :size-32 :size-24]]]
@@ -19,7 +20,7 @@
:any])
(defn- view-internal
[{:keys [value accessibility-label]
[{:keys [value accessibility-label container-style]
:as props}]
(let [default-props {:status :default
:size :size-32}
@@ -27,7 +28,7 @@
[rn/view
{:accessible true
:accessibility-label (or accessibility-label :collectible-counter)
:style (style/container props)}
:style (merge (style/container props) container-style)}
[text/text
{:weight :medium
:size (style/get-text-size props)
@@ -58,14 +58,15 @@
:on-press on-press}
[rn/view
{:style (style/row-container sub-label)}
[rn/view
{:accessibility-label :left-icon-for-action
:accessible true
:style (style/left-icon sub-label)}
[icon/icon icon
{:color (or icon-color (get-icon-color danger? theme))
:no-color no-icon-color?
:size 20}]]
(when icon
[rn/view
{:accessibility-label :left-icon-for-action
:accessible true
:style (style/left-icon sub-label)}
[icon/icon icon
{:color (or icon-color (get-icon-color danger? theme))
:no-color no-icon-color?
:size 20}]])
[rn/view
{:style style/text-container}
[text/text
@@ -59,4 +59,15 @@
:button-one-label "Request to join"}])
(h/is-truthy (h/get-by-text "Eligible to join as"))
(h/is-truthy (h/get-by-text "Admin"))
(h/is-truthy (h/get-by-text "Request to join")))
(h/test "render with top description with custom text & 1 action"
(render [bottom-actions/view
{:description :top
:role :admin
:actions :one-action
:description-top-text "You'll be an"
:button-one-label "Request to join"}])
(h/is-truthy (h/get-by-text "You'll be an"))
(h/is-truthy (h/get-by-text "Admin"))
(h/is-truthy (h/get-by-text "Request to join"))))
@@ -19,6 +19,7 @@
[:actions [:maybe [:enum :one-action :two-actions]]]
[:description {:optional true} [:maybe [:enum :top :bottom :top-error]]]
[:description-text {:optional true} [:maybe :string]]
[:description-top-text {:optional true} [:maybe :string]]
[:error-message {:optional true} [:maybe :string]]
[:role {:optional true} [:maybe [:enum :admin :member :token-master :owner]]]
[:button-one-label {:optional true} [:maybe :string]]
@@ -38,8 +39,8 @@
:owner :i/crown})
(defn- view-internal
[{:keys [actions description description-text error-message role button-one-label button-two-label
blur? button-one-props button-two-props theme scroll? container-style]}]
[{:keys [actions description description-text description-top-text error-message role button-one-label
button-two-label blur? button-one-props button-two-props theme scroll? container-style]}]
[rn/view
{:style (merge (style/container scroll? blur? theme) container-style)}
(when (= description :top-error)
@@ -54,12 +55,11 @@
error-message]])
(when (and (= description :top) role)
[rn/view
{:style style/description-top}
[rn/view {:style style/description-top}
[text/text
{:size :paragraph-2
:style (style/description-top-text scroll? blur? theme)}
(i18n/label :t/eligible-to-join-as)]
(or description-top-text (i18n/label :t/eligible-to-join-as))]
[context-tag/view
{:type :icon
:size 24
@@ -76,12 +76,12 @@
:blur? overflow-label blur?}
items preview list items (only 4 items is required for preview)
"
[{:keys [type size number blur?]} items]
[{:keys [type size number blur? container-style]} items]
(let [size-key (if (contains? properties/sizes size) size :size-24)
number (or number (count items))
border-type (properties/border-type type)
margin-left (get-in properties/sizes [size-key :margin-left])]
[rn/view {:style {:flex-direction :row}}
[rn/view {:style (assoc container-style :flex-direction :row)}
(for [index (range (if (> number 4) 3 number))]
^{:key (str index number)}
[list-item
+4 -3
View File
@@ -18,9 +18,9 @@
:align-items :center})
(defn action-icon
[{:keys [type on-press on-check disabled? checked?]} theme]
[{:keys [type on-press on-check disabled? checked?]} customization-color theme]
[rn/touchable-opacity
{:on-press (when on-press on-press)}
{:on-press on-press}
(case type
:options
[icons/icon :i/options
@@ -30,6 +30,7 @@
[selectors/view
{:type :checkbox
:checked? checked?
:customization-color customization-color
:accessibility-label :user-list-toggle-check
:disabled? disabled?
:on-change (when on-check on-check)}]
@@ -68,4 +69,4 @@
:style {:color (colors/theme-colors colors/neutral-50 colors/neutral-40)}}
short-chat-key])]
(when accessory
[action-icon accessory theme])]])
[action-icon accessory customization-color theme])]])
@@ -0,0 +1,116 @@
(ns quo.components.profile.collectible-list-item.component-spec
(:require
[quo.components.profile.collectible-list-item.view :as collectible-list-item]
[test-helpers.component :as h]))
(h/describe "Profile/ collectible list item tests"
(h/describe "type card"
(h/test "Renders default and on press fires"
(let [on-press (h/mock-fn)]
(h/render-with-theme-provider
[collectible-list-item/view
{:type :card
:on-press on-press}])
(h/fire-event :press (h/get-by-label-text :collectible-list-item))
(h/was-called on-press)))
(h/test "Renders loading and on press fires"
(let [on-press (h/mock-fn)]
(h/render-with-theme-provider
[collectible-list-item/view
{:type :card
:status :loading
:on-press on-press}])
(h/fire-event :press (h/get-by-label-text :collectible-list-item))
(h/was-not-called on-press)
(h/is-truthy (h/get-by-label-text :gradient-overlay))))
(h/test "Renders counter"
(h/render-with-theme-provider
[collectible-list-item/view
{:type :card
:counter "x500"}])
(h/is-truthy (h/get-by-text "x500")))
(h/test "Renders counter and collectible name"
(h/render-with-theme-provider
[collectible-list-item/view
{:type :card
:collectible-name "Doodle #6822"
:counter "x500"}])
(h/is-truthy (h/get-by-text "x500"))
(h/is-truthy (h/get-by-text "Doodle #6822")))
(h/test "Renders status cant-fetch"
(h/render-with-theme-provider
[collectible-list-item/view
{:type :card
:status :cant-fetch}])
(h/is-truthy (h/get-by-translation-text :t/cant-fetch-info)))
(h/test "Renders status unsupported"
(h/render-with-theme-provider
[collectible-list-item/view
{:type :card
:status :unsupported}])
(h/is-truthy (h/get-by-translation-text :t/unsupported-file)))
(h/test "Renders status unsupported and counter"
(h/render-with-theme-provider
[collectible-list-item/view
{:type :card
:status :unsupported
:counter "x500"}])
(h/is-truthy (h/get-by-text "x500"))
(h/is-truthy (h/get-by-translation-text :t/unsupported-file))))
(h/describe "type image"
(h/test "Renders default and on press fires"
(let [on-press (h/mock-fn)]
(h/render-with-theme-provider
[collectible-list-item/view
{:type :image
:on-press on-press}])
(h/fire-event :press (h/get-by-label-text :collectible-list-item))
(h/was-called on-press)))
(h/test "Renders loading and on press fires"
(let [on-press (h/mock-fn)]
(h/render-with-theme-provider
[collectible-list-item/view
{:type :image
:status :loading
:on-press on-press}])
(h/fire-event :press (h/get-by-label-text :collectible-list-item))
(h/was-not-called on-press)
(h/is-truthy (h/get-by-label-text :gradient-overlay))))
(h/test "Renders counter"
(h/render-with-theme-provider
[collectible-list-item/view
{:type :image
:counter "x500"}])
(h/is-truthy (h/get-by-text "x500")))
(h/test "Renders status cant-fetch"
(h/render-with-theme-provider
[collectible-list-item/view
{:type :image
:status :cant-fetch}])
(h/is-truthy (h/get-by-translation-text :t/cant-fetch-info)))
(h/test "Renders status unsupported"
(h/render-with-theme-provider
[collectible-list-item/view
{:type :image
:status :unsupported}])
(h/is-truthy (h/get-by-translation-text :t/unsupported-file)))
(h/test "Renders status unsupported and counter"
(h/render-with-theme-provider
[collectible-list-item/view
{:type :image
:status :unsupported
:counter "x500"}])
(h/get-by-text "x500")
(h/is-truthy (h/get-by-translation-text :t/unsupported-file)))))
@@ -0,0 +1,90 @@
(ns quo.components.profile.collectible-list-item.style
(:require [quo.foundations.colors :as colors]
[quo.foundations.shadows :as shadows]))
(def container-border-radius 12)
(def card-image-padding-vertical 3)
(def card-image-padding-horizontal 3)
(defn fallback
[{:keys [theme]}]
{:background-color (colors/theme-colors colors/neutral-2_5 colors/neutral-90 theme)
:border-style :dashed
:border-color (colors/theme-colors colors/neutral-20 colors/neutral-80 theme)
:border-width 1
:border-radius container-border-radius
:width "100%"
:aspect-ratio 1
:align-items :center
:justify-content :center})
(def collectible-counter
{:position :absolute
:top 12
:right 12})
(def avatar
{:position :absolute
:bottom 12
:left 12})
(def container
{:flex 1})
(defn card-view-container
[theme]
(merge
{:background-color (colors/theme-colors colors/white colors/neutral-95 theme)
:padding-top card-image-padding-vertical
:padding-left card-image-padding-horizontal
:padding-right card-image-padding-horizontal
:padding-bottom card-image-padding-vertical
:border-radius 14
:border-width 1
:border-color (colors/theme-colors colors/neutral-10 colors/neutral-80 theme)}
(shadows/get 2)))
(def image
{:width "100%"
:flex 1
:border-radius container-border-radius})
(def card-details-container
{:flex-direction :row
:height 27
:margin-top 3
:margin-bottom 2
:align-items :center
:padding-left 8
:padding-right 0
:padding-top 4})
(def card-detail-text
{:flex 1})
(def image-view-container
{:aspect-ratio 1
:border-radius container-border-radius})
(defn loading-square
[theme]
{:height 20
:width 20
:border-radius 6
:align-self :center
:background-color (colors/theme-colors colors/neutral-5 colors/neutral-90 theme)})
(defn loading-message
[theme]
{:height 14
:width 72
:margin-left 8
:border-radius 6
:align-self :center
:background-color (colors/theme-colors colors/neutral-5 colors/neutral-90 theme)})
(defn loading-image
[theme]
{:flex 1
:border-radius container-border-radius
:background-color (colors/theme-colors colors/white-70-blur colors/neutral-95-opa-70-blur theme)})
@@ -0,0 +1,190 @@
(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 text]
[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]}]
[rn/view
{:style (style/fallback {:theme theme})}
[rn/view
[icon/icon :i/sad {:color (colors/theme-colors colors/neutral-40 colors/neutral-50 theme)}]]
[rn/view {:style {:height 4}}]
[text/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)
[text/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}}]
[text/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}}]
[text/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]}]
(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
:label (i18n/label :t/unsupported-file)}]
(= status :cant-fetch)
[fallback-view
{:theme theme
: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
:label (i18n/label :t/unsupported-file)}]
(= status :cant-fetch)
[fallback-view
{:theme theme
: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))
@@ -0,0 +1,40 @@
(ns quo.components.profile.expanded-collectible.component-spec
(:require
[quo.components.profile.expanded-collectible.view :as expanded-collectible]
[test-helpers.component :as h]))
(h/describe "Profile/ expanded collectible "
(h/test "renders with counter and has on-press event"
(let [on-press (h/mock-fn)]
(h/render-with-theme-provider
[expanded-collectible/view
{:image-src
"https://media.istockphoto.com/id/603164912/photo/suburb-asphalt-road-and-sun-flowers.jpg?s=612x612&w=0&k=20&c=qLoQ5QONJduHrQ0kJF3fvoofmGAFcrq6cL84HbzdLQM="
:counter "1200"
:on-press on-press}])
(h/fire-event :press (h/get-by-label-text :expanded-collectible))
(h/was-called on-press)
(h/is-truthy (h/get-by-text "1200"))))
(h/test "renders with status :cant-fetch and has on-press event"
(let [on-press (h/mock-fn)]
(h/render-with-theme-provider
[expanded-collectible/view
{:counter "1200"
:status :cant-fetch
:on-press on-press}])
(h/fire-event :press (h/get-by-label-text :expanded-collectible))
(h/was-called on-press)
(h/is-truthy (h/get-by-translation-text :t/cant-fetch-info))))
(h/test "renders with status :unsupported and has on-press event"
(let [on-press (h/mock-fn)]
(h/render-with-theme-provider
[expanded-collectible/view
{:counter "1200"
:status :unsupported
:on-press on-press}])
(h/fire-event :press (h/get-by-label-text :expanded-collectible))
(h/was-called on-press)
(h/is-truthy (h/get-by-translation-text :t/unsupported-file)))))
@@ -0,0 +1,33 @@
(ns quo.components.profile.expanded-collectible.style
(:require [quo.foundations.colors :as colors]
[quo.foundations.shadows :as shadows]))
(def container
(merge (shadows/get 2)
{:flex 1
:align-items :center
:justify-content :center
:border-radius 16}))
(defn image
[square? aspect-ratio]
{:width "100%"
:aspect-ratio (if square? 1 aspect-ratio)
:border-radius 16})
(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 16
:width "100%"
:aspect-ratio 1
:align-items :center
:justify-content :center})
(def counter
{:position :absolute
:top 12
:right 12})
@@ -0,0 +1,77 @@
(ns quo.components.profile.expanded-collectible.view
(:require
[promesa.core :as p]
[quo.components.counter.collectible-counter.view :as collectible-counter]
[quo.components.icon :as icon]
[quo.components.markdown.text :as text]
[quo.components.profile.expanded-collectible.style :as style]
[quo.foundations.colors :as colors]
[quo.theme]
[react-native.core :as rn]
[schema.core :as schema]
[utils.i18n :as i18n]))
(defn- counter-view
[counter]
(when counter
[collectible-counter/view
{:container-style style/counter
:value counter}]))
(defn- fallback-view
[{:keys [label theme counter]}]
[rn/view
{:style (style/fallback {:theme theme})}
[counter-view counter]
[rn/view
[icon/icon :i/sad {:color (colors/theme-colors colors/neutral-40 colors/neutral-50 theme)}]]
[rn/view {:style {:height 4}}]
[text/text
{:size :paragraph-2
:style {:color (colors/theme-colors colors/neutral-40 colors/neutral-50 theme)}}
label]])
(defn view-internal
[{:keys [container-style square? status on-press counter image-src] :or {status :default}}]
(let [theme (quo.theme/use-theme-value)
[image-size set-image-size] (rn/use-state {})]
(rn/use-effect
(fn []
(p/let [[image-width image-height] (rn/image-get-size image-src)]
(set-image-size {:width image-width
:height image-height
:aspect-ratio (/ image-width image-height)})))
[image-src])
[rn/pressable
{:on-press on-press
:accessibility-label :expanded-collectible
:style (merge container-style style/container)}
(case status
:unsupported [fallback-view
{:label (i18n/label :t/unsupported-file)
:counter counter
:theme theme}]
:cant-fetch [fallback-view
{:label (i18n/label :t/cant-fetch-info)
:counter counter
:theme theme}]
[rn/view {:style {:flex 1}}
[rn/image
{:style (style/image square? (:aspect-ratio image-size))
:source image-src}]
[counter-view counter]])]))
(def ?schema
[:=>
[:catn
[:props
[:map {:closed true}
[:image-src {:optional true} string?]
[:container-style {:optional true} [:maybe :map]]
[:square? {:optional true} [:maybe boolean?]]
[:counter {:optional true} [:maybe string?]]
[:status {:optional true} [:maybe [:enum :default :loading :cant-fetch :unsupported]]]
[:on-press {:optional true} [:maybe fn?]]]]]
:any])
(def view (schema/instrument #'view-internal ?schema))
+51 -45
View File
@@ -53,7 +53,7 @@
:max-fade-percentage fade-end-percentage})]
;; Avoid unnecessary re-rendering.
(when (not= new-percentage (get fading :fade-end-percentage))
(set-fading (assoc fading :fade-end-percentage new-percentage)))))
(set-fading new-percentage))))
(when on-scroll
(on-scroll e)))
@@ -61,13 +61,10 @@
[{:keys [id label notification-dot? accessibility-label]}
index _
{:keys [active-tab-id
set-active-tab-id
blur?
customization-color
flat-list-ref
number-of-items
on-change
scroll-on-press?
on-press
size
style]}]
[rn/view
@@ -84,16 +81,7 @@
:size size
:blur? blur?
:active (= id active-tab-id)
:on-press (fn [id]
(set-active-tab-id id)
(when (and scroll-on-press? @flat-list-ref)
(.scrollToIndex ^js @flat-list-ref
#js
{:animated true
:index index
:viewPosition 0.5}))
(when on-change
(on-change id)))}
:on-press #(on-press % index)}
label]])
(defn view
@@ -125,42 +113,63 @@
size default-tab-size}
:as props}]
(let [[active-tab-id
set-active-tab-id] (rn/use-state default-active)
[fading set-fading] (rn/use-state {:fade-end-percentage fade-end-percentage})
flat-list-ref (rn/use-ref-atom nil)
clean-props (dissoc props
:default-active
:fade-end-percentage
:fade-end?
:on-change
:scroll-on-press?
:size)
on-scroll (rn/use-callback
(partial on-scroll-handler
{:fade-end-percentage fade-end-percentage
:fade-end? fade-end?
:fading fading
:set-fading set-fading
:on-scroll on-scroll})
[fade-end? fading])]
set-active-tab-id] (rn/use-state default-active)
[fading set-fading] (rn/use-state fade-end-percentage)
flat-list-ref (rn/use-ref-atom nil)
clean-props (dissoc props
:default-active
:fade-end-percentage
:fade-end?
:on-change
:scroll-on-press?
:size)
on-scroll (rn/use-callback
(partial on-scroll-handler
{:fade-end-percentage fade-end-percentage
:fade-end? fade-end?
:fading fading
:set-fading set-fading
:on-scroll on-scroll})
[fade-end? fading])
set-initial-scroll-poisition (rn/use-callback
(fn []
(reagent/next-tick
(fn []
(.scrollToIndex
@flat-list-ref
#js
{:animated false
:index
(utils.collection/first-index
#(= active-tab-id (:id %))
data)}))))
[active-tab-id data])
on-tab-press (rn/use-callback (fn [id index]
(set-active-tab-id id)
(when (and scroll-on-press? @flat-list-ref)
(.scrollToIndex ^js @flat-list-ref
#js
{:animated true
:index index
:viewPosition 0.5}))
(when on-change
(on-change id)))
[set-active-tab-id scroll-on-press? on-change])]
(if scrollable?
[rn/view {:style {:margin-top (- (dec unread-count-offset))}}
[masked-view-wrapper
{:fade-end-percentage (get fading :fade-end-percentage) :fade-end? fade-end?}
{:fade-end-percentage fading :fade-end? fade-end?}
[(if in-scroll-view?
gesture/flat-list
rn/flat-list)
(merge
clean-props
(when scroll-on-press?
{:initial-scroll-index (utils.collection/first-index #(= active-tab-id (:id %)) data)})
{:ref #(reset! flat-list-ref %)
:style style
;; The padding-top workaround is needed because on Android
;; {:overflow :visible} doesn't work on components inheriting
;; from ScrollView (e.g. FlatList). There are open issues, here's
;; just one about this topic:
;; https://github.com/facebook/react-native/issues/31218
;; from ScrollView (e.g. FlatList). There are open issues, here's just one about this
;; topic: Https://github.com/facebook/react-native/issues/31218
:content-container-style
(assoc container-style :padding-top (dec unread-count-offset))
:horizontal true
@@ -170,27 +179,24 @@
:key-fn (comp str :id)
:on-scroll-to-index-failed identity
:on-scroll on-scroll
:on-layout set-initial-scroll-poisition
:render-fn tab-view
:render-data {:active-tab-id active-tab-id
:set-active-tab-id set-active-tab-id
:blur? blur?
:customization-color customization-color
:flat-list-ref flat-list-ref
:number-of-items (count data)
:on-change on-change
:scroll-on-press? scroll-on-press?
:size size
:on-press on-tab-press
:style style}})]]]
[rn/view (merge style {:flex-direction :row})
(map-indexed (fn [index item]
^{:key (:id item)}
[tab-view item index nil
{:active-tab-id active-tab-id
:set-active-tab-id set-active-tab-id
:blur? blur?
:customization-color customization-color
:number-of-items (count data)
:on-change on-change
:size size
:on-press on-tab-press
:style style}])
data)])))
@@ -8,6 +8,7 @@
[:enum :default :multiuser :group :channel :community :token :network :multinetwork :account
:collectible :address :icon :audio]]]
[:customization-color {:optional true} [:maybe :schema.common/customization-color]]
[:container-style {:optional true} [:maybe :map]]
[:theme :schema.common/theme]
[:blur? {:optional true} [:maybe :boolean]]
[:state {:optional true} [:maybe [:enum :selected :default]]]])
@@ -38,6 +39,7 @@
(def ^:private ?channel
[:map
[:community-name {:optional true} [:maybe :string]]
[:community-logo {:optional true} [:maybe :schema.common/image-source]]
[:channel-name {:optional true} [:maybe :string]]])
(def ^:private ?community
@@ -36,6 +36,7 @@
(colors/custom-color customization-color 60)
theme)]
(cond-> {:padding 2
:padding-right 8
:flex-direction :row
:align-items :center
:height size
+65 -64
View File
@@ -12,6 +12,7 @@
[quo.foundations.colors :as colors]
[quo.theme :as quo.theme]
[react-native.core :as rn]
[react-native.fast-image :as fast-image]
[schema.core :as schema]))
(defn- tag-skeleton
@@ -30,7 +31,7 @@
(let [text-size (if (= size 24) :paragraph-2 :paragraph-1)
icon-size (if (= size 24) 16 20)]
[rn/view {:style (style/tag-container size)}
[rn/image {:style (style/circle-logo size) :source community-logo}]
[fast-image/fast-image {:style (style/circle-logo size) :source community-logo}]
[rn/view {:style (style/tag-spacing size)}
[text/text
{:style (style/text theme)
@@ -82,81 +83,81 @@
type :default
state :default}
:as props}]
[rn/view
{:style (merge (style/container {:theme theme
:type type
:size size
:state state
:blur? blur?
:customization-color customization-color})
container-style)
:accessibility-label :context-tag}
(case type
:default
[tag-skeleton {:theme theme :size size :text full-name}
[user-avatar/user-avatar
{:full-name full-name
:profile-picture profile-picture
:size (if (= size 24) :xxs 28)
:status-indicator? false
:ring? false
:customization-color customization-color}]]
[rn/view {:style (merge {:align-items :flex-start} container-style)}
[rn/view
{:style (style/container {:theme theme
:type type
:size size
:state state
:blur? blur?
:customization-color customization-color})
:accessibility-label :context-tag}
(case type
:default
[tag-skeleton {:theme theme :size size :text full-name}
[user-avatar/user-avatar
{:full-name full-name
:profile-picture profile-picture
:size (if (= size 24) :xxs 28)
:status-indicator? false
:ring? false
:customization-color customization-color}]]
:multiuser
[preview-list/view {:type :user :size :size-20}
users]
:multiuser
[preview-list/view {:type :user :size :size-20}
users]
:multinetwork
[preview-list/view {:type :network :size :size-20}
networks]
:multinetwork
[preview-list/view {:type :network :size :size-20}
networks]
:audio
[tag-skeleton {:theme theme :text (str duration)}
[rn/view {:style (style/audio-tag-icon-container customization-color theme)}
[icons/icon :i/play {:color style/audio-tag-icon-color :size 12}]]]
:audio
[tag-skeleton {:theme theme :text (str duration)}
[rn/view {:style (style/audio-tag-icon-container customization-color theme)}
[icons/icon :i/play {:color style/audio-tag-icon-color :size 12}]]]
:group
[tag-skeleton {:theme theme :size size :text group-name}
[group-avatar/view
{:icon-name :i/members
:size (if (= size 24) :size-20 :size-28)
:customization-color (colors/custom-color customization-color 50)}]]
:group
[tag-skeleton {:theme theme :size size :text group-name}
[group-avatar/view
{:icon-name :i/members
:size (if (= size 24) :size-20 :size-28)
:customization-color (colors/custom-color customization-color 50)}]]
(:channel :community)
[communities-tag (assoc props :channel? (= type :channel))]
(:channel :community)
[communities-tag (assoc props :channel? (= type :channel))]
:token
[tag-skeleton {:theme theme :size size :text (str amount " " token)}
[token/view
{:style (style/token-logo size)
:token token
:size (if (= size 24) :size-20 :size-28)}]]
:token
[tag-skeleton {:theme theme :size size :text (str amount " " token)}
[token/view
{:style (style/token-logo size)
:token token
:size (if (= size 24) :size-20 :size-28)}]]
:network
[tag-skeleton {:theme theme :size size :text network-name}
[rn/image {:style (style/circle-logo size) :source network-logo}]]
:network
[tag-skeleton {:theme theme :size size :text network-name}
[rn/image {:style (style/circle-logo size) :source network-logo}]]
:collectible
[tag-skeleton
{:theme theme
:size size
:text (str collectible-name " #" collectible-number)}
[rn/image {:style (style/rounded-logo size) :source collectible}]]
:collectible
[tag-skeleton
{:theme theme
:size size
:text (str collectible-name " #" collectible-number)}
[rn/image {:style (style/rounded-logo size) :source collectible}]]
:account
[tag-skeleton {:theme theme :size size :text account-name}
[account-avatar/view
{:customization-color customization-color
:emoji emoji
:size (if (= size 24) 20 28)}]]
:account
[tag-skeleton {:theme theme :size size :text account-name}
[account-avatar/view
{:customization-color customization-color
:emoji emoji
:size (if (= size 24) 20 28)}]]
:address
[address-tag props]
:address
[address-tag props]
:icon
[icon-tag props]
:icon
[icon-tag props]
nil)])
nil)]])
(def view
(quo.theme/with-theme
@@ -115,12 +115,13 @@
emojis))
(defn- view-internal
[{:keys [theme description input blur? input-props container-style]
[{:keys [theme description title input blur? input-props container-style]
emojis :emoji-dash
:as props}]
[rn/view {:style container-style}
[rn/view {:style style/top-container}
[header props]
(when (or title input)
[header props])
(when description
[description-container props])
(when emojis
@@ -2,6 +2,7 @@
(def title-container
{:flex-direction :row
:flex 1
:align-items :center})
(def avatar-container
@@ -7,12 +7,13 @@
[react-native.core :as rn]))
(defn- username-text
[{:keys [theme name-type username blur?]
[{:keys [theme name-type username accessibility-label blur?]
real-name :name}]
[rn/view {:style style/username-text-container}
[text/text
{:size :heading-1
:weight :semi-bold}
{:size :heading-1
:accessibility-label accessibility-label
:weight :semi-bold}
username]
(when (= name-type :nickname)
[:<>
@@ -22,9 +23,10 @@
:weight :medium}
"∙"]
[text/text
{:style (style/real-name-text theme blur?)
:size :paragraph-1
:weight :medium}
{:style (style/real-name-text theme blur?)
:size :paragraph-1
:accessibility-label :real-name
:weight :medium}
real-name]])])
(defn- icon-20
@@ -43,6 +43,7 @@
{:accessibility-label title-accessibility-label
:weight :semi-bold
:ellipsize-mode :tail
:style {:flex 1}
:number-of-lines title-number-of-lines
:size :heading-1}
title]]
+12 -13
View File
@@ -4,19 +4,18 @@
[react-native.platform :as platform]))
(defn container
[{:keys [blur? customization-color theme selected?]}]
{:border-radius 16
:border-width 1
:border-color (if selected?
(if blur?
colors/white
(colors/theme-colors (colors/custom-color customization-color 50)
(colors/custom-color customization-color 60)
theme))
(if blur?
colors/white-opa-5
(colors/theme-colors colors/neutral-10 colors/neutral-80 theme)))
:padding-bottom 8})
[{:keys [blur? customization-color theme selected? container-style]}]
(merge {:border-radius 16
:border-width 1
:border-color (if selected?
(if blur?
colors/white
(colors/resolve-color customization-color theme))
(if blur?
colors/white-opa-5
(colors/theme-colors colors/neutral-10 colors/neutral-80 theme)))
:padding-bottom 8}
container-style))
(def header-container
{:padding-horizontal 12
+19 -20
View File
@@ -11,7 +11,6 @@
[quo.foundations.colors :as colors]
[quo.theme :as quo.theme]
[react-native.core :as rn]
[reagent.core :as reagent]
[utils.i18n :as i18n]))
(defn keypair-string
@@ -34,7 +33,7 @@
:profile-picture profile-picture}]
[icon-avatar/icon-avatar
{:size :size-32
:icon :i/placeholder
:icon :i/seed
:border? true}]))
(defn title-view
@@ -91,23 +90,23 @@
[account-list-card/view item])
(defn- view-internal
[{:keys [default-selected?]}]
(let [selected? (reagent/atom default-selected?)]
(fn [{:keys [accounts action container-style] :as props}]
[rn/pressable
{:style (merge (style/container (merge props {:selected? @selected?})) container-style)
:on-press #(when (= action :selector) (reset! selected? (not @selected?)))}
[rn/view {:style style/header-container}
[avatar props]
[rn/view
{:style {:margin-left 8
:flex 1}}
[title-view (assoc props :selected? @selected?)]
[details-view props]]]
[rn/flat-list
{:data accounts
:render-fn acc-list-card
:separator [rn/view {:style {:height 8}}]
:style {:padding-horizontal 8}}]])))
[{:keys [accounts action container-style selected? on-press] :as props}]
[rn/pressable
{:style (style/container (merge props
{:selected? selected?
:container-style container-style}))
:on-press #(when (= action :selector) (on-press))}
[rn/view {:style style/header-container}
[avatar props]
[rn/view
{:style {:margin-left 8
:flex 1}}
[title-view (assoc props :selected? selected?)]
[details-view props]]]
[rn/flat-list
{:data accounts
:render-fn acc-list-card
:separator [rn/view {:style {:height 8}}]
:style {:padding-horizontal 8}}]])
(def view (quo.theme/with-theme view-internal))
@@ -30,8 +30,12 @@
(defn networks
[values theme]
(let [{:keys [ethereum optimism arbitrum]} values
show-optimism? (and optimism (pos? (:amount optimism)))
show-arbitrum? (and arbitrum (pos? (:amount arbitrum)))]
show-optimism? (and optimism
(or (pos? (:amount optimism))
(= (:amount optimism) "<0.01")))
show-arbitrum? (and arbitrum
(or (pos? (:amount arbitrum))
(= (:amount arbitrum) "<0.01")))]
[rn/view
{:style style/networks-container
:accessibility-label :networks}
+9 -3
View File
@@ -29,7 +29,8 @@
quo.components.common.notification-dot.view
quo.components.common.separator.view
quo.components.community.banner.view
quo.components.community.channel-actions
quo.components.community.channel-action.view
quo.components.community.channel-actions.view
quo.components.community.community-card-view
quo.components.community.community-list-view
quo.components.community.community-stat.view
@@ -55,7 +56,7 @@
quo.components.dropdowns.network-dropdown.view
quo.components.empty-state.empty-state.view
quo.components.gradient.gradient-cover.view
[quo.components.graph.interactive-graph.view :as interactive-graph]
quo.components.graph.interactive-graph.view
quo.components.graph.wallet-graph.view
quo.components.header
quo.components.icon
@@ -109,7 +110,9 @@
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.expanded-collectible.view
quo.components.profile.link-card.view
quo.components.profile.profile-card.view
quo.components.profile.select-profile.view
@@ -229,7 +232,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 +354,8 @@
;;;; Profile
(def collectible quo.components.profile.collectible.view/collectible)
(def collectible-list-item quo.components.profile.collectible-list-item.view/view)
(def expanded-collectible quo.components.profile.expanded-collectible.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)
+2
View File
@@ -63,6 +63,8 @@
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.expanded-collectible.component-spec
quo.components.profile.link-card.component-spec
quo.components.profile.select-profile.component-spec
quo.components.profile.showcase-nav.component-spec
+34
View File
@@ -0,0 +1,34 @@
(ns quo.foundations.gradients
(:require
[quo.foundations.colors :as colors]
[quo.theme]
[react-native.linear-gradient :as linear-gradient]))
(defn- gradient-colors
[index theme]
(case index
:gradient-1 [(colors/resolve-color :yellow theme)
(colors/resolve-color :sky theme)
(colors/resolve-color :purple theme)]
:gradient-2 [(colors/resolve-color :orange theme)
(colors/resolve-color :purple theme)
(colors/resolve-color :blue theme)]
:gradient-3 [(colors/resolve-color :blue theme)
(colors/resolve-color :magenta theme)
(colors/resolve-color :yellow theme)]
:gradient-4 [(colors/resolve-color :army theme)
(colors/resolve-color :orange theme)
(colors/resolve-color :blue theme)]
[(colors/resolve-color :purple theme)
(colors/resolve-color :army theme)
(colors/resolve-color :yellow theme)]))
(defn view
[{:keys [color-index container-style] :or {color-index 1}}]
(let [theme (quo.theme/use-theme-value)]
[linear-gradient/linear-gradient
{:style (merge {:border-radius 16} container-style)
:accessibility-label :gradient-overlay
:colors (gradient-colors color-index theme)
:start {:x 0 :y 0}
:end {:x 0 :y 1}}]))
+27 -6
View File
@@ -95,13 +95,34 @@
(into [{:title title :header? true}] data))
sections))
(defn- find-sticky-indices
[data]
(->> data
(map-indexed (fn [index item] (when (:header? item) index)))
(remove nil?)
(vec)))
(defn- is-last-item-in-section
[data index]
(let [next-item (nth data (inc index) nil)]
(or (nil? next-item) (:header? next-item))))
(defn section-list
[{:keys [sections render-section-header-fn render-fn] :as props}]
[{:keys [sections sticky-section-headers-enabled render-section-header-fn render-section-footer-fn
render-fn]
:or {sticky-section-headers-enabled true}
:as props}]
(let [data (flatten-sections sections)]
[flat-list
(merge props
{:data data
:render-fn (fn [p1 p2 p3 p4]
(if (:header? p1)
[render-section-header-fn p1 p2 p3 p4]
[render-fn p1 p2 p3 p4]))})]))
{:data data
:render-fn (fn [p1 p2 p3 p4]
[:<>
(if (:header? p1)
[render-section-header-fn p1 p2 p3 p4]
[render-fn p1 p2 p3 p4])
(when (and render-section-footer-fn
(is-last-item-in-section data p2))
[render-section-footer-fn p1 p2 p3 p4])])
:sticky-header-indices (when sticky-section-headers-enabled
(find-sticky-indices data))})]))
+9 -1
View File
@@ -5,6 +5,14 @@
(def ^:private ?cofx
[:map])
(def ^:private ?event
[:and
[:vector {:min 1} :any]
[:catn
[:event-id keyword?]
[:event-args [:* :any]]]])
(defn register-schemas
[]
(registry/register ::cofx ?cofx))
(registry/register ::cofx ?cofx)
(registry/register ::event ?event))
+25 -15
View File
@@ -66,26 +66,35 @@
gradient-cover? customization-color hide-handle? blur-radius]
:or {border-radius 12}}]
(let [theme (quo.theme/use-theme-value)
sheet-height (rn/use-ref-atom 0)
item-height (rn/use-ref-atom 0)
set-sheet-height (rn/use-callback #(reset! sheet-height (get-layout-height %)))
set-item-height (rn/use-callback #(reset! item-height (get-layout-height %)))
[sheet-height set-sheet-height] (rn/use-state 0)
handle-sheet-height (rn/use-callback (fn [e]
(when (= sheet-height 0)
(set-sheet-height
(get-layout-height e))))
[sheet-height])
[item-height set-item-height] (rn/use-state 0)
handle-item-height (rn/use-callback (fn [e]
(when (= item-height 0)
(set-item-height
(get-layout-height e))))
[item-height])
{window-height :height} (rn/get-window)
bg-opacity (reanimated/use-shared-value 0)
translate-y (reanimated/use-shared-value window-height)
sheet-gesture (get-sheet-gesture translate-y
bg-opacity
window-height
on-close)
selected-item-smaller-than-sheet? (< @item-height
sheet-gesture (rn/use-memo #(get-sheet-gesture translate-y
bg-opacity
window-height
on-close)
[window-height on-close])
selected-item-smaller-than-sheet? (< item-height
(- window-height
@sheet-height
sheet-height
(:top insets)
(:bottom insets)
bottom-margin))
top (- window-height (:top insets) @sheet-height)
top (- window-height (:top insets) sheet-height)
bottom (if selected-item-smaller-than-sheet?
(+ @sheet-height bottom-margin)
(+ sheet-height bottom-margin)
(:bottom insets))
sheet-max-height (- window-height (:top insets))
content-padding-bottom (or padding-bottom-override
@@ -123,11 +132,12 @@
:overlay-color :transparent}])
(when selected-item
[rn/view
{:on-layout set-item-height
:style (style/selected-item theme top bottom selected-item-smaller-than-sheet? border-radius)}
{:on-layout handle-item-height
:style
(style/selected-item theme top bottom selected-item-smaller-than-sheet? border-radius)}
[selected-item]])
[rn/view
{:on-layout set-sheet-height
{:on-layout handle-sheet-height
:style (style/sheet-content {:theme theme
:shell? shell?
:padding-bottom content-padding-bottom})}
+7 -3
View File
@@ -1,5 +1,9 @@
(ns status-im.common.contact-list.style)
(ns status-im.common.contact-list.style
(:require [quo.foundations.colors :as colors]))
(def contacts-section-footer
{:height 8})
(defn contacts-section-header
[first-item?]
{:padding-top (if first-item? 0 8)})
[theme]
{:background-color (colors/theme-colors colors/white colors/neutral-95 theme)})
+9 -3
View File
@@ -1,10 +1,16 @@
(ns status-im.common.contact-list.view
(:require
[quo.core :as quo]
[quo.theme]
[react-native.core :as rn]
[status-im.common.contact-list.style :as style]))
(defn contacts-section-footer
[]
[rn/view style/contacts-section-footer])
(defn contacts-section-header
[{:keys [title index]}]
[rn/view (style/contacts-section-header (= index 0))
[quo/divider-label title]])
[{:keys [title]}]
(let [theme (quo.theme/use-theme-value)]
[rn/view (style/contacts-section-header theme)
[quo/divider-label title]]))
-8
View File
@@ -4,9 +4,7 @@
[clojure.string :as string]
[native-module.core :as native-module]
[re-frame.core :as re-frame]
[status-im.config :as config]
[taoensso.timbre :as log]
[utils.re-frame :as rf]
[utils.transforms :as transforms]))
(def logs-queue (atom #queue []))
@@ -52,9 +50,3 @@
:logs/set-level
(fn [level]
(setup level)))
(rf/defn set-log-level
[{:keys [db]} log-level]
(let [log-level (or log-level config/log-level)]
{:db (assoc-in db [:profile/profile :log-level] log-level)
:logs/set-level log-level}))
+3 -2
View File
@@ -68,8 +68,9 @@
:right-side page-nav-right-section-buttons
:center-opacity (reanimated/get-shared-value opacity-animation)
:overlay-shown? overlay-shown?}
navigate-back? (assoc :icon-name :i/close
:on-press #(rf/dispatch [:navigate-back]))
navigate-back? (assoc :icon-name :i/close
:accessibility-label :back-button
:on-press #(rf/dispatch [:navigate-back]))
page-nav-props (merge page-nav-props))])
(when title-colum
title-colum)
+3 -2
View File
@@ -7,7 +7,6 @@
[status-im.contexts.chat.messenger.messages.link-preview.events :as link-preview]
[status-im.contexts.chat.messenger.messages.transport.events :as messages.transport]
[status-im.contexts.communities.discover.events]
[status-im.contexts.profile.login.events :as profile.login]
[status-im.contexts.profile.push-notifications.local.events :as local-notifications]
[taoensso.timbre :as log]
[utils.re-frame :as rf]
@@ -37,7 +36,9 @@
^js event-js (.-event data)
type (.-type data)]
(case type
"node.login" (profile.login/login-node-signal cofx (transforms/js->clj event-js))
"node.login" {:fx [[:dispatch
[:profile.login/login-node-signal
(transforms/js->clj event-js)]]]}
"backup.performed" {:db (assoc-in db
[:profile/profile :last-backup]
(.-lastBackup event-js))}
+14
View File
@@ -19,6 +19,7 @@
(def ^:const content-type-system-message-mutual-event-sent 15)
(def ^:const content-type-system-message-mutual-event-accepted 16)
(def ^:const content-type-system-message-mutual-event-removed 17)
(def ^:const content-type-bridge-message 18)
;; Not implemented in status-go, only used for testing/ui work
(def ^:const content-type-gif 100)
@@ -72,6 +73,7 @@
(def ^:const contact-request-message-state-pending 1)
(def ^:const contact-request-message-state-accepted 2)
(def ^:const contact-request-message-state-declined 3)
(def ^:const contact-request-message-max-length 280)
(def request-to-join-pending-state 1)
@@ -186,6 +188,11 @@
; EIP1581 Chat Key 0, the default whisper key
(def ^:const path-whisper (str path-eip1581 "/0'/0"))
(def ^:const path-ropsten-testnet "m/44'/1'/0")
(def ^:const path-ledger "m/44'/60'/0'")
(def ^:const path-ledger-live "m/44'/60'")
(def ^:const path-keepkey "m/44'/60'")
(def ^:const path-default-wallet-keyword (keyword path-default-wallet))
(def ^:const path-whisper-keyword (keyword path-whisper))
(def ^:const path-wallet-root-keyword (keyword path-wallet-root))
@@ -428,6 +435,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")
@@ -465,6 +478,7 @@
(def ^:const bridge-name-transfer "Transfer")
(def ^:const bridge-name-erc-721-transfer "ERC721Transfer")
(def ^:const bridge-name-hop "Hop")
(def ^:const alert-banner-height 40)
@@ -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]]
+2 -18
View File
@@ -14,7 +14,6 @@
[status-im.contexts.chat.messenger.messages.delete-message-for-me.events :as delete-for-me]
[status-im.contexts.chat.messenger.messages.delete-message.events :as delete-message]
[status-im.contexts.chat.messenger.messages.list.state :as chat.state]
[status-im.feature-flags :as ff]
[status-im.navigation.events :as navigation]
[taoensso.timbre :as log]
[utils.datetime :as datetime]
@@ -244,18 +243,6 @@
(update :chats-home-list conj chat-id))
:dispatch [:chat/pop-to-root-and-navigate-to-chat chat-id]}))
(rf/defn decrease-unviewed-count
{:events [:chat/decrease-unviewed-count]}
[{:keys [db]} chat-id {:keys [count countWithMentions]}]
{:db (-> db
;; There might be some other requests being fired, so we need to make sure the count has
;; not been set to
;; 0 in the meantime
(update-in [:chats chat-id :unviewed-messages-count]
#(max (- % count) 0))
(update-in [:chats chat-id :unviewed-mentions-count]
#(max (- % countWithMentions) 0)))})
(rf/defn start-chat
"Start a chat, making sure it exists"
{:events [:chat.ui/start-chat]}
@@ -444,8 +431,5 @@
{:pubkey public-key
:ens ens-name
:success-fn (fn [_]
{:dispatch [:open-modal
(if (ff/enabled? ::ff/profile.new-contact-ui)
:contact-profile
:profile)]})}]}
{:dispatch [:navigate-to :my-profile]}))))
{:dispatch [:open-modal :contact-profile]})}]}
{:dispatch [:open-modal :settings]}))))
@@ -40,3 +40,6 @@
:background-color (colors/theme-colors colors/white colors/neutral-95-opa-70)
:flex-direction :row})
(def floating-shell-button
{:position :absolute
:bottom 21})
@@ -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}]
@@ -112,6 +113,7 @@
members (rf/sub [:contacts/group-members-sections chat-id])
pinned-messages (rf/sub [:chats/pinned chat-id])
current-pk (rf/sub [:multiaccount/public-key])
profile-color (rf/sub [:profile/customization-color])
admin? (get admins current-pk)]
[:<>
[quo/gradient-cover
@@ -126,7 +128,6 @@
group])}])}]
:icon-name :i/arrow-left
:on-press #(rf/dispatch [:navigate-back])}]
[quo/page-top
{:title chat-name
:avatar {:customization-color color}}]
@@ -166,4 +167,12 @@
:render-section-footer-fn contacts-section-footer
:render-data {:chat-id chat-id
:admin? admin?}
:render-fn contact-item-render}]]))
:render-fn contact-item-render}]
[quo/floating-shell-button
{:jump-to {:on-press (fn []
(rf/dispatch [:navigate-back])
(rf/dispatch [:shell/navigate-to-jump-to])
)
:customization-color profile-color
:label (i18n/label :t/jump-to)}}
style/floating-shell-button]]))
@@ -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}])))
@@ -61,9 +61,10 @@
(reset! input-value clipboard-text)
(rf/dispatch [:contacts/set-new-identity
{:input clipboard-text}])))]
(let [{:keys [scanned]} (rf/sub [:contacts/new-identity])
empty-input? (and (string/blank? @input-value)
(string/blank? scanned))]
(let [{:keys [scanned] contact-public-key :id} (rf/sub [:contacts/new-identity])
contact-public-key-or-scanned (or contact-public-key scanned)
empty-input? (and (string/blank? @input-value)
(string/blank? contact-public-key-or-scanned))]
[rn/view {:style style/input-and-scan-container}
[quo/input
{:accessibility-label :enter-contact-code-input
@@ -80,15 +81,16 @@
:button (when empty-input?
{:on-press paste-on-input
:text (i18n/label :t/paste)})
;; NOTE: `scanned` has priority over `@input-value`, we clean it when the input is updated
;; so that it's `nil` and `@input-value` is shown. To fastly clean it, we use
;; `dispatch-sync`. This call could be avoided if `::qr-scanner/scan-code` were able to
;; NOTE: `contact-public-key-or-scanned` has priority over `@input-value`,
;; we clean it when the input is updated so that it's `nil` and
;; `@input-value`is shown. To fastly clean it, we use `dispatch-sync`.
;; This call could be avoided if `::qr-scanner/scan-code` were able to
;; receive a callback function, not only a re-frame event as callback.
:value (or scanned @input-value)
:value (or contact-public-key-or-scanned @input-value)
:on-change-text (fn [new-text]
(reset! input-value new-text)
(as-> [:contacts/set-new-identity {:input new-text}] $
(if (string/blank? scanned)
(if (string/blank? contact-public-key-or-scanned)
(debounce/debounce-and-dispatch $ 600)
(rf/dispatch-sync $))))}]
[rn/view {:style style/scan-button-container}
@@ -1,5 +1,6 @@
(ns status-im.contexts.chat.home.new-chat.styles
(:require
[quo.foundations.colors :as colors]
[react-native.safe-area :as safe-area]))
(def contact-selection-heading
@@ -9,11 +10,16 @@
:margin-top 24
:margin-bottom 16})
(def chat-button
{:position :absolute
:bottom (+ 12 (safe-area/get-bottom))
:left 20
:right 20})
(defn chat-button-container
[theme]
{:position :absolute
:bottom 0
:padding-bottom 33
:background-color (colors/theme-colors colors/white-opa-70 colors/neutral-95-opa-70 theme)
:padding-top 12
:padding-horizontal 20
:left 0
:right 0})
(defn no-contacts
[]
@@ -2,7 +2,7 @@
(:require
[quo.core :as quo]
[quo.foundations.colors :as colors]
[quo.theme :as quo.theme]
[quo.theme]
[re-frame.core :as re-frame]
[react-native.core :as rn]
[react-native.gesture :as gesture]
@@ -49,27 +49,54 @@
(rf/dispatch [:open-modal :new-contact]))}
(i18n/label :t/add-a-contact)]]))
(defn contact-item-render
[_]
(fn [{:keys [public-key] :as item}]
(let [user-selected? (rf/sub [:is-contact-selected? public-key])
on-toggle #(if user-selected?
(re-frame/dispatch [:deselect-contact public-key])
(re-frame/dispatch [:select-contact public-key]))]
[contact-list-item/contact-list-item
{:on-press on-toggle
:allow-multiple-presses? true
:accessory {:type :checkbox
:checked? user-selected?
:on-check on-toggle}}
item])))
(def ^:private contacts-selection-limit (dec constants/max-group-chat-participants))
(defn- view-internal
[{:keys [scroll-enabled? on-scroll close theme]}]
(let [contacts (rf/sub [:contacts/sorted-and-grouped-by-first-letter])
(defn- toggle-selection
[public-key user-selected?]
(let [selected-contacts-count (rf/sub [:selected-contacts-count])]
(if user-selected?
(re-frame/dispatch [:deselect-contact public-key])
(if (= contacts-selection-limit
selected-contacts-count)
(do
(rf/dispatch
[:toasts/upsert
{:id :remove-nickname
:type :negative
:text (i18n/label :t/new-group-limit
{:max-contacts
contacts-selection-limit})}])
true)
(re-frame/dispatch [:select-contact public-key])))))
(defn contact-item-render
[{:keys [public-key] :as item} set-has-error]
(let [user-selected? (rf/sub [:is-contact-selected? public-key])
on-toggle (fn []
(-> public-key
(toggle-selection user-selected?)
boolean
set-has-error))]
[contact-list-item/contact-list-item
{:on-press on-toggle
:allow-multiple-presses? true
:accessory {:type :checkbox
:checked? user-selected?
:on-check on-toggle}}
item]))
(defn view
[{:keys [scroll-enabled? on-scroll close]}]
(let [theme (quo.theme/use-theme-value)
contacts (rf/sub [:contacts/sorted-and-grouped-by-first-letter])
selected-contacts-count (rf/sub [:selected-contacts-count])
selected-contacts (rf/sub [:group/selected-contacts])
customization-color (rf/sub [:profile/customization-color])
one-contact-selected? (= selected-contacts-count 1)
[has-error? set-has-error] (rn/use-state false)
render-fn (rn/use-callback (fn [item]
(contact-item-render item set-has-error))
[set-has-error])
contacts-selected? (pos? selected-contacts-count)
{:keys [primary-name public-key]} (when one-contact-selected?
(rf/sub [:contacts/contact-by-identity
@@ -86,38 +113,42 @@
{:weight :semi-bold
:size :heading-1
:style {:color (colors/theme-colors colors/neutral-100 colors/white theme)}}
(i18n/label :t/new-chat)]
(if (or (not contacts-selected?) one-contact-selected?)
(i18n/label :t/new-chat)
(i18n/label :t/new-group-chat))]
(when (seq contacts)
[quo/text
{:size :paragraph-2
:weight :regular
:style {:margin-bottom 2
:color (colors/theme-colors colors/neutral-40 colors/neutral-50 theme)}}
:color (if has-error?
(colors/theme-colors colors/danger-50 colors/danger-60 theme)
(colors/theme-colors colors/neutral-40 colors/neutral-50 theme))}}
(i18n/label :t/selected-count-from-max
{:selected selected-contacts-count
:max constants/max-group-chat-participants})])]]
:max contacts-selection-limit})])]]
(if (empty? contacts)
[no-contacts-view {:theme theme}]
[gesture/section-list
{:key-fn :title
:sticky-section-headers-enabled false
:sections (rf/sub [:contacts/filtered-active-sections])
:render-section-header-fn contact-list/contacts-section-header
:content-container-style {:padding-bottom 70}
:render-fn contact-item-render
:scroll-enabled @scroll-enabled?
:on-scroll on-scroll}])
{:key-fn :title
:sections (rf/sub [:contacts/filtered-active-sections])
:render-section-header-fn contact-list/contacts-section-header
:render-section-footer-fn contact-list/contacts-section-footer
:content-container-style {:padding-bottom 70}
:render-fn render-fn
:scroll-enabled @scroll-enabled?
:on-scroll on-scroll}])
(when contacts-selected?
[quo/button
{:type :primary
:accessibility-label :next-button
:container-style style/chat-button
:on-press (fn []
(if one-contact-selected?
(rf/dispatch [:chat.ui/start-chat public-key])
(rf/dispatch [:navigate-to :new-group])))}
(if one-contact-selected?
(i18n/label :t/chat-with {:selected-user primary-name})
(i18n/label :t/setup-group-chat))])]))
(def view (quo.theme/with-theme view-internal))
[rn/view
{:style (style/chat-button-container theme)}
[quo/button
{:type :primary
:customization-color customization-color
:accessibility-label :next-button
:on-press (fn []
(if one-contact-selected?
(rf/dispatch [:chat.ui/start-chat public-key])
(rf/dispatch [:navigate-to :new-group])))}
(if one-contact-selected?
(i18n/label :t/chat-with {:selected-user primary-name})
(i18n/label :t/setup-group-chat))]])]))
+40 -45
View File
@@ -106,6 +106,7 @@
:sections items
:sticky-section-headers-enabled false
:render-section-header-fn contact-list/contacts-section-header
:render-section-footer-fn contact-list/contacts-section-footer
:render-fn (fn [data]
(contact-item-render data theme))
:scroll-event-throttle 8
@@ -126,48 +127,42 @@
:title (i18n/label :t/invite-friends-to-status)
:description (i18n/label :t/share-invite-link)}})
(defn- f-view-internal
[{:keys [theme]}]
(let [scroll-ref (atom nil)
set-scroll-ref #(reset! scroll-ref %)]
(fn []
(let [{:keys [universal-profile-url]} (rf/sub [:profile/profile])
customization-color (rf/sub [:profile/customization-color])
pending-contact-requests (rf/sub [:activity-center/pending-contact-requests])
selected-tab (or (rf/sub [:messages-home/selected-tab]) :tab/recent)
scroll-shared-value (reanimated/use-shared-value 0)]
[:<>
(if (= selected-tab :tab/contacts)
[contacts
{:pending-contact-requests pending-contact-requests
:set-scroll-ref set-scroll-ref
:scroll-shared-value scroll-shared-value
:theme theme}]
[chats
{:selected-tab selected-tab
:set-scroll-ref set-scroll-ref
:scroll-shared-value scroll-shared-value
:theme theme}])
[:f> common.banner/animated-banner
{:content (banner-data universal-profile-url)
:customization-color customization-color
:scroll-ref scroll-ref
:tabs [{:id :tab/recent
:label (i18n/label :t/recent)
:accessibility-label :tab-recent}
{:id :tab/groups
:label (i18n/label :t/groups)
:accessibility-label :tab-groups}
{:id :tab/contacts
:label (i18n/label :t/contacts)
:accessibility-label :tab-contacts
:notification-dot? (pos? (count pending-contact-requests))}]
:selected-tab selected-tab
:on-tab-change (fn [tab] (rf/dispatch [:messages-home/select-tab tab]))
:scroll-shared-value scroll-shared-value}]]))))
(defn- internal-chats-home-view
[params]
[:f> f-view-internal params])
(def view (quo.theme/with-theme internal-chats-home-view))
(defn view
[]
(let [theme (quo.theme/use-theme-value)
scroll-ref (rn/use-ref-atom nil)
set-scroll-ref (rn/use-callback #(reset! scroll-ref %))
{:keys [universal-profile-url]} (rf/sub [:profile/profile])
customization-color (rf/sub [:profile/customization-color])
pending-contact-requests (rf/sub [:activity-center/pending-contact-requests])
selected-tab (or (rf/sub [:messages-home/selected-tab]) :tab/recent)
scroll-shared-value (reanimated/use-shared-value 0)]
[:<>
(if (= selected-tab :tab/contacts)
[contacts
{:pending-contact-requests pending-contact-requests
:set-scroll-ref set-scroll-ref
:scroll-shared-value scroll-shared-value
:theme theme}]
[chats
{:selected-tab selected-tab
:set-scroll-ref set-scroll-ref
:scroll-shared-value scroll-shared-value
:theme theme}])
[common.banner/animated-banner
{:content (banner-data universal-profile-url)
:customization-color customization-color
:scroll-ref scroll-ref
:tabs [{:id :tab/recent
:label (i18n/label :t/recent)
:accessibility-label :tab-recent}
{:id :tab/groups
:label (i18n/label :t/groups)
:accessibility-label :tab-groups}
{:id :tab/contacts
:label (i18n/label :t/contacts)
:accessibility-label :tab-contacts
:notification-dot? (pos? (count pending-contact-requests))}]
:selected-tab selected-tab
:on-tab-change (fn [tab] (rf/dispatch [:messages-home/select-tab tab]))
:scroll-shared-value scroll-shared-value}]]))
@@ -200,7 +200,8 @@
[]
(let [chat-input (rf/sub [:chats/current-chat-input])]
{:images (seq (rf/sub [:chats/sending-image]))
:link-previews? (rf/sub [:chats/link-previews?])
:link-previews? (or (rf/sub [:chats/link-previews?])
(rf/sub [:chats/status-link-previews?]))
:audio (rf/sub [:chats/sending-audio])
:reply (rf/sub [:chats/reply-message])
:edit (rf/sub [:chats/edit-message])
@@ -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]
@@ -35,7 +33,7 @@
:description (i18n/label :t/no-pinned-messages-desc)}]])
(defn f-pinned-messages
[{:keys [theme chat-id]}]
[{:keys [theme chat-id disable-message-long-press?]}]
(let [pinned (rf/sub [:chats/pinned-sorted-list chat-id])
render-data (rf/sub [:chats/current-chat-message-list-view-context :in-pinned-view])
current-chat (rf/sub [:chats/chat-by-id chat-id])
@@ -52,24 +50,17 @@
: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
:render-data render-data
:render-data (assoc render-data :disable-message-long-press? disable-message-long-press?)
:render-fn message-render-fn
:footer [rn/view {:style style/list-footer}]
:key-fn list-key-fn
@@ -31,3 +31,7 @@
:opacity (if (and outgoing (= outgoing-status :sending))
0.5
1)})
(def drawer-message-container
{:padding-top 4
:padding-bottom 8})
@@ -14,18 +14,18 @@
(defn mention-tag-wrapper
[first-child-mention]
{:flex-direction :row
:align-items :center
:height (if platform/ios? 22 21)
:border-radius 6
:transform [{:translateY (if platform/ios? (if first-child-mention 4.5 3) 4.5)}]})
{:flex-direction :row
:align-items :center
:height (if platform/ios? 22 21)
:background-color colors/primary-50-opa-10
:padding-horizontal 3
:border-radius 6
:transform [{:translateY (if platform/ios? (if first-child-mention 4.5 3) 4.5)}]})
(def mention-tag-text
{:color (colors/theme-colors colors/primary-50
colors/primary-60)
:selection-color :transparent
:background-color colors/primary-50-opa-10
:padding-horizontal 3
:suppress-highlighting true})
(defn code
@@ -57,16 +57,14 @@
:mention
(conj
units
(let [resolved-mention (rf/sub [:messages/resolve-mention literal])]
[rn/pressable
{:on-press #(rf/dispatch [:chat.ui/show-profile literal])
:key resolved-mention
:style (style/mention-tag-wrapper first-child-mention)}
[quo/text
{:weight :medium
:style style/mention-tag-text
:size :paragraph-1}
resolved-mention]]))
[rn/pressable
{:on-press #(rf/dispatch [:chat.ui/show-profile literal])
:style (style/mention-tag-wrapper first-child-mention)}
[quo/text
{:weight :medium
:style style/mention-tag-text
:size :paragraph-1}
(rf/sub [:messages/resolve-mention literal])]])
:edited
(conj units
@@ -108,6 +106,7 @@
(render-inline acc e chat-id style-override mention-first))
[quo/text
{:size :paragraph-1
:key (rand-int 1000000) ;; https://github.com/status-im/status-mobile/pull/19203
:style {:margin-bottom (if mention-first (if platform/ios? 4 0) 2)
:margin-top (if mention-first (if platform/ios? -4 0) -1)
:color (when (seq style-override) colors/white)
@@ -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]
@@ -75,11 +77,11 @@
(defn system-message-contact-request
[{:keys [chat-id timestamp-str from]} type]
(let [[primary-name _] (rf/sub [:contacts/contact-two-names-by-identity chat-id])
contact (rf/sub [:contacts/contact-by-address chat-id])
photo-path (when (seq (:images contact)) (rf/sub [:chats/photo-path chat-id]))
customization-color (rf/sub [:profile/customization-color])
{:keys [public-key]} (rf/sub [:profile/profile])]
(let [[primary-name _] (rf/sub [:contacts/contact-two-names-by-identity chat-id])
contact (rf/sub [:contacts/contact-by-address chat-id])
photo-path (when (seq (:images contact)) (rf/sub [:chats/photo-path chat-id]))
customization-color (rf/sub [:profile/customization-color])
public-key (rf/sub [:profile/public-key])]
[quo/system-message
{:type type
:timestamp timestamp-str
@@ -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
@@ -122,35 +152,36 @@
show-user-info? preview? theme]}]
(let [{:keys [content-type quoted-message content
outgoing outgoing-status pinned-by
message-id chat-id]} message-data
first-image (first (:album message-data))
outgoing-status (if (= content-type
constants/content-type-album)
(:outgoing-status first-image)
outgoing-status)
outgoing (if (= content-type
constants/content-type-album)
(:outgoing first-image)
outgoing)
context (assoc context
:on-long-press
#(on-long-press message-data
context
keyboard-shown?))
response-to (:response-to content)
height (rf/sub [:dimensions/window-height])
message-id chat-id]} message-data
{:keys [disable-message-long-press?]} context
first-image (first (:album message-data))
outgoing-status (if (= content-type
constants/content-type-album)
(:outgoing-status first-image)
outgoing-status)
outgoing (if (= content-type
constants/content-type-album)
(:outgoing first-image)
outgoing)
context (assoc context
:on-long-press
#(on-long-press message-data
context
keyboard-shown?))
response-to (:response-to content)
height (rf/sub [:dimensions/window-height])
{window-width :width
window-scale :scale} (rn/get-window)
message-container-data {:window-width window-width
:padding-right 20
:padding-left 20
:avatar-container-width 32
:message-margin-left 8}
reactions (rf/sub [:chats/message-reactions message-id
chat-id])
six-reactions? (-> reactions
count
(= 6))]
window-scale :scale} (rn/get-window)
message-container-data {:window-width window-width
:padding-right 20
:padding-left 20
:avatar-container-width 32
:message-margin-left 8}
reactions (rf/sub [:chats/message-reactions message-id
chat-id])
six-reactions? (-> reactions
count
(= 6))]
[rn/touchable-highlight
{:accessibility-label (if (and outgoing (= outgoing-status :sending))
:message-sending
@@ -174,7 +205,8 @@
(reset! show-delivery-state? true)
(js/setTimeout #(reset! show-delivery-state? false)
delivery-state-showing-time-ms))))
:on-long-press #(on-long-press message-data context keyboard-shown?)}
:on-long-press (when-not disable-message-long-press?
#(on-long-press message-data context keyboard-shown?))}
[:<>
(when pinned-by
[pin/pinned-by-view pinned-by])
@@ -246,14 +278,14 @@
(fn []
[rn/view
{:pointer-events :none
:padding-top 4}
:style style/drawer-message-container}
[user-message-content
{:message-data message-data
:context context
:keyboard-shown? keyboard-shown?
:show-reactions? true
:show-user-info? true
:preview? true}]]))}]))
{:message-data message-data
:context context
:keyboard-shown? keyboard-shown?
:in-reaction-and-action-menu? true
:show-user-info? false
:show-reactions? true}]]))}]))
(defn system-message?
[content-type]
@@ -284,6 +316,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]]]]))
@@ -128,4 +128,8 @@
(rf/defn show-pins-bottom-sheet
{:events [:pin-message/show-pins-bottom-sheet]}
[cofx chat-id]
(navigation/show-bottom-sheet cofx {:content (fn [] [pinned-messages-menu/view {:chat-id chat-id}])}))
(navigation/show-bottom-sheet
cofx
{:content (fn [] [pinned-messages-menu/view
{:chat-id chat-id
:disable-message-long-press? (not= :chat (get-in cofx [:db :view-id]))}])}))
@@ -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))))
@@ -8,89 +8,129 @@
[status-im.contexts.communities.actions.addresses-for-permissions.view :as addresses-for-permissions]
[status-im.contexts.communities.actions.airdrop-addresses.view :as airdrop-addresses]
[status-im.contexts.communities.actions.community-rules.view :as community-rules]
[status-im.contexts.communities.actions.permissions-sheet.view :as permissions-sheet]
[status-im.contexts.communities.utils :as communities.utils]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(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])
has-permissions? (rf/sub [:communities/has-permissions? 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)))
open-permission-sheet
(rn/use-callback (fn []
(rf/dispatch [:show-bottom-sheet
{:content (fn [] [permissions-sheet/view id])}]))
[id])]
(rn/use-mount
(fn []
(rf/dispatch [:communities/initialize-permission-addresses id])))
[rn/safe-area-view {:style style/container}
[quo/page-nav
(cond-> {:text-align :left
:icon-name :i/close
:on-press navigate-back
:accessibility-label :back-button}
has-permissions?
(assoc :right-side
[{:icon-left :i/unlocked
:on-press open-permission-sheet
:label (i18n/label :t/permissions)}]))]
[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 {: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}]])]))

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