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
flexsurfer e26d3a856d migrate reagent part 3 (#19165) 2024-03-13 16:46:44 +01:00
231 changed files with 5571 additions and 2936 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 @@
2.28.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))
@@ -1,7 +1,6 @@
(ns quo.components.colors.color-picker.component-spec
(:require
[quo.components.colors.color-picker.view :as color-picker]
[reagent.core :as reagent]
[test-helpers.component :as h]))
(h/describe "color-picker"
@@ -12,7 +11,7 @@
(-> (h/expect event)
(.toHaveBeenCalled))))
(h/test "color picker color changed"
(let [selected (reagent/atom nil)]
(let [selected (atom nil)]
(h/render [color-picker/view {:on-change #(reset! selected %)}])
(h/fire-event :press (get (h/get-all-by-label-text :color-picker-item) 0))
(-> (h/expect @selected)
@@ -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 -76
View File
@@ -6,8 +6,7 @@
[quo.foundations.colors :as colors]
[quo.theme :as quo.theme]
[react-native.core :as rn]
[react-native.reanimated :as reanimated]
[reagent.core :as reagent]))
[react-native.reanimated :as reanimated]))
(def header-height 56)
@@ -57,7 +56,7 @@
:justify-content :center
:align-items :flex-end})
(defn title-style
(defn get-title-style
[{:keys [left right]} title-align]
(merge
absolute-fill
@@ -133,76 +132,77 @@
:size :large}
title])])
(defn- header-internal
[{:keys [left-width right-width]}]
(let [layout (reagent/atom {:left {:width (or left-width 8)
:height header-height}
:right {:width (or right-width 8)
:height header-height}
:title {:width 0
:height header-height}})
handle-layout (fn [el get-layout]
(fn [evt]
(let [width (oget evt "nativeEvent" "layout" "width")
height (oget evt "nativeEvent" "layout" "height")]
(when get-layout
(get-layout el
{:width width
:height height}))
(swap! layout assoc
el
{:width width
:height height}))))]
(fn
[{:keys [left-accessories left-component border-bottom
right-accessories right-component insets get-layout
title subtitle title-component style title-align
background theme]
:or {title-align :center
border-bottom false}}]
(let [status-bar-height (get insets :top 0)
height (+ header-height status-bar-height)]
[reanimated/view
{:style (header-wrapper-style {:height height
:background background
:border-bottom border-bottom
:theme theme})}
[rn/view
{:pointer-events :box-none
:height status-bar-height}]
[rn/view
{:style (merge {:height header-height}
style)
:pointer-events :box-none}
[rn/view
{:style absolute-fill
:pointer-events :box-none}
[rn/view
{:style content
:pointer-events :box-none}
[rn/view
{:style left-style
:on-layout (handle-layout :left get-layout)
:pointer-events :box-none}
[header-actions
{:accessories left-accessories
:component left-component}]]
[rn/view
{:style (title-style @layout title-align)
:on-layout (handle-layout :title get-layout)
:pointer-events :box-none}
[header-title
{:title title
:subtitle subtitle
:title-align title-align
:component title-component}]]
[rn/view
{:style right-style
:on-layout (handle-layout :right get-layout)
:pointer-events :box-none}
[header-actions
{:accessories right-accessories
:component right-component}]]]]]]))))
(def header (quo.theme/with-theme header-internal))
(defn header
[{:keys [left-accessories left-component border-bottom left-width right-width
right-accessories right-component insets get-layout
title subtitle title-component style title-align
background]
:or {title-align :center
border-bottom false}}]
(let [theme (quo.theme/use-theme-value)
[layout set-layout] (rn/use-state {:left {:width (or left-width 8)
:height header-height}
:right {:width (or right-width 8)
:height header-height}
:title {:width 0
:height header-height}})
handle-layout (rn/use-callback
(fn [el get-layout]
(fn [evt]
(let [width (oget evt "nativeEvent" "layout" "width")
height (oget evt "nativeEvent" "layout" "height")]
(when get-layout
(get-layout el
{:width width
:height height}))
(set-layout
(assoc layout
el
{:width width
:height height})))))
[layout])
status-bar-height (get insets :top 0)
height (+ header-height status-bar-height)
title-style (rn/use-memo (fn [] (get-title-style layout title-align))
[layout title-align])]
[reanimated/view
{:style (header-wrapper-style {:height height
:background background
:border-bottom border-bottom
:theme theme})}
[rn/view
{:pointer-events :box-none
:height status-bar-height}]
[rn/view
{:style (merge {:height header-height}
style)
:pointer-events :box-none}
[rn/view
{:style absolute-fill
:pointer-events :box-none}
[rn/view
{:style content
:pointer-events :box-none}
[rn/view
{:style left-style
:on-layout (handle-layout :left get-layout)
:pointer-events :box-none}
[header-actions
{:accessories left-accessories
:component left-component}]]
[rn/view
{:style title-style
:on-layout (handle-layout :title get-layout)
:pointer-events :box-none}
[header-title
{:title title
:subtitle subtitle
:title-align title-align
:component title-component}]]
[rn/view
{:style right-style
:on-layout (handle-layout :right get-layout)
:pointer-events :box-none}
[header-actions
{:accessories right-accessories
:component right-component}]]]]]]))
@@ -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])]])
+22 -22
View File
@@ -5,8 +5,7 @@
[quo.components.markdown.text :as text]
[quo.foundations.colors :as colors]
[quo.theme :as theme]
[react-native.core :as rn]
[reagent.core :as reagent]))
[react-native.core :as rn]))
;;; helpers
(def themes
@@ -137,24 +136,25 @@
style
on-press
warning-label]}]
(let [body-height (reagent/atom nil)]
(fn []
[rn/view
{:on-layout #(reset! body-height (oget % "nativeEvent.layout.height"))
:overflow :hidden
:flex 1}
[hborder {:type :top}]
[hborder {:type :bottom}]
[rn/view
(merge {:width "100%"
:background-color (get-color :background)
:flex-direction :row
:padding 20
:padding-left 31
:margin-vertical 4}
style)
(let [[body-height set-body-height] (rn/use-state nil)
on-layout (rn/use-callback #(set-body-height
(oget % "nativeEvent.layout.height")))]
[rn/view
{:on-layout on-layout
:overflow :hidden
:flex 1}
[hborder {:type :top}]
[hborder {:type :bottom}]
[rn/view
(merge {:width "100%"
:background-color (get-color :background)
:flex-direction :row
:padding 20
:padding-left 31
:margin-vertical 4}
style)
[timeline]
[body timestamp-far timestamp-near on-info-button-pressed on-press warning-label]]
[vborder :left body-height]
[vborder :right body-height]])))
[timeline]
[body timestamp-far timestamp-near on-info-button-pressed on-press warning-label]]
[vborder :left body-height]
[vborder :right body-height]]))
@@ -4,50 +4,48 @@
[quo.components.markdown.text :as text]
[quo.components.numbered-keyboard.keyboard-key.style :as style]
[quo.theme :as quo.theme]
[react-native.core :as rn]
[reagent.core :as reagent]))
[react-native.core :as rn]))
(defn- label->accessibility-label
[label]
(let [label-name (if (keyword? label) (name label) label)]
(keyword (str "keyboard-key-" label-name))))
(defn- view-internal
[]
(let [pressed? (reagent/atom false)]
(fn [{:keys [disabled? theme blur? on-press on-long-press type]} label]
(let [label-color (style/get-label-color disabled? theme blur?)
background-color (style/toggle-background-color @pressed? blur? theme)]
[rn/pressable
{:accessibility-label (label->accessibility-label label)
:disabled (or disabled? (not label))
:on-press (fn []
(when on-press
(on-press label)))
:on-long-press (fn []
(when (fn? on-long-press)
(on-long-press label)))
:allow-multiple-presses? true
:on-press-in #(reset! pressed? true)
:on-press-out #(reset! pressed? false)
:hit-slop {:top 8 :bottom 8 :left 25 :right 25}
:style (style/container background-color)}
(case type
:key [icons/icon
label
{:color label-color
:accessibility-label :icon-label}]
:digit [text/text
{:accessibility-label :text-label
:weight :regular
:size :heading-1
:style {:color label-color}}
label]
:derivation-path [icons/icon
:i/derivation-path
{:color label-color
:size 32
:accessibility-label :derivation-path-label}]
nil)]))))
(def view (quo.theme/with-theme view-internal))
(defn view
[{:keys [disabled? blur? on-press on-long-press type]} label]
(let [theme (quo.theme/use-theme-value)
[pressed? set-pressed?] (rn/use-state false)
on-press (rn/use-callback #(when on-press (on-press label)) [label])
on-long-press (rn/use-callback #(when (fn? on-long-press) (on-long-press label))
[label])
on-press-in (rn/use-callback #(set-pressed? true))
on-press-out (rn/use-callback #(set-pressed? false))
label-color (style/get-label-color disabled? theme blur?)
background-color (style/toggle-background-color pressed? blur? theme)]
[rn/pressable
{:accessibility-label (label->accessibility-label label)
:disabled (or disabled? (not label))
:on-press on-press
:on-long-press on-long-press
:allow-multiple-presses? true
:on-press-in on-press-in
:on-press-out on-press-out
:hit-slop {:top 8 :bottom 8 :left 25 :right 25}
:style (style/container background-color)}
(case type
:key [icons/icon
label
{:color label-color
:accessibility-label :icon-label}]
:digit [text/text
{:accessibility-label :text-label
:weight :regular
:size :heading-1
:style {:color label-color}}
label]
:derivation-path [icons/icon
:i/derivation-path
{:color label-color
:size 32
:accessibility-label :derivation-path-label}]
nil)]))
@@ -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))
@@ -3,48 +3,33 @@
[quo.components.avatars.user-avatar.view :as user-avatar]
[quo.components.markdown.text :as text]
[quo.components.profile.select-profile.style :as style]
[react-native.core :as rn]
[reagent.core :as reagent]))
(defn- on-change-handler
[selected? on-change]
(swap! selected? not)
(when on-change (on-change @selected?)))
[react-native.core :as rn]))
(defn view
"Options
- `default-selected?` The default selected state. Use when the component is not controlled.
- `selected?` Selected state. Use when the component is controlled.
- `name` Full name
- `profile-picture` Profile picture
- `customization-color` Customization color
- `(on-change selected?)` On change event handler
"
[{:keys [default-selected?]}]
(let [internal-selected? (reagent/atom (or default-selected? false))]
(fn [{:keys [selected?
profile-picture
name
customization-color
on-change]
:or {customization-color :turquoise}}]
(when (and (not (nil? selected?)) (not= @internal-selected? selected?))
(reset! internal-selected? selected?))
[rn/touchable-opacity
{:style (style/container customization-color @internal-selected?)
:on-press #(on-change-handler internal-selected? on-change)
:active-opacity 1
:accessibility-label :select-profile}
[rn/view {:style style/header}
[user-avatar/user-avatar
{:full-name name
:status-indicator? false
:size :medium
:profile-picture profile-picture}]
[rn/view {:style (style/select-radio @internal-selected?)}
(when @internal-selected? [rn/view {:style style/select-radio-inner}])]]
[text/text
{:size :heading-2
:weight :semi-bold
:style style/profile-name}
name]])))
[{:keys [selected? profile-picture name customization-color on-change]
:or {customization-color :turquoise}}]
[rn/touchable-opacity
{:style (style/container customization-color selected?)
:on-press #(when on-change (on-change (not selected?)))
:accessibility-label :select-profile}
[rn/view {:style style/header}
[user-avatar/user-avatar
{:full-name name
:status-indicator? false
:size :medium
:profile-picture profile-picture}]
[rn/view {:style (style/select-radio selected?)}
(when selected?
[rn/view {:style style/select-radio-inner}])]]
[text/text
{:size :heading-2
:weight :semi-bold
:style style/profile-name}
name]])
@@ -1,7 +1,6 @@
(ns quo.components.profile.showcase-nav.component-spec
(:require
[quo.components.profile.showcase-nav.view :as view]
[reagent.core :as reagent]
[test-helpers.component :as h]))
(def nav-data
@@ -35,7 +34,7 @@
(.toHaveBeenCalled))))
(h/test "active id updated"
(let [active-id (reagent/atom :recent)]
(let [active-id (atom :recent)]
(h/render [view/view
{:data nav-data
:on-press #(reset! active-id %)}])
@@ -7,17 +7,23 @@
[quo.foundations.colors :as colors]
[quo.theme :as quo.theme]
[react-native.core :as rn]
[react-native.draggable-flatlist :as draggable-flatlist]
[reagent.core :as reagent]))
[react-native.draggable-flatlist :as draggable-flatlist]))
(defn on-drag-end-fn
[data atom-data]
(reset! atom-data data)
(reagent/flush))
(defn key-fn [item index] (str (:title item) index))
(defn- reorder-category-internal
[{:keys [label data blur? theme container-style]}]
(reagent/with-let [atom-data (reagent/atom data)]
(defn reorder-category
[{:keys [label data blur? container-style]}]
(let [theme (quo.theme/use-theme-value)
[atom-data set-atom-data] (rn/use-state data)
render-fn (rn/use-callback
(fn [item _ _ _ _ drag]
[reorder-item/reorder-item item types/item
{:blur? blur? :drag drag}])
[blur?])
on-drag-end-fn (rn/use-callback (fn [_ _ data] (set-atom-data data)))
separator (rn/use-memo (fn [] [rn/view
{:style (style/reorder-separator blur? theme)}])
[blur? theme])]
[rn/view {:style (merge (style/container label) container-style)}
[text/text
{:weight :medium
@@ -25,14 +31,9 @@
:style {:color (colors/theme-colors colors/neutral-50 colors/neutral-40 theme)}}
label]
[draggable-flatlist/draggable-flatlist
{:data @atom-data
:key-fn (fn [item index] (str (:title item) index))
{:data atom-data
:key-fn key-fn
:style style/reorder-items
:render-fn (fn [item _ _ _ _ drag] [reorder-item/reorder-item item types/item
{:blur? blur? :drag drag}])
:on-drag-end-fn (fn [_ _ data]
(on-drag-end-fn data atom-data))
:separator [rn/view
{:style (style/reorder-separator blur? theme)}]}]]))
(def reorder-category (quo.theme/with-theme reorder-category-internal))
:render-fn render-fn
:on-drag-end-fn on-drag-end-fn
:separator separator}]]))
@@ -16,7 +16,6 @@
[quo.foundations.colors :as colors]
[quo.theme]
[react-native.core :as rn]
[reagent.core :as reagent]
[schema.core :as schema]
[utils.i18n :as i18n]))
@@ -190,20 +189,20 @@
(defn- view-internal
[props]
(reagent/with-let [component-width (reagent/atom nil)
container-component [rn/view {:background-color style/overlay-color}]]
(let [[component-width
set-component-width] (rn/use-state nil)
on-layout (rn/use-callback #(set-component-width
(oops/oget % "nativeEvent.layout.width")))
props (-> props
(assoc :component-width component-width)
(clojure.set/rename-keys {:type :share-qr-type}))]
[quo.theme/provider {:theme :dark}
[rn/view
{:accessibility-label :share-qr-code
:style style/outer-container
:on-layout #(reset! component-width (oops/oget % "nativeEvent.layout.width"))}
(conj container-component
(when @component-width
[share-qr-code
(-> props
(assoc :component-width @component-width)
(clojure.set/rename-keys {:type :share-qr-type}))]))]]))
:on-layout on-layout}
[rn/view {:style {:background-color style/overlay-color}}
(when component-width
[share-qr-code props])]]]))
(def view
(quo.theme/with-theme
(schema/instrument #'view-internal component-schema/?schema)))
(def view (schema/instrument #'view-internal component-schema/?schema))
+39 -40
View File
@@ -3,8 +3,7 @@
[quo.components.tabs.tab.view :as tab]
[quo.foundations.colors :as colors]
[quo.theme :as quo.theme]
[react-native.core :as rn]
[reagent.core :as reagent]))
[react-native.core :as rn]))
(def themes-for-blur
{:light {:background-color colors/neutral-80-opa-5}
@@ -14,41 +13,41 @@
{:light {:background-color colors/neutral-10}
:dark {:background-color colors/neutral-90}})
(defn- segmented-control-internal
[{:keys [default-active on-change]}]
(let [active-tab-id (reagent/atom default-active)]
(fn [{:keys [data size theme blur? container-style item-container-style
active-item-container-style]}]
(let [active-id @active-tab-id]
[rn/view
(merge
{:flex-direction :row
:background-color (get-in (if blur? themes-for-blur themes)
[theme :background-color])
:border-radius (case size
32 10
28 10
24 8
20 6)
:padding 2}
container-style)
(for [[indx {:keys [label id]}] (map-indexed vector data)]
^{:key id}
[rn/view
{:margin-left (if (= 0 indx) 0 2)
:flex 1}
[tab/view
{:id id
:active-item-container-style active-item-container-style
:item-container-style item-container-style
:segmented? true
:size size
:blur? blur?
:active (= id active-id)
:on-press (fn [tab-id]
(reset! active-tab-id tab-id)
(when on-change
(on-change tab-id)))}
label]])]))))
(def segmented-control (quo.theme/with-theme segmented-control-internal))
(defn segmented-control
[{:keys [data size blur? container-style item-container-style
active-item-container-style default-active on-change]}]
(let [theme (quo.theme/use-theme-value)
[active-tab-id
set-active-tab-id] (rn/use-state default-active)
on-press (rn/use-callback
(fn [tab-id]
(set-active-tab-id tab-id)
(when on-change (on-change tab-id)))
[on-change])]
[rn/view
(merge
{:flex-direction :row
:background-color (get-in (if blur? themes-for-blur themes)
[theme :background-color])
:border-radius (case size
32 10
28 10
24 8
20 6)
:padding 2}
container-style)
(for [[indx {:keys [label id]}] (map-indexed vector data)]
^{:key id}
[rn/view
{:margin-left (if (= 0 indx) 0 2)
:flex 1}
[tab/view
{:id id
:active-item-container-style active-item-container-style
:item-container-style item-container-style
:segmented? true
:size size
:blur? blur?
:active (= id active-tab-id)
:on-press on-press}
label]])]))
+102 -104
View File
@@ -41,7 +41,7 @@
(into [:<>] children)))
(defn- on-scroll-handler
[{:keys [on-scroll fading fade-end-percentage fade-end?]} ^js e]
[{:keys [on-scroll fading set-fading fade-end-percentage fade-end?]} ^js e]
(when fade-end?
(let [offset-x (oget e "nativeEvent.contentOffset.x")
content-width (oget e "nativeEvent.contentSize.width")
@@ -52,11 +52,8 @@
:layout-width layout-width
:max-fade-percentage fade-end-percentage})]
;; Avoid unnecessary re-rendering.
(when (not= new-percentage
(get @fading :fade-end-percentage))
(swap! fading assoc
:fade-end-percentage
new-percentage))))
(when (not= new-percentage (get fading :fade-end-percentage))
(set-fading new-percentage))))
(when on-scroll
(on-scroll e)))
@@ -66,10 +63,8 @@
{:keys [active-tab-id
blur?
customization-color
flat-list-ref
number-of-items
on-change
scroll-on-press?
on-press
size
style]}]
[rn/view
@@ -85,17 +80,8 @@
:accessibility-label accessibility-label
:size size
:blur? blur?
:active (= id @active-tab-id)
:on-press (fn [id]
(reset! 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)))}
:active (= id active-tab-id)
:on-press #(on-press % index)}
label]])
(defn view
@@ -118,87 +104,99 @@
- `scroll-on-press?` When non-nil, clicking on a tag centers it the middle
(with animation enabled).
"
[{:keys [default-active fade-end-percentage]
:or {fade-end-percentage 0.8}}]
(let [active-tab-id (reagent/atom default-active)
fading (reagent/atom {:fade-end-percentage fade-end-percentage})
flat-list-ref (atom nil)]
(fn
[{:keys [data
fade-end-percentage
fade-end?
on-change
on-scroll
scroll-on-press?
scrollable?
style
container-style
size
blur?
in-scroll-view?
customization-color]
:or {fade-end-percentage fade-end-percentage
fade-end? false
scrollable? false
scroll-on-press? false
size default-tab-size}
:as props}]
(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?}
[(if in-scroll-view?
gesture/flat-list
rn/flat-list)
(merge
(dissoc props
:default-active
:fade-end-percentage
:fade-end?
:on-change
:scroll-on-press?
:size)
(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
:content-container-style
(assoc container-style :padding-top (dec unread-count-offset))
:horizontal true
:scroll-event-throttle 64
:shows-horizontal-scroll-indicator false
:data data
:key-fn (comp str :id)
:on-scroll-to-index-failed identity
:on-scroll (partial on-scroll-handler
{:fade-end-percentage fade-end-percentage
:fade-end? fade-end?
:fading fading
:on-scroll on-scroll})
:render-fn tab-view
:render-data {:active-tab-id 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
: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
:blur? blur?
:customization-color customization-color
:number-of-items (count data)
:on-change on-change
:size size
:style style}])
data)]))))
[{:keys [default-active data fade-end-percentage fade-end? on-change on-scroll scroll-on-press?
scrollable? style container-style size blur? in-scroll-view? customization-color]
:or {fade-end-percentage 0.8
fade-end? false
scrollable? false
scroll-on-press? false
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)
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 fading :fade-end? fade-end?}
[(if in-scroll-view?
gesture/flat-list
rn/flat-list)
(merge
clean-props
{: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
:content-container-style
(assoc container-style :padding-top (dec unread-count-offset))
:horizontal true
:scroll-event-throttle 64
:shows-horizontal-scroll-indicator false
:data data
: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
:blur? blur?
:customization-color customization-color
:number-of-items (count data)
: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
:blur? blur?
:customization-color customization-color
:number-of-items (count data)
: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]]]})))

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