Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
64dba60029 | ||
|
|
a340e2a55c | ||
|
|
88c4521321 | ||
|
|
645a5b312b | ||
|
|
c55f12ecf8 | ||
|
|
6c28e9349f | ||
|
|
6170686e34 | ||
|
|
72e56dcf75 | ||
|
|
4801342a42 | ||
|
|
7282ba04bc | ||
|
|
2e397f0065 | ||
|
|
bcb55a1ab3 | ||
|
|
224d6c7cad | ||
|
|
126a8705cd | ||
|
|
3fce4816dc | ||
|
|
704b160964 | ||
|
|
7350c88920 | ||
|
|
7392b9bf50 | ||
|
|
f5948fa016 | ||
|
|
919fbf2091 | ||
|
|
728d9d01c5 | ||
|
|
9ac14b6fac | ||
|
|
4414f8ffd3 | ||
|
|
1e8ea3fd16 | ||
|
|
17f5ad79f4 | ||
|
|
d76e64b1bb | ||
|
|
ac675e28eb | ||
|
|
5755d2e21a | ||
|
|
cf2a3bfce7 | ||
|
|
dcda44fab6 | ||
|
|
362aa476ae | ||
|
|
25b088833d | ||
|
|
3395baa966 | ||
|
|
4327653b0b | ||
|
|
26dcc16ea6 | ||
|
|
9ed68ee7d1 | ||
|
|
4d7cf3e94e | ||
|
|
4decba8d00 | ||
|
|
229a806f12 | ||
|
|
abe653c086 | ||
|
|
f047665f75 | ||
|
|
ea3b090265 | ||
|
|
c52bf965f7 | ||
|
|
e260187cf5 | ||
|
|
ca0915c940 | ||
|
|
2b4b357c32 | ||
|
|
19ca8e28a5 | ||
|
|
8978e92042 | ||
|
|
c2c79cc1ac | ||
|
|
affd2a5e76 | ||
|
|
ef99bf2ad6 | ||
|
|
1f6f907d57 | ||
|
|
97b254c514 | ||
|
|
ca2ed9d37e | ||
|
|
e64ff76e0b | ||
|
|
88884064b1 | ||
|
|
a6e6716311 | ||
|
|
07d037f2e1 | ||
|
|
36a72f2d63 | ||
|
|
4c0a8d9f6d | ||
|
|
2d860c363a | ||
|
|
186ac482ee | ||
|
|
f015eb929a | ||
|
|
bca7ab7925 | ||
|
|
5f441dfa93 | ||
|
|
5d0aa6a2f7 | ||
|
|
d9f7510d13 | ||
|
|
b953ddb5af | ||
|
|
3058ebe018 | ||
|
|
a7ddda40c4 | ||
|
|
ba8c08650b | ||
|
|
c5a7bf39d7 | ||
|
|
e0a0c6331f | ||
|
|
b5a96a254a | ||
|
|
6b0a51720e | ||
|
|
e0e693791f | ||
|
|
cebc50d409 | ||
|
|
1503f6b250 | ||
|
|
46182ad308 | ||
|
|
fa698dbc30 | ||
|
|
79151ee85d | ||
|
|
4c8671caa0 | ||
|
|
86219dbad8 | ||
|
|
cd32806c96 | ||
|
|
ab16ca34dd | ||
|
|
e2b7a299b4 | ||
|
|
5dcd64c478 | ||
|
|
6d6e6b1eff | ||
|
|
60a8b944d9 | ||
|
|
437cfa9a77 | ||
|
|
36aefd0e5a | ||
|
|
ce82e87cd0 | ||
|
|
8f21cecf81 | ||
|
|
4a4974b541 | ||
|
|
43ef6db7b9 | ||
|
|
6f0d375e8a |
@@ -14,6 +14,13 @@
|
||||
clojure.set set
|
||||
clojure.walk walk
|
||||
taoensso.timbre log}}
|
||||
:shadowed-var {:level :error
|
||||
;; We temporarily use :include to define an
|
||||
;; allowlist of core Clojure vars. In the
|
||||
;; future, as we progressively fix shadowed
|
||||
;; vars, we should be able to delete this
|
||||
;; option and lint all vars.
|
||||
:include [count iter key time]}
|
||||
:invalid-arity {:skip-args [status-im.utils.fx/defn utils.re-frame/defn]}
|
||||
;; TODO remove number when this is fixed
|
||||
;; https://github.com/borkdude/clj-kondo/issues/867
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
module.exports = {
|
||||
testRunner: 'jest',
|
||||
testRegex: '\\.visual\\.js$',
|
||||
'runner-config': 'visual-test/config.json',
|
||||
devices: {
|
||||
simulator: {
|
||||
type: 'ios.simulator',
|
||||
device: {
|
||||
type: 'iPhone 11 Pro',
|
||||
},
|
||||
},
|
||||
},
|
||||
apps: {
|
||||
'ios.release': {
|
||||
name: 'StatusIm',
|
||||
type: 'ios.app',
|
||||
binaryPath: 'ios/build/Build/Products/Release-iphonesimulator/StatusIm.app',
|
||||
build: 'make release-ios',
|
||||
},
|
||||
'ios.debug': {
|
||||
name: 'StatusIm',
|
||||
type: 'ios.app',
|
||||
binaryPath: process.env.TEST_BINARY_PATH,
|
||||
build: "make run-ios SIMULATOR='iPhone 11 Pro'",
|
||||
},
|
||||
},
|
||||
configurations: {
|
||||
'ios.sim.release': {
|
||||
device: 'simulator',
|
||||
app: 'ios.release',
|
||||
},
|
||||
'ios.sim.debug': {
|
||||
device: 'simulator',
|
||||
app: 'ios.debug',
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -43,4 +43,4 @@ As a <user|developer|...>, I want to <task> so that <goal>.
|
||||
[comment]: # (if on Android please replicate bug whilst running adb logcat)
|
||||
```
|
||||
...
|
||||
```
|
||||
```
|
||||
|
||||
@@ -14,17 +14,17 @@ WHITE := $(shell tput -Txterm setaf 7)
|
||||
YELLOW := $(shell tput -Txterm setaf 3)
|
||||
RESET := $(shell tput -Txterm sgr0)
|
||||
HELP_FUN = \
|
||||
%help; \
|
||||
while(<>) { push @{$$help{$$2 // 'options'}}, [$$1, $$3] if /^([a-zA-Z\-]+)\s*:.*\#\#(?:@([a-zA-Z\-]+))?\s(.*)$$/ }; \
|
||||
print "Usage: make [target]\n\nSee STARTING_GUIDE.md for more info.\n\n"; \
|
||||
for (sort keys %help) { \
|
||||
print "${WHITE}$$_:${RESET}\n"; \
|
||||
for (@{$$help{$$_}}) { \
|
||||
$$sep = " " x (32 - length $$_->[0]); \
|
||||
print " ${YELLOW}$$_->[0]${RESET}$$sep${GREEN}$$_->[1]${RESET}\n"; \
|
||||
}; \
|
||||
print "\n"; \
|
||||
}
|
||||
%help; \
|
||||
while(<>) { push @{$$help{$$2 // 'options'}}, [$$1, $$3] if /^([a-zA-Z\-]+)\s*:.*\#\#(?:@([a-zA-Z\-]+))?\s(.*)$$/ }; \
|
||||
print "Usage: make [target]\n\nSee STARTING_GUIDE.md for more info.\n\n"; \
|
||||
for (sort keys %help) { \
|
||||
print "${WHITE}$$_:${RESET}\n"; \
|
||||
for (@{$$help{$$_}}) { \
|
||||
$$sep = " " x (32 - length $$_->[0]); \
|
||||
print " ${YELLOW}$$_->[0]${RESET}$$sep${GREEN}$$_->[1]${RESET}\n"; \
|
||||
}; \
|
||||
print "\n"; \
|
||||
}
|
||||
HOST_OS := $(shell uname | tr '[:upper:]' '[:lower:]')
|
||||
|
||||
# This can come from Jenkins
|
||||
@@ -307,6 +307,7 @@ lint: ##@test Run code style checks
|
||||
clj-kondo --config .clj-kondo/config.edn --cache false --lint src && \
|
||||
ALL_CLOJURE_FILES=$(call find_all_clojure_files) && \
|
||||
zprint '{:search-config? true}' -sfc $$ALL_CLOJURE_FILES && \
|
||||
sh scripts/lint-trailing-newline.sh && \
|
||||
yarn prettier
|
||||
|
||||
# NOTE: We run the linter twice because of https://github.com/kkinnear/zprint/issues/271
|
||||
@@ -315,9 +316,9 @@ lint-fix: ##@test Run code style checks and fix issues
|
||||
ALL_CLOJURE_FILES=$(call find_all_clojure_files) && \
|
||||
zprint '{:search-config? true}' -sw $$ALL_CLOJURE_FILES && \
|
||||
zprint '{:search-config? true}' -sw $$ALL_CLOJURE_FILES && \
|
||||
sh scripts/lint-trailing-newline.sh --fix && \
|
||||
yarn prettier
|
||||
|
||||
|
||||
shadow-server: export TARGET := clojure
|
||||
shadow-server:##@ Start shadow-cljs in server mode for watching
|
||||
yarn shadow-cljs server
|
||||
@@ -343,14 +344,6 @@ test: ##@test Run tests once in NodeJS
|
||||
yarn shadow-cljs compile test && \
|
||||
node --require ./test-resources/override.js target/test/test.js
|
||||
|
||||
|
||||
run-visual-test-ios: export TARGET := clojure
|
||||
run-visual-test-ios: XCODE_DERIVED_DATA := $(HOME)/Library/Developer/Xcode/DerivedData
|
||||
run-visual-test-ios: APPLICATION_NAME := StatusIm-brfnruzfrkkycpbndmdoeyrigthc
|
||||
run-visual-test-ios: export TEST_BINARY_PATH := $(XCODE_DERIVED_DATA)/$(APPLICATION_NAME)/Build/Products/Debug-iphonesimulator/StatusIm.app
|
||||
run-visual-test-ios: ##@test Run tests once in NodeJS
|
||||
detox test --configuration ios.sim.debug
|
||||
|
||||
component-test-watch: export TARGET := clojure
|
||||
component-test-watch: export COMPONENT_TEST := true
|
||||
component-test-watch: export BABEL_ENV := test
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#!/usr/bin/env groovy
|
||||
library 'status-jenkins-lib@v1.7.9'
|
||||
|
||||
/* Options section can't access functions in objects. */
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#!/usr/bin/env groovy
|
||||
library 'status-jenkins-lib@v1.7.9'
|
||||
|
||||
pipeline {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#!/usr/bin/env groovy
|
||||
library 'status-jenkins-lib@v1.7.9'
|
||||
|
||||
/* Options section can't access functions in objects. */
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#!/usr/bin/env groovy
|
||||
library 'status-jenkins-lib@v1.7.9'
|
||||
|
||||
/* Options section can't access functions in objects. */
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#!/usr/bin/env groovy
|
||||
library 'status-jenkins-lib@v1.7.9'
|
||||
|
||||
pipeline {
|
||||
@@ -73,7 +74,7 @@ pipeline {
|
||||
sh 'cp -f $TEST_ETH_ACCOUNTS_FILE users.py'
|
||||
sh """
|
||||
python3 -m pytest \
|
||||
--numprocesses 4 \
|
||||
--numprocesses 6 \
|
||||
--rerun_count=2 \
|
||||
--testrail_report=True \
|
||||
-m testrail_id \
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#!/usr/bin/env groovy
|
||||
library 'status-jenkins-lib@v1.7.9'
|
||||
|
||||
pipeline {
|
||||
@@ -122,7 +123,7 @@ pipeline {
|
||||
sh 'cp -f $TEST_ETH_ACCOUNTS_FILE users.py'
|
||||
sh """
|
||||
python3 -m pytest \
|
||||
--numprocesses 4 \
|
||||
--numprocesses 6 \
|
||||
--rerun_count=2 \
|
||||
--testrail_report=True \
|
||||
-k \"${params.KEYWORD_EXPRESSION}\" \
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#!/usr/bin/env groovy
|
||||
library 'status-jenkins-lib@v1.7.9'
|
||||
|
||||
pipeline {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#!/usr/bin/env groovy
|
||||
library 'status-jenkins-lib@v1.7.9'
|
||||
|
||||
pipeline {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#!/usr/bin/env groovy
|
||||
library 'status-jenkins-lib@v1.7.9'
|
||||
|
||||
pipeline {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#!/usr/bin/env groovy
|
||||
library 'status-jenkins-lib@v1.7.9'
|
||||
|
||||
pipeline {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#!/usr/bin/env groovy
|
||||
/**
|
||||
* This job runs daily and executes `pod repo update` on MacOS
|
||||
* This is done to avoid issues with out of date repo causing errors like:
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#!/usr/bin/env groovy
|
||||
library 'status-jenkins-lib@v1.7.9'
|
||||
|
||||
pipeline {
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
|
||||
[Patching](patching.md)
|
||||
|
||||
[Creating a pixel perfect UI](pixel-perfection.md)
|
||||
|
||||
## Testing
|
||||
|
||||
|
||||
@@ -45,4 +45,4 @@ The `State` field in the Pivotal story is used to track the progress of a Pivota
|
||||
| 5 points | 2 - 3 days |
|
||||
| 8 points | ~1 week |
|
||||
|
||||
We should avoid 8 point stories by breaking them down into smaller stories as much as possible.
|
||||
We should avoid 8 point stories by breaking them down into smaller stories as much as possible.
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
# Git Etiquette Guide
|
||||
|
||||
To ensure smooth collaboration, we've outlined the following Git etiquette guide. This guide will help in writing concise commit messages, managing git branches, pull request descriptions, and other best practices.
|
||||
|
||||
## 1. Commit Messages
|
||||
|
||||
Your commit message should provide clear context about the change. This allows others (and future you) to understand why a particular change was made.
|
||||
|
||||
Here are the guidelines to write concise and meaningful commit messages:
|
||||
|
||||
- **Use the Imperative Mood**: Commit messages should be written in the present tense and imperative mood ("Add feature" not "Added feature" or "Adds feature").
|
||||
- **First Line Should Be Summary**: The first line of your commit message should be a brief summary of the changes, kept under 50 characters whenever possible.
|
||||
- **Body**: Follow this summary line with a blank line, then a more detailed explanation is always helpful but not necessary. This is often useful when the commit has significant importance or complexity.
|
||||
- **Consider Including the 'Why'**: If the commit resolves an issue or bug, mention the issue number and provide a brief explanation of how the changes fix the issue.
|
||||
|
||||
Here's a good commit message example:
|
||||
|
||||
```
|
||||
Fix off-by-one error in loop (issue #123)
|
||||
|
||||
This commit fixes an off-by-one error in the list iteration function.
|
||||
This was causing an index out of bounds exception when processing the last item in the list.
|
||||
Tests have been updated to catch this in the future.
|
||||
```
|
||||
|
||||
## 2. Branch Management
|
||||
|
||||
Git branches should be concise and focused on a single feature, fix, or improvement. Here are a few practices:
|
||||
|
||||
- **Branch Name**: The branch name should be descriptive of the change and follow a specific format such as `type/description`. Example: `feature/login-system`.
|
||||
- **Please don't accept branch recommendation by Github UI**: The branch name recommendation by Github UI will in most cases be a very long branch name concatenated with the issue number, which often results in branch names like this one :
|
||||
`feature/Merge_yada_and_yada_yada_into_one_yada_yada_status-lol_#199021`
|
||||
- **Keep Branches Short-lived**: The longer a branch lives separate from the `main` or `master` branch, the higher the possibility of merge conflicts. Aim to merge branches as soon as the work is complete and has been tested.
|
||||
- **Rebase Frequently**: If your branch lives longer, rebase it frequently on top of the main branch.
|
||||
|
||||
## 3. Pull Requests
|
||||
|
||||
Pull requests (PRs) are how your changes get incorporated into the project. Here are a few key points:
|
||||
|
||||
- **Link PR to an Issue**: Your PR should link to the issue it resolves. This helps track the resolution of bugs or addition of features.
|
||||
- **PR Description**: The PR description should outline what changes have been made and why. This should be a summary of your commits.
|
||||
- **Small and Focused PRs**: Aim to keep PRs small and focused. It's easier to understand and review a PR with a handful of related changes than one with multiple unrelated changes.
|
||||
|
||||
Example PR description:
|
||||
|
||||
```
|
||||
## Description
|
||||
This PR implements a login system (issue #456). It adds a login and logout button, as well as an authentication system. This will allow users to create an account and sign in.
|
||||
|
||||
## Changes
|
||||
- Add login button component
|
||||
- Add logout button component
|
||||
- Add authentication API integration
|
||||
|
||||
## Issue Related
|
||||
This PR closes #456
|
||||
```
|
||||
|
||||
## 4. Other Best Practices
|
||||
|
||||
- **Stay Updated**: Keep your local copy up to date with the upstream regularly.
|
||||
- **Test Before Pushing**: Always test your code and make sure all tests pass before you push.
|
||||
|
||||
Following these guidelines ensures a smoother collaboration and maintains a clean, manageable project history. Thanks for your contributions!
|
||||
|
||||
@@ -169,7 +169,7 @@ For VS Code users.
|
||||
### Start and connect the REPL
|
||||
|
||||
1. Open the `status-mobile` folder.
|
||||
1. Start [Status development](STARTING_GUIDE.md#development) (Starting the `run-clojure` and `run-metro` jobs in split view in the VS Code integrated terminal works great.)
|
||||
1. Start [Status development](starting-guide.md#development) (Starting the `run-clojure` and `run-metro` jobs in split view in the VS Code integrated terminal works great.)
|
||||
1. Run the VS Code command: **Calva: Connect to a running REPL Server in the project**
|
||||
1. Select the project type `shadow-cljs`
|
||||
1. Accept the suggested connection `host:port`
|
||||
|
||||
|
After Width: | Height: | Size: 564 KiB |
@@ -80,6 +80,52 @@ This mistake mostly happens with functional components
|
||||
|
||||
it's important to name functional components with `f-` prefix
|
||||
|
||||
### Component props and API scheme to match Figma as closely as possible
|
||||
|
||||
Ideally, the prop names for components (particularly in quo2 Design System) should match the Figma properties as best as possible. This makes it easier for the developer using that component to configure it correctly for the screen it is being used on and avoids unnecessary overwrites and adjustments being made.
|
||||
|
||||
#### Avoid unnecessarily grouping categories to reduce the number of props
|
||||
For example in Figma if there is a component and it has the following variants:
|
||||
|
||||
|theme: "light" blur: "False"|theme: "dark" blur: "False"|theme: "light" blur: "True"|theme: "dark" blur: "True"|
|
||||
|----------------------------|---------------------------|---------------------------|---------------------------|
|
||||
| type :neutral label "ABC" | type :neutral label "ABC" | | |
|
||||
| type :active label "ABC" | type :active label "ABC" | | |
|
||||
| type :danger label "ABC" | type :danger label "ABC" | type :danger label "ABC" | type :danger label "ABC" |
|
||||
|
||||
```clojure
|
||||
;; bad
|
||||
"theme - :light or :dark
|
||||
type - can be :neutral :active :danger :danger-blur"
|
||||
(defn my-component [{:keys [theme type]} label])
|
||||
|
||||
;; good
|
||||
"theme - :light or :dark
|
||||
type - can be :neutral :active :danger
|
||||
blur? - boolean
|
||||
"
|
||||
(defn my-component [{:keys [theme blur? type]} label])
|
||||
```
|
||||
|
||||
Please note this is only for the external API of the component and there should be no restriction of how the component manages its internal API as that will not affect the developer using the component with the issues described above.
|
||||
|
||||
In some cases this is not always possible or does not make sense. However the thought process should be how easy will it be for another developer to use this component with the correct configuration given the screen designs for Figma.
|
||||
|
||||
#### Avoid unnecessarily renaming props
|
||||
In general it can be helpful to avoid renaming props from their counterpart in Figma.
|
||||
|
||||
For example if Figma has sizes `:small`, `:medium` and `:large`
|
||||
|
||||
```clojure
|
||||
;; bad
|
||||
":size - :little, :default or :big"
|
||||
(defn my-component [{:keys [size]}])
|
||||
|
||||
;; good
|
||||
":size - :small, :medium or :large"
|
||||
(defn my-component [{:keys [size]}])
|
||||
```
|
||||
|
||||
### Component styles
|
||||
|
||||
Prefer to define styles in a separate file named `style.cljs`, colocated with
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
# Pixel Perfection
|
||||
The Status Mobile team aims to align the design implementation perfectly according to a given screens respective Figma design spec.
|
||||
|
||||
Currently the Figma Designs match up with an "iPhone 11 Pro" screen size.
|
||||
|
||||
To test your implementation is correct you can take the following steps
|
||||
|
||||
- Open a new Figma file so that you have write privileges.
|
||||
- Copy in the component or screen from the Figma file.
|
||||
|
||||
- Using the "iPhone 11 Pro" simulator (it is the default now) you take a screenshot of your component and paste it into your Figma file.
|
||||
|
||||
- To get the right size, set your screenshot to width 375px
|
||||
|
||||

|
||||
|
||||
- Lower the opacity so you can see it sitting on top of the Figma mock ups.
|
||||
@@ -3,4 +3,4 @@
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1156,23 +1156,7 @@ RCT_EXPORT_METHOD(deactivateKeepAwake)
|
||||
|
||||
- (NSString*) deviceName
|
||||
{
|
||||
|
||||
NSString* deviceName = nil;
|
||||
|
||||
if ([self.deviceId rangeOfString:@"iPod"].location != NSNotFound) {
|
||||
deviceName = @"iPod Touch";
|
||||
}
|
||||
else if([self.deviceId rangeOfString:@"iPad"].location != NSNotFound) {
|
||||
deviceName = @"iPad";
|
||||
}
|
||||
else if([self.deviceId rangeOfString:@"iPhone"].location != NSNotFound){
|
||||
deviceName = @"iPhone";
|
||||
}
|
||||
else if([self.deviceId rangeOfString:@"AppleTV"].location != NSNotFound){
|
||||
deviceName = @"Apple TV";
|
||||
}
|
||||
|
||||
return deviceName;
|
||||
return [[UIDevice currentDevice] name];;
|
||||
}
|
||||
|
||||
- (NSDictionary *)constantsToExport
|
||||
|
||||
@@ -833,6 +833,37 @@ void _SaveAccountAndLogin(const FunctionCallbackInfo<Value>& args) {
|
||||
|
||||
}
|
||||
|
||||
void _CreateAccountAndLogin(const FunctionCallbackInfo<Value>& args) {
|
||||
Isolate* isolate = args.GetIsolate();
|
||||
Local<Context> context = isolate->GetCurrentContext();
|
||||
|
||||
if (args.Length() != 1) {
|
||||
// Throw an Error that is passed back to JavaScript
|
||||
isolate->ThrowException(Exception::TypeError(
|
||||
String::NewFromUtf8Literal(isolate, "Wrong number of arguments for SaveAccountAndLogin")));
|
||||
return;
|
||||
}
|
||||
|
||||
// Check the argument types
|
||||
|
||||
if (!args[0]->IsString()) {
|
||||
isolate->ThrowException(Exception::TypeError(
|
||||
String::NewFromUtf8Literal(isolate, "Wrong argument type for 'settingsJSON'")));
|
||||
return;
|
||||
}
|
||||
|
||||
String::Utf8Value arg0Obj(isolate, args[0]->ToString(context).ToLocalChecked());
|
||||
char *arg0 = *arg0Obj;
|
||||
|
||||
// Call exported Go function, which returns a C string
|
||||
char *c = CreateAccountAndLogin(arg0);
|
||||
|
||||
Local<String> ret = String::NewFromUtf8(isolate, c).ToLocalChecked();
|
||||
args.GetReturnValue().Set(ret);
|
||||
delete c;
|
||||
|
||||
}
|
||||
|
||||
void _GenerateAlias(const FunctionCallbackInfo<Value>& args) {
|
||||
Isolate* isolate = args.GetIsolate();
|
||||
Local<Context> context = isolate->GetCurrentContext();
|
||||
@@ -1929,6 +1960,7 @@ void init(Local<Object> exports) {
|
||||
NODE_SET_METHOD(exports, "hashMessage", _HashMessage);
|
||||
NODE_SET_METHOD(exports, "resetChainData", _ResetChainData);
|
||||
NODE_SET_METHOD(exports, "saveAccountAndLogin", _SaveAccountAndLogin);
|
||||
NODE_SET_METHOD(exports, "createAccountAndLogin", _CreateAccountAndLogin);
|
||||
NODE_SET_METHOD(exports, "generateAlias", _GenerateAlias);
|
||||
NODE_SET_METHOD(exports, "validateMnemonic", _ValidateMnemonic);
|
||||
NODE_SET_METHOD(exports, "multiformatSerializePublicKey", _MultiformatSerializePublicKey);
|
||||
|
||||
@@ -18,4 +18,4 @@
|
||||
"url": "https://github.com/status-im/react-native-status/issues"
|
||||
},
|
||||
"homepage": "https://github.com/status-im/react-native-status#readme"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,6 +49,12 @@ in {
|
||||
doCheck = false;
|
||||
});
|
||||
|
||||
# Downgrade watchman in attempt to fix "too many files open issue"
|
||||
watchman = callPackage ./pkgs/watchman {
|
||||
inherit (super.darwin.apple_sdk.frameworks) CoreServices;
|
||||
autoconf = super.buildPackages.autoconf269;
|
||||
};
|
||||
|
||||
# Package version adjustments
|
||||
gradle = super.gradle_7;
|
||||
nodejs = super.nodejs-18_x;
|
||||
|
||||
@@ -17,9 +17,20 @@ let
|
||||
|
||||
# Override some packages and utilities
|
||||
pkgsOverlay = import ./overlay.nix;
|
||||
|
||||
# Fix for lack of Android SDK for M1 Macs.
|
||||
systemOverride = let
|
||||
inherit (builtins) currentSystem getEnv;
|
||||
envSystemOverride = getEnv "NIXPKGS_SYSTEM_OVERRIDE";
|
||||
in
|
||||
if envSystemOverride != "" then
|
||||
envSystemOverride
|
||||
else
|
||||
currentSystem;
|
||||
in
|
||||
# import nixpkgs with a config override
|
||||
(import nixpkgsSrc) {
|
||||
config = defaultConfig // config;
|
||||
system = systemOverride;
|
||||
overlays = [ pkgsOverlay ];
|
||||
}
|
||||
|
||||
@@ -3,7 +3,10 @@
|
||||
# for the Android development environment.
|
||||
#
|
||||
|
||||
{ androidenv }:
|
||||
{ androidenv, lib, stdenv }:
|
||||
|
||||
assert lib.assertMsg (stdenv.system != "aarch64-darwin")
|
||||
"aarch64-darwin not supported for Android SDK. Use: NIXPKGS_SYSTEM_OVERRIDE=x86_64-darwin";
|
||||
|
||||
# The "android-sdk-license" license is accepted
|
||||
# by setting android_sdk.accept_license = true.
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
# Issue
|
||||
|
||||
`watchman` was upgraded significantly during the last nixpkgs upgrade (`4.9.0` (Aug 16, 2017) to `2023.01.30.00` - 6 years between):
|
||||
- https://github.com/status-im/status-mobile/pull/14944
|
||||
- https://github.com/status-im/nixpkgs/commit/4e9c02bcc709fe1737a746add0e8e0109133d808
|
||||
|
||||
Probably causing developers to have "too many files open" issue:
|
||||
https://github.com/status-im/status-mobile/issues/16341
|
||||
|
||||
```
|
||||
Error: A non-recoverable condition has triggered. Watchman needs your help!
|
||||
The triggering condition was at timestamp=1687286390: opendir(/Users/javid/Projects/status-mobile/node_modules/metro-core/node_modules/jest-regex-util/build) -> Too many open files
|
||||
All requests will continue to fail with this message until you resolve
|
||||
the underlying problem. You will find more information on fixing this at
|
||||
https://facebook.github.io/watchman/docs/troubleshooting.html#poison-opendir
|
||||
```
|
||||
|
||||
# Fix
|
||||
This is an attempt to fix the issue by downgrading the watchman
|
||||
|
||||
# Upgrade
|
||||
When upgrading in the future, please read the comments:
|
||||
https://github.com/status-im/status-mobile/issues/16341
|
||||
@@ -0,0 +1,48 @@
|
||||
{ stdenv, lib, config, fetchFromGitHub, autoconf, automake, pcre
|
||||
, libtool, pkg-config, openssl
|
||||
, confFile ? config.watchman.confFile or null
|
||||
, withApple ? stdenv.isDarwin, CoreServices
|
||||
}:
|
||||
|
||||
stdenv.mkDerivation rec {
|
||||
pname = "watchman";
|
||||
version = "4.9.0";
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "facebook";
|
||||
repo = "watchman";
|
||||
rev = "v${version}";
|
||||
sha256 = "0fdaj5pmicm6j17d5q7px800m5rmam1a400x3hv1iiifnmhgnkal";
|
||||
};
|
||||
|
||||
nativeBuildInputs = [ autoconf automake pkg-config libtool ];
|
||||
buildInputs = [ pcre openssl ]
|
||||
#++ lib.optionals withApple [ CoreServices ];
|
||||
++ lib.optionals stdenv.isDarwin [ CoreServices ];
|
||||
|
||||
configureFlags = [
|
||||
"--enable-lenient"
|
||||
"--enable-conffile=${if confFile == null then "no" else confFile}"
|
||||
"--with-pcre=yes"
|
||||
|
||||
# For security considerations re: --disable-statedir, see:
|
||||
# https://github.com/facebook/watchman/issues/178
|
||||
"--disable-statedir"
|
||||
];
|
||||
|
||||
prePatch = ''
|
||||
patchShebangs .
|
||||
'';
|
||||
|
||||
preConfigure = ''
|
||||
./autogen.sh
|
||||
'';
|
||||
|
||||
meta = with lib; {
|
||||
description = "Watches files and takes action when they change";
|
||||
homepage = "https://facebook.github.io/watchman";
|
||||
maintainers = with maintainers; [ cstrahan ];
|
||||
platforms = with platforms; linux ++ darwin;
|
||||
license = licenses.asl20;
|
||||
};
|
||||
}
|
||||
@@ -25,7 +25,7 @@ cleanup() {
|
||||
|
||||
# If you want to clean after every build set _NIX_CLEAN=true
|
||||
if [[ -n "${_NIX_CLEAN}" ]]; then
|
||||
trap cleanup EXIT ERR INT QUIT
|
||||
trap cleanup EXIT ERR INT QUIT
|
||||
fi
|
||||
|
||||
# build output will end up under /nix, we have to extract it
|
||||
@@ -44,6 +44,12 @@ if [[ -z "${TARGET}" ]]; then
|
||||
exit 1
|
||||
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.release)$ ]]; then
|
||||
os=$(uname -s | tr '[:upper:]' '[:lower:]')
|
||||
export NIXPKGS_SYSTEM_OVERRIDE="x86_64-${os}"
|
||||
fi
|
||||
|
||||
# Some defaults flags, --pure could be optional in the future.
|
||||
# NOTE: The --keep-failed flag can be used for debugging issues.
|
||||
nixOpts=(
|
||||
|
||||
@@ -8,7 +8,8 @@ file_group() {
|
||||
if [[ "${UNAME}" == "Linux" ]]; then
|
||||
stat -Lc "%G" "${1}" 2>/dev/null
|
||||
elif [[ "${UNAME}" == "Darwin" ]]; then
|
||||
stat -Lf "%Sg" "${1}" 2>/dev/null
|
||||
# Avoid using Nix GNU stat when in Nix shell.
|
||||
/usr/bin/stat -Lf "%Sg" "${1}" 2>/dev/null
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
#
|
||||
# This script is used by the Makefile to have an implicit nix-shell.
|
||||
# The following environment variables modify the script behavior:
|
||||
# - TARGET: This attribute is passed via --attr to Nix, defining the scope.
|
||||
@@ -64,6 +63,12 @@ if [[ -n "${_NIX_PURE}" ]]; then
|
||||
pureDesc='pure '
|
||||
fi
|
||||
|
||||
# Hack fix for missing Android SDK for aarch64 on Darwin. See systemOverride in `nix/pkgs.nix`.
|
||||
if [[ "${TARGET}" =~ ^(android-sdk|android|gradle|keytool|status-go)$ ]]; then
|
||||
os=$(uname -s | tr '[:upper:]' '[:lower:]')
|
||||
export NIXPKGS_SYSTEM_OVERRIDE="x86_64-${os}"
|
||||
fi
|
||||
|
||||
echo -e "${GRN}Configuring ${pureDesc}Nix shell for target '${TARGET}'...${RST}" 1>&2
|
||||
|
||||
# Save derivation from being garbage collected
|
||||
|
||||
@@ -90,7 +90,6 @@
|
||||
"@testing-library/react-native": "^11.2.0",
|
||||
"@types/jest": "^28.1.6",
|
||||
"concurrently": "^7.6.0",
|
||||
"detox": "^19.9.1",
|
||||
"jest": "^26.6.3",
|
||||
"jest-circus": "^26.0.0",
|
||||
"jest-image-snapshot": "^5.1.0",
|
||||
|
||||
@@ -194,4 +194,4 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
After Width: | Height: | Size: 593 KiB |
|
After Width: | Height: | Size: 1.0 MiB |
|
After Width: | Height: | Size: 111 KiB |
|
After Width: | Height: | Size: 210 KiB |
|
After Width: | Height: | Size: 242 KiB |
|
After Width: | Height: | Size: 520 KiB |
|
After Width: | Height: | Size: 213 KiB |
|
After Width: | Height: | Size: 414 KiB |
|
After Width: | Height: | Size: 295 KiB |
|
After Width: | Height: | Size: 540 KiB |
|
After Width: | Height: | Size: 300 KiB |
|
After Width: | Height: | Size: 566 KiB |
@@ -0,0 +1,33 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -eof pipefail
|
||||
|
||||
FILES=$(comm -23 <(sort <(git ls-files --cached --others --exclude-standard)) <(sort <(git ls-files --deleted)) | grep --ignore-case -E '\.(java|cpp|nix|json|sh|md|js|clj|cljs|cljc|edn)$')
|
||||
N_FILES=$(echo "$FILES" | wc -l)
|
||||
LINT_SHOULD_FIX=0
|
||||
|
||||
if [[ -n $1 && $1 != '--fix' ]]; then
|
||||
echo "Unknown option '$1'" >&2
|
||||
exit 1
|
||||
elif [[ $1 == '--fix' ]]; then
|
||||
LINT_SHOULD_FIX=1
|
||||
fi
|
||||
|
||||
echo "Checking ${N_FILES} files for missing trailing newlines."
|
||||
|
||||
# Do not process the whole file and only check the last character. Ignore empty
|
||||
# files. Taken from https://stackoverflow.com/a/10082466.
|
||||
for file in $FILES; do
|
||||
if [ -s "$file" ] && [ "$(tail -c1 "$file"; echo x)" != $'\nx' ]; then
|
||||
if [[ $LINT_SHOULD_FIX -eq 1 ]]; then
|
||||
echo "" >>"$file"
|
||||
else
|
||||
LINT_ERROR=1
|
||||
echo "No trailing newline: $file" >&2
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ $LINT_ERROR -eq 1 ]]; then
|
||||
exit 1
|
||||
fi
|
||||
@@ -0,0 +1,92 @@
|
||||
import { useAnimatedStyle, useDerivedValue } from 'react-native-reanimated';
|
||||
|
||||
export function background(color, progress) {
|
||||
return useDerivedValue(function () {
|
||||
'worklet';
|
||||
const r = parseInt(color.substring(1, 3), 16);
|
||||
const g = parseInt(color.substring(3, 5), 16);
|
||||
const b = parseInt(color.substring(5, 7), 16);
|
||||
|
||||
return progress.value <= 25 ? `rgba(${r}, ${g}, ${b}, .4)` : `rgba(${r}, ${g}, ${b}, .2)`;
|
||||
});
|
||||
}
|
||||
|
||||
export function opacity(progress) {
|
||||
return useDerivedValue(function () {
|
||||
'worklet';
|
||||
return progress.value <= 25 ? 1 : 0.3;
|
||||
});
|
||||
}
|
||||
|
||||
export function avatarOpacity(progress) {
|
||||
return useDerivedValue(function () {
|
||||
'worklet';
|
||||
const progressValue = progress.value;
|
||||
|
||||
switch (true) {
|
||||
case progressValue <= 25:
|
||||
return 1;
|
||||
case progressValue <= 50:
|
||||
return 0.1;
|
||||
default:
|
||||
return 0.3;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function ringOpacity(progress) {
|
||||
return useDerivedValue(function () {
|
||||
'worklet';
|
||||
return progress.value <= 50 ? 1 : 0.3;
|
||||
});
|
||||
}
|
||||
|
||||
export function userHashOpacity(progress) {
|
||||
return useDerivedValue(function () {
|
||||
'worklet';
|
||||
const progressValue = progress.value;
|
||||
switch (true) {
|
||||
case progressValue <= 25:
|
||||
return 1;
|
||||
case progressValue <= 50:
|
||||
return 0.3;
|
||||
case progressValue <= 75:
|
||||
return 1;
|
||||
default:
|
||||
return 0.3;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function userHashColor(progress) {
|
||||
return useDerivedValue(function () {
|
||||
'worklet';
|
||||
const progressValue = progress.value;
|
||||
switch (true) {
|
||||
case progressValue <= 25:
|
||||
return 'rgba(255, 255, 255, .6)';
|
||||
case progressValue <= 50:
|
||||
return 'rgba(255, 255, 255, .6)';
|
||||
case progressValue <= 75:
|
||||
return 'rgb(255, 255, 255)';
|
||||
default:
|
||||
return 'rgba(255, 255, 255, .6)';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function emojiHashStyle(progress) {
|
||||
return useAnimatedStyle(function () {
|
||||
'worklet';
|
||||
const progressValue = progress.value;
|
||||
|
||||
switch (true) {
|
||||
case progressValue <= 25:
|
||||
return { opacity: 1 };
|
||||
case progressValue <= 75:
|
||||
return { opacity: 0.3 };
|
||||
default:
|
||||
return { opacity: 1 };
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -6,3 +6,10 @@ export function infoLayout(input, isTop) {
|
||||
return isTop ? input.value : -input.value;
|
||||
});
|
||||
}
|
||||
|
||||
export function textSheet(input, isHeight) {
|
||||
return useDerivedValue(function () {
|
||||
'worklet';
|
||||
return isHeight ? input.value : -input.value;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { useDerivedValue, withTiming, Easing } from 'react-native-reanimated';
|
||||
|
||||
const slideAnimationDuration = 300;
|
||||
const totalPages = 4;
|
||||
const pageSize = 100 / totalPages;
|
||||
|
||||
const easeOut = {
|
||||
duration: slideAnimationDuration,
|
||||
@@ -15,29 +17,15 @@ export function dynamicProgressBarWidth(staticProgressBarWidth, progress) {
|
||||
});
|
||||
}
|
||||
|
||||
export function carouselLeftPosition(windowWidth, progress) {
|
||||
export function carouselLeftPosition(windowWidth, progress, isDragging, dragAmount) {
|
||||
return useDerivedValue(function () {
|
||||
'worklet';
|
||||
const progressValue = progress.value;
|
||||
switch (true) {
|
||||
case progressValue < 25:
|
||||
return 0;
|
||||
case progressValue === 25:
|
||||
return withTiming(-windowWidth, easeOut);
|
||||
case progressValue < 50:
|
||||
return -windowWidth;
|
||||
case progressValue === 50:
|
||||
return withTiming(-2 * windowWidth, easeOut);
|
||||
case progressValue < 75:
|
||||
return -2 * windowWidth;
|
||||
case progressValue === 75:
|
||||
return withTiming(-3 * windowWidth, easeOut);
|
||||
case progressValue < 100:
|
||||
return -3 * windowWidth;
|
||||
case progressValue === 100:
|
||||
return withTiming(-4 * windowWidth, easeOut);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
const dragAmountValue = dragAmount.value;
|
||||
|
||||
const baseOffset = (Math.floor(progressValue / pageSize) % totalPages) * windowWidth;
|
||||
const adjustedOffset = baseOffset === 0 && dragAmountValue > 0 ? baseOffset : -baseOffset + dragAmountValue;
|
||||
|
||||
return isDragging.value ? withTiming(adjustedOffset, easeOut) : withTiming(-baseOffset, easeOut);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ which is explained in better detail in this video
|
||||
https://www.youtube.com/watch?v=iEBoZDHCN5Y&t=2205s
|
||||
there is a bug with the pitch and roll calculations provided directly from the sensor data so the calculation had to
|
||||
be done using the quaternions directly.
|
||||
This link is useful to understand this: https://engineering.stackexchange.com/questions/3348/calculating-pitch-yaw-and-roll-from-mag-acc-and-gyro-data
|
||||
*/
|
||||
export function sensorAnimatedImage(zIndex, offset, stretch) {
|
||||
'worklet';
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
import { Easing } from 'react-native-reanimated';
|
||||
|
||||
// Home Stack States
|
||||
export const CLOSE_WITH_ANIMATION = 0;
|
||||
export const OPEN_WITH_ANIMATION = 1;
|
||||
export const CLOSE_WITHOUT_ANIMATION = 2;
|
||||
export const OPEN_WITHOUT_ANIMATION = 3;
|
||||
export const CLOSE_WITHOUT_ANIMATION = 0;
|
||||
export const OPEN_WITHOUT_ANIMATION = 1;
|
||||
export const CLOSE_WITH_ANIMATION = 2;
|
||||
export const OPEN_WITH_ANIMATION = 3;
|
||||
|
||||
// Floating Screen States
|
||||
export const CLOSE_SCREEN_WITH_SLIDE_ANIMATION = 0;
|
||||
export const OPEN_SCREEN_WITH_SLIDE_ANIMATION = 1;
|
||||
export const CLOSE_SCREEN_WITH_SHELL_ANIMATION = 2;
|
||||
export const OPEN_SCREEN_WITH_SHELL_ANIMATION = 3;
|
||||
export const CLOSE_SCREEN_WITHOUT_ANIMATION = 4;
|
||||
export const OPEN_SCREEN_WITHOUT_ANIMATION = 5;
|
||||
export const CLOSE_SCREEN_WITHOUT_ANIMATION = 0;
|
||||
export const OPEN_SCREEN_WITHOUT_ANIMATION = 1;
|
||||
export const CLOSE_SCREEN_WITH_SLIDE_ANIMATION = 2;
|
||||
export const OPEN_SCREEN_WITH_SLIDE_ANIMATION = 3;
|
||||
export const CLOSE_SCREEN_WITH_SHELL_ANIMATION = 4;
|
||||
export const OPEN_SCREEN_WITH_SHELL_ANIMATION = 5;
|
||||
|
||||
export const SHELL_ANIMATION_TIME = 200;
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useDerivedValue, withTiming, withSequence, withDelay, Easing } from 'react-native-reanimated';
|
||||
import { useDerivedValue, withTiming, withSequence, withDelay, Easing, runOnJS } from 'react-native-reanimated';
|
||||
import * as constants from './constants';
|
||||
|
||||
// Derived Values
|
||||
@@ -88,3 +88,61 @@ export function screenZIndex(screenState) {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function screenBorderRadius(screenState) {
|
||||
return useDerivedValue(function () {
|
||||
'worklet';
|
||||
switch (screenState.value) {
|
||||
case constants.OPEN_SCREEN_WITH_SHELL_ANIMATION:
|
||||
return withDelay(constants.SHELL_ANIMATION_TIME, withTiming(0, { duration: 0 }));
|
||||
case constants.OPEN_SCREEN_WITH_SLIDE_ANIMATION:
|
||||
case constants.OPEN_SCREEN_WITHOUT_ANIMATION:
|
||||
return 0;
|
||||
case constants.CLOSE_SCREEN_WITH_SLIDE_ANIMATION:
|
||||
return withDelay(constants.SHELL_ANIMATION_TIME, withTiming(20, { duration: 0 }));
|
||||
case constants.CLOSE_SCREEN_WITHOUT_ANIMATION:
|
||||
case constants.CLOSE_SCREEN_WITH_SHELL_ANIMATION:
|
||||
return 20;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function screenGestureOnUpdate(screenLeft) {
|
||||
return function (event) {
|
||||
'worklet';
|
||||
const absoluteX = event.absoluteX;
|
||||
if (absoluteX !== null) {
|
||||
screenLeft.value = event.absoluteX;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function screenGestureOnEnd(data) {
|
||||
return function (event) {
|
||||
'worklet';
|
||||
|
||||
const { screenLeft, screenState, screenWidth, leftVelocity, rightVelocity, screenClosedCallback } = data;
|
||||
const absoluteX = event.absoluteX ?? 0;
|
||||
const velocityX = event.velocityX ?? 0;
|
||||
const closeScreen = velocityX > rightVelocity || (velocityX > leftVelocity && absoluteX >= screenWidth / 2);
|
||||
|
||||
// Velocity (points/sec) = Distance/time
|
||||
var animationVelocity = (screenWidth * 1000) / constants.SHELL_ANIMATION_TIME;
|
||||
|
||||
if (Math.abs(velocityX) > animationVelocity) {
|
||||
animationVelocity = velocityX; // Faster fling
|
||||
}
|
||||
|
||||
const newDistance = closeScreen ? screenWidth - absoluteX : absoluteX;
|
||||
const animationTime = (newDistance * 1000) / animationVelocity;
|
||||
|
||||
screenLeft.value = withTiming(closeScreen ? screenWidth : 0, {
|
||||
duration: animationTime,
|
||||
easing: Easing.bezier(0, 0, 0.58, 1),
|
||||
});
|
||||
|
||||
if (closeScreen) {
|
||||
runOnJS(screenClosedCallback)(animationTime);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -364,77 +364,79 @@ globalThis.__STATUS_MOBILE_JS_IDENTITY_PROXY__ = new Proxy({}, {get() { return (
|
||||
(defn mock
|
||||
[module]
|
||||
(case module
|
||||
"react-native-languages" react-native-languages
|
||||
"react-native-background-timer" background-timer
|
||||
"react-native-image-crop-picker" image-crop-picker
|
||||
"react-native-gesture-handler" react-native-gesture-handler
|
||||
"react-native-static-safe-area-insets" react-native-static-safe-area-insets
|
||||
"react-native-config" config
|
||||
"react-native-iphone-x-helper" (clj->js {:getStatusBarHeight (fn [])
|
||||
:getBottomSpace (fn [])})
|
||||
"react-native-screens" (clj->js {})
|
||||
"react-native-reanimated" react-native-reanimated
|
||||
"react-native-redash/lib/module/v1" react-native-redash
|
||||
"react-native-redash" react-native-redash
|
||||
"react-native-fetch-polyfill" fetch
|
||||
"react-native-status-keycard" status-keycard
|
||||
"react-native-keychain" keychain
|
||||
"react-native-touch-id" touchid
|
||||
"@react-native-community/netinfo" net-info
|
||||
"react-native-dialogs" dialogs
|
||||
"react-native" react-native
|
||||
"react-native-fs" fs
|
||||
"react-native-mail" react-native-mail
|
||||
"react-native-image-resizer" image-resizer
|
||||
"react-native-haptic-feedback" react-native-haptic-feedback
|
||||
"react-native-device-info" react-native-device-info
|
||||
"react-native-push-notification" react-native-push-notification
|
||||
"react-native-linear-gradient" react-native-gradien
|
||||
"@react-native-community/masked-view" masked-view
|
||||
"react-native-blob-util" react-native-blob-util
|
||||
"react-native-navigation" react-native-navigation
|
||||
"@react-native-community/push-notification-ios" push-notification-ios
|
||||
"@react-native-community/blur" react-native-blur
|
||||
"@react-native-community/cameraroll" react-native-camera-roll
|
||||
"react-native-camera-kit" react-native-camera-kit
|
||||
"react-native-permissions" react-native-permissions
|
||||
"rn-emoji-keyboard" rn-emoji-keyboard
|
||||
"react-native-hole-view" react-native-hole-view
|
||||
"react-native-draggable-flatlist" react-native-draggable-flatlist
|
||||
"react-native-webview" react-native-webview
|
||||
"@react-native-community/audio-toolkit" react-native-audio-toolkit
|
||||
"react-native-image-viewing" react-native-image-viewing
|
||||
"react-native-share" react-native-share
|
||||
"@react-native-async-storage/async-storage" async-storage
|
||||
"react-native-svg" react-native-svg
|
||||
"react-native-transparent-video" react-native-transparent-video
|
||||
"react-native-orientation-locker" react-native-orientation-locker
|
||||
"../src/js/worklets/core.js" worklet-factory
|
||||
"../src/js/worklets/shell/bottom_tabs.js" #js {}
|
||||
"../src/js/worklets/shell/home_stack.js" #js {}
|
||||
"../src/js/worklets/shell/floating_screen.js" #js {}
|
||||
"../src/js/worklets/bottom_sheet.js" #js {}
|
||||
"../src/js/worklets/record_audio.js" #js {}
|
||||
"../src/js/worklets/scroll_view.js" #js {}
|
||||
"../src/js/worklets/onboarding_carousel.js" #js {}
|
||||
"../src/js/worklets/lightbox.js" #js {}
|
||||
"../src/js/worklets/parallax.js" #js {}
|
||||
"./fleets.js" default-fleets
|
||||
"@walletconnect/client" wallet-connect-client
|
||||
"../translations/ar.json" (js/JSON.parse (slurp "./translations/ar.json"))
|
||||
"../translations/de.json" (js/JSON.parse (slurp "./translations/de.json"))
|
||||
"../translations/en.json" (js/JSON.parse (slurp "./translations/en.json"))
|
||||
"../translations/es.json" (js/JSON.parse (slurp "./translations/es.json"))
|
||||
"../translations/es_419.json" (js/JSON.parse (slurp "./translations/es_419.json"))
|
||||
"../translations/fil.json" (js/JSON.parse (slurp "./translations/fil.json"))
|
||||
"../translations/fr.json" (js/JSON.parse (slurp "./translations/fr.json"))
|
||||
"../translations/id.json" (js/JSON.parse (slurp "./translations/id.json"))
|
||||
"../translations/it.json" (js/JSON.parse (slurp "./translations/it.json"))
|
||||
"../translations/ko.json" (js/JSON.parse (slurp "./translations/ko.json"))
|
||||
"../translations/pt_BR.json" (js/JSON.parse (slurp "./translations/pt_BR.json"))
|
||||
"../translations/ru.json" (js/JSON.parse (slurp "./translations/ru.json"))
|
||||
"../translations/tr.json" (js/JSON.parse (slurp "./translations/tr.json"))
|
||||
"../translations/zh.json" (js/JSON.parse (slurp "./translations/zh.json"))
|
||||
"../translations/zh_hant.json" (js/JSON.parse (slurp "./translations/zh_hant.json"))
|
||||
"../translations/zh_TW.json" (js/JSON.parse (slurp "./translations/zh_TW.json"))
|
||||
"react-native-languages" react-native-languages
|
||||
"react-native-background-timer" background-timer
|
||||
"react-native-image-crop-picker" image-crop-picker
|
||||
"react-native-gesture-handler" react-native-gesture-handler
|
||||
"react-native-static-safe-area-insets" react-native-static-safe-area-insets
|
||||
"react-native-config" config
|
||||
"react-native-iphone-x-helper" (clj->js {:getStatusBarHeight (fn [])
|
||||
:getBottomSpace (fn [])})
|
||||
"react-native-screens" (clj->js {})
|
||||
"react-native-reanimated" react-native-reanimated
|
||||
"react-native-redash/lib/module/v1" react-native-redash
|
||||
"react-native-redash" react-native-redash
|
||||
"react-native-fetch-polyfill" fetch
|
||||
"react-native-status-keycard" status-keycard
|
||||
"react-native-keychain" keychain
|
||||
"react-native-touch-id" touchid
|
||||
"@react-native-community/netinfo" net-info
|
||||
"react-native-dialogs" dialogs
|
||||
"react-native" react-native
|
||||
"react-native-fs" fs
|
||||
"react-native-mail" react-native-mail
|
||||
"react-native-image-resizer" image-resizer
|
||||
"react-native-haptic-feedback" react-native-haptic-feedback
|
||||
"react-native-device-info" react-native-device-info
|
||||
"react-native-push-notification" react-native-push-notification
|
||||
"react-native-linear-gradient" react-native-gradien
|
||||
"@react-native-community/masked-view" masked-view
|
||||
"react-native-blob-util" react-native-blob-util
|
||||
"react-native-navigation" react-native-navigation
|
||||
"@react-native-community/push-notification-ios" push-notification-ios
|
||||
"@react-native-community/blur" react-native-blur
|
||||
"@react-native-community/cameraroll" react-native-camera-roll
|
||||
"react-native-camera-kit" react-native-camera-kit
|
||||
"react-native-permissions" react-native-permissions
|
||||
"rn-emoji-keyboard" rn-emoji-keyboard
|
||||
"react-native-hole-view" react-native-hole-view
|
||||
"react-native-draggable-flatlist" react-native-draggable-flatlist
|
||||
"react-native-webview" react-native-webview
|
||||
"@react-native-community/audio-toolkit" react-native-audio-toolkit
|
||||
"react-native-image-viewing" react-native-image-viewing
|
||||
"react-native-share" react-native-share
|
||||
"@react-native-async-storage/async-storage" async-storage
|
||||
"react-native-svg" react-native-svg
|
||||
"react-native-transparent-video" react-native-transparent-video
|
||||
"react-native-orientation-locker" react-native-orientation-locker
|
||||
"../src/js/worklets/core.js" worklet-factory
|
||||
"../src/js/worklets/shell/bottom_tabs.js" #js {}
|
||||
"../src/js/worklets/shell/home_stack.js" #js {}
|
||||
"../src/js/worklets/shell/floating_screen.js" #js {}
|
||||
"../src/js/worklets/bottom_sheet.js" #js {}
|
||||
"../src/js/worklets/record_audio.js" #js {}
|
||||
"../src/js/worklets/scroll_view.js" #js {}
|
||||
"../src/js/worklets/onboarding_carousel.js" #js {}
|
||||
"../src/js/worklets/lightbox.js" #js {}
|
||||
"../src/js/worklets/parallax.js" #js {}
|
||||
"../src/js/worklets/identifiers_highlighting.js" #js {}
|
||||
"./fleets.js" default-fleets
|
||||
"@walletconnect/client" wallet-connect-client
|
||||
"../translations/ar.json" (js/JSON.parse (slurp "./translations/ar.json"))
|
||||
"../translations/de.json" (js/JSON.parse (slurp "./translations/de.json"))
|
||||
"../translations/en.json" (js/JSON.parse (slurp "./translations/en.json"))
|
||||
"../translations/es.json" (js/JSON.parse (slurp "./translations/es.json"))
|
||||
"../translations/es_419.json" (js/JSON.parse (slurp "./translations/es_419.json"))
|
||||
"../translations/fil.json" (js/JSON.parse (slurp "./translations/fil.json"))
|
||||
"../translations/fr.json" (js/JSON.parse (slurp "./translations/fr.json"))
|
||||
"../translations/id.json" (js/JSON.parse (slurp "./translations/id.json"))
|
||||
"../translations/it.json" (js/JSON.parse (slurp "./translations/it.json"))
|
||||
"../translations/ko.json" (js/JSON.parse (slurp "./translations/ko.json"))
|
||||
"../translations/pt_BR.json" (js/JSON.parse (slurp "./translations/pt_BR.json"))
|
||||
"../translations/ru.json" (js/JSON.parse (slurp "./translations/ru.json"))
|
||||
"../translations/tr.json" (js/JSON.parse (slurp "./translations/tr.json"))
|
||||
"../translations/zh.json" (js/JSON.parse (slurp "./translations/zh.json"))
|
||||
"../translations/zh_hant.json" (js/JSON.parse (slurp
|
||||
"./translations/zh_hant.json"))
|
||||
"../translations/zh_TW.json" (js/JSON.parse (slurp "./translations/zh_TW.json"))
|
||||
nil))
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
[taoensso.timbre :as log]
|
||||
[react-native.platform :as platform]
|
||||
[react-native.core :as rn]
|
||||
[utils.transforms :as types]))
|
||||
[utils.transforms :as types]
|
||||
[clojure.string :as string]))
|
||||
|
||||
(defn status
|
||||
[]
|
||||
@@ -286,11 +287,11 @@
|
||||
and then compressed. Example input/output :
|
||||
input key = zQ3shTAten2v9CwyQD1Kc7VXAqNPDcHZAMsfbLHCZEx6nFqk9 and
|
||||
output key = 0x025596a7ff87da36860a84b0908191ce60a504afc94aac93c1abd774f182967ce6"
|
||||
[key callback]
|
||||
[input-key callback]
|
||||
(log/info "[native-module] Deserializing and then compressing public key"
|
||||
{:fn :deserialize-and-compress-key
|
||||
:key key})
|
||||
(.deserializeAndCompressKey ^js (status) key callback))
|
||||
:key input-key})
|
||||
(.deserializeAndCompressKey ^js (status) input-key callback))
|
||||
|
||||
(defn compressed-key->public-key
|
||||
"Provides compressed key to status-go and gets back the uncompressed public key via deserialization"
|
||||
@@ -387,6 +388,14 @@
|
||||
:build-id (.-buildId status)
|
||||
:device-id (.-deviceId status)}))
|
||||
|
||||
(defn get-installation-name
|
||||
[]
|
||||
;; NOTE(rasom): Only needed for android devices currently
|
||||
(when platform/android?
|
||||
(string/join " "
|
||||
((juxt :model :device-id)
|
||||
(get-device-model-info)))))
|
||||
|
||||
(defn get-node-config
|
||||
[callback]
|
||||
(log/debug "[native-module] get-node-config")
|
||||
|
||||
@@ -235,31 +235,6 @@
|
||||
[value velocity snap-points]
|
||||
(.snapPoint ^js redash value velocity (to-array snap-points)))
|
||||
|
||||
(defn cancelable-loop
|
||||
[{:keys [clock duration finished on-reach]}]
|
||||
(let [time (value 0)
|
||||
frame-time (value 0)
|
||||
position (value 0)
|
||||
to-value (value 1)
|
||||
state {:time time
|
||||
:frameTime frame-time
|
||||
:finished finished
|
||||
:position position}
|
||||
config {:toValue to-value
|
||||
:duration duration
|
||||
:easing (:linear easings)}]
|
||||
(block
|
||||
[(timing clock state config)
|
||||
(cond* (and* finished
|
||||
(eq position to-value))
|
||||
(call* [] on-reach))
|
||||
(cond* finished
|
||||
[(set finished 0)
|
||||
(set time 0)
|
||||
(set frame-time 0)
|
||||
(set position 0)])
|
||||
position])))
|
||||
|
||||
(defn with-easing
|
||||
[{val :value
|
||||
:keys [snap-points velocity offset state easing duration
|
||||
|
||||
@@ -11,4 +11,4 @@
|
||||
(for [i (keys icons/icons)]
|
||||
[rn/view {:flex-direction :row}
|
||||
[icons/icon (keyword i)]
|
||||
[rn/text i]])])
|
||||
[rn/text i]])])
|
||||
|
||||
@@ -1,12 +1,5 @@
|
||||
(ns quo.previews.preview)
|
||||
|
||||
(defn descriptor->values
|
||||
[{:keys [key options type]}]
|
||||
{key (case type
|
||||
:boolean [false true]
|
||||
:text [nil "Just simple text"] ; NOTE(Ferossgp): add example with long text?
|
||||
:select (mapv :key options))})
|
||||
|
||||
(defmacro list-comp
|
||||
[[binding seq-expr & bindings] body-expr]
|
||||
(cond (not binding)
|
||||
|
||||
@@ -68,8 +68,8 @@
|
||||
:background-color (:ui-background @colors/theme)})
|
||||
|
||||
(defn customizer-boolean
|
||||
[{:keys [label key state]}]
|
||||
(let [state* (reagent/cursor state [key])]
|
||||
[{:keys [label state] :as args}]
|
||||
(let [state* (reagent/cursor state [(:key args)])]
|
||||
[rn/view {:style container}
|
||||
[label-view state label]
|
||||
[rn/view
|
||||
@@ -95,8 +95,8 @@
|
||||
"False"]]]]))
|
||||
|
||||
(defn customizer-text
|
||||
[{:keys [label key state]}]
|
||||
(let [state* (reagent/cursor state [key])]
|
||||
[{:keys [label state] :as args}]
|
||||
(let [state* (reagent/cursor state [(:key args)])]
|
||||
[rn/view {:style container}
|
||||
[label-view state label]
|
||||
[rn/view {:style {:flex 0.6}}
|
||||
@@ -117,8 +117,8 @@
|
||||
(defn customizer-select
|
||||
[]
|
||||
(let [open (reagent/atom nil)]
|
||||
(fn [{:keys [label key state options]}]
|
||||
(let [state* (reagent/cursor state [key])
|
||||
(fn [{:keys [label state options] :as args}]
|
||||
(let [state* (reagent/cursor state [(:key args)])
|
||||
selected (value-for-key @state* options)]
|
||||
[rn/view {:style container}
|
||||
[label-view state label]
|
||||
@@ -133,15 +133,15 @@
|
||||
[rn/view {:style (modal-view)}
|
||||
[rn/scroll-view
|
||||
(doall
|
||||
(for [{:keys [key value]} options]
|
||||
^{:key key}
|
||||
(for [{k :key v :value} options]
|
||||
^{:key k}
|
||||
[rn/touchable-opacity
|
||||
{:style (select-option-style (= @state* key))
|
||||
{:style (select-option-style (= @state* k))
|
||||
:on-press #(do
|
||||
(reset! open false)
|
||||
(reset! state* key))}
|
||||
[quo/text {:color (if (= @state* key) :link :secondary)}
|
||||
value]]))
|
||||
(reset! state* k))}
|
||||
[quo/text {:color (if (= @state* k) :link :secondary)}
|
||||
v]]))
|
||||
[rn/view {:flex-direction :row}
|
||||
[rn/touchable-opacity
|
||||
{:style (select-option-style false)
|
||||
@@ -175,17 +175,15 @@
|
||||
{:style {:flex 1}
|
||||
:padding-horizontal 16}
|
||||
(doall
|
||||
(for [{:keys [key type]
|
||||
:as desc}
|
||||
descriptors
|
||||
:let [descriptor (merge desc
|
||||
{:state state})]]
|
||||
^{:key key}
|
||||
(for [desc descriptors
|
||||
:let [descriptor (merge desc {:state state})]]
|
||||
^{:key (:key desc)}
|
||||
[:<>
|
||||
(case type
|
||||
(case (:type desc)
|
||||
:boolean [customizer-boolean descriptor]
|
||||
:text [customizer-text descriptor]
|
||||
:select [customizer-select descriptor])]))])
|
||||
:select [customizer-select descriptor]
|
||||
nil)]))])
|
||||
|
||||
(comment
|
||||
[{:label "Show error:"
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
(ns quo2.components.avatars.channel-avatar
|
||||
(:require [quo2.components.icon :as icons]
|
||||
[quo2.components.markdown.text :as text]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[quo2.theme :as theme]
|
||||
[react-native.core :as rn]))
|
||||
|
||||
(defn channel-avatar
|
||||
[{:keys [big? locked? emoji-background-color emoji]}]
|
||||
(let [lock-exists? locked?
|
||||
dark? (theme/dark?)]
|
||||
[rn/view
|
||||
{:style {:width (if big? 32 24)
|
||||
:height (if big? 32 24)
|
||||
:border-radius (if big? 32 24)
|
||||
:justify-content :center
|
||||
:align-items :center
|
||||
:background-color emoji-background-color}}
|
||||
[rn/view
|
||||
{:style {:display :flex
|
||||
:justify-content :center
|
||||
:align-items :center}}
|
||||
[text/text
|
||||
{:size (if big?
|
||||
:paragraph-1
|
||||
:label)} emoji]
|
||||
(when lock-exists?
|
||||
[rn/view
|
||||
{:style {:position :absolute
|
||||
:left (if big?
|
||||
14
|
||||
8)
|
||||
:top (if big?
|
||||
15
|
||||
8)
|
||||
:background-color (if dark?
|
||||
colors/neutral-90
|
||||
colors/white)
|
||||
:border-radius 15
|
||||
:padding 2}}
|
||||
[icons/icon
|
||||
(if locked?
|
||||
:main-icons/locked
|
||||
:main-icons/unlocked)
|
||||
{:color (if dark?
|
||||
colors/neutral-40
|
||||
colors/neutral-50)
|
||||
:container-style {:width 12
|
||||
:height 12}
|
||||
:size 12}]])]]))
|
||||
@@ -0,0 +1,35 @@
|
||||
(ns quo2.components.avatars.channel-avatar.component-spec
|
||||
(:require [quo2.components.avatars.channel-avatar.view :as component]
|
||||
[test-helpers.component :as h]))
|
||||
|
||||
(h/describe "Channel Avatar"
|
||||
(h/test "default render"
|
||||
(h/render [component/view])
|
||||
(h/is-truthy (h/query-by-label-text :initials))
|
||||
(h/is-null (h/query-by-label-text :emoji))
|
||||
(h/is-null (h/query-by-label-text :lock)))
|
||||
|
||||
(h/test "with emoji, no lock set, large size"
|
||||
(let [emoji "🍓"]
|
||||
(h/render [component/view {:emoji emoji :size :size/l}])
|
||||
(h/is-null (h/query-by-label-text :initials))
|
||||
(h/is-truthy (h/query-by-text emoji))
|
||||
(h/is-null (h/query-by-label-text :lock))))
|
||||
|
||||
(h/test "locked"
|
||||
(h/render [component/view {:locked? true}])
|
||||
(h/is-truthy (h/query-by-label-text :lock)))
|
||||
|
||||
(h/test "unlocked"
|
||||
(h/render [component/view {:locked? false}])
|
||||
(h/is-truthy (h/query-by-label-text :lock)))
|
||||
|
||||
(h/test "no emoji, smaller size"
|
||||
(h/render [component/view {:full-name "Status Mobile"}])
|
||||
(h/is-truthy (h/query-by-text "S")))
|
||||
|
||||
(h/test "no emoji, large size"
|
||||
(h/render [component/view
|
||||
{:full-name "Status Mobile"
|
||||
:size :size/l}])
|
||||
(h/is-truthy (h/query-by-text "SM"))))
|
||||
@@ -0,0 +1,28 @@
|
||||
(ns quo2.components.avatars.channel-avatar.style
|
||||
(:require [quo2.foundations.colors :as colors]))
|
||||
|
||||
(def lock-icon-size 12)
|
||||
|
||||
(defn outer-container
|
||||
[{:keys [size color]}]
|
||||
(let [size (if (= size :size/l) 32 24)]
|
||||
{:width size
|
||||
:height size
|
||||
:border-radius size
|
||||
:justify-content :center
|
||||
:align-items :center
|
||||
:background-color (colors/theme-alpha color 0.1 0.1)}))
|
||||
|
||||
(defn lock-container
|
||||
[size]
|
||||
(let [distance (if (= size :size/l) 20 12)]
|
||||
{:position :absolute
|
||||
:left distance
|
||||
:top distance
|
||||
:background-color (colors/theme-colors colors/white colors/neutral-95)
|
||||
:border-radius (* 2 lock-icon-size)
|
||||
:padding 2}))
|
||||
|
||||
(def lock-icon
|
||||
{:width lock-icon-size
|
||||
:height lock-icon-size})
|
||||
@@ -0,0 +1,60 @@
|
||||
(ns quo2.components.avatars.channel-avatar.view
|
||||
(:require [clojure.string :as string]
|
||||
[quo2.components.avatars.channel-avatar.style :as style]
|
||||
[quo2.components.icon :as icons]
|
||||
[quo2.components.markdown.text :as text]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[react-native.core :as rn]
|
||||
utils.string))
|
||||
|
||||
(defn- initials
|
||||
[full-name size color]
|
||||
(let [amount-initials (if (= size :size/l) 2 1)]
|
||||
[text/text
|
||||
{:accessibility-label :initials
|
||||
:size :paragraph-2
|
||||
:weight :semi-bold
|
||||
:style {:color color}}
|
||||
(utils.string/get-initials full-name amount-initials)]))
|
||||
|
||||
(defn- lock
|
||||
[locked? size]
|
||||
;; When `locked?` is nil, we must not display the unlocked icon.
|
||||
(when (boolean? locked?)
|
||||
[rn/view
|
||||
{:accessibility-label :lock
|
||||
:style (style/lock-container size)}
|
||||
[icons/icon (if locked? :i/locked :i/unlocked)
|
||||
{:color (colors/theme-colors colors/neutral-50 colors/neutral-40)
|
||||
:container-style style/lock-icon
|
||||
:size 12}]]))
|
||||
|
||||
(defn view
|
||||
"Options:
|
||||
|
||||
:size - keyword (default nil) - Container size, for the moment,
|
||||
only :size/l (meaning large) is supported.
|
||||
|
||||
:emoji - string (default nil)
|
||||
|
||||
:customization-color - color (default nil) If the component is used for a
|
||||
community channel, then the default color should be the community custom
|
||||
color.
|
||||
|
||||
:locked? - nil/bool (default nil) - When true/false display a locked/unlocked
|
||||
icon respectively. When nil does not show icon.
|
||||
|
||||
:full-name - string (default nil) - When :emoji is blank, this value will be
|
||||
used to extract the initials.
|
||||
"
|
||||
[{:keys [size emoji customization-color locked? full-name]}]
|
||||
[rn/view
|
||||
{:accessibility-label :channel-avatar
|
||||
:style (style/outer-container {:size size :color customization-color})}
|
||||
(if (string/blank? emoji)
|
||||
[initials full-name size customization-color]
|
||||
[text/text
|
||||
{:accessibility-label :emoji
|
||||
:size (if (= size :size/l) :paragraph-1 :label)}
|
||||
(string/trim emoji)])
|
||||
[lock locked? size]])
|
||||
@@ -1,22 +1,9 @@
|
||||
(ns quo2.components.avatars.user-avatar.view
|
||||
(:require [clojure.string :as string]
|
||||
[quo2.components.avatars.user-avatar.style :as style]
|
||||
(:require [quo2.components.avatars.user-avatar.style :as style]
|
||||
[quo2.components.markdown.text :as text]
|
||||
[react-native.core :as rn]
|
||||
[react-native.fast-image :as fast-image]))
|
||||
|
||||
(defn trim-whitespace [s] (string/join " " (string/split (string/trim s) #"\s+")))
|
||||
|
||||
(defn- extract-initials
|
||||
[full-name amount-initials]
|
||||
(let [upper-case-first-letter (comp string/upper-case first)
|
||||
names-list (string/split (trim-whitespace full-name) " ")]
|
||||
(if (= (first names-list) "")
|
||||
""
|
||||
(->> names-list
|
||||
(map upper-case-first-letter)
|
||||
(take amount-initials)
|
||||
(string/join)))))
|
||||
[react-native.fast-image :as fast-image]
|
||||
utils.string))
|
||||
|
||||
(defn initials-avatar
|
||||
[{:keys [full-name size draw-ring? customization-color]}]
|
||||
@@ -29,7 +16,7 @@
|
||||
{:style style/initials-avatar-text
|
||||
:size font-size
|
||||
:weight :semi-bold}
|
||||
(extract-initials full-name amount-initials)]]))
|
||||
(utils.string/get-initials full-name amount-initials)]]))
|
||||
|
||||
(def valid-ring-sizes #{:big :medium :small})
|
||||
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
(ns quo2.components.buttons.--tests--.buttons-component-spec
|
||||
(:require ["@testing-library/react-native" :as rtl]
|
||||
[quo2.components.buttons.button :as button]
|
||||
[reagent.core :as reagent]))
|
||||
|
||||
(defn render-button
|
||||
([options label]
|
||||
(rtl/render (reagent/as-element [button/button options label]))))
|
||||
|
||||
(js/global.test "default render of button component"
|
||||
(fn []
|
||||
(render-button {:accessibility-label "test-button"} "")
|
||||
(-> (js/expect (rtl/screen.getByLabelText "test-button"))
|
||||
(.toBeTruthy))))
|
||||
|
||||
(js/global.test "button renders with a label"
|
||||
(fn []
|
||||
(render-button {} "test-label")
|
||||
(-> (js/expect (rtl/screen.getByText "test-label"))
|
||||
(.toBeTruthy))))
|
||||
|
||||
(js/global.test "button on-press works"
|
||||
(let [event (js/jest.fn)]
|
||||
(fn []
|
||||
(render-button {:on-press event} "test-label")
|
||||
(rtl/fireEvent.press (rtl/screen.getByText "test-label"))
|
||||
(-> (js/expect event)
|
||||
(.toHaveBeenCalledTimes 1)))))
|
||||
@@ -0,0 +1,18 @@
|
||||
(ns quo2.components.buttons.button.component-spec
|
||||
(:require [quo2.components.buttons.button.view :as button]
|
||||
[test-helpers.component :as h]))
|
||||
|
||||
(h/describe "button tests"
|
||||
(h/test "default render of button component"
|
||||
(h/render [button/button {:accessibility-label "test-button"} ""])
|
||||
(h/is-truthy (h/get-by-label-text "test-button")))
|
||||
|
||||
(h/test "button renders with a label"
|
||||
(h/render [button/button {} "test-label"])
|
||||
(h/is-truthy (h/get-by-text "test-label")))
|
||||
|
||||
(h/test "button on-press works"
|
||||
(let [event (h/mock-fn)]
|
||||
(h/render [button/button {:on-press event} "test-label"])
|
||||
(h/fire-event :press (h/get-by-text "test-label"))
|
||||
(h/was-called event))))
|
||||
@@ -1,10 +1,46 @@
|
||||
(ns quo2.components.buttons.button
|
||||
(:require [quo2.components.icon :as quo2.icons]
|
||||
[quo2.components.markdown.text :as text]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[quo2.theme :as theme]
|
||||
[react-native.core :as rn]
|
||||
[reagent.core :as reagent]))
|
||||
(ns quo2.components.buttons.button.style
|
||||
(:require [quo2.foundations.colors :as colors]))
|
||||
|
||||
(def blur-view
|
||||
{:position :absolute
|
||||
:top 0
|
||||
:left 0
|
||||
:right 0
|
||||
:bottom 0})
|
||||
|
||||
(defn before-icon-style
|
||||
[{:keys [override-margins size icon-container-size icon-background-color icon-container-rounded?
|
||||
icon-size]}]
|
||||
(merge
|
||||
{:margin-left (or (get override-margins :left)
|
||||
(if (= size 40) 12 8))
|
||||
:margin-right (or (get override-margins :right) 4)
|
||||
:align-items :center
|
||||
:justify-content :center}
|
||||
(when icon-container-size
|
||||
{:width icon-container-size
|
||||
:height icon-container-size})
|
||||
(when icon-background-color
|
||||
{:background-color icon-background-color})
|
||||
(when icon-container-rounded?
|
||||
{:border-radius (/ (or icon-container-size icon-size) 2)})))
|
||||
|
||||
(defn after-icon-style
|
||||
[{:keys [override-margins size icon-container-size icon-background-color icon-container-rounded?
|
||||
icon-size]}]
|
||||
(merge
|
||||
{:margin-left (or (get override-margins :left) 4)
|
||||
:margin-right (or (get override-margins :right)
|
||||
(if (= size 40) 12 8))
|
||||
:align-items :center
|
||||
:justify-content :center}
|
||||
(when icon-container-size
|
||||
{:width icon-container-size
|
||||
:height icon-container-size})
|
||||
(when icon-background-color
|
||||
{:background-color icon-background-color})
|
||||
(when icon-container-rounded?
|
||||
{:border-radius (/ (or icon-container-size icon-size) 2)})))
|
||||
|
||||
(defn themes
|
||||
[customization-color]
|
||||
@@ -66,6 +102,16 @@
|
||||
:background-color {:default colors/neutral-80-opa-5
|
||||
:pressed colors/neutral-80-opa-10
|
||||
:disabled colors/neutral-80-opa-5}}
|
||||
:blurred {:icon-color colors/neutral-100
|
||||
:icon-secondary-color colors/neutral-100
|
||||
:icon-background-color {:default colors/neutral-20
|
||||
:blurred colors/neutral-80-opa-10}
|
||||
:label-color colors/neutral-100
|
||||
:background-color {:default colors/neutral-10
|
||||
:pressed colors/neutral-10
|
||||
:disabled colors/neutral-10-opa-10-blur}
|
||||
:blur-overlay-color colors/neutral-10-opa-40-blur
|
||||
:blur-type :light}
|
||||
:blur-bg-outline {:icon-color colors/neutral-100
|
||||
:icon-secondary-color colors/neutral-80-opa-40
|
||||
:label-color colors/neutral-100
|
||||
@@ -135,6 +181,16 @@
|
||||
:background-color {:default colors/white-opa-5
|
||||
:pressed colors/white-opa-10
|
||||
:disabled colors/white-opa-5}}
|
||||
:blurred {:icon-color colors/white
|
||||
:icon-secondary-color colors/white
|
||||
:icon-background-color {:default colors/neutral-80
|
||||
:blurred colors/white-opa-10}
|
||||
:label-color colors/white
|
||||
:background-color {:default colors/neutral-90
|
||||
:pressed colors/neutral-90
|
||||
:disabled colors/neutral-90-opa-10-blur}
|
||||
:blur-overlay-color colors/neutral-80-opa-40
|
||||
:blur-type :dark}
|
||||
:blur-bg-outline {:icon-color colors/white
|
||||
:icon-secondary-color colors/white-opa-40
|
||||
:label-color colors/white
|
||||
@@ -157,12 +213,11 @@
|
||||
24 8))})
|
||||
|
||||
(defn style-container
|
||||
[type size disabled background-color border-color icon above width before after]
|
||||
[{:keys [type size disabled background-color border-color icon above width before after blur-active?]}]
|
||||
(merge {:height size
|
||||
:align-items :center
|
||||
:justify-content :center
|
||||
:flex-direction (if above :column :row)
|
||||
:background-color background-color
|
||||
:padding-horizontal (when-not (or icon before after)
|
||||
(case size
|
||||
56 16
|
||||
@@ -192,7 +247,11 @@
|
||||
56 0
|
||||
40 9
|
||||
32 5
|
||||
24 4))}
|
||||
24 4))
|
||||
:overflow :hidden}
|
||||
(when (or (and (= type :blurred) (not blur-active?))
|
||||
(not= type :blurred))
|
||||
{:background-color background-color})
|
||||
(shape-style-container type icon size)
|
||||
(when width
|
||||
{:width width})
|
||||
@@ -203,109 +262,3 @@
|
||||
:border-width 1})
|
||||
(when disabled
|
||||
{:opacity 0.3})))
|
||||
|
||||
(defn- button-internal
|
||||
"with label
|
||||
[button opts \"label\"]
|
||||
opts
|
||||
{:type :primary/:secondary/:grey/:dark-grey/:outline/:ghost/
|
||||
:danger/:photo-bg/:blur-bg/:blur-bg-outline/:shell/:community
|
||||
:size 40 [default] /32/24
|
||||
:icon true/false
|
||||
:community-color '#FFFFFF'
|
||||
:community-text-color '#000000'
|
||||
:before :icon-keyword
|
||||
:after :icon-keyword}
|
||||
|
||||
only icon
|
||||
[button {:icon true} :i/close-circle]"
|
||||
[_ _]
|
||||
(let [pressed-in (reagent/atom false)]
|
||||
(fn
|
||||
[{:keys [on-press disabled type size before after above icon-secondary-no-color
|
||||
width customization-color theme override-background-color pressed
|
||||
on-long-press accessibility-label icon icon-no-color style inner-style test-ID]
|
||||
:or {type :primary
|
||||
size 40
|
||||
customization-color :primary}}
|
||||
children]
|
||||
(let [{:keys [icon-color icon-secondary-color background-color label-color border-color]}
|
||||
(get-in (themes customization-color)
|
||||
[theme type])
|
||||
state (cond disabled :disabled
|
||||
(or @pressed-in pressed) :pressed
|
||||
:else :default)
|
||||
icon-size (when (= 24 size) 12)
|
||||
icon-secondary-color (or icon-secondary-color icon-color)]
|
||||
[rn/touchable-without-feedback
|
||||
(merge {:test-ID test-ID
|
||||
:disabled disabled
|
||||
:accessibility-label accessibility-label
|
||||
:on-press-in #(reset! pressed-in true)
|
||||
:on-press-out #(reset! pressed-in nil)}
|
||||
(when on-press
|
||||
{:on-press on-press})
|
||||
(when on-long-press
|
||||
{:on-long-press on-long-press}))
|
||||
[rn/view
|
||||
{:style (merge
|
||||
(shape-style-container type icon size)
|
||||
{:width width}
|
||||
style)}
|
||||
[rn/view
|
||||
{:style (merge
|
||||
(style-container
|
||||
type
|
||||
size
|
||||
disabled
|
||||
(or override-background-color (get background-color state))
|
||||
(get border-color state)
|
||||
icon
|
||||
above
|
||||
width
|
||||
before
|
||||
after)
|
||||
(when (= state :pressed) {:opacity 0.9})
|
||||
inner-style)}
|
||||
(when above
|
||||
[rn/view
|
||||
[quo2.icons/icon above
|
||||
{:container-style {:margin-bottom 2}
|
||||
:color icon-secondary-color
|
||||
:size icon-size}]])
|
||||
(when before
|
||||
[rn/view
|
||||
[quo2.icons/icon before
|
||||
{:container-style {:margin-left (if (= size 40) 12 8)
|
||||
:margin-right 4}
|
||||
:color icon-secondary-color
|
||||
:size icon-size}]])
|
||||
[rn/view
|
||||
(cond
|
||||
(or icon icon-no-color)
|
||||
[quo2.icons/icon children
|
||||
{:color icon-color
|
||||
:no-color icon-no-color
|
||||
:size icon-size}]
|
||||
|
||||
(string? children)
|
||||
[text/text
|
||||
{:size (when (#{56 24} size) :paragraph-2)
|
||||
:weight :medium
|
||||
:number-of-lines 1
|
||||
:style {:color label-color}}
|
||||
|
||||
children]
|
||||
|
||||
(vector? children)
|
||||
children)]
|
||||
(when after
|
||||
[rn/view
|
||||
[quo2.icons/icon after
|
||||
{:container-style {:margin-left 4
|
||||
:margin-right (if (= size 40) 12 8)}
|
||||
:no-color icon-secondary-no-color
|
||||
:color icon-secondary-color
|
||||
:size icon-size}]])]]]))))
|
||||
|
||||
(def button (theme/with-theme button-internal))
|
||||
@@ -0,0 +1,138 @@
|
||||
(ns quo2.components.buttons.button.view
|
||||
(:require [quo2.components.icon :as quo2.icons]
|
||||
[quo2.components.markdown.text :as text]
|
||||
[quo2.theme :as theme]
|
||||
[react-native.core :as rn]
|
||||
[react-native.blur :as blur]
|
||||
[reagent.core :as reagent]
|
||||
[quo2.components.buttons.button.style :as style]))
|
||||
|
||||
(defn- button-internal
|
||||
"with label
|
||||
[button opts \"label\"]
|
||||
opts
|
||||
{:type :primary/:secondary/:grey/:dark-grey/:outline/:ghost/
|
||||
:danger/:photo-bg/:blur-bg/:blur-bg-outline/:shell/:community
|
||||
:size 40 [default] /32/24
|
||||
:icon true/false
|
||||
:community-color '#FFFFFF'
|
||||
:community-text-color '#000000'
|
||||
:before :icon-keyword
|
||||
:after :icon-keyword}
|
||||
|
||||
only icon
|
||||
[button {:icon true} :i/close-circle]"
|
||||
[_ _]
|
||||
(let [pressed-in (reagent/atom false)]
|
||||
(fn
|
||||
[{:keys [on-press disabled type size before after above icon-secondary-no-color
|
||||
width customization-color theme override-background-color pressed
|
||||
on-long-press accessibility-label icon icon-no-color style inner-style test-ID
|
||||
blur-active? override-before-margins override-after-margins icon-size icon-container-size
|
||||
icon-container-rounded?]
|
||||
:or {type :primary
|
||||
size 40
|
||||
customization-color :primary
|
||||
blur-active? true}}
|
||||
children]
|
||||
(let [{:keys [icon-color icon-secondary-color background-color label-color border-color blur-type
|
||||
blur-overlay-color icon-background-color]}
|
||||
(get-in (style/themes customization-color)
|
||||
[theme type])
|
||||
state (cond disabled :disabled
|
||||
(or @pressed-in pressed) :pressed
|
||||
:else :default)
|
||||
blur-state (if blur-active? :blurred :default)
|
||||
icon-size (or icon-size (when (= 24 size) 12))
|
||||
icon-secondary-color (or icon-secondary-color icon-color)]
|
||||
[rn/touchable-without-feedback
|
||||
(merge {:test-ID test-ID
|
||||
:disabled disabled
|
||||
:accessibility-label accessibility-label
|
||||
:on-press-in #(reset! pressed-in true)
|
||||
:on-press-out #(reset! pressed-in nil)}
|
||||
(when on-press
|
||||
{:on-press on-press})
|
||||
(when on-long-press
|
||||
{:on-long-press on-long-press}))
|
||||
[rn/view
|
||||
{:style (merge
|
||||
(style/shape-style-container type icon size)
|
||||
{:width width}
|
||||
style)}
|
||||
[rn/view
|
||||
{:style (merge
|
||||
(style/style-container {:type type
|
||||
:size size
|
||||
:disabled disabled
|
||||
:background-color
|
||||
(or override-background-color (get background-color state))
|
||||
:border-color
|
||||
(get border-color state)
|
||||
:icon icon
|
||||
:above above
|
||||
:width width
|
||||
:before before
|
||||
:after after
|
||||
:blur-active? blur-active?})
|
||||
(when (= state :pressed) {:opacity 0.9})
|
||||
inner-style)}
|
||||
(when (and (= type :blurred)
|
||||
blur-active?)
|
||||
[blur/view
|
||||
{:blur-radius 20
|
||||
:blur-type blur-type
|
||||
:overlay-color blur-overlay-color
|
||||
:style style/blur-view}])
|
||||
(when above
|
||||
[rn/view
|
||||
[quo2.icons/icon above
|
||||
{:container-style {:margin-bottom 2}
|
||||
:color icon-secondary-color
|
||||
:size icon-size}]])
|
||||
(when before
|
||||
[rn/view
|
||||
{:style (style/before-icon-style
|
||||
{:override-margins override-before-margins
|
||||
:size size
|
||||
:icon-container-size icon-container-size
|
||||
:icon-background-color (get icon-background-color blur-state)
|
||||
:icon-container-rounded? icon-container-rounded?
|
||||
:icon-size icon-size})}
|
||||
[quo2.icons/icon before
|
||||
{:color icon-secondary-color
|
||||
:size icon-size}]])
|
||||
[rn/view
|
||||
(cond
|
||||
(or icon icon-no-color)
|
||||
[quo2.icons/icon children
|
||||
{:color icon-color
|
||||
:no-color icon-no-color
|
||||
:size icon-size}]
|
||||
|
||||
(string? children)
|
||||
[text/text
|
||||
{:size (when (#{56 24} size) :paragraph-2)
|
||||
:weight :medium
|
||||
:number-of-lines 1
|
||||
:style {:color label-color}}
|
||||
|
||||
children]
|
||||
|
||||
(vector? children)
|
||||
children)]
|
||||
(when after
|
||||
[rn/view
|
||||
{:style (style/after-icon-style
|
||||
{:override-margins override-after-margins
|
||||
:size size
|
||||
:icon-container-size icon-container-size
|
||||
:icon-background-color (get icon-background-color blur-state)
|
||||
:icon-container-rounded? icon-container-rounded?
|
||||
:icon-size icon-size})}
|
||||
[quo2.icons/icon after
|
||||
{:no-color icon-secondary-no-color
|
||||
:color icon-secondary-color
|
||||
:size icon-size}]])]]]))))
|
||||
|
||||
(def button (theme/with-theme button-internal))
|
||||
@@ -62,7 +62,7 @@
|
||||
:customization-color customize jump-to and mention button color}"
|
||||
[_]
|
||||
(let [pressed? (reagent/atom false)]
|
||||
(fn [{:keys [type label on-press count customization-color style]}]
|
||||
(fn [{:keys [type label on-press customization-color style] :as args}]
|
||||
[rn/touchable-opacity
|
||||
{:on-press-in #(reset! pressed? true)
|
||||
:on-press-out #(reset! pressed? false)
|
||||
@@ -102,6 +102,6 @@
|
||||
(case type
|
||||
:jump-to label
|
||||
:search-with-label label
|
||||
(:mention :notification-down :notification-up) (str count))])
|
||||
(:mention :notification-down :notification-up) (str (:count args)))])
|
||||
(when (#{:jump-to :notification-down :notification-up} type)
|
||||
[icon-view type])]])))
|
||||
|
||||
@@ -2,9 +2,10 @@
|
||||
(:require [react-native.core :as rn]
|
||||
[quo2.components.buttons.predictive-keyboard.style :as style]
|
||||
[quo2.components.info.info-message :as info-message]
|
||||
[quo2.theme :as theme]
|
||||
[react-native.linear-gradient :as linear-gradient]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[quo2.components.buttons.button :as button]))
|
||||
[quo2.components.buttons.button.view :as button]))
|
||||
|
||||
(def ^:private gradients
|
||||
{:light [(colors/alpha colors/neutral-40 0.05) (colors/alpha colors/neutral-40 0)]
|
||||
@@ -12,32 +13,33 @@
|
||||
:blur [colors/white-opa-5 colors/white-opa-0]})
|
||||
|
||||
(defn- word-component
|
||||
[word _ _ {:keys [blur? on-press]}]
|
||||
[word _ _ {:keys [on-press]}]
|
||||
[button/button
|
||||
(merge {:type :blur-bg
|
||||
:size 32
|
||||
:on-press #(on-press word)}
|
||||
(when blur? {:override-theme :dark}))
|
||||
{:type :blur-bg
|
||||
:size 32
|
||||
:on-press #(on-press word)}
|
||||
|
||||
word])
|
||||
|
||||
(defn- separator
|
||||
[]
|
||||
[rn/view {:style {:width 8}}])
|
||||
|
||||
(defn view
|
||||
(defn- view-internal
|
||||
"Options
|
||||
- `type` `:words`/`:error`/`:info`/`:empty`.
|
||||
- `blur?` Boolean to enable blur background support.
|
||||
- `text` error/info text.
|
||||
- `words` List of words to display in the keyboard.
|
||||
- `on-press` Callback called when a word is pressed `(fn [word])`."
|
||||
[{:keys [type blur? text words on-press]}]
|
||||
- `on-press` Callback called when a word is pressed `(fn [word])`
|
||||
- `theme` :light or :dark, received from with-theme HOC."
|
||||
[{:keys [type blur? text words on-press theme]}]
|
||||
[linear-gradient/linear-gradient
|
||||
{:style {:flex-direction :row}
|
||||
:accessibility-label :predictive-keyboard
|
||||
:colors (if blur?
|
||||
(gradients :blur)
|
||||
(colors/theme-colors (gradients :light) (gradients :dark)))}
|
||||
(colors/theme-colors (gradients :light) (gradients :dark) theme))}
|
||||
[rn/view {:style (style/wrapper type)}
|
||||
(case type
|
||||
:words
|
||||
@@ -46,8 +48,7 @@
|
||||
:data words
|
||||
:content-container-style style/word-list
|
||||
:render-fn word-component
|
||||
:render-data {:blur? blur?
|
||||
:on-press on-press}
|
||||
:render-data {:on-press on-press}
|
||||
:shows-horizontal-scroll-indicator false
|
||||
:separator [separator]
|
||||
:horizontal true
|
||||
@@ -70,3 +71,5 @@
|
||||
:icon-color colors/white-opa-70}))
|
||||
text]
|
||||
nil)]])
|
||||
|
||||
(def view (theme/with-theme view-internal))
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
(ns quo2.components.code.snippet
|
||||
(:require [cljs-bean.core :as bean]
|
||||
[clojure.string :as string]
|
||||
[quo2.components.buttons.button :as button]
|
||||
[quo2.components.buttons.button.view :as button]
|
||||
[quo2.components.code.code.style :as style]
|
||||
[quo2.components.markdown.text :as text]
|
||||
[react-native.core :as rn]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
(ns quo2.components.separator
|
||||
(ns quo2.components.common.separator.view
|
||||
(:require [quo2.foundations.colors :as quo2.colors]
|
||||
[react-native.core :as rn]))
|
||||
|
||||
@@ -29,52 +29,6 @@
|
||||
unread-messages?
|
||||
[unread-grey-dot :unviewed-messages-public]))
|
||||
|
||||
(defn communities-list-view-item
|
||||
[props
|
||||
{:keys [name
|
||||
locked?
|
||||
status
|
||||
muted?
|
||||
unread-messages?
|
||||
unread-mentions-count
|
||||
community-icon
|
||||
tokens]}]
|
||||
[rn/view
|
||||
{:style (merge (style/community-card 16)
|
||||
{:margin-bottom 12})}
|
||||
[rn/touchable-highlight
|
||||
(merge {:style {:height 56
|
||||
:border-radius 16}}
|
||||
props)
|
||||
[rn/view {:style style/detail-container}
|
||||
[rn/view (style/list-info-container)
|
||||
[community-icon/community-icon
|
||||
{:images community-icon} 32]
|
||||
[rn/view
|
||||
{:flex 1
|
||||
:margin-horizontal 12}
|
||||
[text/text
|
||||
{:weight :semi-bold
|
||||
:size :paragraph-1
|
||||
:accessibility-label :community-name-text
|
||||
:number-of-lines 1
|
||||
:ellipsize-mode :tail
|
||||
:style {:color (when muted?
|
||||
(colors/theme-colors
|
||||
colors/neutral-40
|
||||
colors/neutral-60))}}
|
||||
name]
|
||||
[community-view/community-stats-column
|
||||
{:type :list-view}]]
|
||||
(if (= status :gated)
|
||||
[community-view/permission-tag-container
|
||||
{:locked? locked?
|
||||
:tokens tokens}]
|
||||
[notification-view
|
||||
{:muted? muted?
|
||||
:unread-mentions-count unread-mentions-count
|
||||
:unread-messages? unread-messages?}])]]]])
|
||||
|
||||
(defn communities-membership-list-item
|
||||
[props
|
||||
{:keys [name
|
||||
|
||||
@@ -5,13 +5,17 @@
|
||||
[quo2.components.tags.permission-tag :as permission]
|
||||
[quo2.components.tags.tag :as tag]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[quo.gesture-handler :as gesture-handler] ;;TODO move to quo2
|
||||
[react-native.core :as rn]))
|
||||
[quo2.theme :as theme]
|
||||
[react-native.core :as rn]
|
||||
[react-native.gesture :as gesture]
|
||||
utils.money))
|
||||
|
||||
(defn community-stats
|
||||
[{:keys [icon members-count icon-color]}]
|
||||
[rn/view (style/stats-count-container)
|
||||
[rn/view {:margin-right 4}
|
||||
[{:keys [icon members-count icon-color accessibility-label]}]
|
||||
[rn/view
|
||||
{:accessibility-label accessibility-label
|
||||
:style (style/stats-count-container)}
|
||||
[rn/view {:margin-right 2}
|
||||
[icons/icon icon
|
||||
{:container-style {:align-items :center
|
||||
:justify-content :center}
|
||||
@@ -20,29 +24,32 @@
|
||||
:color icon-color}]]
|
||||
[text/text
|
||||
{:weight :regular
|
||||
:size :paragraph-1}
|
||||
:size :paragraph-2}
|
||||
members-count]])
|
||||
|
||||
(defn community-stats-column
|
||||
[{:keys [type]}]
|
||||
(let [icon-color (colors/theme-colors colors/neutral-50 colors/neutral-40)]
|
||||
[{:keys [type theme blur? members-count active-count]}]
|
||||
(let [icon-color (if (and (= :dark theme) blur?)
|
||||
colors/white-opa-40
|
||||
(colors/theme-colors colors/neutral-50 colors/neutral-40 theme))]
|
||||
[rn/view
|
||||
(if (= type :card-view)
|
||||
(style/card-stats-container)
|
||||
(style/list-stats-container))
|
||||
[community-stats
|
||||
{:icon :i/group
|
||||
:members-count "629.2K" ;;TODO here should be formatted value, use money/format-members from
|
||||
;;outside this component
|
||||
:icon-color icon-color}]
|
||||
{:accessibility-label :stats-members-count
|
||||
:icon :i/group
|
||||
:members-count (utils.money/format-amount members-count)
|
||||
:icon-color icon-color}]
|
||||
[community-stats
|
||||
{:icon :i/lightning
|
||||
:members-count "112.1K"
|
||||
:icon-color icon-color}]]))
|
||||
{:accessibility-label :stats-active-count
|
||||
:icon :i/active-members
|
||||
:members-count (utils.money/format-amount active-count)
|
||||
:icon-color icon-color}]]))
|
||||
|
||||
(defn community-tags
|
||||
[{:keys [tags container-style last-item-style]}]
|
||||
[gesture-handler/scroll-view
|
||||
[gesture/scroll-view
|
||||
{:shows-horizontal-scroll-indicator false
|
||||
:horizontal true
|
||||
:style container-style}
|
||||
@@ -84,13 +91,16 @@
|
||||
:style {:margin-top (if (= size :large) 8 2)}}
|
||||
description])])
|
||||
|
||||
(defn permission-tag-container
|
||||
[{:keys [locked? tokens on-press]}]
|
||||
(defn- permission-tag-container-internal
|
||||
[{:keys [locked? blur? tokens on-press theme]}]
|
||||
[permission/tag
|
||||
{:background-color (colors/theme-colors
|
||||
colors/neutral-10
|
||||
colors/neutral-80)
|
||||
:locked? locked?
|
||||
:tokens tokens
|
||||
:size 24
|
||||
:on-press on-press}])
|
||||
{:accessibility-label :permission-tag
|
||||
:background-color (if (and (= :dark theme) blur?)
|
||||
colors/white-opa-10
|
||||
(colors/theme-colors colors/neutral-10 colors/neutral-80 theme))
|
||||
:locked? locked?
|
||||
:tokens tokens
|
||||
:size 24
|
||||
:on-press on-press}])
|
||||
|
||||
(def permission-tag-container (theme/with-theme permission-tag-container-internal))
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
:outline colors/neutral-70}})
|
||||
|
||||
(defn get-color
|
||||
[key]
|
||||
(get-in themes [(theme/get-theme) key]))
|
||||
[k]
|
||||
(get-in themes [(theme/get-theme) k]))
|
||||
|
||||
(defn counter
|
||||
[{:keys [type override-text-color override-bg-color style accessibility-label max-value]
|
||||
|
||||
@@ -9,33 +9,33 @@
|
||||
:height 20})
|
||||
|
||||
(defn neutral-border-color
|
||||
[in-blur-view? override-theme]
|
||||
[in-blur-view? theme]
|
||||
(if in-blur-view?
|
||||
(colors/theme-colors colors/neutral-80-opa-5 colors/white-opa-10 override-theme)
|
||||
(colors/theme-colors colors/neutral-20 colors/neutral-80 override-theme)))
|
||||
(colors/theme-colors colors/neutral-80-opa-5 colors/white-opa-10 theme)
|
||||
(colors/theme-colors colors/neutral-20 colors/neutral-80 theme)))
|
||||
|
||||
(def active-background-color (colors/custom-color :blue 50 10))
|
||||
(def complete-background-color (colors/custom-color :blue 50))
|
||||
(defn active-background-color [customization-color] (colors/custom-color customization-color 50 10))
|
||||
(defn complete-background-color [customization-color] (colors/custom-color customization-color 50))
|
||||
|
||||
(defn container
|
||||
[size type in-blur-view? override-theme]
|
||||
[{:keys [size type in-blur-view? theme customization-color]}]
|
||||
(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))
|
||||
:border-color (neutral-border-color in-blur-view? theme))
|
||||
|
||||
(= type :active)
|
||||
(assoc :background-color active-background-color)
|
||||
(assoc :background-color (active-background-color customization-color))
|
||||
|
||||
(= type :complete)
|
||||
(assoc :background-color complete-background-color)))
|
||||
(assoc :background-color (complete-background-color customization-color))))
|
||||
|
||||
(defn text-color
|
||||
([type] (text-color type nil))
|
||||
([type override-theme]
|
||||
([type theme]
|
||||
(case type
|
||||
(:neutral :active) (colors/theme-colors colors/neutral-100-opa-100 colors/white override-theme)
|
||||
(:neutral :active) (colors/theme-colors colors/neutral-100-opa-100 colors/white theme)
|
||||
:complete colors/white)))
|
||||
|
||||
@@ -2,11 +2,12 @@
|
||||
(:require
|
||||
[quo2.components.counter.step.style :as style]
|
||||
[quo2.components.markdown.text :as text]
|
||||
[quo2.theme :as theme]
|
||||
[react-native.core :as rn]
|
||||
[utils.number]))
|
||||
|
||||
(defn step
|
||||
[{:keys [type accessibility-label override-theme in-blur-view?]} value]
|
||||
(defn step-internal
|
||||
[{:keys [type accessibility-label theme in-blur-view? customization-color]} value]
|
||||
(let [type (or type :neutral)
|
||||
value (utils.number/parse-int value)
|
||||
label (str value)
|
||||
@@ -14,8 +15,14 @@
|
||||
[rn/view
|
||||
{:accessible true
|
||||
:accessibility-label (or accessibility-label :step-counter)
|
||||
:style (style/container size type in-blur-view? override-theme)}
|
||||
:style (style/container {:size size
|
||||
:type type
|
||||
:in-blur-view? in-blur-view?
|
||||
:theme theme
|
||||
:customization-color customization-color})}
|
||||
[text/text
|
||||
{:weight :medium
|
||||
:size :label
|
||||
:style {:color (style/text-color type override-theme)}} label]]))
|
||||
:style {:color (style/text-color type theme)}} label]]))
|
||||
|
||||
(def step (theme/with-theme step-internal))
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
(ns quo2.components.dividers.date
|
||||
(:require [quo2.components.markdown.text :as text]
|
||||
[quo2.components.separator :as separator]
|
||||
[quo2.components.common.separator.view :as separator]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[react-native.core :as rn]))
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
(ns quo2.components.dividers.divider-label
|
||||
(:require [quo2.theme :as theme]
|
||||
[quo2.components.icon :as icons]
|
||||
(:require [quo2.components.icon :as icons]
|
||||
[quo2.components.markdown.text :as markdown.text]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[quo2.theme :as theme]
|
||||
[react-native.core :as rn]))
|
||||
|
||||
(def chevron-icon-container-width 20)
|
||||
@@ -36,18 +36,18 @@
|
||||
padding-top (if increase-padding-top? 16 8)
|
||||
text-and-icon-color (if dark? colors/neutral-40 colors/neutral-50)
|
||||
counter-text-color (if dark? colors/white colors/neutral-100)]
|
||||
[rn/touchable-without-feedback
|
||||
{:on-press on-press}
|
||||
[rn/touchable-without-feedback {:on-press on-press}
|
||||
[rn/view
|
||||
{:accessible true
|
||||
:accessibility-label :divider-label
|
||||
:style (merge {:border-top-width 1
|
||||
:border-top-color border-and-counter-bg-color
|
||||
:padding-top padding-top
|
||||
:padding-bottom padding-bottom
|
||||
:padding-horizontal 16
|
||||
:align-items :center
|
||||
:flex-direction :row}
|
||||
:style (merge {:border-top-width 1
|
||||
:border-top-color border-and-counter-bg-color
|
||||
:padding-top padding-top
|
||||
:padding-bottom padding-bottom
|
||||
:padding-left 16
|
||||
:padding-right 16
|
||||
:align-items :center
|
||||
:flex-direction :row}
|
||||
container-style)}
|
||||
(when (= chevron-position :left)
|
||||
[rn/view
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
(ns quo2.components.drawers.documentation-drawers.style)
|
||||
(ns quo2.components.drawers.documentation-drawers.style
|
||||
(:require [quo2.foundations.colors :as colors]
|
||||
[react-native.safe-area :as safe-area]))
|
||||
|
||||
(def outer-container
|
||||
;; Margin negative to fill the bottom-sheet container where this component is used
|
||||
{:margin-bottom (- (+ (safe-area/get-bottom) 8))})
|
||||
|
||||
(def container
|
||||
{:align-items :flex-start
|
||||
@@ -6,4 +12,10 @@
|
||||
|
||||
(def content
|
||||
{:margin-top 8
|
||||
:margin-bottom 16})
|
||||
:margin-bottom (+ (safe-area/get-bottom) 8)})
|
||||
|
||||
(defn title
|
||||
[shell?]
|
||||
{:color (colors/theme-colors colors/neutral-100
|
||||
colors/white
|
||||
(when shell? :dark))})
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
(ns quo2.components.drawers.documentation-drawers.view
|
||||
(:require [quo2.components.markdown.text :as text]
|
||||
(:require [quo2.components.buttons.button.view :as button]
|
||||
[quo2.components.drawers.documentation-drawers.style :as style]
|
||||
[quo2.components.markdown.text :as text]
|
||||
[react-native.core :as rn]
|
||||
[react-native.gesture :as gesture]
|
||||
[quo2.components.buttons.button :as button]
|
||||
[quo2.foundations.colors :as colors]))
|
||||
[react-native.gesture :as gesture]))
|
||||
|
||||
(defn view
|
||||
"Options
|
||||
@@ -14,18 +13,18 @@
|
||||
- `button-icon` button icon
|
||||
- `on-press-button` On press handler for the button
|
||||
- `shell?` use shell theme
|
||||
|
||||
`content` Content of the drawer
|
||||
"
|
||||
[{:keys [title show-button? on-press-button button-label button-icon shell?]} content]
|
||||
[gesture/scroll-view
|
||||
{:style style/outer-container
|
||||
:always-bounce-vertical false
|
||||
:content-inset-adjustment-behavior :never}
|
||||
[rn/view {:style style/container}
|
||||
[text/text
|
||||
{:size :heading-2
|
||||
:accessibility-label :documentation-drawer-title
|
||||
:style {:color (colors/theme-colors colors/neutral-100
|
||||
colors/white
|
||||
(when shell? :dark))}
|
||||
:style (style/title shell?)
|
||||
:weight :semi-bold}
|
||||
title]
|
||||
[rn/view {:style style/content :accessibility-label :documentation-drawer-content}
|
||||
|
||||
@@ -1,9 +1,19 @@
|
||||
(ns quo2.components.drawers.drawer-buttons.component-spec
|
||||
(:require [quo2.components.drawers.drawer-buttons.view :as drawer-buttons]
|
||||
[react-native.core :as rn]
|
||||
[test-helpers.component :as h]))
|
||||
[test-helpers.component :as h]
|
||||
[react-native.safe-area :as safe-area]))
|
||||
|
||||
(h/describe "drawer-buttons"
|
||||
(h/before-each
|
||||
(fn []
|
||||
(h/use-fake-timers)))
|
||||
|
||||
(h/after-each
|
||||
(fn []
|
||||
(h/clear-all-timers)
|
||||
(h/use-real-timers)))
|
||||
|
||||
(h/test "the top heading and subheading render"
|
||||
(h/render [drawer-buttons/view
|
||||
{:top-card {:heading :top-heading}
|
||||
@@ -29,15 +39,16 @@
|
||||
|
||||
(h/test "it clicks the top card"
|
||||
(let [event (h/mock-fn)]
|
||||
(h/render [drawer-buttons/view
|
||||
{:top-card {:on-press event
|
||||
:heading :top-heading}
|
||||
:bottom-card {:heading :bottom-heading}}
|
||||
:top-sub-heading
|
||||
:bottom-sub-heading])
|
||||
(h/fire-event :press (h/get-by-text "top-heading"))
|
||||
(-> (js/expect event)
|
||||
(.toHaveBeenCalled))))
|
||||
(with-redefs [safe-area/get-top (fn [] 10)]
|
||||
(h/render [drawer-buttons/view
|
||||
{:top-card {:on-press event
|
||||
:heading :top-heading}
|
||||
:bottom-card {:heading :bottom-heading}}
|
||||
:top-sub-heading
|
||||
:bottom-sub-heading])
|
||||
(h/fire-event :press (h/get-by-text "top-heading"))
|
||||
(-> (js/expect event)
|
||||
(.toHaveBeenCalled)))))
|
||||
|
||||
(h/test "it clicks the bottom card"
|
||||
(let [event (h/mock-fn)]
|
||||
|
||||
@@ -1,11 +1,20 @@
|
||||
(ns quo2.components.drawers.drawer-buttons.style
|
||||
(:require [quo2.foundations.colors :as colors]))
|
||||
(:require [quo2.foundations.colors :as colors]
|
||||
[react-native.reanimated :as reanimated]))
|
||||
|
||||
(def outer-container
|
||||
{:height 216
|
||||
:border-top-left-radius 20
|
||||
:border-top-right-radius 20
|
||||
:overflow :hidden})
|
||||
(defn outer-container
|
||||
[height border-radius container-style]
|
||||
(reanimated/apply-animations-to-style
|
||||
{:height height
|
||||
:border-top-left-radius border-radius
|
||||
:border-top-right-radius border-radius}
|
||||
(assoc
|
||||
container-style
|
||||
:position :absolute
|
||||
:left 0
|
||||
:right 0
|
||||
:bottom 0
|
||||
:overflow :hidden)))
|
||||
|
||||
(def top-card
|
||||
{:flex 1
|
||||
@@ -17,7 +26,6 @@
|
||||
|
||||
(def bottom-card
|
||||
{:position :absolute
|
||||
:top 80
|
||||
:left 0
|
||||
:right 0
|
||||
:bottom 0
|
||||
@@ -41,6 +49,20 @@
|
||||
:align-items :center
|
||||
:border-color colors/white-opa-5})
|
||||
|
||||
(def blur-view-style
|
||||
{:flex 1
|
||||
:border-top-left-radius 20
|
||||
:border-top-right-radius 20})
|
||||
|
||||
(def blur-content-style
|
||||
{:flex 1
|
||||
:background-color :transparent
|
||||
:position :absolute
|
||||
:top 0
|
||||
:left 0
|
||||
:right 0
|
||||
:bottom 0})
|
||||
|
||||
(def bottom-text
|
||||
{:flex 1
|
||||
:color colors/white-70-blur})
|
||||
@@ -51,4 +73,4 @@
|
||||
(defn heading-text
|
||||
[gap]
|
||||
{:color colors/white
|
||||
:margin-bottom gap})
|
||||
:margin-bottom gap})
|
||||
|
||||
@@ -4,7 +4,12 @@
|
||||
[quo2.components.markdown.text :as text]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[react-native.blur :as blur]
|
||||
[quo2.components.drawers.drawer-buttons.style :as style]))
|
||||
[quo2.components.drawers.drawer-buttons.style :as style]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[react-native.platform :as platform]
|
||||
[react-native.safe-area :as safe-area]))
|
||||
|
||||
(def default-height 216)
|
||||
|
||||
(defn render-bottom
|
||||
[children]
|
||||
@@ -29,35 +34,74 @@
|
||||
children]]
|
||||
[render-bottom children]))
|
||||
|
||||
(defn render-children-top
|
||||
[children]
|
||||
(if (label? children)
|
||||
[text/text
|
||||
{:size :paragraph-2
|
||||
:style style/top-text
|
||||
:weight :semi-bold}
|
||||
children]
|
||||
children))
|
||||
(defn- f-render-children-top
|
||||
[children top-children-opacity]
|
||||
(let [scale (reanimated/interpolate top-children-opacity [1 0] [1 1.1])
|
||||
padding-left (reanimated/interpolate scale [1 1.1] [0 14])]
|
||||
[reanimated/view
|
||||
{:style (reanimated/apply-animations-to-style
|
||||
{:opacity top-children-opacity
|
||||
:transform [{:scale scale}
|
||||
{:translate-x padding-left}]}
|
||||
{})}
|
||||
(if (label? children)
|
||||
[text/text
|
||||
{:size :paragraph-2
|
||||
:style style/top-text
|
||||
:weight :semi-bold}
|
||||
children]
|
||||
children)]))
|
||||
|
||||
(defn card
|
||||
[{:keys [on-press style heading gap accessibility-label top?]} children]
|
||||
(defn- f-card
|
||||
[{:keys [on-press default-on-press style heading gap accessibility-label top? top-title-opacity
|
||||
top-children-opacity
|
||||
animated-heading]
|
||||
:or {top-title-opacity (reanimated/use-shared-value 1)}}
|
||||
children]
|
||||
[rn/touchable-highlight
|
||||
{:accessibility-label accessibility-label
|
||||
:on-press on-press
|
||||
:on-press (fn []
|
||||
(when on-press
|
||||
(on-press))
|
||||
(when default-on-press
|
||||
(default-on-press)))
|
||||
:border-radius 20
|
||||
:style style
|
||||
:underlay-color (:background-color style)}
|
||||
[rn/view
|
||||
[text/text
|
||||
{:size :heading-1
|
||||
:style (style/heading-text gap)
|
||||
:weight :semi-bold}
|
||||
heading]
|
||||
[reanimated/view
|
||||
{:style (reanimated/apply-animations-to-style
|
||||
{:opacity top-title-opacity}
|
||||
{})}
|
||||
[text/text
|
||||
{:size :heading-1
|
||||
:style (style/heading-text gap)
|
||||
:weight :semi-bold}
|
||||
heading]]
|
||||
(when animated-heading
|
||||
(let [animated-heading-opacity (reanimated/interpolate top-children-opacity [1 0] [0 1])]
|
||||
[reanimated/view
|
||||
{:style (reanimated/apply-animations-to-style
|
||||
{:opacity top-title-opacity}
|
||||
{:position :absolute})}
|
||||
[reanimated/view
|
||||
{:style (reanimated/apply-animations-to-style
|
||||
{:opacity animated-heading-opacity}
|
||||
{})}
|
||||
[text/text
|
||||
{:size :heading-1
|
||||
:style (style/heading-text gap)
|
||||
:weight :semi-bold}
|
||||
animated-heading]]]))
|
||||
(if top?
|
||||
[render-children-top children]
|
||||
[:f> f-render-children-top children top-children-opacity]
|
||||
[render-children-bottom children])]])
|
||||
|
||||
(defn view
|
||||
(defn card
|
||||
[props children]
|
||||
[:f> f-card props children])
|
||||
|
||||
(defn f-view
|
||||
"[view opts]
|
||||
opts
|
||||
{:container-style style-object
|
||||
@@ -70,29 +114,101 @@
|
||||
child-1 string, keyword or hiccup
|
||||
child-2 string, keyword or hiccup
|
||||
"
|
||||
[{:keys [container-style top-card bottom-card]} child-1 child-2]
|
||||
[rn/view
|
||||
{:style (merge container-style style/outer-container)}
|
||||
[blur/view
|
||||
{:blur-type :dark
|
||||
:blur-amount 10
|
||||
:style {:flex 1
|
||||
:border-top-left-radius 20
|
||||
:border-top-right-radius 20}}]
|
||||
[rn/view
|
||||
{:style {:flex 1
|
||||
:background-color :transparent
|
||||
:position :absolute
|
||||
:top 0
|
||||
:left 0
|
||||
:right 0
|
||||
:bottom 0}}
|
||||
[card
|
||||
(merge {:gap 4
|
||||
:top? true
|
||||
:style style/top-card}
|
||||
top-card) child-1]
|
||||
[card
|
||||
(merge {:style style/bottom-card
|
||||
:gap 20}
|
||||
bottom-card) child-2]]])
|
||||
[{:keys [container-style top-card bottom-card on-init animations-duration animations-delay]}
|
||||
child-1
|
||||
child-2]
|
||||
(let [max-height (+ (:height (rn/get-window)) (if platform/android? (safe-area/get-top) 0))
|
||||
height (reanimated/use-shared-value default-height)
|
||||
top-padding (reanimated/use-shared-value 12)
|
||||
border-radius (reanimated/use-shared-value 20)
|
||||
bottom-view-top (reanimated/use-shared-value 80)
|
||||
top-title-opacity (reanimated/use-shared-value 1)
|
||||
top-children-opacity (reanimated/use-shared-value 1)
|
||||
animations-delay (/ animations-delay 1.4)
|
||||
start-top-animation (fn []
|
||||
(reanimated/animate-shared-value-with-delay bottom-view-top
|
||||
(:height (rn/get-screen))
|
||||
animations-duration
|
||||
:easing4
|
||||
animations-delay)
|
||||
(reanimated/animate-shared-value-with-delay
|
||||
height
|
||||
max-height
|
||||
animations-duration
|
||||
:easing4
|
||||
animations-delay)
|
||||
(reanimated/animate-shared-value-with-delay
|
||||
top-padding
|
||||
(+ 68 (safe-area/get-top))
|
||||
animations-duration
|
||||
:easing4
|
||||
animations-delay)
|
||||
(reanimated/animate-shared-value-with-delay
|
||||
top-children-opacity
|
||||
0
|
||||
animations-duration
|
||||
:easing4 animations-delay)
|
||||
(reanimated/animate-shared-value-with-delay
|
||||
top-title-opacity
|
||||
0
|
||||
0
|
||||
:linear
|
||||
(+ animations-delay animations-duration 500)))
|
||||
reset-top-animation (fn []
|
||||
(reanimated/set-shared-value top-title-opacity 1)
|
||||
(reanimated/animate-shared-value-with-delay bottom-view-top
|
||||
80
|
||||
animations-duration
|
||||
:easing4
|
||||
50)
|
||||
(reanimated/animate-shared-value-with-timing
|
||||
height
|
||||
default-height
|
||||
animations-duration
|
||||
:easing4)
|
||||
(reanimated/animate-shared-value-with-timing
|
||||
top-padding
|
||||
12
|
||||
animations-duration
|
||||
:easing4)
|
||||
(reanimated/animate-shared-value-with-timing
|
||||
top-children-opacity
|
||||
1
|
||||
animations-duration
|
||||
:easing4))]
|
||||
(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
|
||||
:blur-amount 10
|
||||
:style style/blur-view-style}
|
||||
[rn/view
|
||||
{:style style/blur-content-style}
|
||||
[reanimated/view
|
||||
{:style (reanimated/apply-animations-to-style
|
||||
{:padding-top top-padding}
|
||||
style/top-card)}
|
||||
[card
|
||||
(merge {:gap 4
|
||||
:top? true
|
||||
:style {:flex 1}
|
||||
:top-children-opacity top-children-opacity
|
||||
:top-title-opacity top-title-opacity
|
||||
:default-on-press start-top-animation}
|
||||
top-card)
|
||||
child-1]]
|
||||
[reanimated/view
|
||||
{:style (reanimated/apply-animations-to-style
|
||||
{:top bottom-view-top}
|
||||
style/bottom-card)}
|
||||
[card
|
||||
(merge {:style {:flex 1}
|
||||
:gap 10}
|
||||
bottom-card)
|
||||
child-2]]]]]))
|
||||
|
||||
(defn view
|
||||
[props child-1 child-2]
|
||||
[:f> f-view props child-1 child-2])
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
(ns quo2.components.dropdowns.dropdown
|
||||
(:require [quo2.components.buttons.button :as button]))
|
||||
(:require [quo2.components.buttons.button.view :as button]))
|
||||
|
||||
(defn dropdown
|
||||
[_ _]
|
||||
@@ -7,8 +7,12 @@
|
||||
[button/button
|
||||
(merge
|
||||
opts
|
||||
{:after (if selected :i/pullup :i/dropdown)
|
||||
:icon-secondary-no-color true
|
||||
{:after (if selected :i/chevron-top :i/chevron-down)
|
||||
:icon-size 12
|
||||
:icon-container-size 14
|
||||
:icon-container-rounded? true
|
||||
:override-after-margins {:left 7
|
||||
:right 9}
|
||||
:pressed selected
|
||||
:on-press #(when on-change (on-change selected))})
|
||||
children]))
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
(ns quo2.components.empty-state.empty-state.view
|
||||
(:require [quo2.components.buttons.button :as button]
|
||||
(:require [quo2.components.buttons.button.view :as button]
|
||||
[quo2.components.empty-state.empty-state.styles :as styles]
|
||||
[quo2.components.markdown.text :as text]
|
||||
[react-native.core :as rn]
|
||||
[react-native.fast-image :as fast-image]))
|
||||
[react-native.fast-image :as fast-image]
|
||||
[quo2.theme :as theme]))
|
||||
|
||||
(defn empty-state
|
||||
(defn- empty-state-internal
|
||||
[{:keys [customization-color image title description blur?]
|
||||
upper-button :upper-button
|
||||
lower-button :lower-button
|
||||
@@ -32,19 +33,18 @@
|
||||
upper-button-on-press :on-press} upper-button]
|
||||
[rn/view {:style styles/button-container}
|
||||
[button/button
|
||||
(cond-> {:type :primary
|
||||
:size 32
|
||||
:override-background-color (styles/upper-button-color customization-color)
|
||||
:on-press upper-button-on-press}
|
||||
blur? (assoc :override-theme :dark))
|
||||
{:type :primary
|
||||
:size 32
|
||||
:override-background-color (styles/upper-button-color customization-color)
|
||||
:on-press upper-button-on-press}
|
||||
upper-button-text]
|
||||
|
||||
(when-let [{lower-button-text :text
|
||||
lower-button-on-press :on-press} lower-button]
|
||||
[button/button
|
||||
(cond-> {:style {:margin-top 12}
|
||||
:size 32
|
||||
:type :blur-bg
|
||||
:on-press lower-button-on-press}
|
||||
blur? (assoc :override-theme :dark))
|
||||
{:style {:margin-top 12}
|
||||
:size 32
|
||||
:type :blur-bg
|
||||
:on-press lower-button-on-press}
|
||||
lower-button-text])])])
|
||||
|
||||
(def empty-state (theme/with-theme empty-state-internal))
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
(ns quo2.components.header
|
||||
(:require [oops.core :refer [oget]]
|
||||
[quo2.components.buttons.button :as button]
|
||||
[quo2.components.buttons.button.view :as button]
|
||||
[quo2.components.markdown.text :as text]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[react-native.core :as rn]
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
:error colors/danger-60}})
|
||||
|
||||
(defn get-color
|
||||
[key]
|
||||
(get-in themes [(theme/get-theme) key]))
|
||||
[k]
|
||||
(get-in themes [(theme/get-theme) k]))
|
||||
|
||||
(defn info-message
|
||||
"[info-message opts \"message\"]
|
||||
|
||||
@@ -30,12 +30,12 @@
|
||||
:close-button colors/white}})
|
||||
|
||||
(defn get-color
|
||||
[theme key]
|
||||
(get-in themes [theme key]))
|
||||
[theme k]
|
||||
(get-in themes [theme k]))
|
||||
|
||||
(defn get-color-by-type
|
||||
[theme type key]
|
||||
(get-in themes [theme type key]))
|
||||
[theme type k]
|
||||
(get-in themes [theme type k]))
|
||||
|
||||
(defn container
|
||||
[{:keys [theme type include-button?]}]
|
||||
|
||||