Compare commits

..
Author SHA1 Message Date
Yevheniia Berdnyk 068e47bb79 Android 11 - test 2023-04-13 02:59:43 +03:00
209 changed files with 1606 additions and 2830 deletions
-11
View File
@@ -282,17 +282,6 @@ else
npx react-native run-ios
endif
show-ios-devices: export TARGET := ios
show-ios-devices: ##@other shows connected ios device and its name
xcrun xctrace list devices
run-ios-device: export TARGET := ios
run-ios-device: ##@run iOS app and start it on a connected device by its name
ifndef DEVICE_NAME
$(error Usage: make run-ios-device DEVICE_NAME=your-device-name)
endif
react-native run-ios --device "$(DEVICE_NAME)"
#--------------
# Tests
#--------------
+1 -4
View File
@@ -32,10 +32,7 @@
android:theme="@style/Theme.AppSplash"
android:name=".MainApplication"
android:largeHeap="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`-->
android:usesCleartextTraffic="true">
<meta-data android:name="commitHash" android:value="${commitHash}"/>
<activity
android:name=".MainActivity"
+1 -1
View File
@@ -4,7 +4,7 @@ library 'status-jenkins-lib@v1.6.9'
def isPRBuild = utils.isPRBuild()
pipeline {
agent { label 'macos && arm64 && nix-2.11 && xcode-14.3' }
agent { label 'macos && arm64 && nix-2.11 && xcode-14.2' }
parameters {
string(
+3 -3
View File
@@ -23,13 +23,13 @@ setups and runs the test suite once.
setups and runs the test suite and watches for code changes will then retrigger the test suite.
## Writing Tests
New test files will need their namespace added to either the file "src/quo2/core_spec.cljs" or "src/status_im2/core_spec.cljs. These locations may update overtime but it is dependent on the entrypoint in shadow-cljs config discussed below.
New test files will need their namespace added to either the file "src/quo2/core_spec.cljs" or "src/status_im2/core_spec.cljs. These locations may update overtime but it is dependent on the entrypoint in shadowcljs config discussed below.
### Best practices
For the moment we will keep best practices for tests in our other guidelines document:
To that point these guidelines will follow the conventions of Jest and React Native Testing Library recommendations and Status mobile will just stack their preferences on top.
To that point these guidelines will follow the conventions of Jest and React Native Testing Library recomendations and Status mobile will just stack their preferences on top.
### Utilities
There is a file of utility functions defined in "src/test_helpers/component.cljs" and "src/test_helpers/component.clj". It will be great to use these utilities and to add any common testing tools to these files as it should make writing tests easier and faster.
@@ -52,4 +52,4 @@ It's worth knowing that our tests are compiled to JS and then run in the tempora
### Jest
There is also further configuration for Jest in "test/jest". There is a jest config file which has some mostly standard configuration pieces, where the tests live, what environment variables are set etc. This is documented by Jest here: https://jestjs.io/docs/configuration
There is also a setup file which is used to set some global and default values. Additionally this file is used to mock some of the react native (among other) dependencies
There is also a setup file which is used to set some global and default values. Additionally this file is used to mock some of the react native (among other) dependencies
+9 -5
View File
@@ -417,7 +417,9 @@
TestTargetID = 13B07F861A680F5B00A75B9A;
};
13B07F861A680F5B00A75B9A = {
DevelopmentTeam = 8B5X2M6H2Y;
LastSwiftMigration = 1140;
ProvisioningStyle = Manual;
SystemCapabilities = {
com.apple.BackgroundModes = {
enabled = 1;
@@ -542,7 +544,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = "/usr/bin/env sh";
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";
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";
};
3AAD2AD524A3A60E0075D594 /* Bundle React Native code and images */ = {
isa = PBXShellScriptBuildPhase;
@@ -556,7 +558,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = "/usr/bin/env sh";
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";
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";
};
3AAD2AD724A3A60E0075D594 /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
@@ -841,8 +843,9 @@
BUNDLE_ID_SUFFIX = .debug;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = StatusIm/StatusIm.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CODE_SIGN_IDENTITY = "iPhone Distribution";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CODE_SIGN_STYLE = Manual;
CUSTOM_PRODUCT_NAME = "Status Debug";
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 8B5X2M6H2Y;
@@ -896,7 +899,8 @@
PRESERVE_DEAD_CODE_INITS_AND_TERMS = YES;
PRODUCT_BUNDLE_IDENTIFIER = im.status.ethereum;
PRODUCT_NAME = StatusIm;
PROVISIONING_PROFILE_SPECIFIER = "";
PROVISIONING_PROFILE = "9da75626-9594-43d9-a827-0f6d43c28f54";
PROVISIONING_PROFILE_SPECIFIER = "match Development im.status.ethereum";
SWIFT_OBJC_BRIDGING_HEADER = "StatusIm-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
-13
View File
@@ -15,7 +15,6 @@ stdenv.mkDerivation {
"patchYogaNodePackagePhase"
"patchReactNativePhase"
"patchPodPhase"
"patchReactNativeXcodeScriptPhase"
"installPhase"
];
@@ -107,18 +106,6 @@ stdenv.mkDerivation {
'[RCTConvert UIColor:options.tintColor() ? @(*options.tintColor()) : nil];'
'';
# Patch React Native Xcode Script that searches for nvm
# FIXME: Remove this once we upgrade react-native to 0.69.x
patchReactNativeXcodeScriptPhase = ''
substituteInPlace ./node_modules/react-native/scripts/find-node.sh --replace \
'# Define NVM_DIR and source the nvm.sh setup script' \
'<<MULTI_LINE_COMMENT${"\n"}# Define NVM_DIR and source the nvm.sh setup script'
substituteInPlace ./node_modules/react-native/scripts/find-node.sh --replace \
'# Set up the nodenv node version manager if present' \
'MULTI_LINE_COMMENT${"\n"}# Set up the nodenv node version manager if present'
'';
# The ELF types are incompatible with the host platform, so let's not even try
# TODO: Use Android NDK to strip binaries manually
+1 -5
View File
@@ -1,9 +1,6 @@
{ callPackage, lib, mkShell, pkgs, stdenv
{ callPackage, lib, mkShell, pkgs
, status-go, fastlane }:
assert lib.assertMsg stdenv.isDarwin
"iOS development shell supported only on OSX.";
let
inherit (lib) catAttrs unique;
@@ -20,7 +17,6 @@ in {
buildInputs = with pkgs; [
xcodeWrapper watchman procps
flock # used in nix/scripts/node_modules.sh
ios-deploy # used in 'make run-ios-device'
];
# WARNING: Executes shellHook in reverse order.
+3 -3
View File
@@ -1,15 +1,15 @@
{ mkShell, nodejs, deps }:
mkShell {
# Check if node modules changed and if so install them.
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";
# Check if node modules changed and if so install them.
export STATUS_MOBILE_HOME=$(git rev-parse --show-toplevel)
"$STATUS_MOBILE_HOME/nix/scripts/node_modules.sh" ${deps.nodejs-patched}
'';
}
+1 -13
View File
@@ -44,25 +44,13 @@ in {
});
};
# Fix for missing libarclite_macosx.a in Xcode 14.3.
# https://github.com/ios-control/ios-deploy/issues/580
ios-deploy = super.darwin.ios-deploy.overrideAttrs (old: rec {
version = "1.12.2";
src = super.fetchFromGitHub {
owner = "ios-control";
repo = "ios-deploy";
rev = version;
sha256 = "sha256-TVGC+f+1ow3b93CK3PhIL70le5SZxxb2ug5OkIg8XCA";
};
});
# Package version adjustments
gradle = super.gradle_6;
nodejs = super.nodejs-18_x;
yarn = super.yarn.override { nodejs = super.nodejs-18_x; };
openjdk = super.openjdk8_headless;
xcodeWrapper = callPackage ./pkgs/xcodeenv/compose-xcodewrapper.nix { } {
version = "14.0";
version = "13.3";
allowHigher = true;
};
go = super.go_1_19;
+6 -3
View File
@@ -12,19 +12,22 @@ let
# the default shell with most commonly used tools
default = callPackage ./shell.nix { };
# Combines with many other shells
nodejs-sh = targets.mobile.ios.nodejs-sh;
# An attrset for easier merging with default shell
shells = {
inherit default;
nodejs = nodejs-sh;
# for calling clojure targets in CI or Makefile
clojure = mkShell {
buildInputs = with pkgs; [ clojure flock maven openjdk ];
inputsFrom = [ nodejs-sh ];
# CLASSPATH from clojure deps with 'src' appended to find local sources.
shellHook = with pkgs; ''
export CLASS_PATH="$(find ${deps.clojure} -iname '*.jar' | tr '\n' ':')src"
# Check if node modules changed and if so install them.
"$STATUS_MOBILE_HOME/nix/scripts/node_modules.sh" ${pkgs.deps.nodejs-patched}
'';
};

Before

Width:  |  Height:  |  Size: 6.7 KiB

After

Width:  |  Height:  |  Size: 6.7 KiB

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Before

Width:  |  Height:  |  Size: 539 KiB

After

Width:  |  Height:  |  Size: 539 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 153 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 377 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 738 KiB

+4 -4
View File
@@ -71,7 +71,7 @@
{:background-color (:ui-background @colors/theme)
:flex 1}
[rn/flat-list
{:flex 1
:keyboard-should-persist-taps :always
:header [cool-preview]
:key-fn str}]]))
{:flex 1
:keyboardShouldPersistTaps :always
:header [cool-preview]
:key-fn str}]]))
+4 -4
View File
@@ -79,7 +79,7 @@
{:background-color (:ui-background @colors/theme)
:flex 1}
[rn/flat-list
{:flex 1
:keyboard-should-persist-taps :always
:header [cool-preview]
:key-fn str}]])
{:flex 1
:keyboardShouldPersistTaps :always
:header [cool-preview]
:key-fn str}]])
+5 -5
View File
@@ -44,8 +44,8 @@
{:background-color (:ui-background @colors/theme)
:flex 1}
[rn/flat-list
{:flex 1
:keyboard-should-persist-taps :always
:data all-props
:render-fn render-item
:key-fn str}]])
{:flex 1
:keyboardShouldPersistTaps :always
:data all-props
:render-fn render-item
:key-fn str}]])
+6 -6
View File
@@ -113,9 +113,9 @@
{:background-color (:ui-background @colors/theme)
:flex 1}
[rn/flat-list
{:flex 1
:keyboard-should-persist-taps :always
:header [cool-preview]
:data all-props
:render-fn render-item
:key-fn str}]])
{:flex 1
:keyboardShouldPersistTaps :always
:header [cool-preview]
:data all-props
:render-fn render-item
:key-fn str}]])
+6 -6
View File
@@ -91,9 +91,9 @@
{:background-color (:ui-background @colors/theme)
:flex 1}
[rn/flat-list
{:flex 1
:keyboard-should-persist-taps :always
:header [cool-preview]
:data all-props
:render-fn render-item
:key-fn str}]])
{:flex 1
:keyboardShouldPersistTaps :always
:header [cool-preview]
:data all-props
:render-fn render-item
:key-fn str}]])
+6 -6
View File
@@ -83,9 +83,9 @@
{:background-color (:ui-background @colors/theme)
:flex 1}
[rn/flat-list
{:flex 1
:keyboard-should-persist-taps :always
:header [cool-preview]
:data all-props
:render-fn render-item
:key-fn str}]])
{:flex 1
:keyboardShouldPersistTaps :always
:header [cool-preview]
:data all-props
:render-fn render-item
:key-fn str}]])
+5 -5
View File
@@ -31,8 +31,8 @@
{:background-color (:ui-background @colors/theme)
:flex 1}
[rn/flat-list
{:flex 1
:keyboard-should-persist-taps :always
:data all-props
:render-fn render-item
:key-fn str}]])
{:flex 1
:keyboardShouldPersistTaps :always
:data all-props
:render-fn render-item
:key-fn str}]])
+2 -2
View File
@@ -4,7 +4,7 @@
[quo2.foundations.colors :as colors]
[quo2.theme :as theme]
[react-native.core :as rn]
[utils.number]))
[utils.number :as utils-number]))
(def themes
{:light {:default colors/primary-50
@@ -31,7 +31,7 @@
(= type :default))
colors/white
colors/neutral-100))
value (utils.number/parse-int value)
value (utils-number/parse-int value)
label (if (> value max-value)
(str max-value "+")
(str value))
@@ -1,19 +0,0 @@
(ns quo2.components.counter.step.component-spec
(:require [quo2.components.counter.step.view :as step]
[test-helpers.component :as h]))
(h/describe "step component"
(h/test "default render of step component"
(h/render [step/step {} nil])
(-> (h/expect (h/query-by-label-text :step-counter))
(h/is-truthy)))
(h/test "renders step with a string value"
(h/render [step/step {} "1"])
(-> (h/expect (h/get-by-text "1"))
(h/is-truthy)))
(h/test "renders step with an integer value"
(h/render [step/step {} 1])
(-> (h/expect (h/get-by-text "1"))
(h/is-truthy))))
@@ -1,41 +0,0 @@
(ns quo2.components.counter.step.style
(:require
[quo2.foundations.colors :as colors]))
(def container-base
{:align-items :center
:justify-content :center
:border-radius 6
:height 20})
(defn neutral-border-color
[in-blur-view? override-theme]
(if in-blur-view?
(colors/theme-colors colors/white-opa-10 colors/neutral-80-opa-5 override-theme)
(colors/theme-colors colors/neutral-20 colors/neutral-80 override-theme)))
(def active-background-color (colors/custom-color :blue 50 10))
(def complete-background-color (colors/custom-color :blue 50))
(defn container
[size type in-blur-view? override-theme]
(cond-> container-base
(#{1 2} size) (assoc :width 20)
(= size 3) (assoc :width 28)
(= type :neutral)
(assoc :border-width 1
:border-color (neutral-border-color in-blur-view? override-theme))
(= type :active)
(assoc :background-color active-background-color)
(= type :complete)
(assoc :background-color complete-background-color)))
(defn text-color
([type] (text-color type nil))
([type override-theme]
(case type
(:neutral :active) (colors/theme-colors colors/neutral-100-opa-100 colors/white override-theme)
:complete colors/white)))
@@ -1,21 +0,0 @@
(ns quo2.components.counter.step.view
(:require
[quo2.components.counter.step.style :as style]
[quo2.components.markdown.text :as text]
[react-native.core :as rn]
[utils.number]))
(defn step
[{:keys [type accessibility-label override-theme in-blur-view?]} value]
(let [type (or type :neutral)
value (utils.number/parse-int value)
label (str value)
size (count label)]
[rn/view
{:accessible true
:accessibility-label (or accessibility-label :step-counter)
:style (style/container size type in-blur-view? override-theme)}
[text/text
{:weight :medium
:size :label
:style {:color (style/text-color type override-theme)}} label]]))
+2 -4
View File
@@ -132,9 +132,8 @@
:text text}])]]))))
(defn- password-input
[{:keys [default-shown?]
:or {default-shown? false}}]
(let [password-shown? (reagent/atom default-shown?)]
[_]
(let [password-shown? (reagent/atom false)]
(fn [props]
[base-input
(assoc props
@@ -162,7 +161,6 @@
- :label - A string to set as label for this input.
- :char-limit - A number to set a maximum char limit for this input.
- :on-char-limit-reach - Function executed each time char limit is reached or exceeded.
- :default-shown? - boolean to show password input initially
and supports the usual React Native's TextInput properties to control its behaviour:
- :value
- :default-value
@@ -1,68 +0,0 @@
(ns quo2.components.inputs.search-input.style
(:require [quo2.components.markdown.text :as text]
[quo2.foundations.colors :as colors]))
(defn placeholder-color
[state blur? override-theme]
(cond
(and blur? (= state :active))
(colors/theme-colors colors/neutral-80-opa-20 colors/white-opa-20 override-theme)
blur? ; state is default
(colors/theme-colors colors/neutral-80-opa-40 colors/white-opa-30 override-theme)
(= state :active)
(colors/theme-colors colors/neutral-30 colors/neutral-60 override-theme)
:else ; Not blur and state is default
(colors/theme-colors colors/neutral-40 colors/neutral-50 override-theme)))
(def clear-icon-container
{:justify-content :center
:align-items :center
:margin-left 8
:height 20
:width 20})
(defn clear-icon
[blur? override-theme]
(if blur?
(colors/theme-colors colors/neutral-80-opa-30 colors/white-opa-10 override-theme)
(colors/theme-colors colors/neutral-40 colors/neutral-50 override-theme)))
(defn cursor
[customization-color override-theme]
(colors/theme-colors (colors/custom-color customization-color 50)
(colors/custom-color customization-color 60)
override-theme))
(def tag-separator {:width 8})
(def tag-container
{:flex-direction :row
:margin-right 8})
(def container
{:flex 1
:flex-direction :row
:align-items :center})
(def scroll-container
{:flex-direction :row
:flex 1
:height 32})
(def scroll-content
{:flex-grow 1
:align-items :center
:justify-content :flex-start})
(defn input-text
[disabled?]
(assoc (text/text-style {:size :paragraph-1
:weight :regular})
:flex 1
:padding-vertical 5
:min-width 120
:opacity (if disabled? 0.3 1)
:min-height 32))
@@ -1,89 +0,0 @@
(ns quo2.components.inputs.search-input.view
(:require [oops.core :as oops]
[quo2.components.icon :as icon]
[quo2.components.inputs.search-input.style :as style]
[react-native.core :as rn]
[reagent.core :as reagent]))
(def ^:private tag-separator [rn/view {:style style/tag-separator}])
(defn- inner-tags
[tags-coll]
(into [rn/view {:style style/tag-container}]
(interpose tag-separator)
tags-coll))
(defn- clear-button
[{:keys [on-press blur? override-theme]}]
[rn/touchable-opacity
{:style style/clear-icon-container
:on-press on-press}
[icon/icon :i/clear
{:color (style/clear-icon blur? override-theme)
:size 20}]])
(defn- handle-backspace
[event ^js/Object scroll-view-ref]
(when (and (= (oops/oget event "nativeEvent.key") "Backspace")
scroll-view-ref)
(.scrollToEnd scroll-view-ref #js {:animated false})))
(def ^:private props-to-remove
[:cursor-color :placeholder-text-color :editable :on-change-text :on-focus
:on-blur :on-clear :value :tags :disabled? :blur? :customization-color :override-theme])
(defn- add-children
[text-input children]
(if (seq children)
(into text-input children)
text-input))
(defn search-input
[{:keys [value]}]
(let [state (reagent/atom :default)
set-active #(reset! state :active)
set-default #(reset! state :default)
scroll-view-ref (atom nil)
use-value? (boolean value)]
(fn [{:keys [value tags disabled? blur? on-change-text customization-color
on-clear on-focus on-blur override-theme]
:or {customization-color :blue}
:as props}
& children]
(let [clean-props (apply dissoc props props-to-remove)]
[rn/view {:style style/container}
[rn/scroll-view
{:ref #(reset! scroll-view-ref %)
:style style/scroll-container
:content-container-style style/scroll-content
:horizontal true
:shows-horizontal-scroll-indicator false}
(when (seq tags)
[inner-tags tags])
(add-children
[rn/text-input
(cond-> {:style (style/input-text disabled?)
:cursor-color (style/cursor customization-color override-theme)
:placeholder-text-color (style/placeholder-color @state blur? override-theme)
:editable (not disabled?)
:on-key-press #(handle-backspace % @scroll-view-ref)
:on-change-text (fn [new-text]
(when on-change-text
(on-change-text new-text))
(reagent/flush))
:on-focus (fn []
(set-active)
(when on-focus (on-focus)))
:on-blur (fn []
(set-default)
(when on-blur (on-blur)))}
use-value? (assoc :value value)
(seq clean-props) (merge clean-props))]
(when-not use-value? children))]
(when (or (seq value) (seq children))
[clear-button
{:on-press on-clear
:blur? blur?
:override-theme override-theme}])]))))
@@ -1,49 +0,0 @@
(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))))
@@ -1,8 +0,0 @@
(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})
@@ -1,86 +0,0 @@
(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])
+11 -11
View File
@@ -30,18 +30,18 @@
(when on-press
{:on-press on-press}))
[rn/view
{:style (cond-> {:flex-direction :row
:flex-grow 0
:flex-shrink 1
:align-items :center}
icon (assoc :padding-horizontal 20))}
{:style {:flex-direction :row
:flex-grow 0
:flex-shrink 1
:padding-horizontal 20
:align-items :center}}
[rn/view
{:style (cond-> {:width 20
:height 20
:align-items :center
:justify-content :center}
icon (assoc :margin-right 12))}
(when icon [icons/icon icon {:color icon-color}])]
{:style {:width 20
:height 20
:align-items :center
:justify-content :center
:margin-right 12}}
[icons/icon icon {:color icon-color}]]
[rn/view
[text/text
{:weight :medium
+4 -7
View File
@@ -30,8 +30,7 @@
{:no-color true})))
(defn left-section-view
[{:keys [on-press icon accessibility-label type icon-background-color icon-override-theme]
:or {type :grey}}
[{:keys [on-press icon accessibility-label type icon-background-color] :or {type :grey}}
put-middle-section-on-left?]
[rn/view {:style (when put-middle-section-on-left? {:margin-right 5})}
[button/button
@@ -40,7 +39,6 @@
:type type
:size 32
:accessibility-label accessibility-label
:override-theme icon-override-theme
:override-background-color icon-background-color}
icon]])
@@ -152,7 +150,7 @@
:justify-content :flex-end)}
(let [last-icon-index (-> right-section-buttons count dec)]
(map-indexed (fn [index
{:keys [icon on-press type style icon-override-theme accessibility-label label]
{:keys [icon on-press type style icon-override-theme accessibility-label]
:or {type :grey}}]
^{:key index}
[rn/view
@@ -163,12 +161,11 @@
:accessible true))
[button/button
{:on-press on-press
:icon (not label)
:icon true
:type type
:before (when label icon)
:size 32
:override-theme icon-override-theme}
(if label label icon)]])
icon]])
right-section-buttons))])
(defn page-nav
@@ -1,38 +0,0 @@
(ns quo2.components.notifications.notification.component-spec
(:require
[quo2.components.markdown.text :as text]
[quo2.components.notifications.notification.view :as notification]
[test-helpers.component :as h]))
(h/describe "notification"
(h/test "empty notification"
(h/render [notification/notification {}])
(h/is-null (h/query-by-label-text :notification-avatar))
(h/is-null (h/query-by-label-text :notification-header))
(h/is-null (h/query-by-label-text :notification-body)))
(h/test "notification with title and text"
(h/render [notification/notification
{:title "title"
:title-weight :medium
:text "text"}])
(-> (h/expect (h/get-by-label-text :notification-header))
(.toHaveTextContent "title"))
(-> (h/expect (h/get-by-label-text :notification-body))
(.toHaveTextContent "text")))
(h/test "notification with custom input"
(h/render [notification/notification
{:header [text/text {:accessibility-label :header} "custom header"]
:avatar [text/text {:accessibility-label :avatar} "custom avatar"]
:body [text/text {:accessibility-label :body} "custom body"]}])
(h/is-truthy (h/get-by-label-text :notification-avatar))
(h/is-truthy (h/get-by-label-text :notification-header))
(h/is-truthy (h/get-by-label-text :notification-body))
(h/is-truthy (h/get-by-label-text :avatar))
(h/is-truthy (h/get-by-label-text :header))
(h/is-truthy (h/get-by-label-text :body))
(-> (h/expect (h/get-by-label-text :notification-header))
(.toHaveTextContent "custom header"))
(-> (h/expect (h/get-by-label-text :notification-avatar))
(.toHaveTextContent "custom avatar"))
(-> (h/expect (h/get-by-label-text :notification-body))
(.toHaveTextContent "custom body"))))
@@ -1,39 +0,0 @@
(ns quo2.components.notifications.notification.style
(:require
[quo2.foundations.colors :as colors]
[quo2.foundations.shadows :as shadows]))
(def box-container
{:margin-horizontal 8
:border-radius 16
:overflow :hidden})
(def blur-container
{:height "100%"
:width "100%"
:position :absolute
:padding-vertical 8
:padding-left 10
:padding-right 8
:background-color :transparent})
(defn content-container
[override-theme]
(merge
(:shadow-1 shadows/normal-scale)
{:background-color (colors/theme-colors colors/neutral-80-opa-70 colors/white-opa-70 override-theme)
:flex-direction :row
:padding-vertical 8
:padding-horizontal 12}))
(def right-side-container {:flex 1})
(defn title
[override-theme]
{:color (colors/theme-colors colors/white colors/neutral-100 override-theme)})
(defn text
[override-theme]
{:color (colors/theme-colors colors/white colors/neutral-100 override-theme)})
(def avatar-container {:margin-right 8 :margin-top 4})
@@ -1,74 +0,0 @@
(ns quo2.components.notifications.notification.view
(:require [quo2.components.markdown.text :as text]
[quo2.components.notifications.notification.style :as style]
[react-native.blur :as blur]
[react-native.core :as rn]))
(defn header-container
[& children]
[into
[rn/view {:accessibility-label :notification-header}] children])
(defn body-container
[& children]
[into [rn/view {:accessibility-label :notification-body}] children])
(defn avatar-container
[& children]
[into
[rn/view
{:style style/avatar-container
:accessibility-label :notification-avatar}]
children])
(defn title
([text weight] (title text weight nil))
([text weight override-theme]
[text/text
{:size :paragraph-1
:weight (or weight :semi-bold)
:style (style/title override-theme)
:accessibility-label :notification-title}
text]))
(defn message
[text override-theme]
[text/text
{:size :paragraph-2
:style (style/text override-theme)
:accessibility-label :notification-content}
text])
(defn- notification-container
[{:keys [avatar header body container-style override-theme]}]
[rn/view
{:style (merge style/box-container container-style)}
[blur/view
{:style style/blur-container
:blur-amount 13
:blur-radius 10
:blur-type :transparent
:overlay-color :transparent}]
[rn/view
{:style (style/content-container override-theme)}
avatar
[rn/view
{:style style/right-side-container}
header
body]]])
(defn notification
[{title-text :title :keys [avatar header title-weight text body container-style override-theme]}]
(let [header (or header
(when title-text
[title title-text title-weight override-theme]))
header (when header [header-container header])
body (or body (when text [message text override-theme]))
body (when body [body-container body])
avatar (when avatar [avatar-container avatar])]
[notification-container
{:avatar avatar
:header header
:body body
:container-style container-style
:override-theme override-theme}]))
@@ -0,0 +1,122 @@
(ns quo2.components.notifications.toast
(:require [quo2.components.icon :as icon]
[quo2.components.markdown.text :as text]
[quo2.components.notifications.count-down-circle :as count-down-circle]
[quo2.foundations.colors :as colors]
[quo2.foundations.shadows :as shadows]
[quo2.theme :as theme]
[utils.i18n :as i18n]
[react-native.blur :as blur]
[react-native.core :as rn]))
(def ^:private themes
{:container {:dark {:background-color colors/white-opa-70}
:light {:background-color colors/neutral-80-opa-70}}
:title {:dark {:color colors/neutral-100}
:light {:color colors/white}}
:text {:dark {:color colors/neutral-100}
:light {:color colors/white}}
:icon {:dark {:color colors/neutral-100}
:light {:color colors/white}}
:action-container {:dark {:background-color colors/neutral-80-opa-5}
:light {:background-color colors/white-opa-5}}})
(defn- merge-theme-style
[component-key styles override-theme]
(merge (get-in themes [component-key (or override-theme (theme/get-theme))]) styles))
(defn toast-action-container
[{:keys [on-press style]} & children]
[rn/touchable-highlight
{:on-press on-press
:underlay-color :transparent}
[into
[rn/view
{:style (merge
{:flex-direction :row
:padding-vertical 3
:padding-horizontal 8
:align-items :center
:border-radius 8
:background-color (get-in themes
[:action-container (theme/get-theme)
:background-color])}
style)}]
children]])
(defn toast-undo-action
[duration on-press override-theme]
[toast-action-container
{:on-press on-press :accessibility-label :toast-undo-action}
[rn/view {:style {:margin-right 5}}
[count-down-circle/circle-timer {:duration duration}]]
[text/text
{:size :paragraph-2 :weight :medium :style (merge-theme-style :text {} override-theme)}
[i18n/label :t/undo]]])
(defn- toast-container
[{:keys [left title text right container-style override-theme]}]
[rn/view
{:style (merge {:margin-horizontal 12
:border-radius 12
:overflow :hidden}
container-style)}
[blur/view
{:style {:height "100%"
:width "100%"
:position :absolute
:padding-vertical 8
:padding-left 10
:padding-right 8
:background-color :transparent}
:blur-amount 13
:blur-radius 10
:blur-type :transparent
:overlay-color :transparent}]
[rn/view
{:style (merge-theme-style :container
(merge
(:shadow-1 shadows/normal-scale)
{:flex-direction :row
:justify-content :space-between
:padding-vertical 8
:padding-left 10
:padding-right 8
:border-radius 12})
override-theme)}
[rn/view {:style {:padding 2}} left]
[rn/view {:style {:padding 4 :flex 1}}
(when title
[text/text
{:size :paragraph-1
:weight :semi-bold
:style (merge-theme-style :title {} override-theme)
:accessibility-label :toast-title}
title])
(when text
[text/text
{:size :paragraph-2
:weight :medium
:style (merge-theme-style :text {} override-theme)
:accessibility-label :toast-content}
text])]
(when right right)]])
(defn toast
[{:keys [icon icon-color title text action undo-duration undo-on-press container-style
override-theme]}]
[toast-container
{:left (when icon
[icon/icon icon
{:container-style {:width 20 :height 20}
:color (or icon-color
(get-in themes
[:icon (or override-theme (theme/get-theme))
:color]))}])
:title title
:text text
:right (if undo-duration
[toast-undo-action undo-duration undo-on-press override-theme]
action)
:container-style container-style
:override-theme override-theme}])
@@ -1,55 +0,0 @@
(ns quo2.components.notifications.toast.style
(:require
[quo2.foundations.colors :as colors]
[quo2.foundations.shadows :as shadows]))
(def box-container
{:margin-horizontal 12
:border-radius 12
:overflow :hidden})
(def blur-container
{:height "100%"
:width "100%"
:position :absolute
:padding-vertical 8
:padding-left 10
:padding-right 8
:background-color :transparent})
(defn content-container
[override-theme]
(merge
(:shadow-1 shadows/normal-scale)
{:background-color (colors/theme-colors colors/neutral-80-opa-70 colors/white-opa-70 override-theme)
:flex-direction :row
:justify-content :space-between
:padding-vertical 8
:padding-left 10
:padding-right 8
:border-radius 12}))
(defn title
[override-theme]
{:color (colors/theme-colors colors/white colors/neutral-100 override-theme)})
(defn text
[override-theme]
{:color (colors/theme-colors colors/white colors/neutral-100 override-theme)})
(defn icon
[override-theme]
{:color (colors/theme-colors colors/white colors/neutral-100 override-theme)
:container-style {:width 20 :height 20}})
(def left-side-container {:padding 2})
(def right-side-container {:padding 4 :flex 1})
(defn action-container
[override-theme]
{:background-color (colors/theme-colors colors/white-opa-5 colors/neutral-80-opa-5 override-theme)
:flex-direction :row
:padding-vertical 3
:padding-horizontal 8
:align-items :center
:border-radius 8})
@@ -1,80 +0,0 @@
(ns quo2.components.notifications.toast.view
(:require [quo2.components.avatars.user-avatar.view :as user-avatar]
[quo2.components.icon :as icon]
[quo2.components.markdown.text :as text]
[quo2.components.notifications.count-down-circle :as count-down-circle]
[quo2.components.notifications.toast.style :as style]
[quo2.theme :as theme]
[react-native.blur :as blur]
[react-native.core :as rn]
[utils.i18n :as i18n]))
(defn toast-action-container
[{:keys [on-press style]} & children]
[rn/touchable-highlight
{:on-press on-press
:underlay-color :transparent}
[into
[rn/view
{:style (merge (style/action-container (theme/get-theme)) style)}]
children]])
(defn toast-undo-action
[duration on-press override-theme]
[toast-action-container
{:on-press on-press :accessibility-label :toast-undo-action}
[rn/view {:style {:margin-right 5}}
[count-down-circle/circle-timer {:duration duration}]]
[text/text
{:size :paragraph-2 :weight :medium :style (style/text override-theme)}
[i18n/label :t/undo]]])
(defn- toast-container
[{:keys [left title text right container-style override-theme]}]
[rn/view
{:style (merge style/box-container container-style)}
[blur/view
{:style style/blur-container
:blur-amount 13
:blur-radius 10
:blur-type :transparent
:overlay-color :transparent}]
[rn/view
{:style (style/content-container override-theme)}
[rn/view {:style style/left-side-container} left]
[rn/view {:style style/right-side-container}
(when title
[text/text
{:size :paragraph-1
:weight :semi-bold
:style (style/title override-theme)
:accessibility-label :toast-title}
title])
(when text
[text/text
{:size :paragraph-2
:weight :medium
:style (style/text override-theme)
:accessibility-label :toast-content}
text])]
(when right right)]])
(defn toast
[{:keys [icon icon-color title text action undo-duration undo-on-press container-style
override-theme user]}]
[toast-container
{:left (cond icon
[icon/icon icon
(cond-> (style/icon override-theme)
icon-color
(assoc :color icon-color))]
user
[user-avatar/user-avatar user])
:title title
:text text
:right (if undo-duration
[toast-undo-action undo-duration undo-on-press override-theme]
action)
:container-style container-style
:override-theme override-theme}])
+5 -7
View File
@@ -1,5 +1,4 @@
(ns quo2.components.share.qr-code.style
(:require [quo2.foundations.colors :as colors]))
(ns quo2.components.share.qr-code.style)
(def container
{:flex-direction :row
@@ -7,8 +6,7 @@
(defn image
[width height]
{:width width
:height height
:background-color colors/white-opa-70
:border-radius 12
:aspect-ratio 1})
{:width width
:height height
:border-radius 12
:aspect-ratio 1})
@@ -1,55 +0,0 @@
(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)})
@@ -1,85 +0,0 @@
(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
@@ -0,0 +1,126 @@
(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])
+16 -25
View File
@@ -18,7 +18,6 @@
quo2.components.community.icon
quo2.components.community.token-gating
quo2.components.counter.counter
quo2.components.counter.step.view
quo2.components.dividers.date
quo2.components.dividers.divider-label
quo2.components.dividers.new-messages
@@ -32,15 +31,12 @@
quo2.components.info.info-message
quo2.components.info.information-box
quo2.components.inputs.input.view
quo2.components.inputs.profile-input.view
quo2.components.inputs.search-input.view
quo2.components.inputs.title-input.view
quo2.components.links.url-preview-list.view
quo2.components.inputs.profile-input.view
quo2.components.links.url-preview.view
quo2.components.list-items.channel
quo2.components.list-items.menu-item
quo2.components.list-items.preview-list
quo2.components.list-items.user-list
quo2.components.loaders.skeleton
quo2.components.markdown.text
quo2.components.messages.author.view
@@ -52,9 +48,7 @@
quo2.components.notifications.count-down-circle
quo2.components.notifications.info-count
quo2.components.notifications.notification-dot
quo2.components.notifications.notification.view
quo2.components.notifications.toast.view
quo2.components.onboarding.small-option-card.view
quo2.components.notifications.toast
quo2.components.password.tips.view
quo2.components.profile.profile-card.view
quo2.components.profile.select-profile.view
@@ -68,22 +62,26 @@
quo2.components.settings.privacy-option
quo2.components.share.qr-code.view
quo2.components.share.share-qr-code.view
quo2.components.tabs.account-selector
quo2.components.onboarding.small-option-card.view
quo2.components.tabs.segmented-tab
quo2.components.tabs.account-selector
quo2.components.tabs.tabs
quo2.components.tags.context-tag.view
quo2.components.tags.permission-tag
quo2.components.tags.context-tags
quo2.components.tags.status-tags
quo2.components.tags.permission-tag
quo2.components.tags.tag
quo2.components.tags.tags
quo2.components.tags.token-tag
quo2.components.text-combinations.title.view))
quo2.components.text-combinations.title.view
quo2.components.list-items.user-list))
(def toast quo2.components.notifications.toast/toast)
(def button quo2.components.buttons.button/button)
(def dynamic-button quo2.components.buttons.dynamic-button/dynamic-button)
(def text quo2.components.markdown.text/text)
(def icon quo2.components.icon/icon)
(def separator quo2.components.separator/separator)
(def counter quo2.components.counter.counter/counter)
(def header quo2.components.header/header)
(def dropdown quo2.components.dropdowns.dropdown/dropdown)
(def info-message quo2.components.info.info-message/info-message)
@@ -92,11 +90,12 @@
(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-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 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 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)
@@ -137,10 +136,6 @@
(def token-gating quo2.components.community.token-gating/token-gating)
(def community-icon quo2.components.community.icon/community-icon)
;;;; COUNTER
(def counter quo2.components.counter.counter/counter)
(def step quo2.components.counter.step.view/step)
;;;; DIVIDERS
(def divider-label quo2.components.dividers.divider-label/divider-label)
(def new-messages quo2.components.dividers.new-messages/new-messages)
@@ -154,7 +149,6 @@
;;;; INPUTS
(def input quo2.components.inputs.input.view/input)
(def search-input quo2.components.inputs.search-input.view/search-input)
(def profile-input quo2.components.inputs.profile-input.view/profile-input)
(def title-input quo2.components.inputs.title-input.view/title-input)
@@ -169,8 +163,6 @@
(def info-count quo2.components.notifications.info-count/info-count)
(def notification-dot quo2.components.notifications.notification-dot/notification-dot)
(def count-down-circle quo2.components.notifications.count-down-circle/circle-timer)
(def notification quo2.components.notifications.notification.view/notification)
(def toast quo2.components.notifications.toast.view/toast)
;;;; PASSWORD
(def tips quo2.components.password.tips.view/view)
@@ -207,4 +199,3 @@
;;;; LINKS
(def url-preview quo2.components.links.url-preview.view/view)
(def url-preview-list quo2.components.links.url-preview-list.view/view)
-3
View File
@@ -5,7 +5,6 @@
[quo2.components.buttons.--tests--.buttons-component-spec]
[quo2.components.colors.color-picker.component-spec]
[quo2.components.counter.--tests--.counter-component-spec]
[quo2.components.counter.step.component-spec]
[quo2.components.dividers.--tests--.divider-label-component-spec]
[quo2.components.dividers.strength-divider.component-spec]
[quo2.components.drawers.action-drawers.component-spec]
@@ -14,10 +13,8 @@
[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.notifications.notification.component-spec]
[quo2.components.onboarding.small-option-card.component-spec]
[quo2.components.password.tips.component-spec]
[quo2.components.profile.select-profile.component-spec]
+1 -21
View File
@@ -1,7 +1,5 @@
(ns react-native.hooks
(:require ["@react-native-community/hooks" :as hooks]
[react-native.core :as rn]
[oops.core :as oops]))
(:require ["@react-native-community/hooks" :as hooks]))
(defn use-keyboard
[]
@@ -12,21 +10,3 @@
(defn use-back-handler
[handler]
(.useBackHandler hooks handler))
(defn use-interval
[cb cleanup-cb delay]
(let [saved-callback (rn/use-ref)]
(rn/use-effect
(fn []
(oops/oset! saved-callback "current" cb))
[cb])
(rn/use-effect
(fn []
(let [tick (oops/oget saved-callback "current")]
(when delay
(let [id (js/setInterval tick delay)]
(fn []
(cleanup-cb)
(js/clearInterval id))))))
[delay])))
+1 -1
View File
@@ -8,4 +8,4 @@
(def clippath (reagent/adapt-react-class Svg/ClipPath))
(def defs (reagent/adapt-react-class Svg/Defs))
(def circle (reagent/adapt-react-class Svg/Circle))
(def svgxml (reagent/adapt-react-class Svg/SvgXml))
+14 -32
View File
@@ -87,27 +87,23 @@
(:communities/community-id-input db))
(defn- handle-my-request
[db {:keys [community-id state deleted] :as request}]
(if (and (= constants/community-request-to-join-state-pending state) (not deleted))
(assoc-in db [:communities/my-pending-requests-to-join community-id] request)
(update-in db [:communities/my-pending-requests-to-join] dissoc community-id)))
[db {:keys [community-id state] :as request}]
{:db (if (= constants/community-request-to-join-state-pending state)
(assoc-in db [:communities/my-pending-requests-to-join community-id] request)
(update-in db [:communities/my-pending-requests-to-join] dissoc community-id))})
(defn handle-admin-request
[db {:keys [id community-id deleted] :as request}]
(if deleted
(update-in db [:communities/requests-to-join community-id] dissoc id)
(assoc-in db [:communities/requests-to-join community-id id] request)))
[db {:keys [id community-id] :as request}]
{:db (assoc-in db [:communities/requests-to-join community-id id] request)})
(rf/defn handle-requests-to-join
[{:keys [db]} requests]
(let [my-public-key (get-in db [:multiaccount :public-key])]
{:db (reduce (fn [db {:keys [public-key] :as request}]
(let [my-request? (= my-public-key public-key)]
(if my-request?
(handle-my-request db request)
(handle-admin-request db request))))
db
requests)}))
(rf/defn handle-request-to-join
[{:keys [db]} r]
(let [my-public-key (get-in db [:multiaccount :public-key])
{:keys [id community-id public-key] :as request} (<-request-to-join-community-rpc r)
my-request? (= my-public-key public-key)]
(if my-request?
(handle-my-request db request)
(handle-admin-request db request))))
(rf/defn handle-removed-chats
[{:keys [db]} chat-ids]
@@ -321,7 +317,6 @@
:on-error #(do
(log/error "failed to invite-user community" %)
(re-frame/dispatch [::failed-to-invite-people %]))}]})))
(rf/defn share-community
{:events [::share-community-confirmation-pressed]}
[cofx user-pk contacts]
@@ -903,16 +898,3 @@
:event :communities/toggle-collapsed-category
:category-id category-id
:collapse? collapse?})}]})
(rf/defn check-and-delete-pending-request-to-join
{:events [:communities/check-and-delete-pending-request-to-join]}
[_]
{:json-rpc/call [{:method "wakuext_checkAndDeletePendingRequestToJoinCommunity"
:params []
:js-response true
:on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])
:on-error #(log/info
"failed to fetch communities"
{:error %
:event
:communities/check-and-delete-pending-request-to-join-community})}]})
+1 -2
View File
@@ -60,8 +60,7 @@
(:contacts/contacts db)
public-key)
(assoc :blocked? true
:added? false
:active? false))
:added? false))
from-one-to-one-chat? (not (get-in db [:chats (:current-chat-id db) :group-chat]))]
(rf/merge cofx
{:db (assoc-in db [:contacts/contacts public-key] contact)}
+1 -1
View File
@@ -87,7 +87,7 @@
:identicon (.-identicon chat)
:muted (.-muted chat)
:joined (.-joined chat)
:muted-till (.-mutetill chat)
:chat-id (.-id chat)
:community-id (.-communityId chat)
:synced-from (.-syncedFrom chat)
+1 -2
View File
@@ -59,8 +59,7 @@
status-im2.contexts.shell.events
status-im2.contexts.onboarding.events
status-im.chat.models.gaps
[status-im2.navigation.events :as navigation]
status-im2.contexts.chat.home.events))
[status-im2.navigation.events :as navigation]))
(re-frame/reg-fx
:dismiss-keyboard
+2 -3
View File
@@ -12,8 +12,7 @@
status-im2.navigation.core
status-im2.subs.root ; so integration tests can run independently
[taoensso.timbre :as log]
[utils.security.core :as security]
[status-im2.constants :as constants]))
[utils.security.core :as security]))
(def password "testabc")
@@ -296,7 +295,7 @@
(rf/dispatch-sync [:chat/navigate-to-chat chat-id])
(is (= chat-id @(rf/subscribe [:chats/current-chat-id])))
(is @(rf/subscribe [:chats/chat chat-id]))
(rf/dispatch-sync [:chat.ui/mute chat-id true constants/mute-till-unmuted])
(rf/dispatch-sync [:chat.ui/mute chat-id true])
(rf-test/wait-for
[:chat/mute-successfully]
(is @(rf/subscribe [:chats/muted chat-id]))
+18 -22
View File
@@ -365,25 +365,9 @@
[_]
(status/get-node-config #(re-frame/dispatch [::get-node-config-callback %])))
(rf/defn redirect-to-root
"Decides which root should be initialised depending on user and app state"
[{:keys [db] :as cofx}]
(cond
(get db :onboarding-2/new-account?)
{:dispatch [:onboarding-2/finalize-setup]}
(get db :tos/accepted?)
(rf/merge
cofx
(multiaccounts/switch-theme nil :shell-stack)
(navigation/init-root :shell-stack))
:else
{:dispatch [:init-root :tos]}))
(rf/defn get-settings-callback
{:events [::get-settings-callback]}
[{:keys [db] :as cofx} settings pairing-in-progress?]
[{:keys [db] :as cofx} settings]
(let [{:networks/keys [current-network networks]
:as settings}
(data-store.settings/rpc->settings settings)
@@ -410,13 +394,10 @@
(get-node-config)
(communities/fetch)
(communities/fetch-collapsed-community-categories)
(communities/check-and-delete-pending-request-to-join)
(logging/set-log-level (:log-level multiaccount))
(activity-center/notifications-fetch-pending-contact-requests)
(activity-center/update-seen-state)
(activity-center/notifications-fetch-unread-count)
(when-not pairing-in-progress?
(redirect-to-root)))))
(activity-center/notifications-fetch-unread-count))))
(re-frame/reg-fx
::open-last-chat
@@ -491,6 +472,19 @@
keychain/auth-method-biometric
keychain/auth-method-password))))
(defn redirect-to-root
"Decides which root should be initialised depending on user and app state"
[db]
(cond
(get db :onboarding-2/new-account?)
(re-frame/dispatch [:onboarding-2/finalize-setup])
(get db :tos/accepted?)
(re-frame/dispatch [:init-root :shell-stack])
:else
(re-frame/dispatch [:init-root :tos])))
(rf/defn login-only-events
[{:keys [db] :as cofx} key-uid password save-password?]
(let [auth-method (:auth-method db)
@@ -503,7 +497,9 @@
{:db (assoc db :chats/loading? true)
:json-rpc/call
[{:method "settings_getSettings"
:on-success #(re-frame/dispatch [::get-settings-callback % pairing-in-progress?])}]}
:on-success #(do (re-frame/dispatch [::get-settings-callback %])
(when-not pairing-in-progress?
(redirect-to-root db)))}]}
(notifications/load-notification-preferences)
(when save-password?
(keychain/save-user-password key-uid password))
+5
View File
@@ -1,6 +1,11 @@
(ns status-im.search.core
(:require [utils.re-frame :as rf]))
(rf/defn home-filter-changed
{:events [:search/home-filter-changed]}
[cofx search-filter]
{:db (assoc-in (:db cofx) [:ui/search :home-filter] search-filter)})
(rf/defn currency-filter-changed
{:events [:search/currency-filter-changed]}
[cofx search-filter]
+2 -5
View File
@@ -124,13 +124,10 @@
(models.communities/handle-removed-chats removed-chats-clj)))
(seq requests-to-join-community)
(let [requests (->> requests-to-join-community
types/js->clj
(map models.communities/<-request-to-join-community-rpc))]
(js-delete response-js "requestsToJoinCommunity")
(let [request-js (types/js->clj (.pop requests-to-join-community))]
(rf/merge cofx
(process-next response-js sync-handler)
(models.communities/handle-requests-to-join requests)))
(models.communities/handle-request-to-join request-js)))
(seq emoji-reactions)
(let [reactions (types/js->clj emoji-reactions)]
@@ -1,4 +1,4 @@
(ns status-im2.common.qr-code-viewer.style
(ns status-im.ui.components.qr-code-viewer.styles
(:require [quo.design-system.colors :as colors]))
(def qr-code-padding 16)
@@ -14,4 +14,4 @@
:align-items :center
:justify-content :center
:border-width 1
:border-radius 8})
:border-radius 8})
@@ -0,0 +1,33 @@
(ns status-im.ui.components.qr-code-viewer.views
(:require ["qrcode" :as qr-code-js]
["react-native-svg" :refer (SvgXml)]
[cljs-bean.core :as bean]
[reagent.core :as reagent]
[status-im.ui.components.qr-code-viewer.styles :as styles]
[status-im.ui.components.react :as react]))
(def svgxml (reagent/adapt-react-class SvgXml))
(defn qr-code
[{:keys [size value]}]
(let [uri (reagent/atom nil)]
(.toString
qr-code-js
value
(bean/->js {:margin 0 :width size})
#(reset! uri %2))
(fn []
(when @uri
[svgxml {:xml @uri :width size :height size}]))))
(defn qr-code-view
"Qr Code view including the frame.
Note: `size` includes frame with `styles/qr-code-padding.`"
[size value]
(when (and size value)
[react/view
{:style (styles/qr-code-container size)
:accessibility-label :qr-code-image}
[qr-code
{:value value
:size (- size (* styles/qr-code-padding 2))}]]))
@@ -331,13 +331,13 @@
[rn/view
{:style {:height height}}
[list/flat-list
{:keyboard-should-persist-taps :always
:footer [rn/view {:style {:height 8}}]
:header [rn/view {:style {:height 8}}]
:data suggestions
:key-fn first
:render-data text-input-ref
:render-fn mention-item}]]]))))
{:keyboardShouldPersistTaps :always
:footer [rn/view {:style {:height 8}}]
:header [rn/view {:style {:height 8}}]
:data suggestions
:key-fn first
:render-data text-input-ref
:render-fn mention-item}]]]))))
(defn on-chat-toolbar-layout
[^js ev]
@@ -65,9 +65,9 @@
[]
(letsubs [blocked-contacts [:contacts/blocked]]
[list.views/flat-list
{:data blocked-contacts
:key-fn :address
:render-fn contacts-list-item
:default-separator? true
:enableEmptySections true
:keyboard-should-persist-taps :always}]))
{:data blocked-contacts
:key-fn :address
:render-fn contacts-list-item
:default-separator? true
:enableEmptySections true
:keyboardShouldPersistTaps :always}]))
@@ -44,10 +44,10 @@
:on-change (fn [text]
(re-frame/dispatch [:search/currency-filter-changed text]))}]]
[list/flat-list
{:data (->> currencies
vals
(sort #(compare (:code %1) (:code %2))))
:key-fn :code
:render-data currency-id
:render-fn render-currency
:keyboard-should-persist-taps :always}]]]))
{:data (->> currencies
vals
(sort #(compare (:code %1) (:code %2))))
:key-fn :code
:render-data currency-id
:render-fn render-currency
:keyboardShouldPersistTaps :always}]]]))
+2 -2
View File
@@ -219,11 +219,11 @@
[:ens/search-screen]]
[react/keyboard-avoiding-view {:flex 1}
[react/scroll-view
{:style {:flex 1}
{:style {:flex 1}
;;NOTE required so that switching custom-domain
;;works on first tap and persists keyboard
;;instead of dismissing keyboard and requiring two taps
:keyboard-should-persist-taps :always}
:keyboardShouldPersistTaps :always}
[react/view {:style {:flex 1}}
[react/view
{:style {:flex 1
+5 -5
View File
@@ -76,11 +76,11 @@
(defn toggle-list
[{:keys [contacts render-fn render-data]}]
[list/flat-list
{:data contacts
:key-fn :public-key
:render-data render-data
:render-fn render-fn
:keyboard-should-persist-taps :always}])
{:data contacts
:key-fn :public-key
:render-data render-data
:render-fn render-fn
:keyboardShouldPersistTaps :always}])
(defn no-contacts
[{:keys [no-contacts]}]
@@ -58,8 +58,8 @@
banner-hidden [:keycard/banner-hidden]]
[react/keyboard-avoiding-view {:style ast/multiaccounts-view}
[react/scroll-view
{:keyboard-should-persist-taps :always
:style styles/login-view}
{:keyboardShouldPersistTaps :always
:style styles/login-view}
[react/view styles/login-badge-container
[multiaccount-login-badge multiaccount]
[react/view {:style styles/password-container}
@@ -13,8 +13,7 @@
[status-im.ui.components.toolbar :as toolbar]
[status-im.ui.components.topbar :as topbar]
[status-im.ui.screens.profile.components.sheets :as sheets]
[utils.re-frame :as rf]
[status-im2.constants :as constants]))
[utils.re-frame :as rf]))
(defn actions
[{:keys [public-key added? blocked? ens-name mutual?] :as contact} muted?]
@@ -44,9 +43,7 @@
:selected muted?
:disabled blocked?
:action (when-not blocked?
#(re-frame/dispatch [:chat.ui/mute public-key (not muted?)
(when-not muted?
constants/mute-till-unmuted)]))}]
#(re-frame/dispatch [:chat.ui/mute public-key (not muted?)]))}]
[{:label (i18n/label (if blocked? :t/unblock :t/block))
:negative true
:selected blocked?
@@ -11,7 +11,7 @@
[status-im.ui.components.copyable-text :as copyable-text]
[status-im.ui.components.list-selection :as list-selection]
[status-im.ui.components.profile-header.view :as profile-header]
[status-im2.common.qr-code-viewer.view :as qr-code-viewer]
[status-im.ui.components.qr-code-viewer.views :as qr-code-viewer]
[status-im.ui.components.react :as react]
[status-im.ui.screens.profile.user.edit-picture :as edit]
[status-im.ui.screens.profile.user.styles :as styles]
@@ -6,7 +6,7 @@
[status-im.ethereum.eip681 :as eip681]
[utils.i18n :as i18n]
[status-im.ui.components.copyable-text :as copyable-text]
[status-im2.common.qr-code-viewer.view :as qr-code-viewer]
[status-im.ui.components.qr-code-viewer.views :as qr-code-viewer]
[status-im.ui.components.react :as react])
(:require-macros [status-im.utils.views :as views]))
@@ -1,34 +1,36 @@
(ns utils.image-server
(:require [utils.datetime :as datetime]))
(ns status-im.utils.image-server
(:require [quo.design-system.colors :as colors]))
(def ^:const image-server-uri-prefix "https://localhost:")
(def ^:const identicons-action "/messages/identicons")
(def ^:const account-images-action "/accountImages")
(def ^:const contact-images-action "/contactImages")
(defn timestamp [] (datetime/timestamp))
(defn current-theme-index
[theme]
(case theme
(defn current-theme
[]
(case @colors/theme-type
:light 1
:dark 2))
(defn- timestamp
[]
(.getTime (js/Date.)))
(defn get-identicons-uri
[port public-key theme]
[port public-key]
(str image-server-uri-prefix
port
identicons-action
"?publicKey="
public-key
"&theme="
(current-theme-index theme)
(current-theme)
"&clock="
(timestamp)
"&addRing=1"))
(defn get-account-image-uri
[port public-key image-name key-uid theme]
[port public-key image-name key-uid]
(str image-server-uri-prefix
port
account-images-action
@@ -39,13 +41,13 @@
"&imageName="
image-name
"&theme="
(current-theme-index theme)
(current-theme)
"&clock="
(timestamp)
"&addRing=1"))
(defn get-contact-image-uri
[port public-key image-name clock theme]
[port public-key image-name clock]
(str image-server-uri-prefix
port
contact-images-action
@@ -54,7 +56,7 @@
"&imageName="
image-name
"&theme="
(current-theme-index theme)
(current-theme)
"&clock="
clock
"&addRing=1"))
+1 -1
View File
@@ -51,7 +51,7 @@
(defn mute-chat-action
[chat-id]
(hide-sheet-and-dispatch [:chat.ui/mute chat-id true constants/mute-till-unmuted]))
(hide-sheet-and-dispatch [:chat.ui/mute chat-id true]))
(defn unmute-chat-action
[chat-id]
@@ -1,8 +0,0 @@
(ns status-im2.common.mute-chat-drawer.style
(:require [quo2.foundations.colors :as colors]))
(defn header-text
[]
{:margin-left 20
:margin-bottom 10
:color (colors/theme-colors colors/neutral-50 colors/neutral-40)})
@@ -1,65 +0,0 @@
(ns status-im2.common.mute-chat-drawer.view
(:require [utils.i18n :as i18n]
[quo2.core :as quo]
[react-native.core :as rn]
[status-im2.constants :as constants]
[utils.re-frame :as rf]
[status-im2.common.mute-chat-drawer.style :as style]))
(defn hide-sheet-and-dispatch
[event]
(rf/dispatch [:bottom-sheet/hide])
(rf/dispatch event))
(defn mute-chat-drawer
[chat-id accessibility-label]
[rn/view {:accessibility-label accessibility-label}
[quo/text
{:weight :medium
:size :paragraph-2
:style (style/header-text)} (i18n/label :t/mute-channel)]
[quo/menu-item
{:type :transparent
:title (i18n/label :t/mute-for-15-mins)
:icon-bg-color :transparent
:container-padding-vertical 12
:title-column-style {:margin-left 2}
:on-press (fn []
(hide-sheet-and-dispatch [:chat.ui/mute chat-id true
constants/mute-for-15-mins-type]))}]
[quo/menu-item
{:type :transparent
:title (i18n/label :t/mute-for-1-hour)
:icon-bg-color :transparent
:container-padding-vertical 12
:title-column-style {:margin-left 2}
:on-press (fn []
(hide-sheet-and-dispatch [:chat.ui/mute chat-id true
constants/mute-for-1-hour-type]))}]
[quo/menu-item
{:type :transparent
:title (i18n/label :t/mute-for-8-hours)
:icon-bg-color :transparent
:container-padding-vertical 12
:title-column-style {:margin-left 2}
:on-press (fn []
(hide-sheet-and-dispatch [:chat.ui/mute chat-id true
constants/mute-for-8-hours-type]))}]
[quo/menu-item
{:type :transparent
:title (i18n/label :t/mute-for-1-week)
:icon-bg-color :transparent
:container-padding-vertical 12
:title-column-style {:margin-left 2}
:on-press (fn []
(hide-sheet-and-dispatch [:chat.ui/mute chat-id true
constants/mute-for-1-week]))}]
[quo/menu-item
{:type :transparent
:title (i18n/label :t/mute-till-unmute)
:icon-bg-color :transparent
:container-padding-vertical 12
:title-column-style {:margin-left 2}
:on-press (fn []
(hide-sheet-and-dispatch [:chat.ui/mute chat-id true
constants/mute-till-unmuted]))}]])
@@ -1,31 +0,0 @@
(ns status-im2.common.qr-code-viewer.view
(:require ["qrcode" :as qr-code-js]
[cljs-bean.core :as bean]
[reagent.core :as reagent]
[status-im2.common.qr-code-viewer.style :as style]
[react-native.core :as rn]
[react-native.svg :as svg]))
(defn qr-code
[{:keys [size value]}]
(let [uri (reagent/atom nil)]
(.toString
qr-code-js
value
(bean/->js {:margin 0 :width size})
#(reset! uri %2))
(fn []
(when @uri
[svg/svgxml {:xml @uri :width size :height size}]))))
(defn qr-code-view
"Qr Code view including the frame.
Note: `size` includes frame with `style/qr-code-padding.`"
[size value]
(when (and size value)
[rn/view
{:style (style/qr-code-container size)
:accessibility-label :qr-code-image}
[qr-code
{:value value
:size (- size (* style/qr-code-padding 2))}]]))
+4 -5
View File
@@ -5,12 +5,11 @@
:lifestyle (js/require "../resources/images/ui2/lifestyle.png")
:music (js/require "../resources/images/ui2/music.png")
:podcasts (js/require "../resources/images/ui2/podcasts.png")
:generate-keys (js/require "../resources/images/ui2/generate-keys.png")
:ethereum-address (js/require "../resources/images/ui2/ethereum-address.png")
:sync-device (js/require "../resources/images/ui2/sync-new-device-cover-background.png")
:generate-keys (js/require "../resources/images/ui2/generate_keys.png")
:ethereum-address (js/require "../resources/images/ui2/ethereum_address.png")
:use-keycard (js/require "../resources/images/ui2/keycard.png")
:onboarding-illustration (js/require "../resources/images/ui2/onboarding_illustration.png")
:qr-code (js/require "../resources/images/ui2/qr-code.png")
})
:onboarding-illustration (js/require "../resources/images/ui2/onboarding_illustration.png")})
(def mock-images
{:coinbase (js/require "../resources/images/mock2/coinbase.png")
+6 -9
View File
@@ -28,10 +28,8 @@
(defn toast
[id]
(let [{:keys [type] :as toast-opts} (rf/sub [:toasts/toast id])]
(if (= type :notification)
[quo/notification toast-opts]
[quo/toast toast-opts])))
(let [toast-opts (rf/sub [:toasts/toast id])]
[quo/toast toast-opts]))
(defn container
[id]
@@ -43,7 +41,7 @@
[:f>
(fn []
(let [duration (or (rf/sub [:toasts/toast-cursor id :duration]) 3000)
on-dismissed (or (rf/sub [:toasts/toast-cursor id :on-dismissed]) identity)
on-dismissed #((or (rf/sub [:toasts/toast-cursor id :on-dismissed]) identity) id)
create-timer (fn []
(reset! timer (utils.utils/set-timeout close! duration)))
translate-y (reanimated/use-shared-value 0)
@@ -80,10 +78,10 @@
(create-timer)))))]
;; create auto dismiss timer, clear timer when unmount or duration changed
(rn/use-effect (fn [] (create-timer) clear-timer) [duration])
(rn/use-unmount #(on-dismissed id))
(rn/use-unmount on-dismissed)
[gesture/gesture-detector {:gesture pan}
[reanimated/view
{;; TODO: this will enable layout animation at runtime and causing flicker on android
{;; TODO: this will eanble layout animation at runtime and causing flicker on android
;; we need to resolve this and re-enable layout animation
;; issue at https://github.com/status-im/status-mobile/issues/14752
;; :entering slide-in-up-animation
@@ -100,5 +98,4 @@
[into
[rn/view
{:style style/outmost-transparent-container}]
(doall
(map (fn [id] ^{:key id} [container id]) toasts-ordered))]))
(map (fn [id] ^{:key id} [container id]) toasts-ordered)]))
-6
View File
@@ -36,12 +36,6 @@
(def ^:const activity-center-membership-status-accepted 2)
(def ^:const activity-center-membership-status-declined 3)
(def ^:const mute-for-15-mins-type 1)
(def ^:const mute-for-1-hour-type 2)
(def ^:const mute-for-8-hours-type 3)
(def ^:const mute-for-1-week 4)
(def ^:const mute-till-unmuted 5)
(def ^:const activity-center-mark-all-as-read-undo-time-limit-ms 4000)
(def ^:const activity-center-max-unread-count 99)
@@ -532,33 +532,29 @@
[{:keys [db]} new-notifications]
(let [my-public-key (get-in db [:multiaccount :public-key])]
(reduce (fn [cofx {:keys [author type accepted dismissed message name] :as x}]
(let [user-avatar {:full-name name
:status-indicator? true
:online? nil
:size :small
:ring? false}]
(cond
(and (not= author my-public-key)
(= type types/contact-request)
(not accepted)
(not dismissed))
(toasts/upsert cofx
{:user user-avatar
:icon-color colors/primary-50-opa-40
:title (i18n/label :t/contact-request-sent-toast
{:name name})
:text (get-in message [:content :text])})
(cond
(and (not= author my-public-key)
(= type types/contact-request)
(not accepted)
(not dismissed))
(toasts/upsert cofx
{:icon :placeholder
:icon-color colors/primary-50-opa-40
:title (i18n/label :t/contact-request-sent-toast
{:name name})
:text (get-in message [:content :text])})
(and (= author my-public-key) ;; we show it for user who sent the request
(= type types/contact-request)
accepted
(not dismissed))
(toasts/upsert cofx
{:user user-avatar
:icon-color colors/success-50-opa-40
:title (i18n/label :t/contact-request-accepted-toast
{:name (or name (:alias message))})})
:else
cofx)))
(and (= author my-public-key) ;; we show it for user who sent the request
(= type types/contact-request)
accepted
(not dismissed))
(toasts/upsert cofx
{:icon :placeholder
:icon-color colors/primary-50-opa-40
:title (i18n/label :t/contact-request-accepted-toast
{:name (or name (:alias message))})})
:else
cofx))
{:db db}
new-notifications)))
@@ -8,13 +8,6 @@
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(def tag-params
{:size :small
:override-theme :dark
:color colors/primary-50
:style style/user-avatar-tag
:text-style style/user-avatar-tag-text})
(defn user-avatar-tag
[user-id]
(let [contact (rf/sub [:contacts/contact-by-identity user-id])]
@@ -1,64 +0,0 @@
(ns status-im2.contexts.activity-center.notification.community-request.view
(:require [quo2.core :as quo]
[status-im2.constants :as constants]
[status-im2.contexts.activity-center.notification.common.style :as common-style]
[status-im2.contexts.activity-center.notification.common.view :as common]
[utils.datetime :as datetime]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(defn- swipeable
[{:keys [active-swipeable extra-fn]} child]
[common/swipeable
{:left-button common/swipe-button-read-or-unread
:left-on-press common/swipe-on-press-toggle-read
:right-button common/swipe-button-delete
:right-on-press common/swipe-on-press-delete
:active-swipeable active-swipeable
:extra-fn extra-fn}
child])
(defn- get-header-text-and-context
[community membership-status]
(let [community-name (:name community)
community-image (get-in community [:images :thumbnail :uri])
community-context-tag [quo/context-tag common/tag-params {:uri community-image}
community-name]]
(cond
(= membership-status constants/activity-center-membership-status-idle)
{:header-text (i18n/label :t/community-request-not-accepted)
:context [[quo/text {:style common-style/user-avatar-tag-text}
(i18n/label :t/community-request-not-accepted-body-text-prefix)]
community-context-tag
[quo/text {:style common-style/user-avatar-tag-text}
(i18n/label :t/community-request-not-accepted-body-text-suffix)]]}
(= membership-status constants/activity-center-membership-status-pending)
{:header-text (i18n/label :t/community-request-pending)
:context [[quo/text {:style common-style/user-avatar-tag-text}
(i18n/label :t/community-request-pending-body-text)]
community-context-tag]}
(= membership-status constants/activity-center-membership-status-accepted)
{:header-text (i18n/label :t/community-request-accepted)
:context [[quo/text {:style common-style/user-avatar-tag-text}
(i18n/label :t/community-request-accepted-body-text)]
community-context-tag]}
:else nil)))
(defn view
[{:keys [notification set-swipeable-height] :as props}]
(let [{:keys [community-id membership-status read
timestamp]} notification
community (rf/sub [:communities/community community-id])
{:keys [header-text context]} (get-header-text-and-context community
membership-status)]
[swipeable props
[quo/activity-log
{:title header-text
:icon :i/communities
:on-layout set-swipeable-height
:timestamp (datetime/timestamp->relative timestamp)
:unread? (not read)
:context context}]]))
@@ -6,7 +6,6 @@
(def ^:const mention 3)
(def ^:const reply 4)
(def ^:const contact-request 5)
(def ^:const community-request 7)
(def ^:const admin 8)
(def ^:const contact-verification 10)
@@ -16,7 +15,6 @@
mention
reply
contact-request
community-request
admin
contact-verification})
@@ -28,5 +26,4 @@
"Membership is like a logical group of notifications with different types, i.e.
it doesn't have a corresponding type in the backend. Think of the collection
as a composite key of actual types."
#{private-group-chat
community-request})
#{private-group-chat})
@@ -12,8 +12,6 @@
[status-im2.contexts.activity-center.notification.membership.view :as membership]
[status-im2.contexts.activity-center.notification.mentions.view :as mentions]
[status-im2.contexts.activity-center.notification.reply.view :as reply]
[status-im2.contexts.activity-center.notification.community-request.view :as
community-request]
[status-im2.contexts.activity-center.style :as style]
[utils.i18n :as i18n]
[utils.re-frame :as rf]
@@ -198,12 +196,7 @@
[admin/view props]
(some types/membership [type])
(case type
types/private-group-chat [membership/view props]
types/community-request [community-request/view props]
nil)
[membership/view props]
:else
nil)]))))
@@ -3,6 +3,18 @@
[react-native.platform :as platform]
[quo2.foundations.typography :as typography]))
(defn container-kbd
[]
{:style {:flex 1}
:keyboardVerticalOffset 60})
(def container-image
{:style {:flex 1
:flex-direction :row}})
(def image
{:flex 1})
(defn container-outer
[]
{:style {:flex (if platform/ios? 4.5 5)
@@ -29,8 +41,7 @@
[]
{:size :heading-1
:weight :semi-bold
:style {:margin-top 32
:margin-bottom 6
:style {:margin-bottom 6
:color (colors/theme-colors
colors/neutral-100
colors/white)}})
@@ -116,8 +127,11 @@
:accessibility-label :new-contact-close-button
:size 32
:override-background-color (colors/theme-colors
colors/neutral-10
colors/neutral-90)})
colors/white-opa-60
colors/neutral-80-opa-60)
:style {:position :absolute
:left 20
:top 20}})
(def button-qr
{:type :outline
@@ -5,6 +5,7 @@
[react-native.core :as rn]
[react-native.clipboard :as clipboard]
[reagent.core :as reagent]
[status-im2.common.resources :as resources]
[status-im.qr-scanner.core :as qr-scanner]
[status-im.utils.utils :as utils]
[status-im2.contexts.add-new-contact.style :as style]
@@ -54,9 +55,11 @@
show-paste-button? (and (not (string/blank? @clipboard))
(string/blank? @default-value)
(string/blank? input))]
[rn/view (style/container-outer)
[rn/view style/container-inner
[rn/keyboard-avoiding-view (style/container-kbd)
[rn/view style/container-image
[rn/image
{:source (resources/get-image :add-new-contact)
:style style/image}]
[quo/button
(merge (style/button-close)
{:on-press
@@ -64,54 +67,56 @@
(reset! clipboard nil)
(reset! default-value nil)
(rf/dispatch [:contacts/clear-new-identity])
(rf/dispatch [:navigate-back]))}) :i/close]
[quo/text (style/text-title)
(i18n/label :t/add-a-contact)]
[quo/text (style/text-subtitle)
(i18n/label :t/find-your-friends)]
[quo/text (style/text-description)
(i18n/label :t/ens-or-chat-key)]
[rn/view style/container-text-input
[rn/view (style/text-input-container invalid?)
[rn/text-input
(merge (style/text-input)
{:default-value (or scanned @default-value input)
:placeholder (i18n/label :t/type-some-chat-key)
:on-change-text (fn [v]
(reset! default-value v)
(debounce/debounce-and-dispatch
[:contacts/set-new-identity v nil]
600))})]
(when show-paste-button?
[quo/button
(merge style/button-paste
{:on-press
(fn []
(reset! default-value @clipboard)
(rf/dispatch
[:contacts/set-new-identity @clipboard nil]))})
(i18n/label :t/paste)])]
(rf/dispatch [:navigate-back]))}) :i/close]]
[rn/view (style/container-outer)
[rn/view style/container-inner
[quo/text (style/text-title)
(i18n/label :t/add-a-contact)]
[quo/text (style/text-subtitle)
(i18n/label :t/find-your-friends)]
[quo/text (style/text-description)
(i18n/label :t/ens-or-chat-key)]
[rn/view style/container-text-input
[rn/view (style/text-input-container invalid?)
[rn/text-input
(merge (style/text-input)
{:default-value (or scanned @default-value input)
:placeholder (i18n/label :t/type-some-chat-key)
:on-change-text (fn [v]
(reset! default-value v)
(debounce/debounce-and-dispatch
[:contacts/set-new-identity v nil]
600))})]
(when show-paste-button?
[quo/button
(merge style/button-paste
{:on-press
(fn []
(reset! default-value @clipboard)
(rf/dispatch
[:contacts/set-new-identity @clipboard nil]))})
(i18n/label :t/paste)])]
[quo/button
(merge style/button-qr
{:on-press #(rf/dispatch
[::qr-scanner/scan-code
{:handler :contacts/qr-code-scanned}])})
:i/scan]]
(when invalid?
[rn/view style/container-invalid
[quo/icon :i/alert style/icon-invalid]
[quo/text style/text-invalid
(i18n/label (or msg :t/invalid-ens-or-key))]])
(when (= state :valid)
[found-contact public-key])]
[rn/view
[quo/button
(merge style/button-qr
{:on-press #(rf/dispatch
[::qr-scanner/scan-code
{:handler :contacts/qr-code-scanned}])})
:i/scan]]
(when invalid?
[rn/view style/container-invalid
[quo/icon :i/alert style/icon-invalid]
[quo/text style/text-invalid
(i18n/label (or msg :t/invalid-ens-or-key))]])
(when (= state :valid)
[found-contact public-key])]
[rn/view
[quo/button
(merge (style/button-view-profile state)
{:on-press
(fn []
(reset! clipboard nil)
(reset! default-value nil)
(rf/dispatch [:contacts/clear-new-identity])
(rf/dispatch [:navigate-back])
(rf/dispatch [:chat.ui/show-profile public-key ens]))})
(i18n/label :t/view-profile)]]]))))
(merge (style/button-view-profile state)
{:on-press
(fn []
(reset! clipboard nil)
(reset! default-value nil)
(rf/dispatch [:contacts/clear-new-identity])
(rf/dispatch [:navigate-back])
(rf/dispatch [:chat.ui/show-profile public-key ens]))})
(i18n/label :t/view-profile)]]]]))))
+13 -17
View File
@@ -64,15 +64,13 @@
(defn map-chats
[{:keys [db] :as cofx}]
(fn [val]
(let [chat (or (get (:chats db) (:chat-id val))
(create-new-chat (:chat-id val) cofx))]
(assoc
(merge
(cond-> chat
(comp not :muted) (dissoc chat :muted-till))
val)
:invitation-admin
(:invitation-admin val)))))
(assoc
(merge
(or (get (:chats db) (:chat-id val))
(create-new-chat (:chat-id val) cofx))
val)
:invitation-admin
(:invitation-admin val))))
(rf/defn leave-removed-chat
[{{:keys [view-id current-chat-id chats]} :db
@@ -294,20 +292,18 @@
(rf/defn mute-chat-toggled-successfully
{:events [:chat/mute-successfully]}
[{:keys [db]} chat-id muted-till]
(log/debug "muted chat successfully" chat-id " for" muted-till)
{:db (assoc-in db [:chats chat-id :muted-till] muted-till)})
[_ chat-id]
(log/debug "muted chat successfully" chat-id))
(rf/defn mute-chat
{:events [:chat.ui/mute]}
[{:keys [db]} chat-id muted? mute-type]
(let [method (if muted? "wakuext_muteChatV2" "wakuext_unmuteChat")
params (if muted? [{:chatId chat-id :mutedType mute-type}] [chat-id])]
[{:keys [db]} chat-id muted?]
(let [method (if muted? "wakuext_muteChat" "wakuext_unmuteChat")]
{:db (assoc-in db [:chats chat-id :muted] muted?)
:json-rpc/call [{:method method
:params params
:params [chat-id]
:on-error #(rf/dispatch [:chat/mute-failed chat-id muted? %])
:on-success #(rf/dispatch [:chat/mute-successfully chat-id %])}]}))
:on-success #(rf/dispatch [:chat/mute-successfully chat-id])}]}))
(rf/defn show-clear-history-confirmation
{:events [:chat.ui/show-clear-history-confirmation]}
@@ -8,8 +8,7 @@
[status-im2.common.contact-list-item.view :as contact-list-item]
[status-im2.common.home.actions.view :as actions]
[utils.re-frame :as rf]
[reagent.core :as reagent]
[status-im2.constants :as constants]))
[reagent.core :as reagent]))
(defn back-button
[]
@@ -192,8 +191,7 @@
[rn/touchable-opacity
{:style (style/action-container color)
:accessibility-label :toggle-mute
:on-press #(rf/dispatch [:chat.ui/mute chat-id (not muted)
(when-not muted constants/mute-till-unmuted)])}
:on-press #(rf/dispatch [:chat.ui/mute chat-id (not muted)])}
[quo/icon (if muted :i/muted :i/activity-center)
{:size 20 :color (colors/theme-colors colors/neutral-100 colors/white)}]
[quo/text {:style {:margin-top 16} :size :paragraph-1 :weight :medium}
@@ -14,7 +14,8 @@
[chat-id]
(fn []
(rf/dispatch [:dismiss-keyboard])
(rf/dispatch [:chat/navigate-to-chat chat-id])))
(rf/dispatch [:chat/navigate-to-chat chat-id])
(rf/dispatch [:search/home-filter-changed nil])))
(defn truncate-literal
[literal]
@@ -117,7 +118,7 @@
(defn chat-list-item
[{:keys [chat-id group-chat color name unviewed-messages-count unviewed-mentions-count
timestamp last-message muted]
timestamp last-message]
:as item}]
(let [display-name (if group-chat
name
@@ -142,9 +143,8 @@
:style {:color (colors/theme-colors colors/neutral-50 colors/neutral-40)}}
(get-in last-message [:content :text])]
[render-subheader (get-in last-message [:content :parsed-text])])]
(when-not muted
(if (> unviewed-mentions-count 0)
[quo/info-count {:style {:top 16}}
unviewed-mentions-count]
(when (> unviewed-messages-count 0)
[rn/view {:style (style/count-container)}])))]))
(if (> unviewed-mentions-count 0)
[quo/info-count {:style {:top 16}}
unviewed-mentions-count]
(when (> unviewed-messages-count 0)
[rn/view {:style (style/count-container)}]))]))
@@ -45,12 +45,8 @@
[rn/view {:style (style/contact-requests-icon)}
[quo/icon :i/pending-user {:color (colors/theme-colors colors/neutral-50 colors/neutral-40)}]]
[rn/view {:style {:margin-left 8}}
[quo/text
{:size :paragraph-1
:weight :semi-bold
:style {:color (colors/theme-colors colors/neutral-100 colors/white)}}
(i18n/label :t/pending-requests)]
[quo/text
[rn/text {:weight :semi-bold} (i18n/label :t/pending-requests)]
[rn/text
{:size :paragraph-2
:style {:color (colors/theme-colors colors/neutral-50 colors/neutral-40)}}
(requests-summary requests)]]
@@ -1,8 +0,0 @@
(ns status-im2.contexts.chat.home.events
(:require
[utils.re-frame :as rf]))
(rf/defn messages-home-select-tab-event
{:events [:messages-home/select-tab]}
[{:keys [db]} tab]
{:db (assoc db :messages-home/selected-tab tab)})
+39 -38
View File
@@ -3,6 +3,7 @@
[quo2.core :as quo]
[re-frame.core :as re-frame]
[react-native.core :as rn]
[reagent.core :as reagent]
[status-im2.common.contact-list.view :as contact-list]
[status-im2.common.home.view :as common.home]
[status-im2.contexts.chat.home.chat-list-item.view :as chat-list-item]
@@ -23,7 +24,7 @@
(defn filter-items-by-tab
[tab items]
(if (= tab :tab/groups)
(if (= tab :groups)
(filter :group-chat items)
(filter :chat-id items)))
@@ -36,9 +37,10 @@
(defn chats
[selected-tab top]
(let [unfiltered-items (rf/sub [:chats-stack-items])
items (filter-items-by-tab selected-tab unfiltered-items)]
(if (empty? items)
(let [{:keys [items search-filter]} (rf/sub [:home-items])
items (filter-items-by-tab selected-tab items)]
(if (and (empty? items)
(empty? search-filter))
[welcome-blank-chats]
[rn/flat-list
{:key-fn #(or (:chat-id %) (:public-key %) (:id %))
@@ -91,43 +93,42 @@
(defn get-tabs-data
[dot?]
[{: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
[{:id :recent :label (i18n/label :t/recent) :accessibility-label :tab-recent}
{:id :groups :label (i18n/label :t/groups) :accessibility-label :tab-groups}
{:id :contacts
:label (i18n/label :t/contacts)
:accessibility-label :tab-contacts
:notification-dot? dot?}])
(defn home
[]
(fn []
(let [pending-contact-requests (rf/sub [:activity-center/pending-contact-requests])
selected-tab (or (rf/sub [:messages-home/selected-tab]) :tab/recent)]
[safe-area/consumer
(fn [{:keys [top]}]
[:<>
(if (= selected-tab :tab/contacts)
[contacts pending-contact-requests top]
[chats selected-tab top])
[rn/view
{:style (style/blur-container top)}
[blur/view
{:blur-amount (if platform/ios? 20 10)
:blur-type (if (colors/dark?) :dark (if platform/ios? :light :xlight))
:style style/blur}]
[common.home/top-nav]
[common.home/title-column
{:label (i18n/label :t/messages)
:handler #(rf/dispatch [:show-bottom-sheet
{:content home.sheet/new-chat-bottom-sheet}])
:accessibility-label :new-chat-button}]
[quo/discover-card
{:title (i18n/label :t/invite-friends-to-status)
:description (i18n/label :t/share-invite-link)}]
[quo/tabs
{:style style/tabs
:size 32
:on-change (fn [tab]
(rf/dispatch [:messages-home/select-tab tab]))
:default-active selected-tab
:data (get-tabs-data (pos? (count pending-contact-requests)))}]]])])))
(let [selected-tab (reagent/atom :recent)]
(fn []
(let [pending-contact-requests (rf/sub [:activity-center/pending-contact-requests])]
[safe-area/consumer
(fn [{:keys [top]}]
[:<>
(if (= @selected-tab :contacts)
[contacts pending-contact-requests top]
[chats @selected-tab top])
[rn/view
{:style (style/blur-container top)}
[blur/view
{:blur-amount (if platform/ios? 20 10)
:blur-type (if (colors/dark?) :dark (if platform/ios? :light :xlight))
:style style/blur}]
[common.home/top-nav]
[common.home/title-column
{:label (i18n/label :t/messages)
:handler #(rf/dispatch [:show-bottom-sheet
{:content home.sheet/new-chat-bottom-sheet}])
:accessibility-label :new-chat-button}]
[quo/discover-card
{:title (i18n/label :t/invite-friends-to-status)
:description (i18n/label :t/share-invite-link)}]
[quo/tabs
{:style style/tabs
:size 32
:on-change #(reset! selected-tab %)
:default-active @selected-tab
:data (get-tabs-data (pos? (count pending-contact-requests)))}]]])]))))
@@ -29,9 +29,9 @@
:elevation 5
:max-height (/ max-y 2)})}
[rn/flat-list
{:keyboard-should-persist-taps :always
:data (vals suggestions)
:key-fn :key
:render-fn mention-item
:render-data (:text-input-ref refs)
:accessibility-label :mentions-list}]]))])
{:keyboardShouldPersistTaps :always
:data (vals suggestions)
:key-fn :key
:render-fn mention-item
:render-data (:text-input-ref refs)
:accessibility-label :mentions-list}]]))])
@@ -26,10 +26,10 @@
(i18n/label :t/deleted-this-message)]])
(defn- compute-on-long-press-fn
[{:keys [deleted? pinned deleted-for-me?] :as message}
[{:keys [deleted? pinned] :as message}
{:keys [message-pin-enabled] :as context}]
;; only show drawer for user who has the permission to unpin messages
(when (and pinned (or deleted? deleted-for-me?) message-pin-enabled)
(when (and pinned deleted? message-pin-enabled)
(fn []
(rf/dispatch [:dismiss-keyboard])
(rf/dispatch [:show-bottom-sheet
@@ -89,54 +89,45 @@
(defn link-preview-loader
[link _]
(let [measured-width (reagent/atom 0)
measured-height (reagent/atom 0)]
(reagent/create-class
{:component-did-mount
(fn []
(rf/dispatch [:chat.ui/load-link-preview-data link]))
:component-did-update
(fn [this [_ previous-props]]
(let [[_ props] (.-argv (.-props ^js this))
refresh-photo? (not= previous-props props)]
(when refresh-photo?
(rf/dispatch [:chat.ui/load-link-preview-data props]))))
:reagent-render
(fn [link {:keys [on-long-press]}]
(let [cached-preview-data (rf/sub [:link-preview/cache link])]
(when-let [{:keys [site title thumbnail-url error]} cached-preview-data]
(when (and (not error) site title)
[rn/touchable-opacity
{:style (when-not (is-gif? thumbnail-url)
{:align-self :stretch})
:on-press #(when (security/safe-link? link)
(rf/dispatch [:browser.ui/message-link-pressed link]))
:on-long-press on-long-press}
[rn/view (style/wrapper)
(when-not (is-gif? thumbnail-url)
[:<>
[rn/view (style/title-wrapper)
[rn/image {:style (style/title-site-image)}]
[rn/text {:style (style/title-text)}
site]]
[rn/text {:style (style/main-text)}
title]
[rn/text {:style (style/extra-text)}
link]])
(when-not (string/blank? thumbnail-url)
[:<>
[rn/view (style/separator)]
[fast-image/fast-image
{:source {:uri thumbnail-url}
:on-load (fn [e]
(let [{:keys [width height]} (js->clj (.-nativeEvent e)
:keywordize-keys
true)]
(reset! measured-width width)
(reset! measured-height height)))
:style (style/image {:width @measured-width
:height @measured-height})
:accessibility-label :member-photo}]])]]))))})))
(reagent/create-class
{:component-did-mount
(fn []
(rf/dispatch [:chat.ui/load-link-preview-data link]))
:component-did-update
(fn [this [_ previous-props]]
(let [[_ props] (.-argv (.-props ^js this))
refresh-photo? (not= previous-props props)]
(when refresh-photo?
(rf/dispatch [:chat.ui/load-link-preview-data props]))))
:reagent-render
(fn [link {:keys [on-long-press]}]
(let [cached-preview-data (rf/sub [:link-preview/cache link])]
(when-let [{:keys [site title thumbnail-url error] :as preview-data} cached-preview-data]
(when (and (not error) site title)
[rn/touchable-opacity
{:style (when-not (is-gif? thumbnail-url)
{:align-self :stretch})
:on-press #(when (security/safe-link? link)
(rf/dispatch [:browser.ui/message-link-pressed link]))
:on-long-press on-long-press}
[rn/view (style/wrapper)
(when-not (is-gif? thumbnail-url)
[:<>
[rn/view (style/title-wrapper)
[rn/image {:style (style/title-site-image)}]
[rn/text {:style (style/title-text)}
site]]
[rn/text {:style (style/main-text)}
title]
[rn/text {:style (style/extra-text)}
link]])
(when-not (string/blank? thumbnail-url)
[:<>
[rn/view (style/separator)]
[fast-image/fast-image
{:source {:uri thumbnail-url}
:style (style/image (select-keys preview-data [:height :width]))
:accessibility-label :member-photo}]])]]))))}))
(defn link-preview-enable-request
[]
@@ -186,7 +186,8 @@
(when (and (not locked?) id)
{:on-press (fn []
(rf/dispatch [:dismiss-keyboard])
(rf/dispatch [:chat/navigate-to-chat (str community-id id)]))}))))
(rf/dispatch [:chat/navigate-to-chat (str community-id id)])
(rf/dispatch [:search/home-filter-changed nil]))}))))
(defn add-on-press-handler-to-chats
[community-id chats]
@@ -9,15 +9,14 @@
[dark-overlay?]
[:f>
(fn []
(let [animate? (not dark-overlay?)]
(when animate? (carousel.animation/initialize-animation))
[rn/view
{:style style/background-container}
[carousel/view animate?]
(when dark-overlay?
[blur/view
{:style style/background-blur-overlay
:blur-amount 30
:blur-radius 25
:blur-type :transparent
:overlay-color :transparent}])]))])
(carousel.animation/initialize-animation)
[rn/view
{:style style/background-container}
[carousel/view dark-overlay?]
(when dark-overlay?
[blur/view
{:style style/background-blur-overlay
:blur-amount 30
:blur-radius 25
:blur-type :transparent
:overlay-color :transparent}])])])
@@ -35,22 +35,16 @@
(defn initialize-animation
[]
(reset! progress (reanimated/use-shared-value 0))
(reset! paused (reanimated/use-shared-value false))
(animate-progress @progress @paused))
(when-not @progress
(reset! progress (reanimated/use-shared-value 0))
(reset! paused (reanimated/use-shared-value false))
(animate-progress @progress @paused)))
;; Derived Values
(defn carousel-left-position
[window-width animate?]
(if animate?
(worklets.onboarding-carousel/carousel-left-position window-width @progress)
(-> (or (reanimated/get-shared-value @progress) 0)
(quot -25)
(* window-width))))
[window-width]
(worklets.onboarding-carousel/carousel-left-position window-width @progress))
(defn dynamic-progress-bar-width
[progress-bar-width animate?]
(if animate?
(worklets.onboarding-carousel/dynamic-progress-bar-width progress-bar-width @progress)
(-> (or (reanimated/get-shared-value @progress) 0)
(* progress-bar-width)
(/ 100))))
[progress-bar-width]
(worklets.onboarding-carousel/dynamic-progress-bar-width progress-bar-width @progress))
@@ -48,16 +48,12 @@
:flex-direction :row})
(defn dynamic-progress-bar
[width animate?]
(let [normal-style {:height 2
:border-radius 4
:overflow :hidden
:width width}]
(if animate?
(reanimated/apply-animations-to-style
{:width width}
normal-style)
normal-style)))
[width]
(reanimated/apply-animations-to-style
{:width width}
{:height 2
:border-radius 4
:overflow :hidden}))
(defn progress-bar-container
[progress-bar-width status-bar-height]
@@ -67,15 +63,11 @@
:top (+ 12 status-bar-height)})
(defn carousel-container
[left animate?]
(let [normal-style {:position :absolute
:right 0
:top 0
:bottom 0
:flex-direction :row
:left left}]
(if animate?
(reanimated/apply-animations-to-style
{:left left}
normal-style)
normal-style)))
[left]
(reanimated/apply-animations-to-style
{:left left}
{:position :absolute
:right 0
:top 0
:bottom 0
:flex-direction :row}))
@@ -54,33 +54,30 @@
[rn/view {:style (style/progress-bar-item static? true)}]])
(defn dynamic-progress-bar
[progress-bar-width animate?]
[progress-bar-width]
[:f>
(fn []
(let [width (animation/dynamic-progress-bar-width progress-bar-width animate?)
container-view (if animate? reanimated/view rn/view)]
[container-view {:style (style/dynamic-progress-bar width animate?)}
(let [width (animation/dynamic-progress-bar-width progress-bar-width)]
[reanimated/view {:style (style/dynamic-progress-bar width)}
[progress-bar
{:static? false
:progress-bar-width progress-bar-width}]]))])
(defn view
[animate?]
[]
[:f>
(fn []
(let [window-width (rf/sub [:dimensions/window-width])
view-id (rf/sub [:view-id])
status-bar-height (:status-bar-height @navigation/constants)
progress-bar-width (- window-width 40)
carousel-left (animation/carousel-left-position window-width animate?)
container-view (if animate? reanimated/view rn/view)]
(when animate?
(rn/use-effect
(fn []
(reanimated/set-shared-value @animation/paused (not= view-id :intro)))
[view-id]))
carousel-left (animation/carousel-left-position window-width)]
(rn/use-effect
(fn []
(reanimated/set-shared-value @animation/paused (not= view-id :intro)))
[view-id])
[:<>
[container-view {:style (style/carousel-container carousel-left animate?)}
[reanimated/view {:style (style/carousel-container carousel-left)}
(for [index (range 2)]
^{:key index}
[content-view
@@ -94,5 +91,5 @@
[progress-bar
{:static? true
:progress-bar-width progress-bar-width}]
[dynamic-progress-bar progress-bar-width animate?]]]))])
[dynamic-progress-bar progress-bar-width]]]))])
@@ -4,16 +4,16 @@
[utils.re-frame :as rf]))
(defn navigation-bar
[{:keys [top right-section-buttons disable-back-button?]}]
[rn/view
{:style {:height 56
:margin-top top}}
[{:keys [on-press-info]}]
[rn/view {:style {:height 56}}
[quo/page-nav
{:align-mid? true
:mid-section {:type :text-only :main-text ""}
:mid-section {:type :text-only}
:left-section {:type :blur-bg
:icon :i/arrow-left
:icon-override-theme :dark
:on-press (when-not disable-back-button?
#(rf/dispatch [:navigate-back]))}
:right-section-buttons right-section-buttons}]])
:on-press #(rf/dispatch [:navigate-back])}
:right-section-buttons [{:type :blur-bg
:icon :i/info
:icon-override-theme :dark
:on-press on-press-info}]}]])
@@ -3,7 +3,6 @@
[quo2.core :as quo]
[quo2.foundations.colors :as colors]
[react-native.core :as rn]
[react-native.safe-area :as safe-area]
[reagent.core :as reagent]
[status-im2.contexts.onboarding.common.background.view :as background]
[status-im2.contexts.onboarding.common.navigation-bar.view :as navigation-bar]
@@ -66,7 +65,7 @@
:shown true}
:placeholder (i18n/label :t/password-creation-placeholder-1)
:on-change-text on-change-password
:on-focus on-input-focus}]
:on-focus #(on-input-focus :password)}]
[rn/view {:style style/space-between-inputs}]
[password-with-hint
{:hint {:text hint-2-text
@@ -76,7 +75,7 @@
:error? error?
:placeholder (i18n/label :t/password-creation-placeholder-2)
:on-change-text on-change-repeat-password
:on-focus on-input-focus
:on-focus #(on-input-focus :repeat-password)
:on-blur on-blur-repeat-password}]]))
(def strength-status
@@ -147,9 +146,9 @@
:passwords-match? same-passwords?
:empty-password? empty-password?
:show-password-validation? @show-password-validation?
:on-input-focus (fn []
:on-input-focus (fn [input-id]
(scroll-to-end-fn)
(reset! focused-input :password))
(reset! focused-input input-id))
:on-change-password (fn [new-value]
(reset! password new-value)
(when (same-password-length?)
@@ -163,18 +162,19 @@
(reset! show-password-validation? true))}]]
[rn/view {:style style/bottom-part}
[rn/view {:style style/disclaimer-container}
[quo/disclaimer
{:blur? true
:on-change #(reset! accepts-disclaimer? %)
:checked? @accepts-disclaimer?}
(i18n/label :t/password-creation-disclaimer)]]
(when (= @focused-input :password)
[help
{:validations validations
:password-strength password-strength}])
(when (= @focused-input :repeat-password)
[rn/view {:style style/disclaimer-container}
[quo/disclaimer
{:blur? true
:checked? @accepts-disclaimer?
:on-change #(reset! accepts-disclaimer? %)}
(i18n/label :t/password-creation-disclaimer)]])
[rn/view {:style style/button-container}
[quo/button
{:disabled (not meet-requirements?)
@@ -186,21 +186,14 @@
(defn create-password
[]
[:f>
(let [scroll-view-ref (atom nil)
scroll-to-end-fn #(js/setTimeout ^js/Function (.-scrollToEnd @scroll-view-ref) 250)]
(fn []
(let [{:keys [top]} (safe-area/use-safe-area)]
[:<>
[background/view true]
[rn/scroll-view
{:ref #(reset! scroll-view-ref %)
:style style/overlay
:content-container-style style/content-style}
[navigation-bar/navigation-bar
{:top top
:right-section-buttons [{:type :blur-bg
:icon :i/info
:icon-override-theme :dark
:on-press #(js/alert "Info pressed")}]}]
[password-form {:scroll-to-end-fn scroll-to-end-fn}]]])))])
(let [scroll-view-ref (atom nil)
scroll-to-end-fn #(js/setTimeout ^js/Function (.-scrollToEnd @scroll-view-ref) 250)]
(fn []
[:<>
[background/view true]
[rn/scroll-view
{:ref #(reset! scroll-view-ref %)
:style style/overlay
:content-container-style style/content-style}
[navigation-bar/navigation-bar {:on-press-info #(js/alert "Info pressed")}]
[password-form {:scroll-to-end-fn scroll-to-end-fn}]]])))

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