Compare commits

..
Author SHA1 Message Date
Ulises M 747d6bb128 WIP: debugging 2024-02-13 13:30:46 -06:00
Ulises M a29264a1a1 Reimplement avatar animations using new worklet approach 2024-02-12 15:06:35 -06:00
Ulises M 1386bd4777 Add worklet translation to shadow-cljs 2024-02-12 15:06:03 -06:00
281 changed files with 2053 additions and 4205 deletions
-3
View File
@@ -194,6 +194,3 @@ test/appium/tests/users.py
## git hooks
lefthook.yml
## build time logs
/logs/*.log
+24 -10
View File
@@ -36,8 +36,6 @@ endif
export TMPDIR = /tmp/tmp-status-mobile-$(BUILD_TAG)
# This has to be specified for both the Node.JS server process and the Qt process.
export REACT_SERVER_PORT ?= 5001
# Default metro port used by scripts/run-android.sh.
export RCT_METRO_PORT ?= 8081
# Fix for ERR_OSSL_EVP_UNSUPPORTED error.
export NODE_OPTIONS += --openssl-legacy-provider
# The path can be anything, but home is usually safest.
@@ -46,7 +44,7 @@ export KEYSTORE_PATH ?= $(HOME)/.gradle/status-im.keystore
# Our custom config is located in nix/nix.conf
export NIX_USER_CONF_FILES = $(PWD)/nix/nix.conf
# Location of symlinks to derivations that should not be garbage collected
export _NIX_GCROOTS = ./.nix-gcroots
export _NIX_GCROOTS = /nix/var/nix/gcroots/per-user/$(USER)/status-mobile
# Defines which variables will be kept for Nix pure shell, use semicolon as divider
export _NIX_KEEP ?= TMPDIR,BUILD_ENV,\
BUILD_TYPE,BUILD_NUMBER,COMMIT_HASH,\
@@ -56,6 +54,12 @@ export _NIX_KEEP ?= TMPDIR,BUILD_ENV,\
# Useful for Android release builds
TMP_BUILD_NUMBER := $(shell ./scripts/version/gen_build_no.sh | cut -c1-10)
# MacOS root is read-only, read nix/README.md for details
UNAME_S := $(shell uname -s)
ifeq ($(UNAME_S),Darwin)
export NIX_IGNORE_SYMLINK_STORE=1
endif
#----------------
# Nix targets
#----------------
@@ -210,7 +214,7 @@ build-fdroid: ##@build Build release for F-Droid
build-android: export BUILD_ENV ?= prod
build-android: export BUILD_TYPE ?= nightly
build-android: export ORG_GRADLE_PROJECT_versionCode ?= $(TMP_BUILD_NUMBER)
build-android: export BUILD_NUMBER ?= $(TMP_BUILD_NUMBER)
build-android: export ANDROID_ABI_SPLIT ?= false
build-android: export ANDROID_ABI_INCLUDE ?= armeabi-v7a;arm64-v8a;x86
build-android: ##@build Build unsigned Android APK
@@ -263,7 +267,7 @@ run-clojure: ##@run Watch for and build Clojure changes for mobile
run-metro: export TARGET := clojure
run-metro: ##@run Start Metro to build React Native changes
@scripts/run-metro.sh
@scripts/start-react-native.sh
run-re-frisk: export TARGET := clojure
run-re-frisk: ##@run Start re-frisk server
@@ -274,15 +278,22 @@ run-android: export TARGET := android
# Disabled for debug builds to avoid 'maximum call stack exceeded' errors.
# https://github.com/status-im/status-mobile/issues/18493
run-android: export ORG_GRADLE_PROJECT_hermesEnabled := false
# INFO: If it's empty (no devices attached, parsing issues, script error) - for Nix it's the same as not set.
run-android: export ANDROID_ABI_INCLUDE ?= $(shell ./scripts/adb_devices_abis.sh)
run-android: ##@run Build Android APK and start it on the device
@scripts/run-android.sh
npx react-native run-android --appIdSuffix debug
SIMULATOR=iPhone 13
# TODO: fix IOS_STATUS_GO_TARGETS to be either amd64 or arm64 when RN is upgraded
run-ios: export TARGET := ios
run-ios: export IOS_STATUS_GO_TARGETS := ios/arm64;iossimulator/amd64
run-ios: ##@run Build iOS app and start it in on the simulator
@scripts/run-ios.sh "${SIMULATOR}"
run-ios: export XCBeautify=$(shell which xcbeautify) # for react-native-cli to pick this up and to auto format output
run-ios: ##@run Build iOS app and start it in a simulator/device
ifneq ("$(SIMULATOR)", "")
npx react-native run-ios --simulator="$(SIMULATOR)"
else
npx react-native run-ios
endif
show-ios-devices: ##@other shows connected ios device and its name
xcrun xctrace list devices
@@ -290,8 +301,11 @@ show-ios-devices: ##@other shows connected ios device and its name
# TODO: fix IOS_STATUS_GO_TARGETS to be either amd64 or arm64 when RN is upgraded
run-ios-device: export TARGET := ios
run-ios-device: export IOS_STATUS_GO_TARGETS := ios/arm64;iossimulator/amd64
run-ios-device: ##@run iOS app and start it on the first connected iPhone
@scripts/run-ios-device.sh
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
+3 -3
View File
@@ -37,7 +37,7 @@ project dependencies, coding guidelines and testing procedures.
Check out our [coding guidelines](doc/new-guidelines.md).
- **Community Management**
Metcalfe's law states that the value of a network is proportional to the square of the number of connected users of the system - without community Status is meaningless. We're looking to create a positive, fun environment to explore new ideas, experiment and grow the Status community. Building a community takes a lot of work but the people you'll meet and the long-lasting relationships you form will be well worth it, check out our [Mission and Community Principles](https://status.app/manifesto)
Metcalfe's law states that the value of a network is proportional to the square of the number of connected users of the system - without community Status is meaningless. We're looking to create a positive, fun environment to explore new ideas, experiment and grow the Status community. Building a community takes a lot of work but the people you'll meet and the long-lasting relationships you form will be well worth it, check out our [Mission and Community Principles](https://status.im/about)
- **Specification / Documentation**
John Dewey once said, "Education is not preparation for life; education is life *itself* ". Developers and Designers need guidance and it all starts from documentation and specifications. Our software is only as good as its documentation, check out our [docs](doc/) and see how you can improve what we have.
@@ -53,10 +53,10 @@ Status is a visual interface to make permanent changes on the Blockchain, it han
- **Evangelism**
Help us spread the word! Tell a friend *right now*, in fact, tell **everyone** - yell from a mountain if you have to, every person counts! If you've got a great story to tell or have some interesting way you've spread the word about Status let us know about it in our [chat](https://join.status.im/chat/public/status)
## Give me Binaries!
You can get our Beta builds for both Android and iOS on our [website](https://status.app), through our [nightly builds](https://status.im/nightly/), or by [building it yourself](doc/starting-guide.md).
You can get our Beta builds for both Android and iOS on our [website](https://status.im), through our [nightly builds](https://status.im/nightly/), or by [building it yourself](https://status.im/technical/build_status/).
## Core Contributors
+2 -2
View File
@@ -1,11 +1,11 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.8.7'
library 'status-jenkins-lib@v1.8.5'
/* Options section can't access functions in objects. */
def isPRBuild = utils.isPRBuild()
pipeline {
agent { label 'linux && x86_64 && nix-2.19' }
agent { label 'linux && x86_64 && nix-2.14' }
options {
timestamps()
+6 -2
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.8.7'
library 'status-jenkins-lib@v1.8.5'
pipeline {
agent { label 'linux' }
@@ -35,6 +35,8 @@ pipeline {
stage('Prep') {
steps { script {
println("Current JOB: ${env.JOB_NAME}")
/* just for a shorter access */
btype = utils.getBuildType()
} }
}
stage('Build') {
@@ -82,8 +84,10 @@ pipeline {
when { expression { params.PUBLISH } }
steps { script {
switch (btype) {
case 'nightly': /* Create JSON file with newest build URLs */
case 'nightly':
/* Create JSON file with newest build URLs */
s3.updateBucketJSON(urls, 'latest.json');
build(job: 'website/status.im', wait: false);
break;
case 'release':
github.publishReleaseFiles(repo: 'status-mobile');
+1 -1
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.8.7'
library 'status-jenkins-lib@v1.8.5'
pipeline {
agent { label 'linux' }
+4 -2
View File
@@ -1,11 +1,11 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.8.7'
library 'status-jenkins-lib@v1.8.5'
/* Options section can't access functions in objects. */
def isPRBuild = utils.isPRBuild()
pipeline {
agent { label 'macos && arm64 && nix-2.19 && xcode-15.1' }
agent { label 'macos && arm64 && nix-2.14 && xcode-15.1' }
parameters {
string(
@@ -39,6 +39,8 @@ pipeline {
LANGUAGE = "en_US.UTF-8"
TARGET = 'ios'
NIX_CONF_DIR = "${env.WORKSPACE}/nix"
/* See nix/README.md */
NIX_IGNORE_SYMLINK_STORE = 1
FASTLANE_DISABLE_COLORS = 1
BUNDLE_PATH = "${HOME}/.bundle"
}
+2 -2
View File
@@ -1,11 +1,11 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.8.7'
library 'status-jenkins-lib@v1.8.5'
/* Options section can't access functions in objects. */
def isPRBuild = utils.isPRBuild()
pipeline {
agent { label 'linux && x86_64 && nix-2.19' }
agent { label 'linux && x86_64 && nix-2.14' }
options {
timestamps()
+1 -1
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.8.7'
library 'status-jenkins-lib@v1.8.5'
pipeline {
+1 -1
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.8.7'
library 'status-jenkins-lib@v1.8.5'
pipeline {
+1 -1
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.8.7'
library 'status-jenkins-lib@v1.8.5'
pipeline {
+3 -1
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.8.7'
library 'status-jenkins-lib@v1.8.5'
pipeline {
agent { label 'macos' }
@@ -10,6 +10,8 @@ pipeline {
LC_ALL = 'en_US.UTF-8'
TARGET = 'ios'
FASTLANE_DISABLE_COLORS = 1
/* See nix/README.md */
NIX_IGNORE_SYMLINK_STORE = 1
/* avoid writing to r/o /nix */
GEM_HOME = '~/.rubygems'
}
+4 -2
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.8.7'
library 'status-jenkins-lib@v1.8.5'
pipeline {
agent { label params.AGENT_LABEL }
@@ -18,6 +18,8 @@ pipeline {
}
environment {
/* See nix/README.md */
NIX_IGNORE_SYMLINK_STORE = 1
/* we source .bash_profile to be able to use nix-store */
NIX_SSHOPTS = "-oStrictHostKeyChecking=no"
NIX_CONF_DIR = "${env.WORKSPACE}/nix"
@@ -80,7 +82,7 @@ pipeline {
env.NIXPKGS_SYSTEM_OVERRIDE = nixSysOverride(os, arch, 'android')
/* Build/fetch deps required to build android release. */
nix.build(
attr: 'targets.mobile.android.build.buildInputs',
attr: 'targets.mobile.android.release.buildInputs',
sandbox: false,
pure: false,
link: false
+3 -1
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.8.7'
library 'status-jenkins-lib@v1.8.5'
pipeline {
agent { label 'linux' }
@@ -10,6 +10,8 @@ pipeline {
LC_ALL = 'en_US.UTF-8'
TARGET = 'ios'
FASTLANE_DISABLE_COLORS = 1
/* See nix/README.md */
NIX_IGNORE_SYMLINK_STORE = 1
/* avoid writing to r/o /nix */
GEM_HOME = '~/.rubygems'
}
+1 -1
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.8.7'
library 'status-jenkins-lib@v1.8.5'
pipeline {
agent {
-4
View File
@@ -10,8 +10,6 @@
[Coding guidelines](new-guidelines.md)
[UI components coding guidelines](ui-guidelines.md)
[Release Checklist](release-checklist.md)
[Release Guide](release-guide.md)
@@ -30,8 +28,6 @@
[Contributing to status-go](status-go-changes.md)
[Malli schemas (recorded demo)](https://www.youtube.com/watch?v=SlRio70aYVI) ([slides](files/forging-code-with-schemas-sep-2023-slides.pdf))
## Testing
[How to run local tests](testing.md)
+2 -1
View File
@@ -122,9 +122,10 @@ See below:
Do the following:
Ensure you have 2 terminals running the following
Ensure you have 3 terminals running the following
- `make run-clojure`
- `make run-metro`
- `make run-ios` / `make run-android`
[See the STARTING GUIDE for details](STARTING_GUIDE.md#development)
Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

+23 -37
View File
@@ -4,41 +4,22 @@ This document provides information on how to start developing Status App.
# Getting Started
To start developing clone the status-mobile repo in the directory of your choice.
To start developing start a shell for the platform you are interested in.
```
git clone https://github.com/status-im/status-mobile.git
make shell TARGET=android
```
This step will take a while the first time as it will download all dependencies.
Then open a terminal and cd into this directory.
# Development
```
cd status-mobile
```
There are three steps necessary to start development, in this case for Android:
Then build the clojure terminal
1. `make run-clojure` - Compiles Clojure into JavaScript, watches for changes on cljs files, and hot-reloads code in the app.
2. `make run-metro` - Starts metro bundler and watches JavaScript code.
3. `make run-android` or `make run-ios` - Builds the Android/iOS app and starts it on the device.
```
make run-clojure
```
note: ⚠️ This might take a while if this is your first time.
This command installs `nix` and pulls in all the dependencies.
Do answer with "Y" to all the prompts and press "Enter" when `nix` setup asks you to Acknowledge.
This command builds the `jsbundle` and then compiles `Clojure` into `JavaScript`, watches for changes on `cljs` files, and hot-reloads code in the app.
wait till you see the following message :
```
[:mobile] Build completed. (1801 files, 52 compiled, 0 warnings, 9.52s)
```
Once the clojure terminal is running you need to run the appropriate command next for your platform in a separate terminal :
`make run-android` or `make run-ios`
These commands will build the app, start a metro bundler and deploy the app on your simulator OR connected device (android only). For building and deploying to connected iPhones use `make run-ios-device` instead of `make run-ios`
Also check [developing on a physical iOS Device](#Additional-requirements-for-developing-on-physical-ios-device).
The first two will continue watching for changes and keep re-building the app. They need to be ready first.
The last one will exit once the app is up and ready.
## Simulators and Devices
### Android
@@ -65,9 +46,13 @@ Running `make run-ios` will target `iPhone 13` by default.
If you need to run on any other simulator, you can specify the simulator type by adding the `SIMULATOR` flag:
```sh
make run-ios SIMULATOR="iPhone 15"
make run-ios SIMULATOR="iPhone 13"
```
#### Running on a physical device
Some manual steps are necessary for [developing on a physical iOS Device](#physical-ios-device).
# Build release
To build the app, you can simply run on of the following:
@@ -117,15 +102,16 @@ Steps:
3. [Setup Git to sign commits](https://help.github.com/en/github/authenticating-to-github/signing-commits)
4. [Setup GitHub to validate commits](https://help.github.com/en/github/authenticating-to-github/adding-a-new-gpg-key-to-your-github-account)
## Additional requirements for developing on Physical iOS Device
## Physical iOS Device
To use a physical iPhone your device UDID must be added to provisioning profiles and your Apple account invited as Developer to Status team.
1. [Get your UDID of your iPhone.](https://www.extentia.com/post/finding-the-udid-of-an-ios-device)
2. Request from someone with access like @cammellos or @jakubgs to
- Add the UDID to development devices on Apple Developer Portal.
- Invite your Apple account to be Developer in Status team.
3. Open XCode using the project from `status-mobile/ios` directory.
- You might see error: `Select a development team in the Signing & Capabilities editor`
- Select `Status Research & Development GmbH` as the development team.
4. In a new terminal execute `make clean` and then `make xcode-clean`
- Add the UDID to development devices on Apple Developer Portal.
- Invite your Apple account to be Developer in Status team.
3. Run a build in XCode using the project from `status-mobile/ios` directory.
- You might see error: `Select a development team in the Signing & Capabilities editor`
- Select `Status Research & Development GmbH` as the development team and rebuild again.
Once build finishes Status should start on your iPhone with its logs in terminal running `make run-metro`.
+6 -32
View File
@@ -2,12 +2,14 @@
## Unit & integration tests
To run all tests:
To run tests:
```
make test
```
Also test watcher can be launched. It will re-run the entire test suite when any file is modified
```
@@ -49,46 +51,18 @@ Here I'm showing a terminal-only experience using Tmux (left pane Emacs, right p
[2022-12-19 13-17.webm](https://user-images.githubusercontent.com/46027/208471199-1909c446-c82d-42a0-9350-0c15ca562713.webm)
## Component tests only
## Component tests
To run tests:
```
make component-test
make component-test
```
Also test watcher can be launched. It will re-run the entire test suite when any file is modified
```
make component-test-watch
make component-test-watch
```
Check [component tests doc](./component-tests-overview.md) for more.
## Unit tests only
To run unit tests:
```
make test-unit
```
Also test watcher can be launched. It will re-run the entire test suite when any file is modified
```
make test-unit WATCH=true
```
## Integration tests only
To run integration tests:
```
make test-integration
```
Also test watcher can be launched. It will re-run the entire test suite when any file is modified
```
make test-integration WATCH=true
```
+20 -1
View File
@@ -88,7 +88,6 @@ info Visit https://yarnpkg.com/en/docs/cli/install for documentation about this
Update yarn.lock file. In order to do this, perform the following steps on a clean `status-mobile` repo:
```
cd status-mobile
make shell
yarn install
```
and don't forget to commit updated `yarn.lock` together with `package.json`.
@@ -128,3 +127,23 @@ Status-mobile uses `shadow-cljs` for hot reloading changes and uses its own [rel
### Solution
Open react native's [In-App Developer Menu](https://reactnative.dev/docs/debugging#accessing-the-in-app-developer-menu) and press "Disable Fast Refresh" or "Disable Hot Reloading"
## App Crashes after few reloads
### Cause
For x86 CPU architecture Android Devices, Hermes is creating the issue and the app crashes after a few reloads.
([Original Issue](https://github.com/status-im/status-mobile/issues/14031))
<details>
<summary>How to Find CPU architecture</summary>
CPU architecture of android device can be found using
- `adb shell uname -m` or
- `adb shell getprop ro.product.cpu.abilist`
</details>
### Solution
Disable Hermes while building the app
`make run-android DISABLE_HERMES=true`
-254
View File
@@ -1,254 +0,0 @@
# UI components coding guidelines
> [!IMPORTANT]
> React apps are made out of components. A component is a piece of the UI (user interface) that has its own logic and appearance. A component can be as small as a button, or as large as an entire screen.
> React components are JavaScript functions that return markup
> This document will provide best practices on how to write efficient React components in ClojureScript
At the time of creating the Status app, the Reagent library was a solid choice. Back then, hooks didn't exist, and there weren't any libraries providing effective global state management. After Reagent's emergence, another library called Re-frame built upon Reagent. Together, they offered powerful tools for developing React applications with ClojureScript. However, as React evolved, significant changes occurred. Class components, utilized in Reagent, became deprecated. Instead, functional components and hooks emerged for state management. In Status 2.0, we began incorporating more functional components and hooks, resulting in a blend of both approaches. To simplify matters and reduce confusion, we opted to transition to functional components and hooks for local state management.
BEFORE:
```clojure
(defn- view-internal
[_ _]
(let [pressed? (reagent/atom false)]
(fn
[{:keys [theme on-press on-long-press icon]}]
[rn/pressable
{:style (style/main @pressed? theme)
:on-press on-press
:on-press-in #(reset! pressed? true)
:on-press-out #(reset! pressed? nil)
:on-long-press on-long-press}
[quo.icons/icon icon]])))
(def view (theme/with-theme view-internal))
```
NOW:
```clojure
(defn view
[{:keys [on-press on-long-press icon]}]
(let [[pressed? set-pressed] (rn/use-state false)
theme (theme/use-theme-value)
on-press-in (rn/use-callback #(set-pressed true))
on-press-out (rn/use-callback #(set-pressed nil))]
[rn/pressable
{:style (style/main pressed? theme)
:on-press on-press
:on-press-in on-press-in
:on-press-out on-press-out
:on-long-press on-long-press}
[quo.icons/icon icon]]))
```
- We no longer need to create an anonymous function for rendering. This removes unnecessary confusion and the need for specific knowledge on how it works and why it was needed.
- `rn/use-state` is used instead of `reagent/atom`
- State values no longer need to be dereferenced; they are accessible as regular symbols. This eliminates a common bug where the "@" symbol was inadvertently omitted.
- `theme/with-theme` wrapper is not needed anymore, `(theme/use-theme-value)` hook can be used directly in the components
- `:f>` not needed anymore, all components are functional by default
- `rn/use-callback` hook should be used for anon callback functions
> [!IMPORTANT]
> DO NOT USE anon functions directly in the props
BAD
```clojure
(defn view
[]
(let [[pressed? set-pressed] (rn/use-state false)]
[rn/pressable
{:style (style/main pressed?)
:on-press-in #(set-pressed true)
:on-press-out #(set-pressed nil)}]))
```
GOOD:
```clojure
(defn view
[]
(let [[pressed? set-pressed] (rn/use-state false)
on-press-in (rn/use-callback #(set-pressed true))
on-press-out (rn/use-callback #(set-pressed nil))]
[rn/pressable
{:style (style/main pressed?)
:on-press-in on-press-in
:on-press-out on-press-out}]))
```
## Global state and subscriptions
For global state management, we utilize Re-frame subscriptions. They can be likened to React state. To obtain the state, `(rf/sub [])` is employed, and to modify it, `(rf/dispatch [])` is utilized. However, they update components in a similar manner to React states.
```clojure
(defn view
[{:keys [selected-tab]}]
(let [collectible-list (rf/sub [:wallet/all-collectibles])
on-collectible-press (rn/use-callback
(fn [{:keys [id]}]
(rf/dispatch [:wallet/get-collectible-details id])))]
[rn/view {:style style/container}
(case selected-tab
:assets [assets/view]
:collectibles [collectibles/view {:collectibles collectible-list
:on-collectible-press on-collectible-press}])
[activity/view]]))
```
## Regular atoms
In certain instances, components utilized regular atoms; however, they should now be used with `rn/use-ref-atom`
BEFORE:
```clojure
(defn view
[]
(let [focused? (atom false)]
(fn []
(let [on-clear #(reset! status (if @focused? :active :default))
on-focus #(reset! focused? true)
on-blur #(reset! focused? false)]))))
```
NOW:
```clojure
(defn view
[]
(let [focused? (rn/use-ref-atom false)
on-clear (rn/use-callback #(set-status (if @focused? :active :default)))
on-focus (rn/use-callback #(reset! focused? true))
on-blur (rn/use-callback #(reset! focused? false))]))
```
## Effects
LIFECYCLE:
```clojure
(defn view
[{:keys []}]
(let [opacity (reanimated/use-shared-value 0)]
(rn/use-mount #(reanimated/animate opacity 1))
[rn/view
{:style (style/opacity opacity)}]))
```
```clojure
(defn view
[{:keys []}]
(let []
(rn/use-unmount #(rn/dispatch [:unmounted]))
[rn/view]))
```
> [!IMPORTANT]
> Effects should NOT be utilized as a response to state changes for modifying logic. If you're unsure how to achieve this without using effects, please consult the team in the general chat. There may be instances where using effects is appropriate, so we can explore a solution together and enhance our guidelines.
BAD:
```clojure
(defn f-zoom-button
[{:keys [selected? current-zoom]}]
(let [size (reanimated/use-shared-value (if selected? 37 25))]
(rn/use-effect #(reanimated/animate size (if selected? 37 25)) [current-zoom])
[rn/touchable-opacity
{:style (style/zoom-button-container size)}]))
```
BAD:
```clojure
(defn view
[collectible-list (rf/sub [:wallet/all-collectibles])]
(let []
(rn/use-effect #(rn/dispatch [:all-collectibles-changed]) [collectible-list])
[rn/view]))
```
Instead `:all-collectibles-changed` should be used in the handler which changes `collectible-list` state
## Performance tips
To begin with, we need to understand that there are two distinct stages for a component: creation and update. React creates a render tree, a UI tree, composed of the rendered components.
![react_tree.png](react_tree.png)
### Component creation
For component creation, the most critical factor is the number of elements involved, so we should strive to minimize them. For instance, it's advisable to avoid using unnecessary wrappers or containers.
BAD:
```clojure
(defn view
[]
(let []
[rn/view {:style {:padding-top 20}}
[quo/button]]))
```
GOOD:
```clojure
(defn view
[]
(let []
[quo/button {:container-style {:padding-top 20}}]))
```
### Component updates
For component updates, it's crucial to recognize that React will invoke the function where state is utilized. Therefore, if you utilize state in the root component, React will execute the root function and re-render the entire root component along with all its children (unless optimizations like memoization are implemented).
BAD:
```clojure
(defn component
[{:keys [label]}]
(let []
[rn/text label]))
(defn component2
[{:keys [label2]}]
(let []
[rn/text label2]))
(defn screen
[]
(let [screen-params (rf/sub [:screen-params])]
[component screen-params]
[component1]
[component2 screen-params]
[component3]
[rn/view {:padding-top 20}
[quo/button]]))
```
Here, we have lost control over the `screen-params` map. It can contain any data, and if any field within this map changes, the entire screen function will be executed, resulting in the re-rendering of both `component` and `component2`.
GOOD:
```clojure
(defn component
[]
(let [label (rf/sub [:screen-params-label])]
[rn/text label]))
(defn component2
[]
(let [label2 (rf/sub [:screen-params-label2])]
[rn/text label2]))
(defn screen
[]
(let []
[component]
[component1]
[component2]
[component3]
[rn/view {:padding-top 20}
[quo/button]]))
```
So, now the screen component function will never be invoked, and `component` and `component2` will be re-rendered only when `label` or `label2` have changed.
+1 -1
View File
@@ -793,7 +793,7 @@ CHECKOUT OPTIONS:
:submodules: true
SPEC CHECKSUMS:
boost: 64032b9e9b938fda23325e68a3771f0fabf414dc
boost: 57d2868c099736d80fcd648bf211b4431e51a558
BVLinearGradient: 612a04ff38e8480291f3379ee5b5a2c571f03fe0
CryptoSwift: c4f2debceb38bf44c80659afe009f71e23e4a082
DoubleConversion: 5189b271737e1565bdce30deb4a08d647e3f5f54
-18
View File
@@ -1,18 +0,0 @@
# Description
This directory is the destination of logs created during build time of debug builds.
# Logs
* `xcrun_device_install.log` - Output from `status-mobile/scripts/run-ios-device.sh`.
- Created by redirecting output of `xcrun simctl install "$UDID" "$APP_PATH"`.
* `xcrun_device_process_launch.log` - Output from `status-mobile/scripts/run-ios-device.sh`.
- Created by specifying `--json-output` flag for `xcrun devicectl device process launch --no-activate --verbose --device "${DEVICE_UUID}" "${INSTALLATION_URL}"`.
* `xcrun_device_process_resume.log` - Output from `status-mobile/scripts/run-ios-device.sh`.
- Created by redirecting output of `xcrun devicectl device process resume --device "${DEVICE_UUID}" --pid "${STATUS_PID}"`.
* `adb_install.log` - Output from `scripts/run-android.sh`.
- Created by redirecting output of `adb install -r ./result/app-debug.apk`.
* `adb_shell_monkey.log` - Output from `status-mobile/scripts/run-android.sh`.
- Created by redirecting output of `adb shell monkey -p im.status.ethereum.debug 1 >`.
* `ios_simulators_list.log` - Output from `status-mobile/scripts/run-ios.sh`.
- Created by redirecting output of `xcrun simctl list devices -j`.
@@ -342,14 +342,4 @@ public class AccountManager extends ReactContextBaseJavaModule {
final String keyStoreDir = this.utils.getKeyStorePath(keyUID);
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.deleteMultiaccount(keyUID, keyStoreDir), callback);
}
@ReactMethod
public void getRandomMnemonic(final Callback callback) throws JSONException {
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.getRandomMnemonic(), callback);
}
@ReactMethod
public void createAccountFromMnemonicAndDeriveAccountsForPaths(final String mnemonic, final Callback callback) throws JSONException {
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.createAccountFromMnemonicAndDeriveAccountsForPaths(mnemonic), callback);
}
}
@@ -214,20 +214,4 @@ RCT_EXPORT_METHOD(logout) {
NSLog(@"%@", result);
}
RCT_EXPORT_METHOD(getRandomMnemonic:(RCTResponseSenderBlock)callback) {
#if DEBUG
NSLog(@"GetRandomMnemonic() method called");
#endif
NSString *result = StatusgoGetRandomMnemonic();
callback(@[result]);
}
RCT_EXPORT_METHOD(createAccountFromMnemonicAndDeriveAccountsForPaths:(NSString *)mnemonic callback:(RCTResponseSenderBlock)callback) {
#if DEBUG
NSLog(@"createAccountFromMnemonicAndDeriveAccountsForPaths() method called");
#endif
NSString *result = StatusgoCreateAccountFromMnemonicAndDeriveAccountsForPaths(mnemonic);
callback(@[result]);
}
@end
@@ -120,12 +120,9 @@ RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(checkAddressChecksum:(NSString *)address)
return StatusgoCheckAddressChecksum(address);
}
RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(isAddress:(NSString *)address) {
return StatusgoIsAddress(address);
}
RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(toChecksumAddress:(NSString *)address) {
return StatusgoToChecksumAddress(address);
}
@end
+5 -7
View File
@@ -61,7 +61,7 @@ We will use the `make jsbundle` target as an example of a derivation you can bui
3. [`build.sh`](/nix/scripts/build.sh) calls `nix-build --attr targets.mobile.jsbundle` with extra arguments
4. `nix-build` builds the derivation from [`nix/mobile/jsbundle/default.nix`](/nix/mobile/jsbundle/default.nix)
The same can be done for other targets like `targets.mobile.android.build`.
The same can be done for other targets like `targets.mobile.android.release`.
Except in that case extra arguments are required which is why the [`scripts/release-android.sh`](/scripts/release-android.sh) is used in the `make release-android` target.
If you run `make release-android` you'll see the `nix-build` command used:
@@ -71,23 +71,21 @@ nix-build \
--fallback \
--no-out-link \
--show-trace \
--attr targets.mobile.android.build \
--attr targets.mobile.android.release \
--argstr secrets-file '/tmp/tmp-status-mobile-559a3a441/tmp.xAnrPuNtAP' \
--option extra-sandbox-paths '/home/joe/.gradle/status-im.keystore /tmp/tmp-status-mobile-559a3a441/tmp.xAnrPuNtAP' \
default.nix
```
Some of those are required which is why just calling:
```
nix-build --attr targets.mobile.android.build
nix-build --attr targets.mobile.android.release
```
Would fail.
# Garbage Collection
The `make nix-gc` target calls `nix-store --gc` and normally would remove almost everything, but to prevent that we place symlinks to protected derivations in `.nix-gcroots` folder. Specifically:
The `make nix-gc` target calls `nix-store --gc` and normally would remove almost everything, but to prevent that we place symlinks to protected derivations in `/nix/var/nix/gcroots` subfolder. Specifically:
```sh
_NIX_GCROOTS="${_NIX_GCROOTS:-${GIT_ROOT}/.nix-gcroots}
_NIX_GCROOTS="${_NIX_GCROOTS:-/nix/var/nix/gcroots/per-user/${USER}/status-mobile}"
```
These symlinks in turn will be symlinked from `/nix/var/nix/gcroots/auto` through use of `nix-store --add-gcroots`.
Whenever `nix/scripts/build.sh` or `nix/scripts/shell.sh` are called they update symlinks named after given targets in that folder. This in combination with `keep-outputs = true` set in `nix/nix.conf` prevents garbage collection from removing too much.
+1 -1
View File
@@ -28,7 +28,7 @@ export STATUS_GO_IPFS_GATEWAY_URL="https://ipfs.status.im/"
```
You can see the defaults in code:
- [`nix/status-go/default.nix`](./status-go/default.nix)
- [`nix/mobile/android/release.nix`](./mobile/android/build.nix)
- [`nix/mobile/android/release.nix`](./mobile/android/release.nix)
## Shell
+1 -1
View File
@@ -6,7 +6,7 @@ This directory contains the tools and the data that allows Nix to manage Gradle
Simply calling `generate.sh` should result in a `deps.json` file which is used in the derivation that provides Gradle dependencies when building the Android app.
You can see in [`nix/mobile/android/release.nix`](../../mobile/android/build.nix) that it's used via the `-Dmaven.repo.local='${deps.gradle}'` Gradle flag.
You can see in [`nix/mobile/android/release.nix`](../../mobile/android/release.nix) that it's used via the `-Dmaven.repo.local='${deps.gradle}'` Gradle flag.
# Files
+2 -2
View File
@@ -2,7 +2,7 @@
, jsbundle, status-go, androidPkgs, androidShell }:
rec {
build = callPackage ./build.nix {
release = callPackage ./release.nix {
inherit jsbundle status-go;
};
@@ -15,7 +15,7 @@ rec {
];
inputsFrom = [
(build {})
(release {})
androidShell
];
@@ -7,15 +7,15 @@
# Path to the file containing secret environment variables
secretsFile ? "",
# Build type (influences which .env file gets used for feature flags)
# TODO: pr or relase for default?
buildType ? lib.getEnvWithDefault "BUILD_TYPE" "release",
# Used for versionCode
versionCode ? lib.getEnvWithDefault "ORG_GRADLE_PROJECT_versionCode" 9999,
buildNumber ? lib.getEnvWithDefault "BUILD_NUMBER" 9999,
# Included in APK Manifest for easier identification.
commitHash ? lib.getEnvWithDefault "ORG_GRADLE_PROJECT_commitHash" "unknown",
# Disabled for debug builds to avoid 'maximum call stack exceeded' errors.
# https://github.com/status-im/status-mobile/issues/18493
hermesEnabled ? lib.getEnvWithDefault "ORG_GRADLE_PROJECT_hermesEnabled" "true",
buildUrl ? lib.getEnvWithDefault "ORG_GRADLE_PROJECT_buildUrl" null,
# TODO: or GIT_COMMIT from Jenkins?
commitHash ? lib.getEnvWithDefault "COMMIT_HASH" "unknown",
# Gradle options passed for Android builds
androidGradleOpts ? lib.getEnvWithDefault "ANDROID_GRADLE_OPTS" null,
statusGoSrcOverride ? lib.getEnvWithDefault "STATUS_GO_SRC_OVERRIDE" null,
# If APKs should be split based on architectures
androidAbiSplit ? lib.getEnvWithDefault "ANDROID_ABI_SPLIT" "false",
@@ -40,10 +40,8 @@ let
else if (elem buildType ["pr" "manual"]) then ".env.jenkins"
else ".env";
gradleBuildType =
if buildType == "pr" then "Pr"
else if buildType == "debug" then "Debug"
else "Release";
# There are only two types of Gradle build targets: pr and release
gradleBuildType = if buildType == "pr" then "Pr" else "Release";
apksPath = "./android/app/build/outputs/apk/${toLower gradleBuildType}";
@@ -83,10 +81,7 @@ in stdenv.mkDerivation rec {
ANDROID_ABI_INCLUDE = androidAbiInclude;
# Disabled for debug builds to avoid 'maximum call stack exceeded' errors.
# https://github.com/status-im/status-mobile/issues/18493
ORG_GRADLE_PROJECT_versionCode = versionCode;
ORG_GRADLE_PROJECT_commitHash = commitHash;
ORG_GRADLE_PROJECT_buildUrl = buildUrl;
ORG_GRADLE_PROJECT_hermesEnabled = hermesEnabled;
ORG_GRADLE_PROJECT_hermesEnabled = true;
# Fix for ERR_OSSL_EVP_UNSUPPORTED error.
NODE_OPTIONS = "--openssl-legacy-provider";
@@ -121,6 +116,8 @@ in stdenv.mkDerivation rec {
# Symlink React Native entrypoint.
cp -Lr ${builtJsBundle} ./result
pwd
find -L result
# Copy android/ directory
mkdir -p ./android/build
@@ -147,6 +144,7 @@ in stdenv.mkDerivation rec {
"LD_LIBRARY_PATH=$LD_LIBRARY_PATH:${makeLibraryPath [ pkgs.zlib ]}";
gradleCommand = ''
${pkgs.gradle}/bin/gradle \
${toString androidGradleOpts} \
--console=plain \
--offline \
--no-daemon \
@@ -154,6 +152,8 @@ in stdenv.mkDerivation rec {
--no-watch-fs \
--no-build-cache \
-Dmaven.repo.local='${deps.gradle}' \
-PversionCode=${toString buildNumber} \
-PcommitHash=${commitHash} \
assemble${gradleBuildType}
'';
in
@@ -171,14 +171,12 @@ in stdenv.mkDerivation rec {
${adhocEnvVars} ${gradleCommand}
popd > /dev/null
'';
doCheck = buildType != "debug";
checkPhase = ''
doCheck = true;
checkPhase = ''
ls ${apksPath}/*.apk \
| xargs -n1 ${pkgs.unzip}/bin/unzip -qql \
| grep 'index.android.bundle'
'';
installPhase = ''
mkdir -p $out
cp ${apksPath}/*.apk $out/
+1 -1
View File
@@ -20,8 +20,8 @@ in {
buildInputs = with pkgs; [
xcodeWrapper watchman procps
flock # used in nix/scripts/node_modules.sh
ios-deploy # used in 'make run-ios-device'
xcbeautify # used in 'make run-ios'
libimobiledevice # used in `make run-ios-device`
];
# WARNING: Executes shellHook in reverse order.
+12
View File
@@ -26,6 +26,18 @@ in {
react-native = callPackage ./deps/react-native { };
};
# 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";
};
});
# Clojure's linter receives frequent upgrades, and we want to take advantage
# of the latest available rules.
clj-kondo = super.clj-kondo.override rec {
+1 -1
View File
@@ -45,7 +45,7 @@ if [[ -z "${TARGET}" ]]; then
fi
# Hack fix for missing Android SDK for aarch64 on Darwin. See systemOverride in `nix/pkgs.nix`.
if [[ "${TARGET}" =~ ^(targets.status-go.mobile.android|targets.mobile.android.build)$ ]]; then
if [[ "${TARGET}" =~ ^(targets.status-go.mobile.android|targets.mobile.android.release)$ ]]; then
os=$(uname -s | tr '[:upper:]' '[:lower:]')
export NIXPKGS_SYSTEM_OVERRIDE="x86_64-${os}"
fi
+2 -2
View File
@@ -2,12 +2,12 @@
set -Ee
_NIX_GCROOTS="${_NIX_GCROOTS:-/nix/var/nix/gcroots/per-user/${USER}/status-mobile}"
GIT_ROOT=$(cd "${BASH_SOURCE%/*}" && git rev-parse --show-toplevel)
source "${GIT_ROOT}/nix/scripts/source.sh"
source "${GIT_ROOT}/scripts/colors.sh"
_NIX_GCROOTS="${_NIX_GCROOTS:-${GIT_ROOT}/.nix-gcroots}"
TARGET="${1}"
shift
if [[ -z "${TARGET}" ]]; then
+5 -3
View File
@@ -1,6 +1,8 @@
#!/usr/bin/env bash
export NIX_VERSION="2.19.3"
export NIX_PACKAGE="nixVersions.nix_2_19"
# WARNING: Versions 2.14, 2.15, 2.16 have an issue creating gcroots:
# https://github.com/NixOS/nix/issues/8564
export NIX_VERSION="2.13.4"
export NIX_PACKAGE="nixVersions.nix_2_13"
export NIX_INSTALL_URL="https://nixos.org/releases/nix/nix-${NIX_VERSION}/install"
export NIX_INSTALL_SHA256="73d47b0ab783fddca1b2d44a03d52a74c97c28a1fc8ff5a29419079302ef9c3d"
export NIX_INSTALL_SHA256="a9908cc48f5886b4f22172bdd2f9657873276fd295e78c6ed97fb308c6d284d0"
export NIX_INSTALL_PATH="/tmp/nix-install-${NIX_VERSION}"
+3 -1
View File
@@ -21,6 +21,8 @@ function append_env_export() {
VAR_VALUE=$(must_get_env "${VAR_NAME}")
echo "export ${VAR_NAME}=\"${VAR_VALUE}\";" >> "${SECRETS_FILE_PATH}"
}
export COMMIT_HASH="$(git rev-parse --verify HEAD)"
nixOpts=()
# We create if now so the trap knows its location
@@ -71,4 +73,4 @@ else
fi
"${GIT_ROOT}/nix/scripts/build.sh" targets.mobile.android.build "${nixOpts[@]}"
"${GIT_ROOT}/nix/scripts/build.sh" targets.mobile.android.release "${nixOpts[@]}"
-30
View File
@@ -1,30 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
GIT_ROOT=$(cd "${BASH_SOURCE%/*}" && git rev-parse --show-toplevel)
ADB_INSTALL_LOG_FILE="${GIT_ROOT}/logs/adb_install.log"
ADB_SHELL_MONKEY_LOG_FILE="${GIT_ROOT}/logs/adb_shell_monkey.log"
# Generate android debug build.
export ANDROID_ABI_INCLUDE=$("${GIT_ROOT}/scripts/adb_devices_abis.sh")
export BUILD_ENV=debug
export BUILD_TYPE=debug
"${GIT_ROOT}/scripts/build-android.sh"
# Install the APK on running emulator or android device.
installAndLaunchApp() {
adb install -r ./result/app-debug.apk > "${ADB_INSTALL_LOG_FILE}" 2>&1
"${GIT_ROOT}/scripts/wait-for-metro-port.sh" 2>&1
# connected android devices need this port to be exposed for metro
adb reverse "tcp:${RCT_METRO_PORT}" "tcp:${RCT_METRO_PORT}"
adb shell monkey -p im.status.ethereum.debug 1 > "${ADB_SHELL_MONKEY_LOG_FILE}" 2>&1
}
showAdbLogs() {
cat "${ADB_INSTALL_LOG_FILE}" >&2;
cat "${ADB_SHELL_MONKEY_LOG_FILE}" >&2;
}
trap showAdbLogs EXIT ERR INT QUIT
installAndLaunchApp &
exec "${GIT_ROOT}/scripts/run-metro.sh" 2>&1
-55
View File
@@ -1,55 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
set -m # needed to access jobs
GIT_ROOT=$(cd "${BASH_SOURCE%/*}" && git rev-parse --show-toplevel)
XCRUN_DEVICE_INSTALL_LOG_DIR="${GIT_ROOT}/logs/xcrun_device_install.log"
XCRUN_DEVICE_PROCESS_LAUNCH_LOG_DIR="${GIT_ROOT}/logs/xcrun_device_process_launch.log"
XCRUN_DEVICE_PROCESS_RESUME_LOG_DIR="${GIT_ROOT}/logs/xcrun_device_process_resume.log"
# Install on the connected device
installAndLaunchApp() {
xcrun devicectl device install app --device "${DEVICE_UUID}" "${APP_PATH}" --json-output "${XCRUN_DEVICE_INSTALL_LOG_DIR}" 2>&1
# Extract installationURL
INSTALLATION_URL=$(jq -r '.result.installedApplications[0].installationURL' "${XCRUN_DEVICE_INSTALL_LOG_DIR}")
# launch the app and put it in background
xcrun devicectl device process launch --no-activate --verbose --device "${DEVICE_UUID}" "${INSTALLATION_URL}" --json-output "${XCRUN_DEVICE_PROCESS_LAUNCH_LOG_DIR}"
# Extract background PID of status app
STATUS_PID=$(jq -r '.result.process.processIdentifier' "${XCRUN_DEVICE_PROCESS_LAUNCH_LOG_DIR}")
"${GIT_ROOT}/scripts/wait-for-metro-port.sh" 2>&1
# now that metro is ready, resume the app from background
xcrun devicectl device process resume --device "${DEVICE_UUID}" --pid "${STATUS_PID}" > "${XCRUN_DEVICE_PROCESS_RESUME_LOG_DIR}" 2>&1
}
showXcrunLogs() {
cat "${XCRUN_DEVICE_INSTALL_LOG_DIR}" >&2;
cat "${XCRUN_DEVICE_PROCESS_LAUNCH_LOG_DIR}" >&2;
cat "${XCRUN_DEVICE_PROCESS_RESUME_LOG_DIR}" >&2;
}
# find the first connected iPhone's UUID
DEVICE_UUID=$(idevice_id -l)
# Check if any device is connected
if [ -z "${DEVICE_UUID}" ]; then
echo "No connected iPhone device detected."
exit 1
else
echo "Connected iPhone UDID: ${DEVICE_UUID}"
fi
BUILD_DIR="${GIT_ROOT}/build"
#iOS build of debug scheme
xcodebuild -workspace "ios/StatusIm.xcworkspace" -configuration Debug -scheme StatusIm -destination id="${DEVICE_UUID}" -derivedDataPath "${BUILD_DIR}" -verbose | xcbeautify
APP_PATH="${BUILD_DIR}/Build/Products/Debug-iphoneos/StatusIm.app"
trap showXcrunLogs EXIT ERR INT QUIT
installAndLaunchApp &
exec "${GIT_ROOT}/scripts/run-metro.sh" 2>&1
-69
View File
@@ -1,69 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
set -m # needed to access jobs
GIT_ROOT=$(cd "${BASH_SOURCE%/*}" && git rev-parse --show-toplevel)
XCRUN_INSTALL_LOG_FILE="${GIT_ROOT}/logs/xcrun_install.log"
XCRUN_LAUNCH_LOG_FILE="${GIT_ROOT}/logs/xcrun_launch.log"
XCRUN_SIMULATOR_JSON_FILE="${GIT_ROOT}/logs/ios_simulators_list.log"
# Install on the simulator
installAndLaunchApp() {
xcrun simctl install "$UDID" "$APP_PATH" > "${XCRUN_INSTALL_LOG_FILE}" 2>&1
"${GIT_ROOT}/scripts/wait-for-metro-port.sh" 2>&1
xcrun simctl launch "$UDID" im.status.ethereum.debug > "${XCRUN_LAUNCH_LOG_FILE}" 2>&1
}
showXcrunLogs() {
cat "${XCRUN_INSTALL_LOG_FILE}" >&2;
cat "${XCRUN_LAUNCH_LOG_FILE}" >&2;
}
# Check if the first argument is provided
if [ -z "${1-}" ]; then
echo "Error: No simulator name provided." >&2
exit 1
fi
# fetch available iOS Simulators
xcrun simctl list devices -j > "${XCRUN_SIMULATOR_JSON_FILE}"
SIMULATOR=${1}
# get the first available UDID for Simulators that match the name
read -r UDID SIMULATOR_STATE IS_AVAILABLE < <(jq --raw-output --arg simulator "${SIMULATOR}" '
[ .devices[] | .[] | select(.name == $simulator) ] |
map(select(.isAvailable)) + map(select(.isAvailable | not)) |
first |
"\(.udid) \(.state) \(.isAvailable)"
' "${XCRUN_SIMULATOR_JSON_FILE}")
if [ "${IS_AVAILABLE}" == false ] || [ "${UDID}" == null ]; then
echo "Error: Simulator ${SIMULATOR} is not available, Please find and install them."
echo "For help please refer"
echo "https://developer.apple.com/documentation/safari-developer-tools/adding-additional-simulators#Add-and-remove-Simulators " >&2
exit 1
fi
# sometimes a simulator is already running, shut it down to avoid errors
if [ "${SIMULATOR_STATE}" != "Shutdown" ]; then
xcrun simctl shutdown "${UDID}"
fi
# boot up iOS for simulator
xcrun simctl boot "${UDID}"
# start the simulator
open -a Simulator --args -CurrentDeviceUDID "${UDID}"
BUILD_DIR="${GIT_ROOT}/build"
#iOS build of debug scheme
xcodebuild -workspace "ios/StatusIm.xcworkspace" -configuration Debug -scheme StatusIm -destination id="${UDID}" -derivedDataPath "${BUILD_DIR}" -verbose | xcbeautify
APP_PATH="${BUILD_DIR}/Build/Products/Debug-iphonesimulator/StatusIm.app"
trap showXcrunLogs EXIT ERR INT QUIT
installAndLaunchApp &
exec "${GIT_ROOT}/scripts/run-metro.sh" 2>&1
-5
View File
@@ -1,5 +0,0 @@
#!/usr/bin/env bash
pkill -f 'react-native start'
react-native start --reset-cache
+17
View File
@@ -0,0 +1,17 @@
#!/usr/bin/env bash
GIT_ROOT=$(cd "${BASH_SOURCE%/*}" && git rev-parse --show-toplevel)
source "${GIT_ROOT}/scripts/colors.sh"
METRO_PORT=8081
METRO_PID="$(lsof -i :${METRO_PORT} | awk 'NR!=1 {print $2}' | sort -u | tr '\r\n' ' ')"
if [ ! -z "$METRO_PID" ]; then
echo -e "${YLW}TCP port ${METRO_PORT} is required by the Metro packager.\nThe following processes currently have the port open, preventing Metro from starting:${RST}"
ps -fp $METRO_PID
echo -e "${YLW}Do you want to terminate them (y/n)?${RST}"
read -n 1 term
[[ $term == 'y' ]] && kill $METRO_PID
fi
react-native start --reset-cache
-14
View File
@@ -1,14 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
TIMEOUT=10 # Metro should not take this long to start.
while [ "${TIMEOUT}" -gt 0 ]; do
if ! lsof -i:8081 &> /dev/null; then
echo "."
sleep 1
((TIMEOUT--))
else
break
fi
done
+3
View File
@@ -45,6 +45,9 @@
;; To match the folder created by Nix build of JSBundle.
:output-dir "result"
:init-fn status-im.core/init
:build-hooks [(status-im.setup.build-hooks.worklets/transform-output)
(status-im.setup.build-hooks.worklets/optimize-start)
(status-im.setup.build-hooks.worklets/optimize-output)]
;; When false, the Shadow-CLJS watcher won't automatically refresh
;; the target files (a.k.a hot reload). When false, you can manually
;; reload by calling `shadow.cljs.devtools.api/watch-compile-all!`.
@@ -28,10 +28,10 @@
[:f>
(fn []
(rn/use-mount (fn []
(rn/hw-back-add-listener dismiss-bottom-sheet-callback)
(fn []
(rn/hw-back-remove-listener dismiss-bottom-sheet-callback))))
(rn/use-effect (fn []
(rn/hw-back-add-listener dismiss-bottom-sheet-callback)
(fn []
(rn/hw-back-remove-listener dismiss-bottom-sheet-callback))))
[theme/provider {:theme (or page-theme (theme/get-theme))}
[bottom-sheet/bottom-sheet opts
(when content
@@ -16,14 +16,12 @@
:align-self :center})
(def backdrop
{:position :absolute
:left 0
:right 0
:bottom 0
:top 0})
(def backdrop-color
{:background-color colors/neutral-100})
{:position :absolute
:left 0
:right 0
:bottom 0
:top 0
:background-color colors/neutral-100})
(def container
{:position :absolute
+2 -4
View File
@@ -207,13 +207,11 @@
[@show-bottom-sheet? @expanded? @gesture-running?])
[:<>
[rn/pressable
{:on-press (when backdrop-dismiss? close-bottom-sheet)
:style styles/backdrop}
[rn/touchable-without-feedback {:on-press (when backdrop-dismiss? close-bottom-sheet)}
[reanimated/view
{:style (reanimated/apply-animations-to-style
{:opacity bg-opacity}
styles/backdrop-color)}]]
styles/backdrop)}]]
(cond->> [reanimated/view
{:style (reanimated/apply-animations-to-style
{:transform [{:translateY translate-y}]}
@@ -36,7 +36,7 @@
[(mailserver/process-next-messages-request)
(bottom-sheet/hide-bottom-sheet-old)
(wallet/restart-wallet-service nil)
#(add-new-contact/set-new-identity-reconnected %)]
(add-new-contact/set-new-identity-reconnected)]
logged-in?
[(mailserver/process-next-messages-request)
@@ -31,6 +31,7 @@
(let [key-uid (get-in db [:profile/profile :key-uid])]
(rf/merge cofx
{:set-root :progress
:chat.ui/clear-inputs nil
:effects.shell/reset-state nil
:hide-popover nil
::logout nil
+1 -1
View File
@@ -72,7 +72,7 @@
:PeerExchange true
:Port 0
:UDPPort 0
:LightClient false})
:LightClient true})
(def login-node-config
{:WalletConfig (cond-> {:Enabled true}
+1 -5
View File
@@ -81,9 +81,5 @@
{:db (-> db
(assoc :contacts/identity identity)
(assoc :contacts/ens-name ens-name))
:dispatch [:contacts/build-contact
{:pubkey identity
:ens ens-name
:success-fn (fn [_]
{:dispatch [:open-modal :profile]})}]}
:dispatch [:contacts/build-contact identity ens-name true]}
{:dispatch [:navigate-to :my-profile]})))
@@ -1,12 +1,13 @@
(ns legacy.status-im.ui.components.keyboard-avoid-presentation
(:require
[legacy.status-im.ui.components.react :as react]
[react-native.utils :as rn.utils]
[reagent.core :as reagent]))
(defn keyboard-avoiding-view
[& argv]
(let [[props children] (rn.utils/get-props-and-children argv)]
[]
(let [this (reagent/current-component)
props (reagent/props this)
children (reagent/children this)]
(reagent/as-element
(into [react/keyboard-avoiding-view
(update props
@@ -3,16 +3,16 @@
[legacy.status-im.ui.components.spacing :as spacing]
[legacy.status-im.ui.components.text :as text]
[react-native.core :as rn]
[react-native.utils :as rn.utils]))
[reagent.core :as reagent]))
(defn footer
[& argv]
(let [[props children] (rn.utils/get-props-and-children argv)
[]
(let [this (reagent/current-component)
{:keys [color]
:or {color :secondary}}
props]
(reagent/props this)]
[rn/view
{:style (merge (:base spacing/padding-horizontal)
(:small spacing/padding-vertical))}
(into [text/text {:color color}]
children)]))
(reagent/children this))]))
@@ -3,18 +3,18 @@
[legacy.status-im.ui.components.spacing :as spacing]
[legacy.status-im.ui.components.text :as text]
[react-native.core :as rn]
[react-native.utils :as rn.utils]))
[reagent.core :as reagent]))
(defn header
[& argv]
(let [[props children] (rn.utils/get-props-and-children argv)
[]
(let [this (reagent/current-component)
{:keys [color]
:or {color :secondary}}
props]
(reagent/props this)]
[rn/view
{:style (merge (:base spacing/padding-horizontal)
(:x-tiny spacing/padding-vertical))}
(into [text/text
{:color color
:style {:margin-top 10}}]
children)]))
(reagent/children this))]))
+7 -5
View File
@@ -3,7 +3,7 @@
[legacy.status-im.ui.components.colors :as colors]
[legacy.status-im.ui.components.typography :as typography]
[react-native.core :as rn]
[react-native.utils :as rn.utils]))
[reagent.core :as reagent]))
(defn text-style
[{:keys [size align weight monospace color style]}]
@@ -40,9 +40,11 @@
style))
(defn text
[& argv]
(let [[props children] (rn.utils/get-props-and-children argv)]
(into [rn/text
[]
(let [this (reagent/current-component)
props (reagent/props this)
component rn/text]
(into [component
(merge {:style (text-style props)}
(dissoc props
:style
@@ -51,4 +53,4 @@
:color
:align
:animated?))]
children)))
(reagent/children this))))
@@ -20,7 +20,7 @@
current-fleet
webview-debug
test-networks-enabled?
is-goerli-enabled?]}]
is-sepolia-enabled?]}]
(keep
identity
[{:size :small
@@ -112,13 +112,13 @@
:accessory :switch
:active test-networks-enabled?}
{:size :small
:title "Enable Goerli as test network"
:title "Enable Sepolia as test network"
:accessibility-label :enable-sepolia-as-test-network
:container-margin-bottom 8
:on-press
#(re-frame/dispatch [:profile.settings/toggle-goerli-test-network])
#(re-frame/dispatch [:profile.settings/toggle-sepolia-test-network])
:accessory :switch
:active is-goerli-enabled?}
:active is-sepolia-enabled?}
{:size :small
:title (i18n/label :t/set-currency)
:accessibility-label :wallet-change-currency
@@ -139,7 +139,7 @@
(views/defview advanced-settings
[]
(views/letsubs [test-networks-enabled? [:profile/test-networks-enabled?]
is-goerli-enabled? [:profile/is-goerli-enabled?]
is-sepolia-enabled? [:profile/is-sepolia-enabled?]
light-client-enabled? [:profile/light-client-enabled?]
webview-debug [:profile/webview-debug]
network-name [:network-name]
@@ -156,6 +156,6 @@
:dev-mode? false
:webview-debug webview-debug
:test-networks-enabled? test-networks-enabled?
:is-goerli-enabled? is-goerli-enabled?})
:is-sepolia-enabled? is-sepolia-enabled?})
:key-fn (fn [_ i] (str i))
:render-fn render-item}]))
@@ -55,8 +55,7 @@
:on-change (fn [text]
(re-frame/dispatch [:wallet-legacy/search-recipient-filter-changed text])
(re-frame/dispatch [:set-in [:contacts/new-identity :state] :searching])
(debounce/debounce-and-dispatch [:contacts/set-new-identity {:input text}]
300))}]]))
(debounce/debounce-and-dispatch [:contacts/set-new-identity text] 300))}]]))
(defn section
[_ _ _]
-10
View File
@@ -573,13 +573,3 @@
(defn init-status-go-logging
[{:keys [enable? mobile-system? log-level callback]}]
(.initLogging ^js (log-manager) enable? mobile-system? log-level callback))
(defn get-random-mnemonic
[callback]
(.getRandomMnemonic ^js (account-manager) #(callback (types/json->clj %))))
(defn create-account-from-mnemonic
[mnemonic callback]
(.createAccountFromMnemonicAndDeriveAccountsForPaths ^js (account-manager)
(types/clj->json mnemonic)
#(callback (types/json->clj %))))
@@ -12,7 +12,7 @@
(defn- initials
[{:keys [full-name size customization-color theme]}]
(let [amount-initials (if (#{:size-32 :size-64} size) 2 1)
channel-name (utils.string/safe-replace full-name "#" "")]
channel-name (string/replace full-name "#" "")]
[text/text
(cond-> {:accessibility-label :initials
:style {:color (colors/resolve-color customization-color theme)}
@@ -3,16 +3,16 @@
[quo.components.avatars.user-avatar.view :as user-avatar]
[test-helpers.component :as h]))
(defonce mock-picture 1)
(defonce mock-picture {:uri (js/require "../resources/images/mock2/user_picture_male4.png")})
(h/describe "user avatar"
(h/describe "Profile picture"
(h/test "Renders"
(h/render-with-theme-provider
(h/render
[user-avatar/user-avatar {:profile-picture mock-picture}])
(h/is-truthy (h/get-by-label-text :profile-picture)))
(h/test "Renders even if `:full-name` is passed"
(h/render-with-theme-provider
(h/render
[user-avatar/user-avatar {:profile-picture mock-picture}])
(h/is-truthy (h/get-by-label-text :profile-picture)))))
@@ -1,21 +0,0 @@
(ns quo.components.avatars.user-avatar.schema
(:require
[quo.components.avatars.user-avatar.style :as style]))
(def ?schema
[:=>
[:catn
[:props
[:map
[:full-name {:optional true} [:maybe string?]]
[:size {:optional true} [:maybe (into [:enum] (keys style/sizes))]]
[:customization-color {:optional true} [:maybe :schema.common/customization-color]]
[:static? {:optional true} [:maybe boolean?]]
[:status-indicator? {:optional true} [:maybe boolean?]]
[:online? {:optional true} [:maybe boolean?]]
[:ring? {:optional true} [:maybe boolean?]]
[:theme :schema.common/theme]
[:profile-picture
{:optional true}
[:maybe :schema.quo/profile-picture-source]]]]]
:any])
@@ -1,13 +1,11 @@
(ns quo.components.avatars.user-avatar.view
(:require
[quo.components.avatars.user-avatar.schema :as component-schema]
[quo.components.avatars.user-avatar.style :as style]
[quo.components.common.no-flicker-image :as no-flicker-image]
[quo.components.markdown.text :as text]
[quo.theme]
[react-native.core :as rn]
[react-native.fast-image :as fast-image]
[schema.core :as schema]
utils.string))
(defn initials-avatar
@@ -25,11 +23,32 @@
(defn user-avatar-internal
"Render user avatar with `profile-picture`
`profile-picture` should be one of {:uri profile-picture-uri} or {:fn profile-picture-fn}
WARNING:
When calling the `profile-picture-fn` and passing the `:ring?` key, be aware that the `profile-picture-fn`
may have an `:override-ring?` value. If it does then the `:ring?` value will not be used.
For reference, refer to the `utils.image-server` namespace for these `profile-picture-fn` are generated."
`profile-picture-fn` should return an image URI, there's helper fn to generate
it in `utils.image-server`
params for `profile-picture-fn`
{:length initials' length
:full-name used to generate initials
:font-size initials font size
:indicator-size status indicator outer radius, set to nil or 0 when no indicator
:indicator-border `indicator-size`-`indicator-border` is the inner radius
:indicator-color color for status indicator
:theme :light or :dark
:background-color intials avatar background color
:color intials avatar text color
:size intials avatar radius
:ring? render ident ring around avatar? NOTE: this option may not work if override-ring? is not nil}
supported color formats:
#RRGGBB
#RRGGBBAA
rgb(255,255,255)
rgba(255,255,255,0.1) note alpha is 0-1
the reason we use the `profile-picture-fn` here is to separate
logic (pubkey, key-uid... in subs) and style (color, size... in this component)"
[{:keys [full-name size profile-picture customization-color static?
status-indicator? online? ring? theme]
:or {size :big
@@ -39,7 +58,7 @@
customization-color :blue}
:as props}]
(let [full-name (or full-name "Your Name")
;; image generated with `profile-picture-fn` is round cropped
;; image generated with profile-picture-fn is round cropped
;; no need to add border-radius for them
outer-styles (style/outer size (not (:fn profile-picture)))
;; Once image is loaded, fast image re-renders view with the help of reagent atom,
@@ -89,6 +108,4 @@
:else {:uri profile-picture})}])]))
(def user-avatar
(quo.theme/with-theme
(schema/instrument #'user-avatar-internal component-schema/?schema)))
(def user-avatar (quo.theme/with-theme user-avatar-internal))
@@ -27,7 +27,7 @@
(let [selected (reagent/atom default-selected)
{window-width :width} (rn/get-window)
ref (atom nil)]
(rn/use-mount
(rn/use-effect
(fn []
(js/setTimeout
(fn []
+26 -23
View File
@@ -5,32 +5,35 @@
[react-native.platform :as platform]
[reagent.core :as reagent]))
(def cached-sources (js/Set. (js/Array.)))
(defn- caching-image
[{:keys [source]} on-source-loaded]
(reagent/create-class
{:component-did-update
(fn []
(when (oops/ocall cached-sources "has" source)
(on-source-loaded source)))
:reagent-render
(fn [{:keys [source] :as props}]
[rn/image
(assoc props
;; hide the cache image under the real one
;; have to render it for the on-load event
:style {:width 1
:height 1
:left "50%"
:top "50%"
:position :absolute}
:on-load
(fn [_]
(when-not (oops/ocall cached-sources "has" source)
(oops/ocall cached-sources "add" source)
(on-source-loaded source)))
:on-error js/console.error)])}))
[_ on-source-loaded]
(let [this (reagent/current-component)]
(reagent/create-class
{:component-did-update
(fn []
(let [source (-> this reagent/props :source)]
(when (oops/ocall cached-sources "has" source)
(on-source-loaded source))))
:reagent-render
(fn [{:keys [source] :as props}]
[rn/image
(assoc props
;; hide the cache image under the real one
;; have to render it for the on-load event
:style {:width 1
:height 1
:left "50%"
:top "50%"
:position :absolute}
:on-load
(fn [_]
(when-not (oops/ocall cached-sources "has" source)
(oops/ocall cached-sources "add" source)
(on-source-loaded source)))
:on-error js/console.error)])})))
(defn image
"Same as rn/image but cache the image source in a js/Set, so the image won't
@@ -3,7 +3,7 @@
(def container
{:height 40
:flex-direction :row
:padding-horizontal 16
:padding-horizontal 20
:align-items :center})
(defn text
@@ -30,7 +30,7 @@
(defn circular-progress
[{:keys [color percentage]}]
(let [strength-indicator-radius 7.5
(let [strength-indicator-radius 6.5
strength-indicator-circumference (* 2 Math/PI strength-indicator-radius)]
[svg/svg
{:view-box "0 0 16 16"
@@ -63,10 +63,7 @@
:alert [icon/icon :i/alert
{:color color
:size 16}]
[rn/view
{:padding-left 4
:padding-right 2}
[circular-progress {:color color :percentage percentage}]])))
[circular-progress {:color color :percentage percentage}])))
(defn view
"Options
@@ -53,7 +53,7 @@
:style {:color (colors/theme-colors colors/danger-50 colors/danger-60 theme)}}
error-message]])
(when (and (= description :top) role)
(when (= description :top)
[rn/view
{:style style/description-top}
[text/text
@@ -177,9 +177,9 @@
1
animations-duration
:easing4))]
(rn/use-mount (fn []
(when on-init
(on-init reset-top-animation))))
(rn/use-effect (fn []
(when on-init
(on-init reset-top-animation))))
[reanimated/view {:style (style/outer-container height border-radius container-style)}
[blur/view
{:blur-type :dark
@@ -137,8 +137,7 @@
:description description}]))
(defn- right-icon
[{:keys [theme type on-button-press on-button-long-press button-disabled? button-icon button-type]
:or {button-type :primary}}]
[{:keys [theme type on-button-press on-button-long-press button-disabled? button-icon]}]
(cond
(= :info type)
[icons/icon
@@ -154,7 +153,7 @@
:on-press on-button-press
:on-long-press on-button-long-press
:disabled? button-disabled?
:type button-type
:type :primary
:size 24
:icon-only? true}
button-icon]))
@@ -183,7 +182,7 @@
(defn- view-internal
[{:keys [title title-icon type theme description blur? community-name community-logo button-icon
account-name emoji context-tag-type button-type
account-name emoji context-tag-type
on-button-press
on-button-long-press
button-disabled? account-avatar-emoji account-avatar-type customization-color icon-avatar
@@ -222,7 +221,6 @@
[right-icon
{:theme theme
:type type
:button-type button-type
:on-button-press on-button-press
:on-button-long-press on-button-long-press
:button-disabled? button-disabled?
@@ -6,9 +6,8 @@
(h/describe "Profile Input"
(h/test "on press event fires"
(let [event (h/mock-fn)]
(h/render-with-theme-provider
[profile-input/profile-input
{:placeholder "Your Name"
:on-press event}])
(h/render [profile-input/profile-input
{:placeholder "Your Name"
:on-press event}])
(h/fire-event :press (h/get-by-label-text :select-profile-picture-button))
(h/was-called-times event 1))))
@@ -12,34 +12,34 @@
(h/describe "List items: saved contact address"
(h/test "default render"
(h/render-with-theme-provider [saved-contact-address/view])
(h/render [saved-contact-address/view])
(h/is-truthy (h/query-by-label-text :container)))
(h/test "renders account detail when passing one account"
(h/render-with-theme-provider [saved-contact-address/view {:accounts (repeat 1 account)}])
(h/render [saved-contact-address/view {:accounts (repeat 1 account)}])
(h/is-truthy (h/query-by-label-text :account-container)))
(h/test "renders account count when passing multiple accounts"
(h/render-with-theme-provider [saved-contact-address/view {:accounts (repeat 2 account)}])
(h/render [saved-contact-address/view {:accounts (repeat 2 account)}])
(h/is-truthy (h/query-by-label-text :accounts-count)))
(h/test "on-press-in changes state to :pressed"
(h/render-with-theme-provider [saved-contact-address/view {:accounts (repeat 1 account)}])
(h/render [saved-contact-address/view {:accounts (repeat 1 account)}])
(h/fire-event :on-press-in (h/get-by-label-text :container))
(h/wait-for #(h/has-style (h/query-by-label-text :container)
{:backgroundColor (colors/custom-color :blue 50 5)})))
(h/test "on-press-out changes state to :active if active-state? is true (default value)"
(h/render-with-theme-provider [saved-contact-address/view {:accounts (repeat 1 account)}])
(h/render [saved-contact-address/view {:accounts (repeat 1 account)}])
(h/fire-event :on-press-in (h/get-by-label-text :container))
(h/fire-event :on-press-out (h/get-by-label-text :container))
(h/wait-for #(h/has-style (h/query-by-label-text :container)
{:backgroundColor (colors/custom-color :blue 50 10)})))
(h/test "on-press-out changes state to :default if active-state? is false"
(h/render-with-theme-provider [saved-contact-address/view
{:accounts (repeat 1 account)
:active-state? false}])
(h/render [saved-contact-address/view
{:accounts (repeat 1 account)
:active-state? false}])
(h/fire-event :on-press-in (h/get-by-label-text :container))
(h/fire-event :on-press-out (h/get-by-label-text :container))
(h/wait-for #(h/has-style (h/query-by-label-text :container)
@@ -47,9 +47,8 @@
(h/test "on-press calls on-press"
(let [on-press (h/mock-fn)]
(h/render-with-theme-provider
[saved-contact-address/view
{:on-press on-press
:accounts (repeat 1 account)}])
(h/render [saved-contact-address/view
{:on-press on-press
:accounts (repeat 1 account)}])
(h/fire-event :on-press (h/get-by-label-text :container))
(h/was-called on-press))))
@@ -5,19 +5,19 @@
(h/describe "tests for markdown/list component"
(h/test "renders component with title"
(h/render-with-theme-provider [list/view {:title "test title"}])
(h/render [list/view {:title "test title"}])
(h/is-truthy (h/get-by-text "test title")))
(h/test "renders component with description"
(h/render-with-theme-provider [list/view
{:title "test title"
:description "test description"}])
(h/render [list/view
{:title "test title"
:description "test description"}])
(h/is-truthy (h/get-by-text "test description")))
(h/test "renders component with title and description"
(h/render-with-theme-provider [list/view
{:title "test title"
:description "test description"}])
(h/render [list/view
{:title "test title"
:description "test description"}])
(h/is-truthy (h/get-by-text "test title"))
(h/is-truthy (h/get-by-text "test description")))
@@ -29,11 +29,11 @@
(h/is-truthy (h/get-by-label-text :step-counter)))
(h/test "renders decription with a context tag component and description after the tag"
(h/render-with-theme-provider [list/view
{:step-number 1
:description "Lorem ipsum "
:tag-name "dolor"
:description-after-tag "text after tag"}])
(h/render [list/view
{:step-number 1
:description "Lorem ipsum "
:tag-name "dolor"
:description-after-tag "text after tag"}])
(h/is-truthy (h/get-by-text "Lorem ipsum"))
(h/is-truthy (h/get-by-label-text :user-avatar))
(h/is-truthy (h/get-by-text "dolor"))
+5 -3
View File
@@ -4,7 +4,7 @@
[quo.foundations.typography :as typography]
[quo.theme :as quo.theme]
[react-native.core :as rn]
[react-native.utils :as rn.utils]))
[reagent.core :as reagent]))
(defn text-style
[{:keys [size align weight style theme]}]
@@ -41,6 +41,8 @@
(def ^:private text-view (quo.theme/with-theme text-view-internal))
(defn text
[& argv]
(let [[props children] (rn.utils/get-props-and-children argv)]
[]
(let [this (reagent/current-component)
props (reagent/props this)
children (reagent/children this)]
(into [text-view props] children)))
@@ -32,7 +32,7 @@
"
[{:keys [icon new-notifications? notification-indicator counter-label
on-press pass-through? icon-color-anim accessibility-label test-ID
customization-color]
customization-color on-long-press]
:or {customization-color :blue}}]
(let [icon-animated-style (reanimated/apply-animations-to-style
{:tint-color icon-color-anim}
@@ -46,8 +46,9 @@
{:width 90
:height 40
:border-radius 10})]
[rn/pressable
[rn/touchable-without-feedback
{:test-ID test-ID
:on-long-press on-long-press ;;NOTE - this is temporary while supporting old wallet
:allow-multiple-presses? true
:on-press on-press
:on-press-in #(toggle-background-color background-color false pass-through?)
@@ -311,7 +311,7 @@
- title
- description
- picture: a valid rn/image `:source` value
`:wallet-networks`
`:wallet-network`
- networks: a vector of network image source
- networks-on-press: a callback
`:community`
@@ -5,7 +5,7 @@
(h/describe "Top Nav component"
(h/test "Renders default"
(h/render-with-theme-provider [top-nav/view])
(h/render [top-nav/view])
(h/is-truthy (h/get-by-label-text :open-scanner-button))
(h/is-truthy (h/get-by-label-text :open-activity-center-button))
(h/is-truthy (h/get-by-label-text :show-qr-button))
@@ -17,12 +17,11 @@
activity-center-on-press (h/mock-fn)
qr-code-on-press (h/mock-fn)]
(h/render-with-theme-provider
[top-nav/view
{:avatar-on-press avatar-on-press
:scan-on-press scan-on-press
:activity-center-on-press activity-center-on-press
:qr-code-on-press qr-code-on-press}])
(h/render [top-nav/view
{:avatar-on-press avatar-on-press
:scan-on-press scan-on-press
:activity-center-on-press activity-center-on-press
:qr-code-on-press qr-code-on-press}])
(h/fire-event :press (h/get-by-label-text :open-scanner-button))
(h/was-called scan-on-press)
@@ -5,12 +5,12 @@
(h/describe "select-profile component"
(h/test "render component"
(h/render-with-theme-provider [select-profile/view])
(h/render [select-profile/view])
(-> (h/expect (h/get-by-label-text :select-profile))
(.toBeTruthy)))
(h/test "call on-change handler when clicked"
(let [on-change (h/mock-fn)]
(h/render-with-theme-provider [select-profile/view {:on-change on-change}])
(h/render [select-profile/view {:on-change on-change}])
(h/fire-event :on-press (h/get-by-label-text :select-profile))
(-> (h/expect on-change)
(.toHaveBeenCalledTimes 1)))))
@@ -15,7 +15,7 @@
[quo.foundations.colors :as colors]
[quo.theme :as quo.theme]
[react-native.audio-toolkit :as audio]
[react-native.core :as rn]
[react-native.core :as rn :refer [use-effect]]
[react-native.platform :as platform]
[reagent.core :as reagent]
[taoensso.timbre :as log]
@@ -528,20 +528,20 @@
(reset! reached-max-duration? false))
(reset! touch-timestamp nil))]
(fn []
(rn/use-mount (fn []
(when on-check-audio-permissions
(on-check-audio-permissions))
(when on-init
(on-init reset-recorder))
(when audio-file
(let [filename (last (string/split audio-file "/"))]
(reload-player filename)))
(reset! app-state-listener
(.addEventListener rn/app-state
"change"
#(when (= % "background")
(reset! playing-audio? false))))
#(.remove @app-state-listener)))
(use-effect (fn []
(when on-check-audio-permissions
(on-check-audio-permissions))
(when on-init
(on-init reset-recorder))
(when audio-file
(let [filename (last (string/split audio-file "/"))]
(reload-player filename)))
(reset! app-state-listener
(.addEventListener rn/app-state
"change"
#(when (= % "background")
(reset! playing-audio? false))))
#(.remove @app-state-listener)))
[rn/view
{:style style/bar-container
:pointer-events :box-none}
@@ -11,8 +11,8 @@
:padding-bottom 8})
(defn settings-items
[{:keys [label blur? theme]}]
{:margin-top (if label 12 4)
[{:keys [blur? theme]}]
{:margin-top 12
:border-radius 16
:background-color (if blur?
colors/white-opa-5
@@ -12,47 +12,47 @@
(h/describe "Settings list tests"
(h/test "Default render of Setting list component"
(h/render-with-theme-provider [settings-item/view props])
(h/render [settings-item/view props])
(h/is-truthy (h/get-by-label-text :settings-item)))
(h/test "It renders a title"
(h/render-with-theme-provider [settings-item/view props])
(h/render [settings-item/view props])
(h/is-truthy (h/get-by-text "Account")))
(h/test "its gets passed an on press event"
(let [event (h/mock-fn)]
(h/render-with-theme-provider [settings-item/view
(merge props {:on-press event})])
(h/render [settings-item/view
(merge props {:on-press event})])
(h/fire-event :press (h/get-by-text "Account"))
(h/was-called event)))
(h/test "on change event gets fired for toggle"
(let [on-change (h/mock-fn)]
(h/render-with-theme-provider [settings-item/view
(merge props
{:action :selector
:action-props {:on-change on-change}})])
(h/render [settings-item/view
(merge props
{:action :selector
:action-props {:on-change on-change}})])
(h/fire-event :press (h/get-by-label-text :toggle-off))
(h/was-called on-change)))
(h/test "It renders a label"
(h/render-with-theme-provider [settings-item/view (merge props {:label :color})])
(h/render [settings-item/view (merge props {:label :color})])
(h/is-truthy (h/get-by-label-text :label-component)))
(h/test "It renders a status tag component"
(h/render-with-theme-provider [settings-item/view
(merge props
{:tag :context
:tag-props {:context "Test Tag"
:icon :i/placeholder}})])
(h/render [settings-item/view
(merge props
{:tag :context
:tag-props {:context "Test Tag"
:icon :i/placeholder}})])
(h/is-truthy (h/get-by-text "Test Tag")))
(h/test "on press event gets fired for button"
(let [event (h/mock-fn)]
(h/render-with-theme-provider [settings-item/view
(merge props
{:action :button
:action-props {:button-text "test button"
:on-press event}})])
(h/render [settings-item/view
(merge props
{:action :button
:action-props {:button-text "test button"
:on-press event}})])
(h/fire-event :press (h/get-by-text "test button"))
(h/was-called event))))
@@ -83,35 +83,35 @@
(h/is-truthy (h/get-by-label-text :gif)))
(h/test "Status: Read, Type: Audio, Avatar: true"
(h/render-with-theme-provider [group-messaging-card/view
{:avatar true
:status :read
:type :audio
:title "Title"
:content {:duration "00:32"}}])
(h/render [group-messaging-card/view
{:avatar true
:status :read
:type :audio
:title "Title"
:content {:duration "00:32"}}])
(h/is-truthy (h/get-by-text (utils/subtitle :audio nil)))
(h/is-truthy (h/get-by-text "00:32")))
(h/test "Status: Read, Type: Community, Avatar: true"
(h/render-with-theme-provider [group-messaging-card/view
{:avatar true
:status :read
:type :community
:title "Title"
:content {:community-avatar coinbase-community
:community-name "Coinbase"}}])
(h/render [group-messaging-card/view
{:avatar true
:status :read
:type :community
:title "Title"
:content {:community-avatar coinbase-community
:community-name "Coinbase"}}])
(h/is-truthy (h/get-by-text (utils/subtitle :community nil)))
(h/is-truthy (h/get-by-label-text :group-avatar))
(h/is-truthy (h/get-by-text "Coinbase")))
(h/test "Status: Read, Type: Link, Avatar: true"
(h/render-with-theme-provider [group-messaging-card/view
{:avatar true
:status :read
:type :link
:title "Title"
:content {:icon :placeholder
:text "Rolling St..."}}])
(h/render [group-messaging-card/view
{:avatar true
:status :read
:type :link
:title "Title"
:content {:icon :placeholder
:text "Rolling St..."}}])
(h/is-truthy (h/get-by-text (utils/subtitle :link nil)))
(h/is-truthy (h/get-by-label-text :group-avatar))
(h/is-truthy (h/get-by-text "Rolling St..."))))
@@ -1,52 +0,0 @@
(ns quo.components.tags.collectible-tag.component-spec
(:require
[quo.components.tags.collectible-tag.view :as collectible-tag]
[test-helpers.component :as h]))
(def collectible-name "Collectible")
(def collectible-id "#123")
(defn get-test-data
[{:keys [options blur? size]}]
{:collectible-name collectible-name
:collectible-id collectible-id
:collectible-img-src {:uri "https://example.com/image.jpg"}
:options options
:blur? (or blur? false)
:size (or size :size-24)})
(h/describe "Collectible_tag tests"
(h/test "Renders Default option"
(let [data (get-test-data {})]
(h/render-with-theme-provider [collectible-tag/view data])
(h/is-truthy (h/get-by-text collectible-name))))
(h/test "Renders Add option"
(let [data (get-test-data {:options :add})]
(h/render-with-theme-provider [collectible-tag/view data])
(h/is-truthy (h/get-by-text collectible-name))))
(h/test "Renders Hold option"
(let [data (get-test-data {:options :hold})]
(h/render-with-theme-provider [collectible-tag/view data])
(h/is-truthy (h/get-by-text collectible-name))))
(h/test "Renders with Blur"
(let [data (get-test-data {:blur? true})]
(h/render-with-theme-provider [collectible-tag/view data])
(h/is-truthy (h/get-by-text collectible-name))))
(h/test "Renders without Blur"
(let [data (get-test-data {:blur? false})]
(h/render-with-theme-provider [collectible-tag/view data])
(h/is-truthy (h/get-by-text collectible-name))))
(h/test "Renders with Size 24"
(let [data (get-test-data {:size :size-24})]
(h/render-with-theme-provider [collectible-tag/view data])
(h/is-truthy (h/get-by-text collectible-name))))
(h/test "Renders with Size 32"
(let [data (get-test-data {:size :size-32})]
(h/render-with-theme-provider [collectible-tag/view data])
(h/is-truthy (h/get-by-text collectible-name)))))
@@ -1,15 +0,0 @@
(ns quo.components.tags.collectible-tag.schema)
(def ?schema
[:=>
[:catn
[:props
[:map
[:options {:optional true} [:maybe [:enum :add :hold]]]
[:size {:optional true} [:maybe [:enum :size-24 :size-32]]]
[:blur? {:optional true} [:maybe :boolean]]
[:theme :schema.common/theme]
[:collectible-img-src [:maybe :schema.common/image-source :string]]
[:collectible-name :string]
[:collectible-id {:optional true} [:maybe :string]]]]]
:any])
@@ -1,59 +1,70 @@
(ns quo.components.tags.collectible-tag.view
(:require
[oops.core :as oops]
[quo.components.icon :as icons]
[quo.components.markdown.text :as text]
[quo.components.tags.collectible-tag.schema :as component-schema]
[quo.components.tags.collectible-tag.style :as style]
[quo.theme]
[react-native.core :as rn]
[react-native.hole-view :as hole-view]
[reagent.core :as reagent]
[schema.core :as schema]))
(def ?schema
[:=>
[:catn
[:props
[:map {:closed true}
[:options {:optional true} [:maybe [:enum false :add :hold]]]
[:size {:optional true} [:enum :size-24 :size-32]]
[:blur? {:optional true} :boolean]
[:theme :schema.common/theme]
[:collectible-img-src [:or :int :string]]
[:collectible-name :string]
[:collectible-id :string]
[:container-width :number]
[:on-layout {:optional true} [:maybe fn?]]]]]
:any])
(defn- view-internal
[]
(let [container-width (reagent/atom 0)
on-layout #(->> (oops/oget % :nativeEvent :layout :width)
(reset! container-width))]
(fn [{:keys [options blur? theme collectible-img-src collectible-name collectible-id] :as props}]
(let [size (or (:size props) :size-24)]
[rn/view
{:on-layout on-layout}
[hole-view/hole-view
{:holes (if options
[{:x (- @container-width
(case size
:size-24 10
:size-32 12
nil))
:y (case size
:size-24 -6
:size-32 -4
nil)
:width 16
:height 16
:borderRadius 8}]
[])}
[rn/view {:style (style/container size options blur? theme)}
[rn/image {:style (style/collectible-img size) :source collectible-img-src}]
[text/text
{:size :paragraph-2
:weight :medium
:style (style/label theme)}
collectible-name]
[text/text
{:size :paragraph-2
:weight :medium
:margin-left 5
:style (style/label theme)}
collectible-id]]]
(when options
[rn/view {:style (style/options-icon size)}
[icons/icon (if (= options :hold) :i/hold :i/add-token)
{:size 20
:no-color true}]])]))))
(fn [{:keys [options size blur? theme collectible-img-src collectible-name collectible-id
container-width on-layout]
:or {size :size-24}}]
[rn/view
{:on-layout on-layout}
[hole-view/hole-view
{:holes (if options
[{:x (- container-width
(case size
:size-24 10
:size-32 12
nil))
:y (case size
:size-24 -6
:size-32 -4
nil)
:width 16
:height 16
:borderRadius 8}]
[])}
[rn/view {:style (style/container size options blur? theme)}
[rn/image {:style (style/collectible-img size) :source collectible-img-src}]
[text/text
{:size :paragraph-2
:weight :medium
:style (style/label theme)}
collectible-name]
[text/text
{:size :paragraph-2
:weight :medium
:margin-left 5
:style (style/label theme)}
collectible-id]]]
(when options
[rn/view {:style (style/options-icon size)}
[icons/icon (if (= options :hold) :i/hold :i/add-token)
{:size 20
:no-color true}]])]))
(def view
(quo.theme/with-theme
(schema/instrument #'view-internal component-schema/?schema)))
(schema/instrument #'view-internal ?schema)))
@@ -1,104 +0,0 @@
(ns quo.components.tags.context-tag.schema
(:require [malli.core :as malli]))
(def ^:private ?context-base
[:map
[:type {:optional true}
[:maybe
[:enum :default :multiuser :group :channel :community :token :network :multinetwork :account
:collectible :address :icon :audio]]]
[:customization-color {:optional true} [:maybe :schema.common/customization-color]]
[:theme :schema.common/theme]
[:blur? {:optional true} [:maybe :boolean]]
[:state {:optional true} [:maybe [:enum :selected :default]]]])
(def ^:private ?size
[:map
[:size {:optional true} [:maybe [:enum 24 32]]]])
(def ^:private ?default
[:map
[:profile-picture {:optional true} [:maybe :schema.quo/profile-picture-source]]
[:full-name {:optional true} [:maybe :string]]])
(def ^:private ?multiuser
[:map
[:users {:optional true}
[:maybe
[:sequential
[:map
[:profile-picture {:optional true} [:maybe :schema.quo/profile-picture-source]]
[:full-name {:optional true} [:maybe :string]]
[:customization-color {:optional true} [:maybe :schema.common/customization-color]]]]]]])
(def ^:private ?group
[:map
[:group-name {:optional true} [:maybe :string]]])
(def ^:private ?channel
[:map
[:community-name {:optional true} [:maybe :string]]
[:channel-name {:optional true} [:maybe :string]]])
(def ^:private ?community
[:map
[:community-name {:optional true} [:maybe :string]]])
(def ^:private ?token
[:map
[:amount {:optional true} [:maybe [:or :string :int]]]
[:token {:optional true} [:maybe :string]]])
(def ^:private ?network
[:map
[:network-logo {:optional true} [:maybe :schema.common/image-source]]
[:network-name {:optional true} [:maybe :string]]])
(def ^:private ?multinetwork
[:map
[:networks {:optional true} [:maybe [:sequential ?network]]]])
(def ^:private ?account
[:map
[:account-name {:optional true} [:maybe :string]]
[:emoji {:optional true} [:maybe :string]]])
(def ^:private ?collectible
[:map
[:collectible {:optional true} [:maybe :schema.common/image-source]]
[:collectible-name {:optional true} [:maybe :string]]
[:collectible-number {:optional true} [:maybe [:or :string :int]]]])
(def ^:private ?address
[:map
[:address {:optional true} [:maybe :string]]])
(def ^:private ?icon
[:map
[:icon {:optional true} [:maybe :keyword]]
[:context {:optional true} [:maybe :string]]])
(def ^:private ?audio
[:map
[:duration {:optional true} [:maybe :string]]])
(def ?schema
[:=>
[:catn
[:props
[:multi {:dispatch :type}
[::malli/default [:merge ?default ?size ?context-base]]
[:default [:merge ?default ?size ?context-base]]
[:multiuser [:merge ?multiuser ?context-base]]
[:group [:merge ?group ?size ?context-base]]
[:channel [:merge ?channel ?size ?context-base]]
[:community [:merge ?community ?size ?context-base]]
[:token [:merge ?token ?size ?context-base]]
[:network [:merge ?network ?context-base]]
[:multinetwork [:merge ?multinetwork ?context-base]]
[:account [:merge ?account ?size ?context-base]]
[:collectible [:merge ?collectible ?size ?context-base]]
[:address [:merge ?address ?size ?context-base]]
[:icon [:merge ?icon ?size ?context-base]]
[:audio [:merge ?audio ?context-base]]]]]
:any])
+65 -5
View File
@@ -6,13 +6,11 @@
[quo.components.icon :as icons]
[quo.components.list-items.preview-list.view :as preview-list]
[quo.components.markdown.text :as text]
[quo.components.tags.context-tag.schema :as component-schema]
[quo.components.tags.context-tag.style :as style]
[quo.components.utilities.token.view :as token]
[quo.foundations.colors :as colors]
[quo.theme :as quo.theme]
[react-native.core :as rn]
[schema.core :as schema]))
[react-native.core :as rn]))
(defn- tag-skeleton
[{:keys [theme size text] :or {size 24}} logo-component]
@@ -159,5 +157,67 @@
nil)])
(def view
(quo.theme/with-theme
(schema/instrument #'view-internal component-schema/?schema)))
"Properties:
type, state, blur? & customization-color
Depending on the `type` selected, different properties are accepted:
- `:default` or `nil`:
- size
- profile-picture
- full-name
- `:multiuser`:
- users (vector of {:profile-picture pic, :full-name \"a name\"})
- `:group`
- size
- group-name
- `:community`
- size
- community-logo (valid rn/image :source value)
- community-name
- `:channel`
- size
- community-logo (valid rn/image :source value)
- community-name
- channel-name
- `:token`
- size
- amount
- token
- `:network`
- size
- network-logo (valid rn/image :source value)
- network-name
- `:multinetworks`
- networks (vector of {:network-logo pic, :network-name \"a name\"})
- `:account`
- size
- account-name
- emoji (string containing an emoji)
- `:collectible`
- size
- collectible (valid rn/image :source value)
- collectible-name
- collectible-number
- `:address`
- size
- address (string)
- `:icon`
- size
- icon
- context (string)
- `:audio`
- duration (string)
"
(quo.theme/with-theme view-internal))
@@ -38,12 +38,11 @@
(h/is-truthy (h/get-by-text "Rare Artifact")))
(h/test "User view render"
(h/render-with-theme-provider
[summary-tag/view
{:type :user
:label "Bob Smith"
:image-source "path/to/profile-pic.png"
:customization-color "#0000ff"}])
(h/render [summary-tag/view
{:type :user
:label "Bob Smith"
:image-source "path/to/profile-pic.png"
:customization-color "#0000ff"}])
(h/is-truthy (h/get-by-text "Bob Smith")))
(h/test "Token view render"
+9 -15
View File
@@ -27,19 +27,6 @@
:blurred-border-color colors/white-opa-10
:text-color {:style {:color colors/white}}}}})
(defn- emoji-comp
[size resource]
(let [dimension (case size
32 20
24 12
nil)]
(if (string? resource)
[rn/text {:style {:margin-right 4 :font-size dimension}}
resource]
[rn/image
{:source resource
:style {:margin-right 4 :width dimension :height dimension}}])))
(defn tag-resources
[size type resource icon-color label text-color labelled?]
[rn/view
@@ -60,7 +47,13 @@
24 12)
:color icon-color}])
(when (= type :emoji)
[emoji-comp size resource])
[text/text
{:style {:margin-right 4}
:size (case size
32 :paragraph-1
24 :paragraph-2
nil)}
resource])
(when labelled?
[text/text
(merge {:size (case size
@@ -80,7 +73,7 @@
:size 32/24
:on-press fn
:blurred? true/false
:resource icon/image/text(emojis)
:resource icon/image
:labelled? true/false
:disabled? true/false}
@@ -114,3 +107,4 @@
[tag-resources size type resource icon-color label text-color labelled?]]]))
(def tag (quo.theme/with-theme tag-internal))
@@ -37,26 +37,26 @@
(h/is-truthy (h/get-by-text "This is a textual description")))
(h/test "Context tag"
(h/render-with-theme-provider [page-top/view
{:title "Title"
:description :context-tag
:context-tag context-tag-data}])
(h/render [page-top/view
{:title "Title"
:description :context-tag
:context-tag context-tag-data}])
(h/is-truthy (h/get-by-text "Title"))
(h/is-truthy (h/get-by-label-text :context-tag)))
(h/test "Summary"
(h/render-with-theme-provider [page-top/view
{:title "Title"
:description :summary
:summary {:row-1 {:text-1 "Send"
:text-2 "from"
:context-tag-1 context-tag-data
:context-tag-2 context-tag-data}
:row-2 {:text-1 "to"
:text-2 "via"
:context-tag-1 context-tag-data
:context-tag-2 context-tag-data}}}])
(h/render [page-top/view
{:title "Title"
:description :summary
:summary {:row-1 {:text-1 "Send"
:text-2 "from"
:context-tag-1 context-tag-data
:context-tag-2 context-tag-data}
:row-2 {:text-1 "to"
:text-2 "via"
:context-tag-1 context-tag-data
:context-tag-2 context-tag-data}}}])
(h/is-truthy (h/get-by-text "Title"))
(h/is-truthy (h/get-by-text "Send"))
@@ -12,8 +12,7 @@
:height 32})
(def header-title
{:flex 1
:flex-direction :row
{:flex-direction :row
:column-gap 8})
(def header-counter
@@ -8,7 +8,6 @@
[quo.components.markdown.text :as text]
[quo.components.tags.context-tag.view :as context-tag]
[quo.components.text-combinations.page-top.style :as style]
[quo.components.text-combinations.standard-title.view :as standard-title]
[quo.theme]
[react-native.core :as rn]
[react-native.fast-image :as fast-image]
@@ -33,20 +32,18 @@
(format-counter counter-bottom))]])
(defn- header
[{:keys [title title-accessibility-label input counter-top counter-bottom
title-right title-right-props]
[{:keys [title input counter-top counter-bottom]
avatar-props :avatar}]
(let [title-props (assoc title-right-props
:title title
:right title-right
:accessibility-label title-accessibility-label)]
[rn/view {:style style/header}
[rn/view {:style style/header-title}
(when avatar-props
[channel-avatar/view (assoc avatar-props :size :size-32)])
[standard-title/view title-props]]
(when (= input :recovery-phrase)
[header-counter counter-top counter-bottom])]))
[rn/view {:style style/header}
[rn/view {:style style/header-title}
(when avatar-props
[channel-avatar/view (assoc avatar-props :size :size-32)])
[text/text
{:weight :semi-bold
:size :heading-1}
title]]
(when (= input :recovery-phrase)
[header-counter counter-top counter-bottom])])
(defn- summary-description
[{:keys [row-1 row-2] :as _summary-props} blur?]
@@ -115,10 +112,10 @@
emojis))
(defn- view-internal
[{:keys [theme description input blur? input-props container-style]
[{:keys [theme description input blur? input-props]
emojis :emoji-dash
:as props}]
[rn/view {:style container-style}
[rn/view
[rn/view {:style style/top-container}
[header props]
(when description
@@ -2,8 +2,7 @@
(:require [quo.foundations.colors :as colors]))
(def container
{:flex 1
:flex-direction :row
{:flex-direction :row
:justify-content :space-between})
(def right-container {:margin-left 20})
@@ -53,12 +53,9 @@
:icon-color (style/right-tag-icon-color blur? theme)}]))
(defn- view-internal
[{:keys [title right accessibility-label] :as props}]
[{:keys [title right] :as props}]
[rn/view {:style style/container}
[text/text
{:size :heading-1
:weight :semi-bold
:accessibility-label accessibility-label}
[text/text {:size :heading-1 :weight :semi-bold}
title]
(when right
[rn/view {:style style/right-container}
@@ -21,7 +21,6 @@
(defn view-internal
[{:keys [container-style
title
title-number-of-lines
avatar
title-accessibility-label
description
@@ -29,8 +28,7 @@
button-icon
button-on-press
customization-color
emoji-hash]
:or {title-number-of-lines 1}}]
emoji-hash]}]
[rn/view {:style container-style}
[rn/view
{:style {:flex-direction :row
@@ -43,7 +41,7 @@
{:accessibility-label title-accessibility-label
:weight :semi-bold
:ellipsize-mode :tail
:number-of-lines title-number-of-lines
:number-of-lines 1
:size :heading-1}
title]]
(when button-icon
+1 -1
View File
@@ -15,7 +15,7 @@
[:token {:optional true} [:maybe [:or keyword? string?]]]
[:style {:optional true} map?]
;; Ignores `token` and uses this as parameter to `rn/image`'s source.
[:image-source {:optional true} [:maybe :schema.common/image-source]]]]
[:image-source {:optional true} [:maybe [:or :schema.common/image-source :string]]]]]
:any])
(defn- size->number
@@ -3,11 +3,17 @@
(defn gradient-start-color
[theme customization-color]
(colors/resolve-color customization-color theme 0))
(colors/theme-colors
(colors/resolve-color customization-color theme 0)
colors/neutral-95
theme))
(defn gradient-end-color
[theme customization-color]
(colors/resolve-color customization-color theme 6))
(colors/theme-colors
(colors/resolve-color customization-color theme 6)
colors/neutral-95
theme))
(defn alert-icon-color
[theme]
@@ -9,7 +9,7 @@
(def ^:private ?default-keypair
[:map
[:user-name {:optional true} [:maybe :string]]
[:profile-picture {:optional true} [:maybe :schema.common/image-source]]
[:profile-picture {:optional true} [:maybe [:or :schema.common/image-source :string]]]
[:derivation-path {:optional true} [:maybe :string]]
[:on-press {:optional true} [:maybe fn?]]
[:customization-color {:optional true} [:maybe :schema.common/customization-color]]])
@@ -1,5 +1,5 @@
(ns quo.components.wallet.account-permissions.schema
(:require [quo.components.wallet.required-tokens.schema :as required-tokens-schema]))
(:require [quo.components.wallet.required-tokens.view :as required-tokens]))
(def ?schema
[:=>
@@ -12,12 +12,11 @@
[:address [:maybe :string]]
[:emoji [:maybe :string]]
[:customization-color {:optional true} [:maybe :schema.common/customization-color]]]]
[:token-details {:optional true} [:maybe [:sequential required-tokens-schema/?schema]]]
[:token-details {:optional true} [:maybe [:sequential required-tokens/?schema]]]
[:keycard? {:optional true} [:maybe :boolean]]
[:checked? {:optional true} [:maybe :boolean]]
[:disabled? {:optional true} [:maybe :boolean]]
[:on-change {:optional true} [:maybe fn?]]
[:container-style {:optional true} [:maybe :map]]
[:customization-color {:optional true} [:maybe :schema.common/customization-color]]
[:theme :schema.common/theme]]]]
:any])

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