Compare commits

...
Author SHA1 Message Date
Ulises Manuel Cárdenas 6c1929096c Add blur variants for context-tag (#15621)
- Split context-tags into context-tag.view & context-tag.style namespaces
- Fix context-tags preview screen & add blur option
2023-04-13 12:07:05 -06:00
Icaro Motta d902fb10d1 New component - URL Preview List (#15620)
Implements the URL Preview List component.

Fixes https://github.com/status-im/status-mobile/issues/15617

Notes
=====

The quo component view implements the pattern recently described by @ulisesmac.
See his great explanation here:
https://github.com/status-im/status-mobile/issues/15552#issuecomment-1492590074.

Steps to test: Go to `Quo2.0 Preview` > `links` > `url-preview-list`
2023-04-13 10:52:27 -03:00
Siddarth Kumar 270f5ab258 Add `extractNativeLibs' flag to reduce apk size (#15638) 2023-04-13 17:21:58 +05:30
jakub c3e52dbf47 ios: provide explicit NODE_ARGS in Nix shell
Some users have reported local `make run-ios` failures with errors like:
```
Command PhaseScriptExecution failed with a nonzero exit code
```
Where the actual error that can be found in `ios/logs/react-native-xcode.log` is:
```
node: bad option: --openssl-legacy-provider
```
Caused by a flag we apply to our pinned Node.js `18.9.1` to fix:
```
opensslErrorStack: [ 'error:03000086:digital envelope routines::initialization error' ],
library: 'digital envelope routines',
reason: 'unsupported',
code: 'ERR_OSSL_EVP_UNSUPPORTED'
```
From: https://github.com/status-im/status-mobile/pull/15167

And the need for that should go away once we upgrade Node.js further.
But for now a decent fix is to not apply that flag directly in Xcode
config so as to avoid the `bad option` error when Xcode us called
outside of Nix context.

Fixes: https://github.com/status-im/status-mobile/issues/15631

Signed-off-by: Jakub Sokołowski <jakub@status.im>
2023-04-13 09:36:42 +02:00
15 changed files with 460 additions and 196 deletions
+4 -1
View File
@@ -32,7 +32,10 @@
android:theme="@style/Theme.AppSplash"
android:name=".MainApplication"
android:largeHeap="true"
android:usesCleartextTraffic="true">
android:usesCleartextTraffic="true"
android:extractNativeLibs="true">
<!-- After upgrading Android Gradle Plugin to 4.2.0 and above we must get rid of `extractNativeLibs="true"`
and use`useLegacyPackaging` flag in our app's `build.gradle`-->
<meta-data android:name="commitHash" android:value="${commitHash}"/>
<activity
android:name=".MainActivity"
+2 -2
View File
@@ -544,7 +544,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = "/usr/bin/env sh";
shellScript = "set -o errexit\nexport NODE_BINARY=\"${NODE_BINARY:-node}\"\nexport NODE_ARGS=\" --openssl-legacy-provider --max-old-space-size=16384 \"\n\nbash -x ../node_modules/react-native/scripts/react-native-xcode.sh > ./logs/react-native-xcode.log 2>&1";
shellScript = "set -o errexit\nexport NODE_BINARY=\"${NODE_BINARY:-node}\"\nexport NODE_ARGS=\"${NODE_ARGS:- --max-old-space-size=16384 }\"\n\nbash -x ../node_modules/react-native/scripts/react-native-xcode.sh > ./logs/react-native-xcode.log 2>&1";
};
3AAD2AD524A3A60E0075D594 /* Bundle React Native code and images */ = {
isa = PBXShellScriptBuildPhase;
@@ -558,7 +558,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = "/usr/bin/env sh";
shellScript = "set -o errexit\nexport NODE_BINARY=\"${NODE_BINARY:-node}\"\nexport NODE_ARGS=\" --openssl-legacy-provider --max-old-space-size=16384 \"\n\nbash -x ../node_modules/react-native/scripts/react-native-xcode.sh > ./logs/react-native-xcode.log 2>&1";
shellScript = "set -o errexit\nexport NODE_BINARY=\"${NODE_BINARY:-node}\"\nexport NODE_ARGS=\"${NODE_ARGS:- --max-old-space-size=16384 }\"\n\nbash -x ../node_modules/react-native/scripts/react-native-xcode.sh > ./logs/react-native-xcode.log 2>&1";
};
3AAD2AD724A3A60E0075D594 /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
+2
View File
@@ -5,6 +5,8 @@ mkShell {
shellHook = ''
# Fix for ERR_OSSL_EVP_UNSUPPORTED error.
export NODE_OPTIONS="--openssl-legacy-provider";
# Same fix but for Xcode React Native script.
export NODE_ARGS="--openssl-legacy-provider --max-old-space-size=16384";
# Fix Xcode using system Node.js version.
export NODE_BINARY="${nodejs}/bin/node";
@@ -0,0 +1,49 @@
(ns quo2.components.links.url-preview-list.component-spec
(:require
[oops.core :as oops]
[quo2.components.links.url-preview-list.view :as view]
[test-helpers.component :as h]))
(def previews
(->> (range 3)
(map inc)
(mapv (fn [index]
{:title (str "Title " index)
:body (str "status.im." index)
:loading? false
:url (str "status.im." index)}))))
(h/describe "Links - URL Preview List"
(h/test "default render"
(h/render [view/view
{:data previews
:key-fn :url
:horizontal-spacing 10}])
(-> (count (h/query-all-by-label-text :url-preview))
(h/expect)
(.toEqual 3))
(-> (map #(oops/oget % "props.children")
(h/query-all-by-label-text :title))
(clj->js)
(h/expect)
(.toStrictEqual #js ["Title 1" "Title 2" "Title 3"])))
(h/test "on-clear event is individually handled by each preview"
(let [on-clear (h/mock-fn)]
(h/render [view/view
{:data previews
:key-fn :url
:on-clear on-clear}])
(h/fire-event :press (first (h/get-all-by-label-text :button-clear-preview)))
(h/fire-event :press (second (h/get-all-by-label-text :button-clear-preview)))
(h/was-called-times on-clear 2)))
(h/test "previews have separate loading states"
(h/render [view/view
{:data (assoc-in previews [1 :loading?] true)
:key-fn :url}])
(h/is-truthy (h/get-by-label-text :url-preview-loading))
(-> (count (h/query-all-by-label-text :url-preview))
(h/expect)
(.toEqual 2))))
@@ -0,0 +1,8 @@
(ns quo2.components.links.url-preview-list.style)
(def url-preview-gap 12)
(def url-preview-separator
{:width url-preview-gap
:padding-top 12
:padding-bottom 8})
@@ -0,0 +1,86 @@
(ns quo2.components.links.url-preview-list.view
(:require
[oops.core :as oops]
[quo2.components.links.url-preview-list.style :as style]
[quo2.components.links.url-preview.view :as url-preview]
[react-native.core :as rn]
[reagent.core :as reagent]))
(defn- use-scroll-to-last-item
[flat-list-ref item-count item-width]
(rn/use-effect
(fn []
(when (and (pos? item-count) (pos? item-width))
;; We use a delay because calling `scrollToOffset` without a delay does
;; nothing while the flatlist is still rendering its children.
;; `scrollToEnd` doesn't work because it positions the item off-center
;; and there's no argument to offset it.
(let [timer-id (js/setTimeout
(fn []
(when (and @flat-list-ref (pos? item-count))
(.scrollToOffset ^js @flat-list-ref
#js
{:animated true
:offset (* (+ item-width style/url-preview-gap)
(max 0 (dec item-count)))})))
25)]
(fn []
(js/clearTimeout timer-id)))))
[item-count item-width]))
(defn- separator
[]
[rn/view {:style style/url-preview-separator}])
(defn- item-component
[{:keys [title body loading? logo]} _ _
{:keys [width on-clear loading-message container-style]}]
[url-preview/view
{:logo logo
:title title
:body body
:loading? loading?
:loading-message loading-message
:on-clear on-clear
:container-style (merge container-style {:width width})}])
(defn- calculate-width
[preview-width horizontal-spacing ^js e]
(reset! preview-width
(- (oops/oget e "nativeEvent.layout.width")
(* 2 horizontal-spacing))))
(defn- view-component
[]
(let [preview-width (reagent/atom 0)
flat-list-ref (atom nil)]
(fn [{:keys [data key-fn horizontal-spacing on-clear loading-message
container-style container-style-item]}]
(use-scroll-to-last-item flat-list-ref (count data) @preview-width)
;; We need to use a wrapping view expanded to 100% instead of "flex 1",
;; otherwise `on-layout` will be triggered multiple times as the flat list
;; renders its children.
[rn/view
{:style (merge container-style {:width "100%"})
:accessibility-label :url-preview-list}
[rn/flat-list
{:ref #(reset! flat-list-ref %)
:key-fn key-fn
:on-layout #(calculate-width preview-width horizontal-spacing %)
:horizontal true
:deceleration-rate :fast
:on-scroll-to-index-failed identity
:content-container-style {:padding-horizontal horizontal-spacing}
:separator [separator]
:snap-to-interval (+ @preview-width style/url-preview-gap)
:shows-horizontal-scroll-indicator false
:data data
:render-fn item-component
:render-data {:width @preview-width
:on-clear on-clear
:loading-message loading-message
:container-style container-style-item}}]])))
(defn view
[props]
[:f> view-component props])
@@ -0,0 +1,55 @@
(ns quo2.components.tags.context-tag.style
(:require [quo2.foundations.colors :as colors]))
(defn base-tag
[override-theme blur?]
{:border-radius 100
:padding-vertical 3
:flex-direction :row
:padding-right 8
:padding-left 8
:background-color (if blur?
(colors/theme-colors colors/neutral-80-opa-5 colors/white-opa-5 override-theme)
(colors/theme-colors colors/neutral-10 colors/neutral-90 override-theme))})
(def context-tag-image
{:width 20
:border-radius 10
:background-color :white
:height 20})
(defn context-tag-icon-color
[blur?]
(if blur?
(colors/theme-colors colors/neutral-80-opa-40 colors/white-opa-40)
(colors/theme-colors colors/neutral-50 colors/neutral-40)))
(def context-tag-text-container
{:align-items :center
:flex-direction :row})
(def audio-tag-container
{:padding-left 2
:padding-vertical 2})
(def audio-tag-icon-container
{:width 20
:height 20
:border-radius 10
:align-items :center
:justify-content :center
:background-color colors/primary-50})
(def audio-tag-icon-color colors/white)
(defn audio-tag-text-color
[override-theme]
(colors/theme-colors colors/neutral-100 colors/white override-theme))
(def community-tag
{:padding-vertical 2})
(defn community-tag-text
[override-theme]
{:margin-left 2
:color (colors/theme-colors colors/neutral-100 colors/white override-theme)})
@@ -0,0 +1,85 @@
(ns quo2.components.tags.context-tag.view
(:require [quo2.components.avatars.group-avatar :as group-avatar]
[quo2.components.icon :as icons]
[quo2.components.markdown.text :as text]
[quo2.components.tags.context-tag.style :as style]
[react-native.core :as rn]))
(defn trim-public-key
[pk]
(str (subs pk 0 6) "..." (subs pk (- (count pk) 3))))
(defn base-tag
[{:keys [override-theme style blur?]} & children]
(into
[rn/view {:style (merge (style/base-tag override-theme blur?) style)}]
children))
(defn group-avatar-tag
[label opts]
[base-tag
(-> opts
(select-keys [:override-theme :style :blur?])
(assoc-in [:style :padding-left] 3)
(assoc-in [:style :padding-vertical] 2))
[group-avatar/group-avatar opts]
[text/text
{:weight :medium
:size :paragraph-2
:style (:text-style opts)}
(str " " label)]])
(defn public-key-tag
[params public-key]
[base-tag params
[text/text
{:weight :monospace
:size :paragraph-2}
(trim-public-key public-key)]])
(defn context-tag
[{:keys [text-style blur?] :as params} photo name channel-name]
(let [text-params {:weight :medium
:size :paragraph-2
:style (assoc text-style :justify-content :center)}]
[base-tag (assoc-in params [:style :padding-left] 3)
[rn/image
{:style style/context-tag-image
:source photo}]
[rn/view {:style style/context-tag-text-container}
[text/text text-params (str " " name)]
(when channel-name
[:<>
[icons/icon
:i/chevron-right
{:color (style/context-tag-icon-color blur?)
:size 16}]
[text/text text-params (str "# " channel-name)]])]]))
(defn user-avatar-tag
[params username photo]
[context-tag params {:uri photo} username])
(defn audio-tag
[duration params]
[base-tag (merge {:style style/audio-tag-container} params)
[rn/view {:style style/audio-tag-icon-container}
[icons/icon
:i/play
{:color style/audio-tag-icon-color
:size 12}]]
[text/text
{:weight :medium
:size :paragraph-2
:style {:margin-left 4
:color (style/audio-tag-text-color (:override-theme params))}}
duration]])
(defn community-tag
[avatar community-name {:keys [override-theme] :as params}]
[context-tag
(merge {:style style/community-tag
:text-style (style/community-tag-text override-theme)}
params)
avatar
community-name])
-126
View File
@@ -1,126 +0,0 @@
(ns quo2.components.tags.context-tags
(:require [quo2.components.avatars.group-avatar :as group-avatar]
[quo2.components.icon :as icons]
[quo2.components.markdown.text :as text]
[quo2.foundations.colors :as colors]
[quo2.theme :as quo2.theme]
[react-native.core :as rn]))
(defn trim-public-key
[pk]
(str (subs pk 0 6) "..." (subs pk (- (count pk) 3))))
(defn base-tag
[_ _]
(fn [{:keys [override-theme style]} & children]
(let [theme (or override-theme (quo2.theme/get-theme))]
(into
[rn/view
(merge
{:border-radius 100
:padding-vertical 3
:flex-direction :row
:padding-right 8
:padding-left 8
:background-color (if (= theme :light)
colors/neutral-10
colors/neutral-90)}
style)]
children))))
(defn group-avatar-tag
[_ _]
(fn [label opts]
[base-tag
(-> opts
(select-keys [:override-theme :style])
(assoc-in [:style :padding-left] 3)
(assoc-in [:style :padding-vertical] 2))
[group-avatar/group-avatar opts]
[text/text
{:weight :medium
:size :paragraph-2
:style (:text-style opts)}
(str " " label)]]))
(defn public-key-tag
[_ _]
(fn [params public-key]
[base-tag params
[text/text
{:weight :monospace
:size :paragraph-2}
(trim-public-key public-key)]]))
(defn context-tag
[_ _]
(fn [params photo name channel-name]
(let [text-style (:text-style params)
text-params {:weight :medium
:size :paragraph-2
:style (assoc text-style :justify-content :center)}
icon-color (colors/theme-colors colors/neutral-50 colors/neutral-40)]
[base-tag (assoc-in params [:style :padding-left] 3)
[rn/image
{:style {:width 20
:border-radius 10
:background-color :white
:height 20}
:source photo}]
[rn/view
{:style {:align-items :center
:flex-direction :row}}
[text/text text-params (str " " name)]
(when channel-name
[:<>
[icons/icon
:i/chevron-right
{:color icon-color
:size 16}]
[text/text text-params (str "# " channel-name)]])]])))
(defn user-avatar-tag
[]
(fn [params username photo]
[context-tag params {:uri photo} username]))
(defn audio-tag
[duration params]
[base-tag
(merge
{:style {:padding-left 2
:padding-vertical 2}}
params)
[rn/view
{:width 20
:height 20
:border-radius 10
:align-items :center
:justify-content :center
:background-color colors/primary-50}
[icons/icon
:i/play
{:color colors/white
:size 12}]]
[text/text
{:weight :medium
:size :paragraph-2
:style {:margin-left 4
:color (colors/theme-colors
colors/neutral-100
colors/white
(:override-theme params))}}
duration]])
(defn community-tag
[avatar community-name params]
[context-tag
(merge
{:style {:padding-vertical 2}
:text-style {:margin-left 2
:color (colors/theme-colors
colors/neutral-100
colors/white
(:override-theme params))}}
params)
avatar community-name])
+8 -7
View File
@@ -34,6 +34,7 @@
quo2.components.inputs.title-input.view
quo2.components.inputs.profile-input.view
quo2.components.links.url-preview.view
quo2.components.links.url-preview-list.view
quo2.components.list-items.channel
quo2.components.list-items.menu-item
quo2.components.list-items.preview-list
@@ -66,7 +67,7 @@
quo2.components.tabs.segmented-tab
quo2.components.tabs.account-selector
quo2.components.tabs.tabs
quo2.components.tags.context-tags
quo2.components.tags.context-tag.view
quo2.components.tags.status-tags
quo2.components.tags.permission-tag
quo2.components.tags.tag
@@ -90,12 +91,11 @@
(def system-message quo2.components.messages.system-message/system-message)
(def reaction quo2.components.reactions.reaction/reaction)
(def add-reaction quo2.components.reactions.reaction/add-reaction)
(def user-avatar-tag quo2.components.tags.context-tags/user-avatar-tag)
(def context-tag quo2.components.tags.context-tags/context-tag)
(def group-avatar-tag quo2.components.tags.context-tags/group-avatar-tag)
(def audio-tag quo2.components.tags.context-tags/audio-tag)
(def community-tag quo2.components.tags.context-tags/community-tag)
(def user-avatar-tag quo2.components.tags.context-tag.view/user-avatar-tag)
(def context-tag quo2.components.tags.context-tag.view/context-tag)
(def group-avatar-tag quo2.components.tags.context-tag.view/group-avatar-tag)
(def audio-tag quo2.components.tags.context-tag.view/audio-tag)
(def community-tag quo2.components.tags.context-tag.view/community-tag)
(def floating-shell-button quo2.components.navigation.floating-shell-button/floating-shell-button)
(def page-nav quo2.components.navigation.page-nav/page-nav)
(def disclaimer quo2.components.selectors.disclaimer.view/view)
@@ -199,3 +199,4 @@
;;;; LINKS
(def url-preview quo2.components.links.url-preview.view/view)
(def url-preview-list quo2.components.links.url-preview-list.view/view)
+1
View File
@@ -13,6 +13,7 @@
[quo2.components.inputs.input.component-spec]
[quo2.components.inputs.profile-input.component-spec]
[quo2.components.inputs.title-input.component-spec]
[quo2.components.links.url-preview-list.component-spec]
[quo2.components.links.url-preview.component-spec]
[quo2.components.markdown.--tests--.text-component-spec]
[quo2.components.onboarding.small-option-card.component-spec]
@@ -0,0 +1,47 @@
(ns status-im2.contexts.quo-preview.links.url-preview-list
(:require
[quo2.core :as quo]
[quo2.foundations.colors :as colors]
[react-native.core :as rn]
[reagent.core :as reagent]
[status-im2.common.resources :as resources]
[status-im2.contexts.quo-preview.preview :as preview]
utils.number))
(def descriptor
[{:label "Number of previews"
:key :previews-length
:type :text}])
(defn cool-preview
[]
(let [state (reagent/atom {:previews-length "3"})]
(fn []
(let [previews-length (min 6 (utils.number/parse-int (:previews-length @state)))]
[rn/view {:style {:padding-bottom 150}}
[preview/customizer state descriptor]
[rn/view
{:style {:align-items :center
:margin-top 50}}
[quo/url-preview-list
{:horizontal-spacing 20
:on-clear #(js/alert "Clear button pressed")
:key-fn :url
:data (for [index (range previews-length)
:let [index (inc index)]]
{:title (str "Title " index)
:body (str "status.im." index)
:logo (resources/get-mock-image :status-logo)
:loading? false
:url (str "status.im." index)})}]]]))))
(defn preview
[]
[rn/view
{:style {:background-color (colors/theme-colors colors/white colors/neutral-95)
:flex 1}}
[rn/flat-list
{:flex 1
:keyboard-should-persist-taps :always
:header [cool-preview]
:key-fn str}]])
@@ -40,6 +40,7 @@
[status-im2.contexts.quo-preview.inputs.profile-input :as profile-input]
[status-im2.contexts.quo-preview.inputs.title-input :as title-input]
[status-im2.contexts.quo-preview.links.url-preview :as url-preview]
[status-im2.contexts.quo-preview.links.url-preview-list :as url-preview-list]
[status-im2.contexts.quo-preview.list-items.channel :as channel]
[status-im2.contexts.quo-preview.list-items.preview-lists :as preview-lists]
[status-im2.contexts.quo-preview.markdown.text :as text]
@@ -183,7 +184,10 @@
:component title-input/preview-title-input}]
:links [{:name :url-preview
:options {:insets {:top? true}}
:component url-preview/preview}]
:component url-preview/preview}
{:name :url-preview-list
:options {:insets {:top? true}}
:component url-preview-list/preview}]
:list-items [{:name :channel
:insets {:top false}
:component channel/preview-channel}
@@ -1,10 +1,10 @@
(ns status-im2.contexts.quo-preview.tags.context-tags
(:require [quo2.components.tags.context-tags :as quo2]
(:require [quo2.components.tags.context-tag.view :as quo2]
[quo2.foundations.colors :as colors]
[react-native.core :as rn]
[reagent.core :as reagent]
[status-im2.common.resources :as resources]
[status-im.multiaccounts.core :as multiaccounts]
[status-im2.common.resources :as resources]
[status-im2.contexts.quo-preview.preview :as preview]))
(def group-avatar-default-params
@@ -20,7 +20,7 @@
(def example-photo2
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAApgAAAKYB3X3/OAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAANCSURBVEiJtZZPbBtFFMZ/M7ubXdtdb1xSFyeilBapySVU8h8OoFaooFSqiihIVIpQBKci6KEg9Q6H9kovIHoCIVQJJCKE1ENFjnAgcaSGC6rEnxBwA04Tx43t2FnvDAfjkNibxgHxnWb2e/u992bee7tCa00YFsffekFY+nUzFtjW0LrvjRXrCDIAaPLlW0nHL0SsZtVoaF98mLrx3pdhOqLtYPHChahZcYYO7KvPFxvRl5XPp1sN3adWiD1ZAqD6XYK1b/dvE5IWryTt2udLFedwc1+9kLp+vbbpoDh+6TklxBeAi9TL0taeWpdmZzQDry0AcO+jQ12RyohqqoYoo8RDwJrU+qXkjWtfi8Xxt58BdQuwQs9qC/afLwCw8tnQbqYAPsgxE1S6F3EAIXux2oQFKm0ihMsOF71dHYx+f3NND68ghCu1YIoePPQN1pGRABkJ6Bus96CutRZMydTl+TvuiRW1m3n0eDl0vRPcEysqdXn+jsQPsrHMquGeXEaY4Yk4wxWcY5V/9scqOMOVUFthatyTy8QyqwZ+kDURKoMWxNKr2EeqVKcTNOajqKoBgOE28U4tdQl5p5bwCw7BWquaZSzAPlwjlithJtp3pTImSqQRrb2Z8PHGigD4RZuNX6JYj6wj7O4TFLbCO/Mn/m8R+h6rYSUb3ekokRY6f/YukArN979jcW+V/S8g0eT/N3VN3kTqWbQ428m9/8k0P/1aIhF36PccEl6EhOcAUCrXKZXXWS3XKd2vc/TRBG9O5ELC17MmWubD2nKhUKZa26Ba2+D3P+4/MNCFwg59oWVeYhkzgN/JDR8deKBoD7Y+ljEjGZ0sosXVTvbc6RHirr2reNy1OXd6pJsQ+gqjk8VWFYmHrwBzW/n+uMPFiRwHB2I7ih8ciHFxIkd/3Omk5tCDV1t+2nNu5sxxpDFNx+huNhVT3/zMDz8usXC3ddaHBj1GHj/As08fwTS7Kt1HBTmyN29vdwAw+/wbwLVOJ3uAD1wi/dUH7Qei66PfyuRj4Ik9is+hglfbkbfR3cnZm7chlUWLdwmprtCohX4HUtlOcQjLYCu+fzGJH2QRKvP3UNz8bWk1qMxjGTOMThZ3kvgLI5AzFfo379UAAAAASUVORK5CYII=")
(def coinbase-community (resources/get-mock-image :coinbase))
(def coinbase-community-image (resources/get-mock-image :coinbase))
(def main-descriptor
[{:label "Type"
@@ -37,7 +37,10 @@
{:key :audio
:value "Audio"}
{:key :community
:value "Community"}]}])
:value "Community"}]}
{:label "Blur"
:key :blur?
:type :boolean}])
(def context-tag-descriptor
[{:label "Label"
@@ -51,73 +54,113 @@
[]
(let [state (reagent/atom {:label "Name"
:channel-name "Channel"
:type :group-avatar})]
:type :group-avatar
:duration "00:32"})]
(fn []
(let [contacts {example-pk {:public-key example-pk
:primary-name "Automatic incompatible Coati"
:photo example-photo}
example-pk2 {:public-key example-pk2
:primary-name "Clearcut Flickering Rattlesnake"
:photo example-photo2}}
(let [contacts {example-pk {:public-key example-pk
:primary-name "Automatic incompatible Coati"
:photo example-photo}
example-pk2 {:public-key example-pk2
:primary-name "Clearcut Flickering Rattlesnake"
:photo example-photo2}}
contacts-public-keys (map (fn [{:keys [public-key]}]
{:key public-key
:value (get-in contacts [public-key :primary-name])})
(vals contacts))
current-username (if (seq (:contact @state))
(->> @state
:contact
contacts
multiaccounts/displayed-name)
"Please select a user")
descriptor
(cond
(= (:type @state) :context-tag) (into main-descriptor context-tag-descriptor)
(= (:type @state) :group-avatar) (conj main-descriptor
{:label "Label"
:key :label
:type :text})
(= (:type @state) :avatar) (let [photo (-> @state :contact contacts :photo)]
(when-not (contains? @state :contacts)
(swap! state assoc :contacts contacts-public-keys))
(when-not (= (:photo @state)
photo)
(swap! state assoc :photo photo))
(conj main-descriptor
{:label "Contacts"
:key :contact
:type :select
:options contacts-public-keys})))]
current-username (if (seq (:contact @state))
(->> @state
:contact
contacts
multiaccounts/displayed-name)
"Please select a user")
descriptor (cond
(= (:type @state) :context-tag)
(into main-descriptor context-tag-descriptor)
(= (:type @state) :group-avatar)
(conj main-descriptor
{:label "Label"
:key :label
:type :text})
(= (:type @state) :avatar)
(let [photo (-> @state :contact contacts :photo)]
(when-not (contains? @state :contacts)
(swap! state assoc :contacts contacts-public-keys))
(when-not (= (:photo @state)
photo)
(swap! state assoc :photo photo))
(conj main-descriptor
{:label "Contacts"
:key :contact
:type :select
:options contacts-public-keys}))
(= (:type @state) :community)
(conj main-descriptor
{:label "Community name"
:key :label
:type :text})
(= (:type @state) :audio)
(conj main-descriptor
{:label "Duration"
:key :duration
:type :text})
:else
main-descriptor)]
[rn/touchable-without-feedback {:on-press rn/dismiss-keyboard!}
[rn/view {:padding-bottom 150}
[rn/view {:flex 1}
[rn/view {:style {:padding-bottom 150}}
[rn/view {:style {:flex 1}}
[preview/customizer state descriptor]]
[rn/view
{:padding-vertical 60
:flex-direction :row
:justify-content :center}
(case (:type @state)
:context-tag
[quo2/context-tag group-avatar-default-params {:uri example-photo2} (:label @state)
(:channel-name @state)]
:group-avatar
[quo2/group-avatar-tag (:label @state) group-avatar-default-params]
:public-key
[quo2/public-key-tag {} example-pk]
:avatar
[quo2/user-avatar-tag {} current-username (:photo @state)]
:audio
[quo2/audio-tag "00:32"]
:community
[quo2/community-tag coinbase-community "Coinbase"])]]]))))
[rn/view {:style {:padding-vertical 60}}
[preview/blur-view
{:style {:flex 1
:margin-vertical 20
:margin-horizontal 40}
:show-blur-background? (:blur? @state)}
(case (:type @state)
:context-tag [quo2/context-tag
{:blur? (:blur? @state)
:size :small
:color :purple}
{:uri example-photo2}
(:label @state)
(:channel-name @state)]
:group-avatar [quo2/group-avatar-tag (:label @state)
{:blur? (:blur? @state)
:size :small
:color :purple}]
:public-key [quo2/public-key-tag
{:blur? (:blur? @state)
:size :small
:color :purple}
example-pk]
:avatar [quo2/user-avatar-tag
{:blur? (:blur? @state)
:size :small
:color :purple}
current-username (:photo @state)]
:audio [quo2/audio-tag (:duration @state) {:blur? (:blur? @state)}]
:community [quo2/community-tag
coinbase-community-image
(:label @state)
{:blur? (:blur? @state)}])]]]]))))
(defn preview-context-tags
[]
[rn/view
{:background-color (colors/theme-colors colors/white
colors/neutral-95)
:flex 1}
{:style {:background-color (colors/theme-colors colors/white
colors/neutral-95)
:flex 1}}
[rn/flat-list
{:flex 1
{:style {:flex 1}
:keyboardShouldPersistTaps :always
:header [cool-preview]
:key-fn str}]])
+6
View File
@@ -61,6 +61,8 @@
"Pretty-print to STDOUT the current component tree."
(with-node-or-screen :debug))
(def within rtl/within)
(defn fire-event
([event-name node]
(fire-event event-name node nil))
@@ -188,3 +190,7 @@
(defn was-called
[mock]
(.toHaveBeenCalled (js/expect mock)))
(defn was-called-times
[^js mock number-of-times]
(.toHaveBeenCalledTimes (js/expect mock) number-of-times))