Compare commits

...
Author SHA1 Message Date
Lungu Cristian 4127fdae9e not depending on the db password in the input 2024-02-16 17:04:59 +02:00
Lungu Cristian 99074382bc fix(biometric): pressing biometric quickly errors 2024-02-08 00:14:13 +02:00
Lungu Cristian 84ad0d03fb ref(biometrics): moved schemas to a separate file 2024-02-07 23:48:39 +02:00
Lungu Cristian c4b27cad05 feat(biometric): added missing schema 2024-02-07 22:41:54 +02:00
Lungu Cristian 7c231f1fc3 test(standard-auth): added integration tests 2024-02-07 22:14:57 +02:00
Lungu Cristian bd68f60524 feat(standard-auth): schemas and removed old auth 2024-02-07 15:06:15 +02:00
Lungu Cristian b8b77d0d03 ref(standard-auth): authorize using events 2024-02-07 13:13:08 +02:00
Lungu Cristian 5d21482506 test(biometrics): fixed event tests 2024-02-06 19:19:03 +02:00
Lungu Cristian 66d10bd116 ref(standard-auth): refactored authorize 2024-02-06 18:37:05 +02:00
Lungu Cristian 1ab55787dd test(biometrics): tests & schemas for events 2024-02-06 16:01:56 +02:00
Lungu Cristian 77b97199ff fix(biometrics): removed unnecessary event 2024-02-02 14:19:25 +02:00
Lungu Cristian 5059a4bea4 test(biometric-events): show-message 2024-02-02 12:13:11 +02:00
Lungu Cristian 146c766892 ref(biometric): events using reg-event-fx & other 2024-02-01 15:37:18 +02:00
Volodymyr Kozieiev a95f2a0f52 Implement menu on collectible preview page (#18651) 2024-02-01 12:48:48 +00:00
Icaro Motta 38dbd6687e Disable flag ACCOUNT_SELECTION_ENABLED by default (#18690) 2024-01-31 23:58:37 -03:00
Ajay SivanandIcaro Motta 4633fc22ed Show token permissions only for role permissions (#18549)
Token requirements that are not role permissions (currently channel permissions)
should not be displayed to the user while they see permissions to join.

Admin, Master, Owner or minted token permissions are not membership permissions,
but they still should be displayed so the user understand the role they will
assume after joining.

Co-authored-by: Icaro Motta <icaro.ldm@gmail.com>
2024-01-31 21:03:54 -03:00
Ibrahem Khalil 7e31e028fa Bring back enable-notifications onboarding screen static image (#18654) 2024-01-31 16:01:30 +02:00
Mohamed Javid 067b2d5afb [Fix] Wallet - Route not found (#18682)
This commit fixes the route not fetched bug on the Wallet send flow.

Signed-off-by: Mohamed Javid <19339952+smohamedjavid@users.noreply.github.com>
2024-01-31 16:45:21 +05:30
BalogunofAfrica e4ba0d3062 fix: android shadow (#18504) 2024-01-31 12:02:27 +01:00
Icaro Motta 11e49c0cc3 Fix community logo/name not rendered correctly (#18633) 2024-01-30 19:37:45 -03:00
BalogunofAfrica eda9464b6c fix(ios): button overlap (#18620) 2024-01-30 16:34:12 +01:00
frank 8f3385fc9f fix: endless logout (#18492) 2024-01-30 20:25:53 +08:00
Paul Fitzgerald 7eb4331de1 Chore(wallet): add bridge token page (#18560) 2024-01-30 03:22:45 -08:00
Anton Iakimov 46f01f5eb3 Revert "ci: don't fail on Diawi upload failure"
This reverts commit 36168256bf.
2024-01-30 11:42:04 +01:00
Shivek Khurana 0349b0ed3d 🎡 Don't scroll on press (#18662)
- Hack fix
- Scroll on press breaks something with FlatList
- Which causes some items to not render
- Could be related to scroll view inside scroll view
- But fixing this bug by compromising the UX a tiny bit
2024-01-30 08:32:20 +00:00
Siddarth Kumar f57a26b5f5 Remove hacks from darwin nix purge script (#18656)
## Summary
In this commit we : 
- instead of `cd` to `/Library/LaunchDaemons` and then attempting to `launchctl unload` the nixos plist files we just pass the full path to unload as seen in `nix` documentation here : https://nixos.org/manual/nix/stable/installation/uninstall.html#:~:text=Stop%20and%20remove%20the%20Nix%20daemon%20services%3A

- move killing a process by prompting for confirmation to a new shell script as per feedback from previous PR : https://github.com/status-im/status-mobile/pull/18192#discussion_r1439495310

- fix few small typos

## Platforms
- macOS
2024-01-30 09:00:26 +05:30
Lungu Cristian ab509da60e fix: profile image & customization color for share-qr-code (#18643) 2024-01-29 14:14:51 +02:00
Lungu Cristian 901818492d Replace unmaintained biometrics package (#18531)
* feat: added react-native-biometrics dependency

* chore: added malli schema to auth

* fix: malli schema

* feat: using react-native-biometrics

* fix: removed biometry not-enrolled error supression

* feat: added check for enabled biometric

* fix: biometrics error handling on ios

* chore: remove touch-id library

* chore: cleanup

* removed proj.list dep

* fix: gradle get_projects regex edge-case

Handles cases when the gradle project has a description, which shows up when running `gradle projects` as (`react-native-biometrics` - react-native-biometrics), breaking `make nix-update-gradle`. Here we're just adjusting the regex to ignore everything in the line after the closing (`).

* build: ran "make nix-update-gradle"

* chore: comment typo

* chore: replaced old lib in test mocks

* fix: addressed review comments

* fix: using event for standard-auth biometrics

* ref: using ex-cause for biometric error codes

* fix: removed promesa changes

* fix: auth slide biometric success not triggered
2024-01-29 13:33:46 +02:00
Ibrahem Khalil 302020653b Add lastOpenedAt and JoinedAt for communities (#18439) 2024-01-28 14:59:10 +02:00
Yevheniia Berdnyk 205b74cd34 e2e: remived xfail marks 2024-01-26 20:03:12 +02:00
mmilad75 be618bfafe Wallet: Disable long-press feature on tokens in watch-only accounts. #18597 (#18598)
* add functionality

* update condition
2024-01-26 21:30:01 +03:30
Ulises Manuel 550fa04e33 [#18512] incomplete list of collectibles (#18577)
* Fix var naming react-native-svg namespace

* Update collectible components to show SVGs

* Display collectibles containing collection images

* Show collectibles containing SVG animations as static images

* Reduce collectibles fetching priority

* Add support to visualize SVGs in collectible detail screen
2024-01-26 09:52:04 -06:00
yqrashawnandAjay Sivan 1acf8f0d07 feat: show highest permission role when join community (#18497)
* feat: get revealed accounts for joined community

Signed-off-by: yqrashawn <namy.19@gmail.com>

* Show token requirements only when membership permissions are present.

- Add membership-permissions? to community state.

* feat: show highest permission role in overview and req to join

Signed-off-by: yqrashawn <namy.19@gmail.com>

* feat: get highest perm role in addr for perms

Signed-off-by: yqrashawn <namy.19@gmail.com>

* feat: ui for address for perm drawer

* test: unit test and spec for handle-community

Signed-off-by: yqrashawn <namy.19@gmail.com>

* fix: for #18581

* refactor: based on PR feedback

- move <-rpc to data store
- `role->translation-key`
- highest-permission-role-text -> highest-role-text
- filter out nils for handle community test

Signed-off-by: yqrashawn <namy.19@gmail.com>

---------

Signed-off-by: yqrashawn <namy.19@gmail.com>
Co-authored-by: Ajay Sivan <ajayesivan@gmail.com>
2024-01-26 15:38:10 +08:00
Parvesh Monu d82bf3365d fix bottom tabs blur overlay color (#18621) 2024-01-26 11:44:58 +05:30
Jamie Caprani d8e0d1c36b chore: remove mock data from wallet and feature flag incomplete features (#18569) 2024-01-25 13:13:33 -08:00
Yevheniia Berdnyk ad7a95ed3d e2e: updated deep/universal links tests 2024-01-25 22:20:21 +02:00
Paul Fitzgerald cc24794b74 chore (shell): add indicators to share wallet qrs (#18523) 2024-01-25 19:00:18 +00:00
Omar Basem 1fb6c60f72 Wallet: network receiver preferences (#18583)
* wallet: network receiver preferences
2024-01-25 15:45:45 +04:00
108 changed files with 2139 additions and 1739 deletions
+1 -3
View File
@@ -78,9 +78,7 @@ pipeline {
}
stage('Upload') {
steps { script {
catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') {
env.DIAWI_URL = ios.uploadToDiawi()
}
env.DIAWI_URL = ios.uploadToDiawi()
env.PKG_URL = env.DIAWI_URL
jenkins.setBuildDesc(IPA: env.PKG_URL)
} }
+2 -2
View File
@@ -144,9 +144,9 @@ used for keycard
used for svg icons, mostly collectibles are using svg
TODO: updating requires a pod update on iOS
## "react-native-touch-id": "^4.4.1"
## "react-native-biometrics": "^3.0.1"
used for touch-id identification
used for biometric authentication on Android and iOS
## "react-native-webview": "git+https://github.com/status-im/react-native-webview.git#v8.0.7_3"
+7 -7
View File
@@ -305,6 +305,8 @@ PODS:
- glog
- react-native-background-timer (2.2.0):
- React
- react-native-biometrics (3.0.1):
- React-Core
- react-native-blob-util (0.13.18):
- React-Core
- react-native-blur (4.3.3):
@@ -517,8 +519,6 @@ PODS:
- SocketRocket (0.6.1)
- SSZipArchive (2.4.3)
- TOCropViewController (2.6.1)
- TouchID (4.4.1):
- React
- Yoga (1.14.0)
DEPENDENCIES:
@@ -548,6 +548,7 @@ DEPENDENCIES:
- React-jsinspector (from `../node_modules/react-native/ReactCommon/jsinspector`)
- React-logger (from `../node_modules/react-native/ReactCommon/logger`)
- react-native-background-timer (from `../node_modules/react-native-background-timer`)
- react-native-biometrics (from `../node_modules/react-native-biometrics`)
- react-native-blob-util (from `../node_modules/react-native-blob-util`)
- "react-native-blur (from `../node_modules/@react-native-community/blur`)"
- "react-native-cameraroll (from `../node_modules/@react-native-camera-roll/camera-roll`)"
@@ -603,7 +604,6 @@ DEPENDENCIES:
- RNSVG (from `../node_modules/react-native-svg`)
- secp256k1 (from `https://github.com/status-im/secp256k1.swift.git`)
- SSZipArchive (= 2.4.3)
- TouchID (from `../node_modules/react-native-touch-id`)
- Yoga (from `../node_modules/react-native/ReactCommon/yoga`)
SPEC REPOS:
@@ -669,6 +669,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native/ReactCommon/logger"
react-native-background-timer:
:path: "../node_modules/react-native-background-timer"
react-native-biometrics:
:path: "../node_modules/react-native-biometrics"
react-native-blob-util:
:path: "../node_modules/react-native-blob-util"
react-native-blur:
@@ -778,8 +780,6 @@ EXTERNAL SOURCES:
secp256k1:
:git: https://github.com/status-im/secp256k1.swift.git
:submodules: true
TouchID:
:path: "../node_modules/react-native-touch-id"
Yoga:
:path: "../node_modules/react-native/ReactCommon/yoga"
@@ -793,7 +793,7 @@ CHECKOUT OPTIONS:
:submodules: true
SPEC CHECKSUMS:
boost: 64032b9e9b938fda23325e68a3771f0fabf414dc
boost: 57d2868c099736d80fcd648bf211b4431e51a558
BVLinearGradient: 612a04ff38e8480291f3379ee5b5a2c571f03fe0
CryptoSwift: c4f2debceb38bf44c80659afe009f71e23e4a082
DoubleConversion: 5189b271737e1565bdce30deb4a08d647e3f5f54
@@ -822,6 +822,7 @@ SPEC CHECKSUMS:
React-jsinspector: aef73cbd43b70675f572214d10fa438c89bf11ba
React-logger: 2e4aee3e11b3ec4fa6cfd8004610bbb3b8d6cca4
react-native-background-timer: 1f7d560647b40e6a60b01c452ba29c54bf581fc4
react-native-biometrics: 352e5a794bfffc46a0c86725ea7dc62deb085bdc
react-native-blob-util: 600972b1782380a5a7d5db61a3817ea32349dae9
react-native-blur: c6d0a1dc2b4b519f7afe3b14d8151998632b6d18
react-native-cameraroll: 4701ae7c3dbcd3f5e9e150ca17f250a276154b35
@@ -881,7 +882,6 @@ SPEC CHECKSUMS:
SocketRocket: f32cd54efbe0f095c4d7594881e52619cfe80b17
SSZipArchive: fe6a26b2a54d5a0890f2567b5cc6de5caa600aef
TOCropViewController: edfd4f25713d56905ad1e0b9f5be3fbe0f59c863
TouchID: ba4c656d849cceabc2e4eef722dea5e55959ecf4
Yoga: 86fed2e4d425ee4c6eab3813ba1791101ee153c6
PODFILE CHECKSUM: 3f98ce893757dfa17e609ef7cd24fa41635b73a6
+25 -531
View File
@@ -1055,21 +1055,6 @@
}
},
{
"path": "androidx/databinding/databinding-common/3.3.1",
"repo": "https://dl.google.com/dl/android/maven2",
"files": {
"databinding-common-3.3.1.pom": {
"sha1": "2e932d3219ea5f6d1078b24a8a3ce24b209c9309",
"sha256": "sha256-J5Qv7Gy8ROM19MN5Rx/lo2BsA7Zwt+NG6lXxYtjrF10="
},
"databinding-common-3.3.1.jar": {
"sha1": "45795e2f688474b219d37beb7f9f6756578e6454",
"sha256": "sha256-mq9hUr+3QZCgovJ1St/aoqkP7Ef50KwR811ej5iYkyw="
}
}
},
{
"path": "androidx/databinding/databinding-common/3.5.4",
"repo": "https://dl.google.com/dl/android/maven2",
@@ -1179,21 +1164,6 @@
}
},
{
"path": "androidx/databinding/databinding-compiler-common/3.3.1",
"repo": "https://dl.google.com/dl/android/maven2",
"files": {
"databinding-compiler-common-3.3.1.pom": {
"sha1": "123c2b1dd44ec6e2441be9441bdf393462936928",
"sha256": "sha256-na2hPeqxkcTcC9T7EvFs12+r1ygfSfnOHIirb3kXyzI="
},
"databinding-compiler-common-3.3.1.jar": {
"sha1": "e96aa159e1ed5c5a3461d15adfc42ef5b1f68b59",
"sha256": "sha256-sfLOroi0d73GMp2r8SCNhCHFrT/HzPpEOXEOVBcvxh0="
}
}
},
{
"path": "androidx/databinding/databinding-compiler-common/3.5.4",
"repo": "https://dl.google.com/dl/android/maven2",
@@ -2755,21 +2725,6 @@
}
},
{
"path": "com/android/databinding/baseLibrary/3.3.1",
"repo": "https://dl.google.com/dl/android/maven2",
"files": {
"baseLibrary-3.3.1.pom": {
"sha1": "611fd96b47fdd27dd88afc23829975278d47774c",
"sha256": "sha256-dKLQobB7s6ExmWyEIG/CHmDQaT4pa7EI07c9B7hnUj8="
},
"baseLibrary-3.3.1.jar": {
"sha1": "702acc804e85563d3ae7b8ee49122e4f857dde83",
"sha256": "sha256-5QRyEqpp1J0FULCvlrQQC4xslwG4PD+24ZzGbzxK6cQ="
}
}
},
{
"path": "com/android/databinding/baseLibrary/3.5.4",
"repo": "https://dl.google.com/dl/android/maven2",
@@ -3288,21 +3243,6 @@
}
},
{
"path": "com/android/tools/analytics-library/crash/26.3.1",
"repo": "https://dl.google.com/dl/android/maven2",
"files": {
"crash-26.3.1.pom": {
"sha1": "7b667eb48f02b8ba2a981a962e9c1137e251c1e0",
"sha256": "sha256-m0FH4hP4dmWwzUXF6w47Q79EWJf5r9rKF/c8wjjF01c="
},
"crash-26.3.1.jar": {
"sha1": "46163f2cf0e16a1ba9be2ad6dddc39f1a1d6b613",
"sha256": "sha256-k5OoPOLz+pZ4LCU98yROaZo7PfGG3pJssTiVj6+VYpM="
}
}
},
{
"path": "com/android/tools/analytics-library/crash/26.5.4",
"repo": "https://dl.google.com/dl/android/maven2",
@@ -3442,21 +3382,6 @@
}
},
{
"path": "com/android/tools/analytics-library/protos/26.3.1",
"repo": "https://dl.google.com/dl/android/maven2",
"files": {
"protos-26.3.1.pom": {
"sha1": "d6015a3a017dcb62d9a9a56c28b5c47bb6727a91",
"sha256": "sha256-IP1qlda7IElg7qdLFBTEWy78J0+4Tf90MnqRYezfc3k="
},
"protos-26.3.1.jar": {
"sha1": "f35a0accd93cfbb4306268ea748e1ac49920a0a8",
"sha256": "sha256-70/09xLY//RrI3jBwQh5l1hXdvpsGhwgBpbXd0eNnUw="
}
}
},
{
"path": "com/android/tools/analytics-library/protos/26.5.4",
"repo": "https://dl.google.com/dl/android/maven2",
@@ -3596,21 +3521,6 @@
}
},
{
"path": "com/android/tools/analytics-library/shared/26.3.1",
"repo": "https://dl.google.com/dl/android/maven2",
"files": {
"shared-26.3.1.pom": {
"sha1": "af1e1e7d120696bfee452247b5224290d91d828f",
"sha256": "sha256-3Hxmxmp5mFLNaGRaEXOJSRxiTU1U+OzdX5QENgHtys4="
},
"shared-26.3.1.jar": {
"sha1": "3457faee7a68d84dcbd258889567153acfc731a2",
"sha256": "sha256-bSe5quJj4rwth0SR72dh86WuH34wzEq2v7ktd/2tO/A="
}
}
},
{
"path": "com/android/tools/analytics-library/shared/26.5.4",
"repo": "https://dl.google.com/dl/android/maven2",
@@ -3750,21 +3660,6 @@
}
},
{
"path": "com/android/tools/analytics-library/tracker/26.3.1",
"repo": "https://dl.google.com/dl/android/maven2",
"files": {
"tracker-26.3.1.pom": {
"sha1": "6775a4eeafd2ef5270750388ee53503eeafa688b",
"sha256": "sha256-+mgVCnuDFGnXWVQ1ZGPkmcJjl1ubk/YmTQ3qjRHlKwg="
},
"tracker-26.3.1.jar": {
"sha1": "26248cad2525e003752322cfc6bd86182df7daac",
"sha256": "sha256-JG6AgEtANgzjGNp7nRKUjgrUHQwpzHvbOGF9weaWnYg="
}
}
},
{
"path": "com/android/tools/analytics-library/tracker/26.5.4",
"repo": "https://dl.google.com/dl/android/maven2",
@@ -3904,21 +3799,6 @@
}
},
{
"path": "com/android/tools/annotations/26.3.1",
"repo": "https://dl.google.com/dl/android/maven2",
"files": {
"annotations-26.3.1.pom": {
"sha1": "bce2159e811cceee12498cb34812cbae1e7b8eda",
"sha256": "sha256-Y7XWCr1wC4On07xPXk1+cRxZsOB6WsMmd2FOP/1xJLE="
},
"annotations-26.3.1.jar": {
"sha1": "3d46d5da6d5dd17df682a22b914cdc6b84677731",
"sha256": "sha256-U0rc5Q64KdT4yXW8NOpVs49oxjAOAA4rR8Q6xnLQxyE="
}
}
},
{
"path": "com/android/tools/annotations/26.5.4",
"repo": "https://dl.google.com/dl/android/maven2",
@@ -4346,21 +4226,6 @@
}
},
{
"path": "com/android/tools/build/apksig/3.3.1",
"repo": "https://dl.google.com/dl/android/maven2",
"files": {
"apksig-3.3.1.pom": {
"sha1": "e916d810d293ce4ab620435b41d2e3bc67972cd3",
"sha256": "sha256-cGliMgmhK5sal8XJypuekagqDkDG4h4LlMc5barHh80="
},
"apksig-3.3.1.jar": {
"sha1": "5dc32667e573a18b05119685ac3f2b8c0f17182d",
"sha256": "sha256-NXs57dinjUgKlT5rl8CYWf1AyXLBpJtvnTvT1LmYyy0="
}
}
},
{
"path": "com/android/tools/build/apksig/3.5.4",
"repo": "https://dl.google.com/dl/android/maven2",
@@ -4470,21 +4335,6 @@
}
},
{
"path": "com/android/tools/build/apkzlib/3.3.1",
"repo": "https://dl.google.com/dl/android/maven2",
"files": {
"apkzlib-3.3.1.pom": {
"sha1": "02214cdec00c2553430192a7f36e9a28cf96bf6f",
"sha256": "sha256-IVhIC03ar9F8K15CEeAPstojFB93BY+VjRqUlFBZ0IU="
},
"apkzlib-3.3.1.jar": {
"sha1": "0563a5b71668b4fe7da03a0a3054c9fdd973d3cf",
"sha256": "sha256-ZAVmwOT1BZATm7z7sP90TB9tzZ8mL48tAVn8QZQTgcw="
}
}
},
{
"path": "com/android/tools/build/apkzlib/3.5.4",
"repo": "https://dl.google.com/dl/android/maven2",
@@ -4624,21 +4474,6 @@
}
},
{
"path": "com/android/tools/build/builder-model/3.3.1",
"repo": "https://dl.google.com/dl/android/maven2",
"files": {
"builder-model-3.3.1.pom": {
"sha1": "4011d22709777c4063e84d39dbfe4ed535a31905",
"sha256": "sha256-XVNezIVtl4YN/ZElCFrqki4FTrfZ4SRPg3p0n76b++M="
},
"builder-model-3.3.1.jar": {
"sha1": "2c47cf0451da2eaad484ccd2d580a8cfd23fa064",
"sha256": "sha256-BXtSlcP+jNze+uaN47+/nHbTnaI+BMw0ZdZgA3oxfwA="
}
}
},
{
"path": "com/android/tools/build/builder-model/3.5.4",
"repo": "https://dl.google.com/dl/android/maven2",
@@ -4790,21 +4625,6 @@
}
},
{
"path": "com/android/tools/build/builder-test-api/3.3.1",
"repo": "https://dl.google.com/dl/android/maven2",
"files": {
"builder-test-api-3.3.1.pom": {
"sha1": "e79a310b9c89fcb62f343b727f5747783c778861",
"sha256": "sha256-heZof7B9lqEFRE1Rouwnrz9798H5w72QcGZ9QblfZAY="
},
"builder-test-api-3.3.1.jar": {
"sha1": "c1a1ce91c0f34c43a52c54c1a2f6fdbaafadd3da",
"sha256": "sha256-KYnV5vE5YwFoEC40dwJCFbnKvew+Gqc4saBze0tfyww="
}
}
},
{
"path": "com/android/tools/build/builder-test-api/3.5.4",
"repo": "https://dl.google.com/dl/android/maven2",
@@ -4956,21 +4776,6 @@
}
},
{
"path": "com/android/tools/build/builder/3.3.1",
"repo": "https://dl.google.com/dl/android/maven2",
"files": {
"builder-3.3.1.pom": {
"sha1": "fbca96adc8069b8fcb01c7271c3b4be4f901b517",
"sha256": "sha256-pg/e6U4EqMemXDi6m2UFhcOkv0cisGFnuI85cO4UA+Q="
},
"builder-3.3.1.jar": {
"sha1": "e4d2ad1ef694fca700b3ab1f4df4b79313d17c98",
"sha256": "sha256-zoj1PYZLXN+oW1cC5yiz1u0NOqkoy2HghCRtSlUBXFI="
}
}
},
{
"path": "com/android/tools/build/builder/3.5.4",
"repo": "https://dl.google.com/dl/android/maven2",
@@ -5092,21 +4897,6 @@
}
},
{
"path": "com/android/tools/build/bundletool/0.6.0",
"repo": "https://dl.google.com/dl/android/maven2",
"files": {
"bundletool-0.6.0.pom": {
"sha1": "5a6e5b5af1687285125f43e00a8e5a8efe6f76a4",
"sha256": "sha256-YDqi6WyRrkPynACNA16mdo0fJya6qjAqXwzYBFfgRiI="
},
"bundletool-0.6.0.jar": {
"sha1": "fb944be26f692e6ac937924ad5be7faa4093dd80",
"sha256": "sha256-QAU1QDlstRlZ0GYLSihk7mqBaXi/AT/UwB3L7IlcS7o="
}
}
},
{
"path": "com/android/tools/build/bundletool/0.9.0",
"repo": "https://dl.google.com/dl/android/maven2",
@@ -5242,21 +5032,6 @@
}
},
{
"path": "com/android/tools/build/gradle-api/3.3.1",
"repo": "https://dl.google.com/dl/android/maven2",
"files": {
"gradle-api-3.3.1.pom": {
"sha1": "c9a6cecdb5e233c2ffde76507bddc6f26ade5528",
"sha256": "sha256-3BUSdrg4w9TdT8QdcwRoOkTGotjb3ngpdN9p+1g8dRQ="
},
"gradle-api-3.3.1.jar": {
"sha1": "93aac19942998e480db4195212150fb30f7a78cd",
"sha256": "sha256-SMmx/OFMswX3/3XdL97Ds/qtZK/pFQbviYoEsIbmtBY="
}
}
},
{
"path": "com/android/tools/build/gradle-api/3.5.4",
"repo": "https://dl.google.com/dl/android/maven2",
@@ -5457,21 +5232,6 @@
}
},
{
"path": "com/android/tools/build/gradle/3.3.1",
"repo": "https://dl.google.com/dl/android/maven2",
"files": {
"gradle-3.3.1.pom": {
"sha1": "1769370bffda87132eb79580bf54ccb9eb339020",
"sha256": "sha256-9eitp3Q6B3or5f+qF0Q0VmkSQa7ZEoYVgAXzUcRA/3w="
},
"gradle-3.3.1.jar": {
"sha1": "7d642f14aa35443dd7aeecd0600c17da37d3bccc",
"sha256": "sha256-9WSZq8Ux35uuhlFo5y8kCHAtSgH0bXuMGgowDWLcEb0="
}
}
},
{
"path": "com/android/tools/build/gradle/3.5.4",
"repo": "https://dl.google.com/dl/android/maven2",
@@ -5593,21 +5353,6 @@
}
},
{
"path": "com/android/tools/build/jetifier/jetifier-core/1.0.0-beta02",
"repo": "https://dl.google.com/dl/android/maven2",
"files": {
"jetifier-core-1.0.0-beta02.pom": {
"sha1": "db878af76000b681798b114a5169163b1efe59ea",
"sha256": "sha256-kJGGklY7MCjkeLrxyUM3jfSIOTpSeJWMbzaWO2jfw7k="
},
"jetifier-core-1.0.0-beta02.jar": {
"sha1": "fa93fdb83bdfd51e80e09a808fb2515a7134d406",
"sha256": "sha256-72H4QwL4tB3OOFjB/H56kOx0omOgITsfZegMVhRaR5M="
}
}
},
{
"path": "com/android/tools/build/jetifier/jetifier-core/1.0.0-beta04",
"repo": "https://dl.google.com/dl/android/maven2",
@@ -5672,21 +5417,6 @@
}
},
{
"path": "com/android/tools/build/jetifier/jetifier-processor/1.0.0-beta02",
"repo": "https://dl.google.com/dl/android/maven2",
"files": {
"jetifier-processor-1.0.0-beta02.pom": {
"sha1": "3bf006f5a449806a9ad493a99c9f9417b3040ef0",
"sha256": "sha256-+zYwiX233O8PE6VViKrYxkvcGPZ64KHizNR1igcioa8="
},
"jetifier-processor-1.0.0-beta02.jar": {
"sha1": "624d187319c8dfd6bc8281b4afbab87c39bbb005",
"sha256": "sha256-J+UFZWvlNLNIYHQy/EEeKVQLCE0NTkhlIyqnYswe9Aw="
}
}
},
{
"path": "com/android/tools/build/jetifier/jetifier-processor/1.0.0-beta04",
"repo": "https://dl.google.com/dl/android/maven2",
@@ -5781,21 +5511,6 @@
}
},
{
"path": "com/android/tools/build/manifest-merger/26.3.1",
"repo": "https://dl.google.com/dl/android/maven2",
"files": {
"manifest-merger-26.3.1.pom": {
"sha1": "1aad18d13e7389cf148b1c6c468b2947ca23cbbd",
"sha256": "sha256-YNhLNKJlpgVeZhxpOvIFB1mgbYpuXLpk370esi0vpPU="
},
"manifest-merger-26.3.1.jar": {
"sha1": "aa94f738e318fc73059d9207f433f13556072d05",
"sha256": "sha256-hNrba75FBJgCeexO/2RdkaGgsPpagAQjmjS5vOZ1crU="
}
}
},
{
"path": "com/android/tools/build/manifest-merger/26.5.4",
"repo": "https://dl.google.com/dl/android/maven2",
@@ -5947,21 +5662,6 @@
}
},
{
"path": "com/android/tools/common/26.3.1",
"repo": "https://dl.google.com/dl/android/maven2",
"files": {
"common-26.3.1.pom": {
"sha1": "b79360c83ea68ba7f0ac0fadf7c48e1a53511352",
"sha256": "sha256-mvrBYjeX9GBEevDT9gMuQfLdXx1N7pSbd3OBSR6NxVM="
},
"common-26.3.1.jar": {
"sha1": "b0e3aa846dd94f9608018f7ef6501d1069f6488c",
"sha256": "sha256-QashymLYGxzYciSbVSlD1rzTZmN32f1/cY3rQd7HM9Y="
}
}
},
{
"path": "com/android/tools/common/26.5.4",
"repo": "https://dl.google.com/dl/android/maven2",
@@ -6101,21 +5801,6 @@
}
},
{
"path": "com/android/tools/ddms/ddmlib/26.3.1",
"repo": "https://dl.google.com/dl/android/maven2",
"files": {
"ddmlib-26.3.1.pom": {
"sha1": "14405d92c982c96ace23b7a4c505b0d9de58cd8d",
"sha256": "sha256-MhUp9OEUJ8VtX0uLtcJkLAHza1LkO1wwnEk81IM9sNE="
},
"ddmlib-26.3.1.jar": {
"sha1": "61ca2873fcce1012ba9782adf7e9b0e164fb6007",
"sha256": "sha256-oTYJ+lhJr4+Os0JzaOG8KMp7DwSvKGwLqVoAfrkkHro="
}
}
},
{
"path": "com/android/tools/ddms/ddmlib/26.5.4",
"repo": "https://dl.google.com/dl/android/maven2",
@@ -6255,21 +5940,6 @@
}
},
{
"path": "com/android/tools/dvlib/26.3.1",
"repo": "https://dl.google.com/dl/android/maven2",
"files": {
"dvlib-26.3.1.pom": {
"sha1": "c438f3c025bd878ac3b54368e012b3792f9c8928",
"sha256": "sha256-3lL/6GFK8OCRXxbiIujskxfriVuL9GtfE7hU8B2mDdY="
},
"dvlib-26.3.1.jar": {
"sha1": "971430b6163a834656d07434c46fee64d109ad8e",
"sha256": "sha256-cLMOL4Sc+kKqE7+GWenhTAKtfLSkbLKB4CKOuC5XM4s="
}
}
},
{
"path": "com/android/tools/dvlib/26.5.4",
"repo": "https://dl.google.com/dl/android/maven2",
@@ -6514,21 +6184,6 @@
}
},
{
"path": "com/android/tools/layoutlib/layoutlib-api/26.3.1",
"repo": "https://dl.google.com/dl/android/maven2",
"files": {
"layoutlib-api-26.3.1.pom": {
"sha1": "0355e0146c59a91fbb303d7faaa6d2d0413f5dde",
"sha256": "sha256-az/hSE+y4dWr/4VYc0KxX5tM3W6E/Vkjm9r7ShTtLXg="
},
"layoutlib-api-26.3.1.jar": {
"sha1": "969ef3a7c0c3b245a3efe8aff7a2f6f15ff4e824",
"sha256": "sha256-Tk6yS7wTU2sl1t063kHZJWr1rnuBpBe5a1WEMLUKQV4="
}
}
},
{
"path": "com/android/tools/layoutlib/layoutlib-api/26.5.4",
"repo": "https://dl.google.com/dl/android/maven2",
@@ -6728,21 +6383,6 @@
}
},
{
"path": "com/android/tools/lint/lint-gradle-api/26.3.1",
"repo": "https://dl.google.com/dl/android/maven2",
"files": {
"lint-gradle-api-26.3.1.pom": {
"sha1": "dbdbed4b5fa948b991335771c7005fc8aa8be73b",
"sha256": "sha256-6xds70C7k1Yy8gaACv2XSeMP+suuYIgzflDCP2vG5CA="
},
"lint-gradle-api-26.3.1.jar": {
"sha1": "d55e1bcbe4e7c0bb97f5c385a003c4339e38d07f",
"sha256": "sha256-RcBjcp/izzXWOh/9Ih17gtPkpxWay2AvqWuc/5BN5sk="
}
}
},
{
"path": "com/android/tools/lint/lint-gradle-api/26.5.4",
"repo": "https://dl.google.com/dl/android/maven2",
@@ -7017,21 +6657,6 @@
}
},
{
"path": "com/android/tools/repository/26.3.1",
"repo": "https://dl.google.com/dl/android/maven2",
"files": {
"repository-26.3.1.pom": {
"sha1": "ab5a2f6cbedccf4ff9efbd5301fe26c9d1aaea2a",
"sha256": "sha256-VRlYrn5H3gUTtUim8TrCf8Bv8/Ww/x6aQ8SAjzRz6zc="
},
"repository-26.3.1.jar": {
"sha1": "0fe4c713437ebfb8c68e95c717c063843bd63758",
"sha256": "sha256-UZR25PiBJMbbndC98J8MSqXMi/Hvq4Dd3uL3Wmug784="
}
}
},
{
"path": "com/android/tools/repository/26.5.4",
"repo": "https://dl.google.com/dl/android/maven2",
@@ -7171,21 +6796,6 @@
}
},
{
"path": "com/android/tools/sdklib/26.3.1",
"repo": "https://dl.google.com/dl/android/maven2",
"files": {
"sdklib-26.3.1.pom": {
"sha1": "d6cfc0d8a0f49620138cfaea6c51201c7c678633",
"sha256": "sha256-gnUcqRaojEMoL7ZX1kJerqAstwsEAJlroYEZr6GRRCE="
},
"sdklib-26.3.1.jar": {
"sha1": "85c3c1de8824ca1f5ff491690931256c23a7297b",
"sha256": "sha256-aEN9Fbfmle8G6Yu88HEQQJlVtjsBijR7pofwGuxQfQo="
}
}
},
{
"path": "com/android/tools/sdklib/26.5.4",
"repo": "https://dl.google.com/dl/android/maven2",
@@ -7325,21 +6935,6 @@
}
},
{
"path": "com/android/tools/sdk-common/26.3.1",
"repo": "https://dl.google.com/dl/android/maven2",
"files": {
"sdk-common-26.3.1.pom": {
"sha1": "9b7b4248e21db9c342dba7c3e891f740246b97c3",
"sha256": "sha256-jFp1bExxaochJmmIvOMohkjrj3uDF3DFct1Pcp85iqg="
},
"sdk-common-26.3.1.jar": {
"sha1": "c9bed0f05024f919fe6168ef381afbe72074a272",
"sha256": "sha256-s2dcStd5EUHIfzaADxkUIz8q9Rx2b+F67BsVIsgOL8g="
}
}
},
{
"path": "com/android/tools/sdk-common/26.5.4",
"repo": "https://dl.google.com/dl/android/maven2",
@@ -11342,17 +10937,6 @@
}
},
{
"path": "com/google/guava/guava-parent/26.0-jre",
"repo": "https://repo.maven.apache.org/maven2",
"files": {
"guava-parent-26.0-jre.pom": {
"sha1": "3a638a46e3277ff6a3d43d2a50bcccfac2966815",
"sha256": "sha256-u31c1BfA19714+Jwkv3SNSLT/CUa2KB5VsE84Fc66qM="
}
}
},
{
"path": "com/google/guava/guava-parent/27.0.1-jre",
"repo": "https://repo.maven.apache.org/maven2",
@@ -11505,21 +11089,6 @@
}
},
{
"path": "com/google/guava/guava/26.0-jre",
"repo": "https://repo.maven.apache.org/maven2",
"files": {
"guava-26.0-jre.pom": {
"sha1": "7883e19f8b0cca8c4498d476743e31b107674155",
"sha256": "sha256-HDN63JpKtLhE2oHahZNlgbiUbHy3EoTF3L2vHqp+4Qk="
},
"guava-26.0-jre.jar": {
"sha1": "6a806eff209f36f635f943e16d97491f00f6bfab",
"sha256": "sha256-oOnKutZlvCC80rAfEI5fwD91bhOuqAq6rbn0BwM76iw="
}
}
},
{
"path": "com/google/guava/guava/27.0.1-jre",
"repo": "https://repo.maven.apache.org/maven2",
@@ -14121,16 +13690,16 @@
},
{
"path": "net/bytebuddy/byte-buddy-agent/1.14.10",
"path": "net/bytebuddy/byte-buddy-agent/1.14.11",
"repo": "https://repo.maven.apache.org/maven2",
"files": {
"byte-buddy-agent-1.14.10.pom": {
"sha1": "ab24aa41b81d9496ec9ccd188a0449327d93bfdf",
"sha256": "sha256-U7yX6ca/fC0OX5y6x9Xeaykk2RbPS4F+ajo1kpx5a0o="
"byte-buddy-agent-1.14.11.pom": {
"sha1": "00a2165ce3253489dd9fd0836a169dfce74e2042",
"sha256": "sha256-VBMQ/3WsTurkYFUJn8Ec3b5TqcBe6vry9wMgZQ2zzOk="
},
"byte-buddy-agent-1.14.10.jar": {
"sha1": "90ed94ac044ea8953b224304c762316e91fd6b31",
"sha256": "sha256-Z5k6idR8pY/4aIAqREjd0VDl/k5aVkXe2ZDXtNVXprk="
"byte-buddy-agent-1.14.11.jar": {
"sha1": "f9cb566608fbac6bc7bf54901a7aa11543a989ee",
"sha256": "sha256-L1N6Yhpk+nAT1oxpWnajTujXna105jXKyhbdViV664A="
}
}
},
@@ -14158,12 +13727,12 @@
},
{
"path": "net/bytebuddy/byte-buddy-parent/1.14.10",
"path": "net/bytebuddy/byte-buddy-parent/1.14.11",
"repo": "https://repo.maven.apache.org/maven2",
"files": {
"byte-buddy-parent-1.14.10.pom": {
"sha1": "4c560a925c30d5911dc875af5af4737e21b397be",
"sha256": "sha256-xpghkGD7DlZaDyyWCU6Ssg7+FG/WFjayyeTAO9m6Sns="
"byte-buddy-parent-1.14.11.pom": {
"sha1": "696bf3e007e88bd1c0c2d877d74e0f3c56f2b96f",
"sha256": "sha256-RsDxP8l3jcLrtpdIgjqixMvwfqt9GMaqGRxSnRZQiSs="
}
}
},
@@ -14199,16 +13768,16 @@
},
{
"path": "net/bytebuddy/byte-buddy/1.14.10",
"path": "net/bytebuddy/byte-buddy/1.14.11",
"repo": "https://repo.maven.apache.org/maven2",
"files": {
"byte-buddy-1.14.10.pom": {
"sha1": "8806052a8770a6b3e14362ed0ce6ef263e6a20ab",
"sha256": "sha256-zVh4KEX/ju3y7YOgw+30Xu65nhTAWvii6QGGDqCAzq8="
"byte-buddy-1.14.11.pom": {
"sha1": "5ecfcd2f75aa8c7b6347d864a4d0a5212c360301",
"sha256": "sha256-NYRJ1sc1OFhFCN2K5s/eVrr0o0t2e3HZzEZE8PH0IRo="
},
"byte-buddy-1.14.10.jar": {
"sha1": "8117daf4a612122eb4f517f66adff778cb8b4737",
"sha256": "sha256-MObgRGQ3pn2zfit/fTP1B4fd/ZcDWTGd/QVGnaoty84="
"byte-buddy-1.14.11.jar": {
"sha1": "725602eb7c8c56b51b9c21f273f9df5c909d9e7d",
"sha256": "sha256-Yq4oGH7SsGKBPaap1We/7nM8NBWCaZti3ZgCMHKaAxM="
}
}
},
@@ -17822,21 +17391,6 @@
}
},
{
"path": "org/jetbrains/kotlin/kotlin-reflect/1.3.20",
"repo": "https://repo.maven.apache.org/maven2",
"files": {
"kotlin-reflect-1.3.20.pom": {
"sha1": "7cc0e8dc8e9bf863127aee4501449e25e85a6f78",
"sha256": "sha256-ajZdjTUpX69X8t86ssuQQgnaqsiQb8Y3R9Pjv6sJPeI="
},
"kotlin-reflect-1.3.20.jar": {
"sha1": "cd49eec32cf964333faf59e04b4085eac7008477",
"sha256": "sha256-7hqSbtZY594ObfAkLNV0s7TgjmT+emgngibG8tM3Mjg="
}
}
},
{
"path": "org/jetbrains/kotlin/kotlin-reflect/1.3.50",
"repo": "https://repo.maven.apache.org/maven2",
@@ -18227,21 +17781,6 @@
}
},
{
"path": "org/jetbrains/kotlin/kotlin-stdlib-common/1.3.20",
"repo": "https://repo.maven.apache.org/maven2",
"files": {
"kotlin-stdlib-common-1.3.20.pom": {
"sha1": "507fa9faf5120c5c5247bc1b23476ad91760c09c",
"sha256": "sha256-BIjdHCYv5hfXc2K8Sa+BjYztQJQ6pbA8GITb8kdRCjA="
},
"kotlin-stdlib-common-1.3.20.jar": {
"sha1": "7d7934e26ce34da1a0a8d00e38038d7cf3375e89",
"sha256": "sha256-Br3Yrto0fvbvPk6diKASVMzbcHhLaXSV9qQh/WY6tkk="
}
}
},
{
"path": "org/jetbrains/kotlin/kotlin-stdlib-common/1.3.31",
"repo": "https://repo.maven.apache.org/maven2",
@@ -18527,21 +18066,6 @@
}
},
{
"path": "org/jetbrains/kotlin/kotlin-stdlib-jdk7/1.3.20",
"repo": "https://repo.maven.apache.org/maven2",
"files": {
"kotlin-stdlib-jdk7-1.3.20.pom": {
"sha1": "665178dfa4d04de64edecf5f0dbda61b55f8f4e3",
"sha256": "sha256-SdtmBiZNOmpI+QgzXASEYirVyPTfjEjdSgAmdA4eFsU="
},
"kotlin-stdlib-jdk7-1.3.20.jar": {
"sha1": "aa17d6fd473ce53061a7b2b9d2ae96f547cae93d",
"sha256": "sha256-/Sr3C90rwCT7A8vtYzyhQ4cso2pqFuIYzGfIkLefsx0="
}
}
},
{
"path": "org/jetbrains/kotlin/kotlin-stdlib-jdk7/1.3.50",
"repo": "https://repo.maven.apache.org/maven2",
@@ -18722,21 +18246,6 @@
}
},
{
"path": "org/jetbrains/kotlin/kotlin-stdlib-jdk8/1.3.20",
"repo": "https://repo.maven.apache.org/maven2",
"files": {
"kotlin-stdlib-jdk8-1.3.20.pom": {
"sha1": "5c65523f57e3918ef722a15faae5173fc9a31331",
"sha256": "sha256-DF+73Rh7hSpRoKP7YskCSdpOdN//jf/5RphOL3AlCkI="
},
"kotlin-stdlib-jdk8-1.3.20.jar": {
"sha1": "b1f3cb184c4ce4139741454df2f8fca5320f822d",
"sha256": "sha256-bAgx5+OsqjkL8i952B8y8hLcj94ZgHo1Sk7k9migxHg="
}
}
},
{
"path": "org/jetbrains/kotlin/kotlin-stdlib-jdk8/1.3.50",
"repo": "https://repo.maven.apache.org/maven2",
@@ -18962,21 +18471,6 @@
}
},
{
"path": "org/jetbrains/kotlin/kotlin-stdlib/1.3.20",
"repo": "https://repo.maven.apache.org/maven2",
"files": {
"kotlin-stdlib-1.3.20.pom": {
"sha1": "9d1e01f424795aa471a8def0b5dc8aeeb537aafd",
"sha256": "sha256-Mu+dGkDXXOr0F5KW7VTdylp+ekpl4aAZ5kmOusg14Rw="
},
"kotlin-stdlib-1.3.20.jar": {
"sha1": "eb2a232734e09fcd1b958a5c7520a93c6de38b32",
"sha256": "sha256-YB+RDalo+z2o6te2Tta/XJcQ2DzqN+SmMYR+fWiOM2E="
}
}
},
{
"path": "org/jetbrains/kotlin/kotlin-stdlib/1.3.31",
"repo": "https://repo.maven.apache.org/maven2",
@@ -19666,16 +19160,16 @@
},
{
"path": "org/mockito/mockito-core/5.8.0",
"path": "org/mockito/mockito-core/5.9.0",
"repo": "https://repo.maven.apache.org/maven2",
"files": {
"mockito-core-5.8.0.pom": {
"sha1": "a2b7b33c5d649a2f48b1e7aab95d81671f66875f",
"sha256": "sha256-dJWKzd4UjzC/ox/8CFi2L3H2PMws602KjGfX9CjUOi0="
"mockito-core-5.9.0.pom": {
"sha1": "2054dcc15b9ede899cb9ec6e8e960e36c68b4574",
"sha256": "sha256-BJDEL+Yu7WRzQdpAojcHGW2BO0TbKj3KMB2IFz56yPc="
},
"mockito-core-5.8.0.jar": {
"sha1": "df310627f77f859114ad31e1376fff0dce263cca",
"sha256": "sha256-wyD2YqA8KVHtzFGkS2TXmo6ZQ3P/VIRTtf2vad6+RoI="
"mockito-core-5.9.0.jar": {
"sha1": "faa88b96db3aeb96a93e83dec7491345bfbfc414",
"sha256": "sha256-u62Rhe1zSWX6x+Nn8OUVlvaVMeUdiyy87BBI3W+0Hyw="
}
}
},
-33
View File
@@ -49,7 +49,6 @@ androidx.core:core:1.7.0
androidx.cursoradapter:cursoradapter:1.0.0
androidx.customview:customview:1.0.0
androidx.databinding:databinding-common:3.2.1
androidx.databinding:databinding-common:3.3.1
androidx.databinding:databinding-common:3.5.4
androidx.databinding:databinding-common:4.1.0
androidx.databinding:databinding-common:7.0.4
@@ -57,7 +56,6 @@ androidx.databinding:databinding-common:7.2.1
androidx.databinding:databinding-common:7.3.1
androidx.databinding:databinding-common:7.4.2
androidx.databinding:databinding-compiler-common:3.2.1
androidx.databinding:databinding-compiler-common:3.3.1
androidx.databinding:databinding-compiler-common:3.5.4
androidx.databinding:databinding-compiler-common:4.1.0
androidx.databinding:databinding-compiler-common:7.0.4
@@ -159,7 +157,6 @@ com.android.databinding:baseLibrary:1.0-rc5
com.android.databinding:baseLibrary:3.0.0
com.android.databinding:baseLibrary:3.0.1
com.android.databinding:baseLibrary:3.2.1
com.android.databinding:baseLibrary:3.3.1
com.android.databinding:baseLibrary:3.5.4
com.android.databinding:baseLibrary:4.1.0
com.android.databinding:baseLibrary:7.0.4
@@ -170,7 +167,6 @@ com.android.databinding:compilerCommon:1.0-rc5
com.android.databinding:compilerCommon:3.0.0
com.android.databinding:compilerCommon:3.0.1
com.android.tools.analytics-library:crash:26.2.1
com.android.tools.analytics-library:crash:26.3.1
com.android.tools.analytics-library:crash:26.5.4
com.android.tools.analytics-library:crash:27.1.0
com.android.tools.analytics-library:crash:30.0.4
@@ -180,7 +176,6 @@ com.android.tools.analytics-library:crash:30.4.2
com.android.tools.analytics-library:protos:26.0.0
com.android.tools.analytics-library:protos:26.0.1
com.android.tools.analytics-library:protos:26.2.1
com.android.tools.analytics-library:protos:26.3.1
com.android.tools.analytics-library:protos:26.5.4
com.android.tools.analytics-library:protos:27.1.0
com.android.tools.analytics-library:protos:30.0.4
@@ -190,7 +185,6 @@ com.android.tools.analytics-library:protos:30.4.2
com.android.tools.analytics-library:shared:26.0.0
com.android.tools.analytics-library:shared:26.0.1
com.android.tools.analytics-library:shared:26.2.1
com.android.tools.analytics-library:shared:26.3.1
com.android.tools.analytics-library:shared:26.5.4
com.android.tools.analytics-library:shared:27.1.0
com.android.tools.analytics-library:shared:30.0.4
@@ -200,7 +194,6 @@ com.android.tools.analytics-library:shared:30.4.2
com.android.tools.analytics-library:tracker:26.0.0
com.android.tools.analytics-library:tracker:26.0.1
com.android.tools.analytics-library:tracker:26.2.1
com.android.tools.analytics-library:tracker:26.3.1
com.android.tools.analytics-library:tracker:26.5.4
com.android.tools.analytics-library:tracker:27.1.0
com.android.tools.analytics-library:tracker:30.0.4
@@ -208,12 +201,10 @@ com.android.tools.analytics-library:tracker:30.2.1
com.android.tools.analytics-library:tracker:30.3.1
com.android.tools.analytics-library:tracker:30.4.2
com.android.tools.build.jetifier:jetifier-core:1.0.0-alpha10
com.android.tools.build.jetifier:jetifier-core:1.0.0-beta02
com.android.tools.build.jetifier:jetifier-core:1.0.0-beta04
com.android.tools.build.jetifier:jetifier-core:1.0.0-beta09
com.android.tools.build.jetifier:jetifier-core:1.0.0-beta10
com.android.tools.build.jetifier:jetifier-processor:1.0.0-alpha10
com.android.tools.build.jetifier:jetifier-processor:1.0.0-beta02
com.android.tools.build.jetifier:jetifier-processor:1.0.0-beta04
com.android.tools.build.jetifier:jetifier-processor:1.0.0-beta09
com.android.tools.build.jetifier:jetifier-processor:1.0.0-beta10
@@ -232,7 +223,6 @@ com.android.tools.build:aaptcompiler:7.4.2
com.android.tools.build:apksig:3.0.0
com.android.tools.build:apksig:3.0.1
com.android.tools.build:apksig:3.2.1
com.android.tools.build:apksig:3.3.1
com.android.tools.build:apksig:3.5.4
com.android.tools.build:apksig:4.1.0
com.android.tools.build:apksig:7.0.4
@@ -240,7 +230,6 @@ com.android.tools.build:apksig:7.2.1
com.android.tools.build:apksig:7.3.1
com.android.tools.build:apksig:7.4.2
com.android.tools.build:apkzlib:3.2.1
com.android.tools.build:apkzlib:3.3.1
com.android.tools.build:apkzlib:3.5.4
com.android.tools.build:apkzlib:4.1.0
com.android.tools.build:apkzlib:7.0.4
@@ -252,7 +241,6 @@ com.android.tools.build:builder-model:1.5.0
com.android.tools.build:builder-model:3.0.0
com.android.tools.build:builder-model:3.0.1
com.android.tools.build:builder-model:3.2.1
com.android.tools.build:builder-model:3.3.1
com.android.tools.build:builder-model:3.5.4
com.android.tools.build:builder-model:4.1.0
com.android.tools.build:builder-model:7.0.4
@@ -264,7 +252,6 @@ com.android.tools.build:builder-test-api:1.5.0
com.android.tools.build:builder-test-api:3.0.0
com.android.tools.build:builder-test-api:3.0.1
com.android.tools.build:builder-test-api:3.2.1
com.android.tools.build:builder-test-api:3.3.1
com.android.tools.build:builder-test-api:3.5.4
com.android.tools.build:builder-test-api:4.1.0
com.android.tools.build:builder-test-api:7.0.4
@@ -276,7 +263,6 @@ com.android.tools.build:builder:1.5.0
com.android.tools.build:builder:3.0.0
com.android.tools.build:builder:3.0.1
com.android.tools.build:builder:3.2.1
com.android.tools.build:builder:3.3.1
com.android.tools.build:builder:3.5.4
com.android.tools.build:builder:4.1.0
com.android.tools.build:builder:7.0.4
@@ -284,7 +270,6 @@ com.android.tools.build:builder:7.2.1
com.android.tools.build:builder:7.3.1
com.android.tools.build:builder:7.4.2
com.android.tools.build:bundletool:0.5.0
com.android.tools.build:bundletool:0.6.0
com.android.tools.build:bundletool:0.9.0
com.android.tools.build:bundletool:0.14.0
com.android.tools.build:bundletool:1.6.0
@@ -294,7 +279,6 @@ com.android.tools.build:bundletool:1.11.4
com.android.tools.build:gradle-api:3.0.0
com.android.tools.build:gradle-api:3.0.1
com.android.tools.build:gradle-api:3.2.1
com.android.tools.build:gradle-api:3.3.1
com.android.tools.build:gradle-api:3.5.4
com.android.tools.build:gradle-api:4.1.0
com.android.tools.build:gradle-api:7.0.4
@@ -311,7 +295,6 @@ com.android.tools.build:gradle:1.5.0
com.android.tools.build:gradle:3.0.0
com.android.tools.build:gradle:3.0.1
com.android.tools.build:gradle:3.2.1
com.android.tools.build:gradle:3.3.1
com.android.tools.build:gradle:3.5.4
com.android.tools.build:gradle:4.1.0
com.android.tools.build:gradle:7.0.4
@@ -322,7 +305,6 @@ com.android.tools.build:manifest-merger:24.5.0
com.android.tools.build:manifest-merger:26.0.0
com.android.tools.build:manifest-merger:26.0.1
com.android.tools.build:manifest-merger:26.2.1
com.android.tools.build:manifest-merger:26.3.1
com.android.tools.build:manifest-merger:26.5.4
com.android.tools.build:manifest-merger:27.1.0
com.android.tools.build:manifest-merger:30.0.4
@@ -336,7 +318,6 @@ com.android.tools.ddms:ddmlib:24.5.0
com.android.tools.ddms:ddmlib:26.0.0
com.android.tools.ddms:ddmlib:26.0.1
com.android.tools.ddms:ddmlib:26.2.1
com.android.tools.ddms:ddmlib:26.3.1
com.android.tools.ddms:ddmlib:26.5.4
com.android.tools.ddms:ddmlib:27.1.0
com.android.tools.ddms:ddmlib:30.0.4
@@ -355,7 +336,6 @@ com.android.tools.layoutlib:layoutlib-api:24.5.0
com.android.tools.layoutlib:layoutlib-api:26.0.0
com.android.tools.layoutlib:layoutlib-api:26.0.1
com.android.tools.layoutlib:layoutlib-api:26.2.1
com.android.tools.layoutlib:layoutlib-api:26.3.1
com.android.tools.layoutlib:layoutlib-api:26.5.4
com.android.tools.layoutlib:layoutlib-api:27.1.0
com.android.tools.layoutlib:layoutlib-api:30.0.4
@@ -371,7 +351,6 @@ com.android.tools.lint:lint-checks:24.5.0
com.android.tools.lint:lint-checks:26.0.0
com.android.tools.lint:lint-checks:26.0.1
com.android.tools.lint:lint-gradle-api:26.2.1
com.android.tools.lint:lint-gradle-api:26.3.1
com.android.tools.lint:lint-gradle-api:26.5.4
com.android.tools.lint:lint-gradle-api:27.1.0
com.android.tools.lint:lint-model:27.1.0
@@ -412,7 +391,6 @@ com.android.tools:annotations:24.5.0
com.android.tools:annotations:26.0.0
com.android.tools:annotations:26.0.1
com.android.tools:annotations:26.2.1
com.android.tools:annotations:26.3.1
com.android.tools:annotations:26.5.4
com.android.tools:annotations:27.1.0
com.android.tools:annotations:30.0.4
@@ -424,7 +402,6 @@ com.android.tools:common:24.5.0
com.android.tools:common:26.0.0
com.android.tools:common:26.0.1
com.android.tools:common:26.2.1
com.android.tools:common:26.3.1
com.android.tools:common:26.5.4
com.android.tools:common:27.1.0
com.android.tools:common:30.0.4
@@ -436,7 +413,6 @@ com.android.tools:dvlib:24.5.0
com.android.tools:dvlib:26.0.0
com.android.tools:dvlib:26.0.1
com.android.tools:dvlib:26.2.1
com.android.tools:dvlib:26.3.1
com.android.tools:dvlib:26.5.4
com.android.tools:dvlib:27.1.0
com.android.tools:dvlib:30.0.4
@@ -446,7 +422,6 @@ com.android.tools:dvlib:30.4.2
com.android.tools:repository:26.0.0
com.android.tools:repository:26.0.1
com.android.tools:repository:26.2.1
com.android.tools:repository:26.3.1
com.android.tools:repository:26.5.4
com.android.tools:repository:27.1.0
com.android.tools:repository:30.0.4
@@ -458,7 +433,6 @@ com.android.tools:sdklib:24.5.0
com.android.tools:sdklib:26.0.0
com.android.tools:sdklib:26.0.1
com.android.tools:sdklib:26.2.1
com.android.tools:sdklib:26.3.1
com.android.tools:sdklib:26.5.4
com.android.tools:sdklib:27.1.0
com.android.tools:sdklib:30.0.4
@@ -470,7 +444,6 @@ com.android.tools:sdk-common:24.5.0
com.android.tools:sdk-common:26.0.0
com.android.tools:sdk-common:26.0.1
com.android.tools:sdk-common:26.2.1
com.android.tools:sdk-common:26.3.1
com.android.tools:sdk-common:26.5.4
com.android.tools:sdk-common:27.1.0
com.android.tools:sdk-common:30.0.4
@@ -590,7 +563,6 @@ com.google.guava:failureaccess:1.0.1
com.google.guava:guava:17.0
com.google.guava:guava:22.0
com.google.guava:guava:23.0
com.google.guava:guava:26.0-jre
com.google.guava:guava:27.0.1-jre
com.google.guava:guava:28.1-jre
com.google.guava:guava:29.0-jre
@@ -817,7 +789,6 @@ org.jetbrains.kotlin:kotlin-project-model:1.6.20
org.jetbrains.kotlin:kotlin-project-model:1.9.0
org.jetbrains.kotlin:kotlin-reflect:1.1.3-2
org.jetbrains.kotlin:kotlin-reflect:1.2.0
org.jetbrains.kotlin:kotlin-reflect:1.3.20
org.jetbrains.kotlin:kotlin-reflect:1.3.50
org.jetbrains.kotlin:kotlin-reflect:1.3.72
org.jetbrains.kotlin:kotlin-reflect:1.4.32
@@ -834,7 +805,6 @@ org.jetbrains.kotlin:kotlin-scripting-jvm:1.6.20
org.jetbrains.kotlin:kotlin-scripting-jvm:1.9.0
org.jetbrains.kotlin:kotlin-script-runtime:1.9.0
org.jetbrains.kotlin:kotlin-stdlib-common:1.2.71
org.jetbrains.kotlin:kotlin-stdlib-common:1.3.20
org.jetbrains.kotlin:kotlin-stdlib-common:1.3.50
org.jetbrains.kotlin:kotlin-stdlib-common:1.3.72
org.jetbrains.kotlin:kotlin-stdlib-common:1.4.32
@@ -843,7 +813,6 @@ org.jetbrains.kotlin:kotlin-stdlib-common:1.6.20
org.jetbrains.kotlin:kotlin-stdlib-common:1.7.22
org.jetbrains.kotlin:kotlin-stdlib-common:1.9.0
org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.2.71
org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.20
org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.50
org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.72
org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.4.32
@@ -852,7 +821,6 @@ org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.6.20
org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.7.22
org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.9.0
org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.2.71
org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.20
org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.50
org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.72
org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.4.32
@@ -861,7 +829,6 @@ org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.7.22
org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.9.0
org.jetbrains.kotlin:kotlin-stdlib:1.1.3-2
org.jetbrains.kotlin:kotlin-stdlib:1.2.71
org.jetbrains.kotlin:kotlin-stdlib:1.3.20
org.jetbrains.kotlin:kotlin-stdlib:1.3.50
org.jetbrains.kotlin:kotlin-stdlib:1.3.72
org.jetbrains.kotlin:kotlin-stdlib:1.4.32
+4 -38
View File
@@ -62,7 +62,6 @@ https://dl.google.com/dl/android/maven2/androidx/core/core/1.7.0/core-1.7.0.pom
https://dl.google.com/dl/android/maven2/androidx/cursoradapter/cursoradapter/1.0.0/cursoradapter-1.0.0.pom
https://dl.google.com/dl/android/maven2/androidx/customview/customview/1.0.0/customview-1.0.0.pom
https://dl.google.com/dl/android/maven2/androidx/databinding/databinding-common/3.2.1/databinding-common-3.2.1.pom
https://dl.google.com/dl/android/maven2/androidx/databinding/databinding-common/3.3.1/databinding-common-3.3.1.pom
https://dl.google.com/dl/android/maven2/androidx/databinding/databinding-common/3.5.4/databinding-common-3.5.4.pom
https://dl.google.com/dl/android/maven2/androidx/databinding/databinding-common/4.1.0/databinding-common-4.1.0.pom
https://dl.google.com/dl/android/maven2/androidx/databinding/databinding-common/7.0.4/databinding-common-7.0.4.pom
@@ -70,7 +69,6 @@ https://dl.google.com/dl/android/maven2/androidx/databinding/databinding-common/
https://dl.google.com/dl/android/maven2/androidx/databinding/databinding-common/7.3.1/databinding-common-7.3.1.pom
https://dl.google.com/dl/android/maven2/androidx/databinding/databinding-common/7.4.2/databinding-common-7.4.2.pom
https://dl.google.com/dl/android/maven2/androidx/databinding/databinding-compiler-common/3.2.1/databinding-compiler-common-3.2.1.pom
https://dl.google.com/dl/android/maven2/androidx/databinding/databinding-compiler-common/3.3.1/databinding-compiler-common-3.3.1.pom
https://dl.google.com/dl/android/maven2/androidx/databinding/databinding-compiler-common/3.5.4/databinding-compiler-common-3.5.4.pom
https://dl.google.com/dl/android/maven2/androidx/databinding/databinding-compiler-common/4.1.0/databinding-compiler-common-4.1.0.pom
https://dl.google.com/dl/android/maven2/androidx/databinding/databinding-compiler-common/7.0.4/databinding-compiler-common-7.0.4.pom
@@ -170,7 +168,6 @@ https://dl.google.com/dl/android/maven2/android/arch/lifecycle/runtime/1.0.0/run
https://dl.google.com/dl/android/maven2/com/android/databinding/baseLibrary/3.0.0/baseLibrary-3.0.0.pom
https://dl.google.com/dl/android/maven2/com/android/databinding/baseLibrary/3.0.1/baseLibrary-3.0.1.pom
https://dl.google.com/dl/android/maven2/com/android/databinding/baseLibrary/3.2.1/baseLibrary-3.2.1.pom
https://dl.google.com/dl/android/maven2/com/android/databinding/baseLibrary/3.3.1/baseLibrary-3.3.1.pom
https://dl.google.com/dl/android/maven2/com/android/databinding/baseLibrary/3.5.4/baseLibrary-3.5.4.pom
https://dl.google.com/dl/android/maven2/com/android/databinding/baseLibrary/4.1.0/baseLibrary-4.1.0.pom
https://dl.google.com/dl/android/maven2/com/android/databinding/baseLibrary/7.0.4/baseLibrary-7.0.4.pom
@@ -205,7 +202,6 @@ https://dl.google.com/dl/android/maven2/com/android/support/support-v4/26.0.2/su
https://dl.google.com/dl/android/maven2/com/android/support/support-vector-drawable/26.0.2/support-vector-drawable-26.0.2.pom
https://dl.google.com/dl/android/maven2/com/android/support/support-vector-drawable/27.0.1/support-vector-drawable-27.0.1.pom
https://dl.google.com/dl/android/maven2/com/android/tools/analytics-library/crash/26.2.1/crash-26.2.1.pom
https://dl.google.com/dl/android/maven2/com/android/tools/analytics-library/crash/26.3.1/crash-26.3.1.pom
https://dl.google.com/dl/android/maven2/com/android/tools/analytics-library/crash/26.5.4/crash-26.5.4.pom
https://dl.google.com/dl/android/maven2/com/android/tools/analytics-library/crash/27.1.0/crash-27.1.0.pom
https://dl.google.com/dl/android/maven2/com/android/tools/analytics-library/crash/30.0.4/crash-30.0.4.pom
@@ -215,7 +211,6 @@ https://dl.google.com/dl/android/maven2/com/android/tools/analytics-library/cras
https://dl.google.com/dl/android/maven2/com/android/tools/analytics-library/protos/26.0.0/protos-26.0.0.pom
https://dl.google.com/dl/android/maven2/com/android/tools/analytics-library/protos/26.0.1/protos-26.0.1.pom
https://dl.google.com/dl/android/maven2/com/android/tools/analytics-library/protos/26.2.1/protos-26.2.1.pom
https://dl.google.com/dl/android/maven2/com/android/tools/analytics-library/protos/26.3.1/protos-26.3.1.pom
https://dl.google.com/dl/android/maven2/com/android/tools/analytics-library/protos/26.5.4/protos-26.5.4.pom
https://dl.google.com/dl/android/maven2/com/android/tools/analytics-library/protos/27.1.0/protos-27.1.0.pom
https://dl.google.com/dl/android/maven2/com/android/tools/analytics-library/protos/30.0.4/protos-30.0.4.pom
@@ -225,7 +220,6 @@ https://dl.google.com/dl/android/maven2/com/android/tools/analytics-library/prot
https://dl.google.com/dl/android/maven2/com/android/tools/analytics-library/shared/26.0.0/shared-26.0.0.pom
https://dl.google.com/dl/android/maven2/com/android/tools/analytics-library/shared/26.0.1/shared-26.0.1.pom
https://dl.google.com/dl/android/maven2/com/android/tools/analytics-library/shared/26.2.1/shared-26.2.1.pom
https://dl.google.com/dl/android/maven2/com/android/tools/analytics-library/shared/26.3.1/shared-26.3.1.pom
https://dl.google.com/dl/android/maven2/com/android/tools/analytics-library/shared/26.5.4/shared-26.5.4.pom
https://dl.google.com/dl/android/maven2/com/android/tools/analytics-library/shared/27.1.0/shared-27.1.0.pom
https://dl.google.com/dl/android/maven2/com/android/tools/analytics-library/shared/30.0.4/shared-30.0.4.pom
@@ -235,7 +229,6 @@ https://dl.google.com/dl/android/maven2/com/android/tools/analytics-library/shar
https://dl.google.com/dl/android/maven2/com/android/tools/analytics-library/tracker/26.0.0/tracker-26.0.0.pom
https://dl.google.com/dl/android/maven2/com/android/tools/analytics-library/tracker/26.0.1/tracker-26.0.1.pom
https://dl.google.com/dl/android/maven2/com/android/tools/analytics-library/tracker/26.2.1/tracker-26.2.1.pom
https://dl.google.com/dl/android/maven2/com/android/tools/analytics-library/tracker/26.3.1/tracker-26.3.1.pom
https://dl.google.com/dl/android/maven2/com/android/tools/analytics-library/tracker/26.5.4/tracker-26.5.4.pom
https://dl.google.com/dl/android/maven2/com/android/tools/analytics-library/tracker/27.1.0/tracker-27.1.0.pom
https://dl.google.com/dl/android/maven2/com/android/tools/analytics-library/tracker/30.0.4/tracker-30.0.4.pom
@@ -245,7 +238,6 @@ https://dl.google.com/dl/android/maven2/com/android/tools/analytics-library/trac
https://dl.google.com/dl/android/maven2/com/android/tools/annotations/26.0.0/annotations-26.0.0.pom
https://dl.google.com/dl/android/maven2/com/android/tools/annotations/26.0.1/annotations-26.0.1.pom
https://dl.google.com/dl/android/maven2/com/android/tools/annotations/26.2.1/annotations-26.2.1.pom
https://dl.google.com/dl/android/maven2/com/android/tools/annotations/26.3.1/annotations-26.3.1.pom
https://dl.google.com/dl/android/maven2/com/android/tools/annotations/26.5.4/annotations-26.5.4.pom
https://dl.google.com/dl/android/maven2/com/android/tools/annotations/27.1.0/annotations-27.1.0.pom
https://dl.google.com/dl/android/maven2/com/android/tools/annotations/30.0.4/annotations-30.0.4.pom
@@ -271,7 +263,6 @@ https://dl.google.com/dl/android/maven2/com/android/tools/build/aaptcompiler/7.4
https://dl.google.com/dl/android/maven2/com/android/tools/build/apksig/3.0.0/apksig-3.0.0.pom
https://dl.google.com/dl/android/maven2/com/android/tools/build/apksig/3.0.1/apksig-3.0.1.pom
https://dl.google.com/dl/android/maven2/com/android/tools/build/apksig/3.2.1/apksig-3.2.1.pom
https://dl.google.com/dl/android/maven2/com/android/tools/build/apksig/3.3.1/apksig-3.3.1.pom
https://dl.google.com/dl/android/maven2/com/android/tools/build/apksig/3.5.4/apksig-3.5.4.pom
https://dl.google.com/dl/android/maven2/com/android/tools/build/apksig/4.1.0/apksig-4.1.0.pom
https://dl.google.com/dl/android/maven2/com/android/tools/build/apksig/7.0.4/apksig-7.0.4.pom
@@ -279,7 +270,6 @@ https://dl.google.com/dl/android/maven2/com/android/tools/build/apksig/7.2.1/apk
https://dl.google.com/dl/android/maven2/com/android/tools/build/apksig/7.3.1/apksig-7.3.1.pom
https://dl.google.com/dl/android/maven2/com/android/tools/build/apksig/7.4.2/apksig-7.4.2.pom
https://dl.google.com/dl/android/maven2/com/android/tools/build/apkzlib/3.2.1/apkzlib-3.2.1.pom
https://dl.google.com/dl/android/maven2/com/android/tools/build/apkzlib/3.3.1/apkzlib-3.3.1.pom
https://dl.google.com/dl/android/maven2/com/android/tools/build/apkzlib/3.5.4/apkzlib-3.5.4.pom
https://dl.google.com/dl/android/maven2/com/android/tools/build/apkzlib/4.1.0/apkzlib-4.1.0.pom
https://dl.google.com/dl/android/maven2/com/android/tools/build/apkzlib/7.0.4/apkzlib-7.0.4.pom
@@ -289,7 +279,6 @@ https://dl.google.com/dl/android/maven2/com/android/tools/build/apkzlib/7.4.2/ap
https://dl.google.com/dl/android/maven2/com/android/tools/build/builder-model/3.0.0/builder-model-3.0.0.pom
https://dl.google.com/dl/android/maven2/com/android/tools/build/builder-model/3.0.1/builder-model-3.0.1.pom
https://dl.google.com/dl/android/maven2/com/android/tools/build/builder-model/3.2.1/builder-model-3.2.1.pom
https://dl.google.com/dl/android/maven2/com/android/tools/build/builder-model/3.3.1/builder-model-3.3.1.pom
https://dl.google.com/dl/android/maven2/com/android/tools/build/builder-model/3.5.4/builder-model-3.5.4.pom
https://dl.google.com/dl/android/maven2/com/android/tools/build/builder-model/4.1.0/builder-model-4.1.0.pom
https://dl.google.com/dl/android/maven2/com/android/tools/build/builder-model/7.0.4/builder-model-7.0.4.pom
@@ -299,7 +288,6 @@ https://dl.google.com/dl/android/maven2/com/android/tools/build/builder-model/7.
https://dl.google.com/dl/android/maven2/com/android/tools/build/builder-test-api/3.0.0/builder-test-api-3.0.0.pom
https://dl.google.com/dl/android/maven2/com/android/tools/build/builder-test-api/3.0.1/builder-test-api-3.0.1.pom
https://dl.google.com/dl/android/maven2/com/android/tools/build/builder-test-api/3.2.1/builder-test-api-3.2.1.pom
https://dl.google.com/dl/android/maven2/com/android/tools/build/builder-test-api/3.3.1/builder-test-api-3.3.1.pom
https://dl.google.com/dl/android/maven2/com/android/tools/build/builder-test-api/3.5.4/builder-test-api-3.5.4.pom
https://dl.google.com/dl/android/maven2/com/android/tools/build/builder-test-api/4.1.0/builder-test-api-4.1.0.pom
https://dl.google.com/dl/android/maven2/com/android/tools/build/builder-test-api/7.0.4/builder-test-api-7.0.4.pom
@@ -309,7 +297,6 @@ https://dl.google.com/dl/android/maven2/com/android/tools/build/builder-test-api
https://dl.google.com/dl/android/maven2/com/android/tools/build/builder/3.0.0/builder-3.0.0.pom
https://dl.google.com/dl/android/maven2/com/android/tools/build/builder/3.0.1/builder-3.0.1.pom
https://dl.google.com/dl/android/maven2/com/android/tools/build/builder/3.2.1/builder-3.2.1.pom
https://dl.google.com/dl/android/maven2/com/android/tools/build/builder/3.3.1/builder-3.3.1.pom
https://dl.google.com/dl/android/maven2/com/android/tools/build/builder/3.5.4/builder-3.5.4.pom
https://dl.google.com/dl/android/maven2/com/android/tools/build/builder/4.1.0/builder-4.1.0.pom
https://dl.google.com/dl/android/maven2/com/android/tools/build/builder/7.0.4/builder-7.0.4.pom
@@ -317,7 +304,6 @@ https://dl.google.com/dl/android/maven2/com/android/tools/build/builder/7.2.1/bu
https://dl.google.com/dl/android/maven2/com/android/tools/build/builder/7.3.1/builder-7.3.1.pom
https://dl.google.com/dl/android/maven2/com/android/tools/build/builder/7.4.2/builder-7.4.2.pom
https://dl.google.com/dl/android/maven2/com/android/tools/build/bundletool/0.5.0/bundletool-0.5.0.pom
https://dl.google.com/dl/android/maven2/com/android/tools/build/bundletool/0.6.0/bundletool-0.6.0.pom
https://dl.google.com/dl/android/maven2/com/android/tools/build/bundletool/0.9.0/bundletool-0.9.0.pom
https://dl.google.com/dl/android/maven2/com/android/tools/build/bundletool/0.14.0/bundletool-0.14.0.pom
https://dl.google.com/dl/android/maven2/com/android/tools/build/bundletool/1.6.0/bundletool-1.6.0.pom
@@ -327,7 +313,6 @@ https://dl.google.com/dl/android/maven2/com/android/tools/build/bundletool/1.11.
https://dl.google.com/dl/android/maven2/com/android/tools/build/gradle-api/3.0.0/gradle-api-3.0.0.pom
https://dl.google.com/dl/android/maven2/com/android/tools/build/gradle-api/3.0.1/gradle-api-3.0.1.pom
https://dl.google.com/dl/android/maven2/com/android/tools/build/gradle-api/3.2.1/gradle-api-3.2.1.pom
https://dl.google.com/dl/android/maven2/com/android/tools/build/gradle-api/3.3.1/gradle-api-3.3.1.pom
https://dl.google.com/dl/android/maven2/com/android/tools/build/gradle-api/3.5.4/gradle-api-3.5.4.pom
https://dl.google.com/dl/android/maven2/com/android/tools/build/gradle-api/4.1.0/gradle-api-4.1.0.pom
https://dl.google.com/dl/android/maven2/com/android/tools/build/gradle-api/7.0.4/gradle-api-7.0.4.pom
@@ -340,7 +325,6 @@ https://dl.google.com/dl/android/maven2/com/android/tools/build/gradle-settings-
https://dl.google.com/dl/android/maven2/com/android/tools/build/gradle/3.0.0/gradle-3.0.0.pom
https://dl.google.com/dl/android/maven2/com/android/tools/build/gradle/3.0.1/gradle-3.0.1.pom
https://dl.google.com/dl/android/maven2/com/android/tools/build/gradle/3.2.1/gradle-3.2.1.pom
https://dl.google.com/dl/android/maven2/com/android/tools/build/gradle/3.3.1/gradle-3.3.1.pom
https://dl.google.com/dl/android/maven2/com/android/tools/build/gradle/3.5.4/gradle-3.5.4.pom
https://dl.google.com/dl/android/maven2/com/android/tools/build/gradle/4.1.0/gradle-4.1.0.pom
https://dl.google.com/dl/android/maven2/com/android/tools/build/gradle/7.0.4/gradle-7.0.4.pom
@@ -348,19 +332,16 @@ https://dl.google.com/dl/android/maven2/com/android/tools/build/gradle/7.2.1/gra
https://dl.google.com/dl/android/maven2/com/android/tools/build/gradle/7.3.1/gradle-7.3.1.pom
https://dl.google.com/dl/android/maven2/com/android/tools/build/gradle/7.4.2/gradle-7.4.2.pom
https://dl.google.com/dl/android/maven2/com/android/tools/build/jetifier/jetifier-core/1.0.0-alpha10/jetifier-core-1.0.0-alpha10.pom
https://dl.google.com/dl/android/maven2/com/android/tools/build/jetifier/jetifier-core/1.0.0-beta02/jetifier-core-1.0.0-beta02.pom
https://dl.google.com/dl/android/maven2/com/android/tools/build/jetifier/jetifier-core/1.0.0-beta04/jetifier-core-1.0.0-beta04.pom
https://dl.google.com/dl/android/maven2/com/android/tools/build/jetifier/jetifier-core/1.0.0-beta09/jetifier-core-1.0.0-beta09.pom
https://dl.google.com/dl/android/maven2/com/android/tools/build/jetifier/jetifier-core/1.0.0-beta10/jetifier-core-1.0.0-beta10.pom
https://dl.google.com/dl/android/maven2/com/android/tools/build/jetifier/jetifier-processor/1.0.0-alpha10/jetifier-processor-1.0.0-alpha10.pom
https://dl.google.com/dl/android/maven2/com/android/tools/build/jetifier/jetifier-processor/1.0.0-beta02/jetifier-processor-1.0.0-beta02.pom
https://dl.google.com/dl/android/maven2/com/android/tools/build/jetifier/jetifier-processor/1.0.0-beta04/jetifier-processor-1.0.0-beta04.pom
https://dl.google.com/dl/android/maven2/com/android/tools/build/jetifier/jetifier-processor/1.0.0-beta09/jetifier-processor-1.0.0-beta09.pom
https://dl.google.com/dl/android/maven2/com/android/tools/build/jetifier/jetifier-processor/1.0.0-beta10/jetifier-processor-1.0.0-beta10.pom
https://dl.google.com/dl/android/maven2/com/android/tools/build/manifest-merger/26.0.0/manifest-merger-26.0.0.pom
https://dl.google.com/dl/android/maven2/com/android/tools/build/manifest-merger/26.0.1/manifest-merger-26.0.1.pom
https://dl.google.com/dl/android/maven2/com/android/tools/build/manifest-merger/26.2.1/manifest-merger-26.2.1.pom
https://dl.google.com/dl/android/maven2/com/android/tools/build/manifest-merger/26.3.1/manifest-merger-26.3.1.pom
https://dl.google.com/dl/android/maven2/com/android/tools/build/manifest-merger/26.5.4/manifest-merger-26.5.4.pom
https://dl.google.com/dl/android/maven2/com/android/tools/build/manifest-merger/27.1.0/manifest-merger-27.1.0.pom
https://dl.google.com/dl/android/maven2/com/android/tools/build/manifest-merger/30.0.4/manifest-merger-30.0.4.pom
@@ -370,7 +351,6 @@ https://dl.google.com/dl/android/maven2/com/android/tools/build/manifest-merger/
https://dl.google.com/dl/android/maven2/com/android/tools/common/26.0.0/common-26.0.0.pom
https://dl.google.com/dl/android/maven2/com/android/tools/common/26.0.1/common-26.0.1.pom
https://dl.google.com/dl/android/maven2/com/android/tools/common/26.2.1/common-26.2.1.pom
https://dl.google.com/dl/android/maven2/com/android/tools/common/26.3.1/common-26.3.1.pom
https://dl.google.com/dl/android/maven2/com/android/tools/common/26.5.4/common-26.5.4.pom
https://dl.google.com/dl/android/maven2/com/android/tools/common/27.1.0/common-27.1.0.pom
https://dl.google.com/dl/android/maven2/com/android/tools/common/30.0.4/common-30.0.4.pom
@@ -380,7 +360,6 @@ https://dl.google.com/dl/android/maven2/com/android/tools/common/30.4.2/common-3
https://dl.google.com/dl/android/maven2/com/android/tools/ddms/ddmlib/26.0.0/ddmlib-26.0.0.pom
https://dl.google.com/dl/android/maven2/com/android/tools/ddms/ddmlib/26.0.1/ddmlib-26.0.1.pom
https://dl.google.com/dl/android/maven2/com/android/tools/ddms/ddmlib/26.2.1/ddmlib-26.2.1.pom
https://dl.google.com/dl/android/maven2/com/android/tools/ddms/ddmlib/26.3.1/ddmlib-26.3.1.pom
https://dl.google.com/dl/android/maven2/com/android/tools/ddms/ddmlib/26.5.4/ddmlib-26.5.4.pom
https://dl.google.com/dl/android/maven2/com/android/tools/ddms/ddmlib/27.1.0/ddmlib-27.1.0.pom
https://dl.google.com/dl/android/maven2/com/android/tools/ddms/ddmlib/30.0.4/ddmlib-30.0.4.pom
@@ -390,7 +369,6 @@ https://dl.google.com/dl/android/maven2/com/android/tools/ddms/ddmlib/30.4.2/ddm
https://dl.google.com/dl/android/maven2/com/android/tools/dvlib/26.0.0/dvlib-26.0.0.pom
https://dl.google.com/dl/android/maven2/com/android/tools/dvlib/26.0.1/dvlib-26.0.1.pom
https://dl.google.com/dl/android/maven2/com/android/tools/dvlib/26.2.1/dvlib-26.2.1.pom
https://dl.google.com/dl/android/maven2/com/android/tools/dvlib/26.3.1/dvlib-26.3.1.pom
https://dl.google.com/dl/android/maven2/com/android/tools/dvlib/26.5.4/dvlib-26.5.4.pom
https://dl.google.com/dl/android/maven2/com/android/tools/dvlib/27.1.0/dvlib-27.1.0.pom
https://dl.google.com/dl/android/maven2/com/android/tools/dvlib/30.0.4/dvlib-30.0.4.pom
@@ -407,7 +385,6 @@ https://dl.google.com/dl/android/maven2/com/android/tools/external/org-jetbrains
https://dl.google.com/dl/android/maven2/com/android/tools/layoutlib/layoutlib-api/26.0.0/layoutlib-api-26.0.0.pom
https://dl.google.com/dl/android/maven2/com/android/tools/layoutlib/layoutlib-api/26.0.1/layoutlib-api-26.0.1.pom
https://dl.google.com/dl/android/maven2/com/android/tools/layoutlib/layoutlib-api/26.2.1/layoutlib-api-26.2.1.pom
https://dl.google.com/dl/android/maven2/com/android/tools/layoutlib/layoutlib-api/26.3.1/layoutlib-api-26.3.1.pom
https://dl.google.com/dl/android/maven2/com/android/tools/layoutlib/layoutlib-api/26.5.4/layoutlib-api-26.5.4.pom
https://dl.google.com/dl/android/maven2/com/android/tools/layoutlib/layoutlib-api/27.1.0/layoutlib-api-27.1.0.pom
https://dl.google.com/dl/android/maven2/com/android/tools/layoutlib/layoutlib-api/30.0.4/layoutlib-api-30.0.4.pom
@@ -421,7 +398,6 @@ https://dl.google.com/dl/android/maven2/com/android/tools/lint/lint-checks/26.0.
https://dl.google.com/dl/android/maven2/com/android/tools/lint/lint-checks/26.0.1/lint-checks-26.0.1.pom
https://dl.google.com/dl/android/maven2/com/android/tools/lint/lint-checks/30.4.2/lint-checks-30.4.2.pom
https://dl.google.com/dl/android/maven2/com/android/tools/lint/lint-gradle-api/26.2.1/lint-gradle-api-26.2.1.pom
https://dl.google.com/dl/android/maven2/com/android/tools/lint/lint-gradle-api/26.3.1/lint-gradle-api-26.3.1.pom
https://dl.google.com/dl/android/maven2/com/android/tools/lint/lint-gradle-api/26.5.4/lint-gradle-api-26.5.4.pom
https://dl.google.com/dl/android/maven2/com/android/tools/lint/lint-gradle-api/27.1.0/lint-gradle-api-27.1.0.pom
https://dl.google.com/dl/android/maven2/com/android/tools/lint/lint-gradle/30.4.2/lint-gradle-30.4.2.pom
@@ -440,7 +416,6 @@ https://dl.google.com/dl/android/maven2/com/android/tools/play-sdk-proto/30.4.2/
https://dl.google.com/dl/android/maven2/com/android/tools/repository/26.0.0/repository-26.0.0.pom
https://dl.google.com/dl/android/maven2/com/android/tools/repository/26.0.1/repository-26.0.1.pom
https://dl.google.com/dl/android/maven2/com/android/tools/repository/26.2.1/repository-26.2.1.pom
https://dl.google.com/dl/android/maven2/com/android/tools/repository/26.3.1/repository-26.3.1.pom
https://dl.google.com/dl/android/maven2/com/android/tools/repository/26.5.4/repository-26.5.4.pom
https://dl.google.com/dl/android/maven2/com/android/tools/repository/27.1.0/repository-27.1.0.pom
https://dl.google.com/dl/android/maven2/com/android/tools/repository/30.0.4/repository-30.0.4.pom
@@ -450,7 +425,6 @@ https://dl.google.com/dl/android/maven2/com/android/tools/repository/30.4.2/repo
https://dl.google.com/dl/android/maven2/com/android/tools/sdklib/26.0.0/sdklib-26.0.0.pom
https://dl.google.com/dl/android/maven2/com/android/tools/sdklib/26.0.1/sdklib-26.0.1.pom
https://dl.google.com/dl/android/maven2/com/android/tools/sdklib/26.2.1/sdklib-26.2.1.pom
https://dl.google.com/dl/android/maven2/com/android/tools/sdklib/26.3.1/sdklib-26.3.1.pom
https://dl.google.com/dl/android/maven2/com/android/tools/sdklib/26.5.4/sdklib-26.5.4.pom
https://dl.google.com/dl/android/maven2/com/android/tools/sdklib/27.1.0/sdklib-27.1.0.pom
https://dl.google.com/dl/android/maven2/com/android/tools/sdklib/30.0.4/sdklib-30.0.4.pom
@@ -460,7 +434,6 @@ https://dl.google.com/dl/android/maven2/com/android/tools/sdklib/30.4.2/sdklib-3
https://dl.google.com/dl/android/maven2/com/android/tools/sdk-common/26.0.0/sdk-common-26.0.0.pom
https://dl.google.com/dl/android/maven2/com/android/tools/sdk-common/26.0.1/sdk-common-26.0.1.pom
https://dl.google.com/dl/android/maven2/com/android/tools/sdk-common/26.2.1/sdk-common-26.2.1.pom
https://dl.google.com/dl/android/maven2/com/android/tools/sdk-common/26.3.1/sdk-common-26.3.1.pom
https://dl.google.com/dl/android/maven2/com/android/tools/sdk-common/26.5.4/sdk-common-26.5.4.pom
https://dl.google.com/dl/android/maven2/com/android/tools/sdk-common/27.1.0/sdk-common-27.1.0.pom
https://dl.google.com/dl/android/maven2/com/android/tools/sdk-common/30.0.4/sdk-common-30.0.4.pom
@@ -715,7 +688,6 @@ https://repo.maven.apache.org/maven2/com/google/guava/guava-parent/17.0/guava-pa
https://repo.maven.apache.org/maven2/com/google/guava/guava-parent/22.0/guava-parent-22.0.pom
https://repo.maven.apache.org/maven2/com/google/guava/guava-parent/23.0/guava-parent-23.0.pom
https://repo.maven.apache.org/maven2/com/google/guava/guava-parent/26.0-android/guava-parent-26.0-android.pom
https://repo.maven.apache.org/maven2/com/google/guava/guava-parent/26.0-jre/guava-parent-26.0-jre.pom
https://repo.maven.apache.org/maven2/com/google/guava/guava-parent/27.0.1-jre/guava-parent-27.0.1-jre.pom
https://repo.maven.apache.org/maven2/com/google/guava/guava-parent/28.1-jre/guava-parent-28.1-jre.pom
https://repo.maven.apache.org/maven2/com/google/guava/guava-parent/29.0-jre/guava-parent-29.0-jre.pom
@@ -728,7 +700,6 @@ https://repo.maven.apache.org/maven2/com/google/guava/guava/17.0/guava-17.0.pom
https://repo.maven.apache.org/maven2/com/google/guava/guava/22.0/guava-22.0.pom
https://repo.maven.apache.org/maven2/com/google/guava/guava/23.0/guava-23.0.pom
https://repo.maven.apache.org/maven2/com/google/guava/guava/26.0-android/guava-26.0-android.pom
https://repo.maven.apache.org/maven2/com/google/guava/guava/26.0-jre/guava-26.0-jre.pom
https://repo.maven.apache.org/maven2/com/google/guava/guava/27.0.1-jre/guava-27.0.1-jre.pom
https://repo.maven.apache.org/maven2/com/google/guava/guava/28.1-jre/guava-28.1-jre.pom
https://repo.maven.apache.org/maven2/com/google/guava/guava/29.0-jre/guava-29.0-jre.pom
@@ -913,13 +884,13 @@ https://repo.maven.apache.org/maven2/junit/junit/4.13.2/junit-4.13.2.pom
https://repo.maven.apache.org/maven2/me/zhanghai/android/materialprogressbar/library/1.4.2/library-1.4.2.pom
https://repo.maven.apache.org/maven2/net/bytebuddy/byte-buddy-agent/1.11.13/byte-buddy-agent-1.11.13.pom
https://repo.maven.apache.org/maven2/net/bytebuddy/byte-buddy-agent/1.11.19/byte-buddy-agent-1.11.19.pom
https://repo.maven.apache.org/maven2/net/bytebuddy/byte-buddy-agent/1.14.10/byte-buddy-agent-1.14.10.pom
https://repo.maven.apache.org/maven2/net/bytebuddy/byte-buddy-agent/1.14.11/byte-buddy-agent-1.14.11.pom
https://repo.maven.apache.org/maven2/net/bytebuddy/byte-buddy-parent/1.11.13/byte-buddy-parent-1.11.13.pom
https://repo.maven.apache.org/maven2/net/bytebuddy/byte-buddy-parent/1.11.19/byte-buddy-parent-1.11.19.pom
https://repo.maven.apache.org/maven2/net/bytebuddy/byte-buddy-parent/1.14.10/byte-buddy-parent-1.14.10.pom
https://repo.maven.apache.org/maven2/net/bytebuddy/byte-buddy-parent/1.14.11/byte-buddy-parent-1.14.11.pom
https://repo.maven.apache.org/maven2/net/bytebuddy/byte-buddy/1.11.13/byte-buddy-1.11.13.pom
https://repo.maven.apache.org/maven2/net/bytebuddy/byte-buddy/1.11.19/byte-buddy-1.11.19.pom
https://repo.maven.apache.org/maven2/net/bytebuddy/byte-buddy/1.14.10/byte-buddy-1.14.10.pom
https://repo.maven.apache.org/maven2/net/bytebuddy/byte-buddy/1.14.11/byte-buddy-1.14.11.pom
https://repo.maven.apache.org/maven2/net/java/dev/jna/jna-platform/5.6.0/jna-platform-5.6.0.pom
https://repo.maven.apache.org/maven2/net/java/dev/jna/jna/5.6.0/jna-5.6.0.pom
https://repo.maven.apache.org/maven2/net/java/jvnet-parent/1/jvnet-parent-1.pom
@@ -1167,7 +1138,6 @@ https://repo.maven.apache.org/maven2/org/jetbrains/kotlin/kotlin-project-model/1
https://repo.maven.apache.org/maven2/org/jetbrains/kotlin/kotlin-project-model/1.9.0/kotlin-project-model-1.9.0.pom
https://repo.maven.apache.org/maven2/org/jetbrains/kotlin/kotlin-reflect/1.1.3-2/kotlin-reflect-1.1.3-2.pom
https://repo.maven.apache.org/maven2/org/jetbrains/kotlin/kotlin-reflect/1.2.0/kotlin-reflect-1.2.0.pom
https://repo.maven.apache.org/maven2/org/jetbrains/kotlin/kotlin-reflect/1.3.20/kotlin-reflect-1.3.20.pom
https://repo.maven.apache.org/maven2/org/jetbrains/kotlin/kotlin-reflect/1.3.50/kotlin-reflect-1.3.50.pom
https://repo.maven.apache.org/maven2/org/jetbrains/kotlin/kotlin-reflect/1.3.72/kotlin-reflect-1.3.72.pom
https://repo.maven.apache.org/maven2/org/jetbrains/kotlin/kotlin-reflect/1.4.32/kotlin-reflect-1.4.32.pom
@@ -1194,7 +1164,6 @@ https://repo.maven.apache.org/maven2/org/jetbrains/kotlin/kotlin-script-runtime/
https://repo.maven.apache.org/maven2/org/jetbrains/kotlin/kotlin-script-runtime/1.9.0/kotlin-script-runtime-1.9.0.pom
https://repo.maven.apache.org/maven2/org/jetbrains/kotlin/kotlin-stdlib-common/1.2.71/kotlin-stdlib-common-1.2.71.pom
https://repo.maven.apache.org/maven2/org/jetbrains/kotlin/kotlin-stdlib-common/1.3.0/kotlin-stdlib-common-1.3.0.pom
https://repo.maven.apache.org/maven2/org/jetbrains/kotlin/kotlin-stdlib-common/1.3.20/kotlin-stdlib-common-1.3.20.pom
https://repo.maven.apache.org/maven2/org/jetbrains/kotlin/kotlin-stdlib-common/1.3.31/kotlin-stdlib-common-1.3.31.pom
https://repo.maven.apache.org/maven2/org/jetbrains/kotlin/kotlin-stdlib-common/1.3.50/kotlin-stdlib-common-1.3.50.pom
https://repo.maven.apache.org/maven2/org/jetbrains/kotlin/kotlin-stdlib-common/1.3.60/kotlin-stdlib-common-1.3.60.pom
@@ -1214,7 +1183,6 @@ https://repo.maven.apache.org/maven2/org/jetbrains/kotlin/kotlin-stdlib-common/1
https://repo.maven.apache.org/maven2/org/jetbrains/kotlin/kotlin-stdlib-common/1.7.22/kotlin-stdlib-common-1.7.22.pom
https://repo.maven.apache.org/maven2/org/jetbrains/kotlin/kotlin-stdlib-common/1.9.0/kotlin-stdlib-common-1.9.0.pom
https://repo.maven.apache.org/maven2/org/jetbrains/kotlin/kotlin-stdlib-jdk7/1.2.71/kotlin-stdlib-jdk7-1.2.71.pom
https://repo.maven.apache.org/maven2/org/jetbrains/kotlin/kotlin-stdlib-jdk7/1.3.20/kotlin-stdlib-jdk7-1.3.20.pom
https://repo.maven.apache.org/maven2/org/jetbrains/kotlin/kotlin-stdlib-jdk7/1.3.50/kotlin-stdlib-jdk7-1.3.50.pom
https://repo.maven.apache.org/maven2/org/jetbrains/kotlin/kotlin-stdlib-jdk7/1.3.72/kotlin-stdlib-jdk7-1.3.72.pom
https://repo.maven.apache.org/maven2/org/jetbrains/kotlin/kotlin-stdlib-jdk7/1.4.10/kotlin-stdlib-jdk7-1.4.10.pom
@@ -1227,7 +1195,6 @@ https://repo.maven.apache.org/maven2/org/jetbrains/kotlin/kotlin-stdlib-jdk7/1.7
https://repo.maven.apache.org/maven2/org/jetbrains/kotlin/kotlin-stdlib-jdk7/1.7.22/kotlin-stdlib-jdk7-1.7.22.pom
https://repo.maven.apache.org/maven2/org/jetbrains/kotlin/kotlin-stdlib-jdk7/1.9.0/kotlin-stdlib-jdk7-1.9.0.pom
https://repo.maven.apache.org/maven2/org/jetbrains/kotlin/kotlin-stdlib-jdk8/1.2.71/kotlin-stdlib-jdk8-1.2.71.pom
https://repo.maven.apache.org/maven2/org/jetbrains/kotlin/kotlin-stdlib-jdk8/1.3.20/kotlin-stdlib-jdk8-1.3.20.pom
https://repo.maven.apache.org/maven2/org/jetbrains/kotlin/kotlin-stdlib-jdk8/1.3.50/kotlin-stdlib-jdk8-1.3.50.pom
https://repo.maven.apache.org/maven2/org/jetbrains/kotlin/kotlin-stdlib-jdk8/1.3.72/kotlin-stdlib-jdk8-1.3.72.pom
https://repo.maven.apache.org/maven2/org/jetbrains/kotlin/kotlin-stdlib-jdk8/1.4.10/kotlin-stdlib-jdk8-1.4.10.pom
@@ -1243,7 +1210,6 @@ https://repo.maven.apache.org/maven2/org/jetbrains/kotlin/kotlin-stdlib/1.2.0/ko
https://repo.maven.apache.org/maven2/org/jetbrains/kotlin/kotlin-stdlib/1.2.20/kotlin-stdlib-1.2.20.pom
https://repo.maven.apache.org/maven2/org/jetbrains/kotlin/kotlin-stdlib/1.2.71/kotlin-stdlib-1.2.71.pom
https://repo.maven.apache.org/maven2/org/jetbrains/kotlin/kotlin-stdlib/1.3.0/kotlin-stdlib-1.3.0.pom
https://repo.maven.apache.org/maven2/org/jetbrains/kotlin/kotlin-stdlib/1.3.20/kotlin-stdlib-1.3.20.pom
https://repo.maven.apache.org/maven2/org/jetbrains/kotlin/kotlin-stdlib/1.3.31/kotlin-stdlib-1.3.31.pom
https://repo.maven.apache.org/maven2/org/jetbrains/kotlin/kotlin-stdlib/1.3.50/kotlin-stdlib-1.3.50.pom
https://repo.maven.apache.org/maven2/org/jetbrains/kotlin/kotlin-stdlib/1.3.60/kotlin-stdlib-1.3.60.pom
@@ -1288,7 +1254,7 @@ https://repo.maven.apache.org/maven2/org/jvnet/staxex/stax-ex/1.8/stax-ex-1.8.po
https://repo.maven.apache.org/maven2/org/jvnet/staxex/stax-ex/2.1.0/stax-ex-2.1.0.pom
https://repo.maven.apache.org/maven2/org/mockito/mockito-core/3.12.4/mockito-core-3.12.4.pom
https://repo.maven.apache.org/maven2/org/mockito/mockito-core/4.0.0/mockito-core-4.0.0.pom
https://repo.maven.apache.org/maven2/org/mockito/mockito-core/5.8.0/mockito-core-5.8.0.pom
https://repo.maven.apache.org/maven2/org/mockito/mockito-core/5.9.0/mockito-core-5.9.0.pom
https://repo.maven.apache.org/maven2/org/mockito/mockito-inline/4.0.0/mockito-inline-4.0.0.pom
https://repo.maven.apache.org/maven2/org/objenesis/objenesis-parent/3.2/objenesis-parent-3.2.pom
https://repo.maven.apache.org/maven2/org/objenesis/objenesis-parent/3.3/objenesis-parent-3.3.pom
+1 -1
View File
@@ -19,4 +19,4 @@ trap show_gradle_log ERR
./gradlew projects --no-daemon --console plain 2>&1 \
| tee "${GRADLE_LOG_FILE}" \
| grep "Project ':" \
| sed -E "s;^.--- Project '\:([@_a-zA-Z0-9\-]+)';\1;"
| sed -E "s;^.--- Project '\:([@_a-zA-Z0-9\-]+)'.*;\1;"
+1 -1
View File
@@ -1,6 +1,7 @@
app
react-native-async-storage_async-storage
react-native-background-timer
react-native-biometrics
react-native-blob-util
react-native-blur
react-native-camera-kit
@@ -36,6 +37,5 @@ react-native-static-safe-area-insets
react-native-status
react-native-status-keycard
react-native-svg
react-native-touch-id
react-native-transparent-video
react-native-webview
+14
View File
@@ -0,0 +1,14 @@
#!/usr/bin/env bash
set -Eeuo pipefail
# script to prompt user for terminating a process
pid="${1}"
read -p "Do you want to terminate this process? (y/n): " choice
if [[ "${choice}" == "y" ]]; then
sudo kill "${pid}"
echo "Process ${pid} terminated."
else
echo "Process not terminated. Please close it manually and retry."
exit 1
fi
+11 -21
View File
@@ -22,12 +22,10 @@ nix_purge_linux_multi_user_users() {
}
nix_purge_darwin_multi_user_service() {
cd /Library/LaunchDaemons
NIX_SERVICES=(org.nixos.darwin-store.plist org.nixos.nix-daemon.plist)
for NIX_SERVICE in "${NIX_SERVICES[@]}"; do
sudo launchctl unload "${NIX_SERVICE}" || true
sudo launchctl remove "${NIX_SERVICE}" || true
done
sudo launchctl unload /Library/LaunchDaemons/org.nixos.nix-daemon.plist
sudo rm /Library/LaunchDaemons/org.nixos.nix-daemon.plist
sudo launchctl unload /Library/LaunchDaemons/org.nixos.darwin-store.plist
sudo rm /Library/LaunchDaemons/org.nixos.darwin-store.plist
}
nix_purge_darwin_multi_user_users() {
@@ -48,18 +46,10 @@ nix_purge_darwin_multi_user_volumes() {
# Identify the process using the volume
local pid=$(lsof +D /nix | awk 'NR==2{print $2}')
if [ -n "$pid" ]; then
if [[ -n "$pid" ]]; then
echo "The volume /nix is in use by process ID $pid."
"${GIT_ROOT}/nix/scripts/kill_proc_prompt.sh" "${pid}" || return 1
# Ask the user whether to terminate the process
read -p "Do you want to terminate this process? (y/n): " choice
if [[ $choice == "y" ]]; then
sudo kill $pid
echo "Process $pid terminated."
else
echo "Process not terminated. Please close it manually and retry."
return 1
fi
else
echo "No process found using /nix. Manual intervention required."
return 1
@@ -71,9 +61,9 @@ nix_purge_darwin_multi_user_volumes() {
nix_purge_multi_user() {
if [[ $(uname -s) == "Darwin" ]]; then
nix_purge_darwin_multi_user_service || true
nix_purge_darwin_multi_user_users || true
nix_purge_darwin_multi_user_volumes || true
nix_purge_darwin_multi_user_service
nix_purge_darwin_multi_user_users
nix_purge_darwin_multi_user_volumes
else
nix_purge_linux_multi_user_service
nix_purge_linux_multi_user_users
@@ -117,7 +107,7 @@ if (return 0 2>/dev/null); then
return
fi
# Confirm user decission, unless --force is used.
# Confirm user decision, unless --force is used.
if [[ "${1}" != "--force" ]]; then
echo -e "${YLW}Are you sure you want to purge Nix?${RST}" >&2
read -p "[y/n]: " -n 1 -r
@@ -129,7 +119,7 @@ if [[ "${1}" != "--force" ]]; then
fi
NIX_INSTALL_TYPE=$(nix_install_type)
# Purging /nix on NixOS would be disasterous.
# Purging /nix on NixOS would be disastrous.
if [[ "${NIX_INSTALL_TYPE}" == "nixos" ]]; then
echo -e "${RED}You should not purge Nix files on NixOS!${RST}" >&2
exit
+1 -1
View File
@@ -35,6 +35,7 @@
"react-dom": "18.0.0",
"react-native": "0.72.5",
"react-native-background-timer": "^2.1.1",
"react-native-biometrics": "^3.0.1",
"react-native-blob-util": "^0.13.18",
"react-native-camera-kit": "14.0.0-beta13",
"react-native-config": "^1.5.0",
@@ -65,7 +66,6 @@
"react-native-static-safe-area-insets": "^2.2.0",
"react-native-status-keycard": "git+https://github.com/status-im/react-native-status-keycard.git#refs/tags/v2.5.39",
"react-native-svg": "13.10.0",
"react-native-touch-id": "^4.4.1",
"react-native-transparent-video": "git+https://github.com/status-im/react-native-transparent-video.git#refs/tags/0.1.1",
"react-native-webview": "13.6.3",
"react-syntax-highlighter": "^15.5.0",
@@ -1,5 +1,8 @@
(ns legacy.status-im.data-store.communities
(:require [clojure.set :as set]))
(:require
[clojure.set :as set]
[clojure.walk :as walk]
[status-im.constants :as constants]))
(defn rpc->channel-permissions
[rpc-channels-permissions]
@@ -7,3 +10,90 @@
(fn [{:keys [viewAndPostPermissions viewOnlyPermissions]}]
{:view-only (set/rename-keys viewOnlyPermissions {:satisfied :satisfied?})
:view-and-post (set/rename-keys viewAndPostPermissions {:satisfied :satisfied?})})))
(defn <-revealed-accounts-rpc
[accounts]
(mapv
#(set/rename-keys % {:isAirdropAddress :airdrop-address?})
(js->clj accounts :keywordize-keys true)))
(defn <-request-to-join-community-rpc
[r]
(set/rename-keys r
{:communityId :community-id
:publicKey :public-key
:chatId :chat-id}))
(defn <-requests-to-join-community-rpc
[requests key-fn]
(reduce #(assoc %1 (key-fn %2) (<-request-to-join-community-rpc %2)) {} requests))
(defn <-chats-rpc
[chats]
(reduce-kv (fn [acc k v]
(assoc acc
(name k)
(-> v
(assoc :can-post? (:canPost v))
(dissoc :canPost)
(update :members walk/stringify-keys))))
{}
chats))
(defn <-categories-rpc
[categ]
(reduce-kv #(assoc %1 (name %2) %3) {} categ))
(defn role-permission?
[token-permission]
(contains? constants/community-role-permissions (:type token-permission)))
(defn membership-permission?
[token-permission]
(= (:type token-permission) constants/community-token-permission-become-member))
(defn <-rpc
[c]
(-> c
(set/rename-keys
{:canRequestAccess :can-request-access?
:canManageUsers :can-manage-users?
:canDeleteMessageForEveryone :can-delete-message-for-everyone?
;; This flag is misleading based on its name alone
;; because it should not be used to decide if the user
;; is *allowed* to join. Allowance is based on token
;; permissions. Still, the flag can be used to know
;; whether or not the user will have to wait until an
;; admin approves a join request.
:canJoin :can-join?
:requestedToJoinAt :requested-to-join-at
:isMember :is-member?
:adminSettings :admin-settings
:tokenPermissions :token-permissions
:communityTokensMetadata :tokens-metadata
:introMessage :intro-message
:muteTill :muted-till
:lastOpenedAt :last-opened-at
:joinedAt :joined-at})
(update :admin-settings
set/rename-keys
{:pinMessageAllMembersEnabled :pin-message-all-members-enabled?})
(update :members walk/stringify-keys)
(update :chats <-chats-rpc)
(update :token-permissions seq)
(update :categories <-categories-rpc)
(assoc :role-permissions?
(->> c
:tokenPermissions
vals
(some role-permission?)))
(assoc :membership-permissions?
(->> c
:tokenPermissions
vals
(some membership-permission?)))
(assoc :token-images
(reduce (fn [acc {sym :symbol image :image}]
(assoc acc sym image))
{}
(:communityTokensMetadata c)))))
+2 -3
View File
@@ -42,7 +42,6 @@
[react-native.core :as rn]
[react-native.permissions :as permissions]
[react-native.platform :as platform]
[status-im.common.biometric.events :as biometric]
status-im.common.serialization
status-im.common.standard-authentication.events
[status-im.common.theme.core :as theme]
@@ -125,7 +124,7 @@
:content (i18n/label :t/biometric-auth-confirm-message)
:confirm-button-text (i18n/label :t/biometric-auth-confirm-try-again)
:cancel-button-text (i18n/label :t/biometric-auth-confirm-logout)
:on-accept #(biometric/authenticate nil {:on-fail on-biometric-auth-fail})
:on-accept #(rf/dispatch [:biometric/authenticate {:on-fail on-biometric-auth-fail}])
:on-cancel #(re-frame/dispatch [:multiaccounts.logout.ui/logout-confirmed])})))
(rf/defn on-return-from-background
@@ -148,7 +147,7 @@
#(when-let [chat-id (:current-chat-id db)]
{:dispatch [:chat/mark-all-as-read chat-id]})
#(when requires-bio-auth
(biometric/authenticate % {:on-fail on-biometric-auth-fail})))))
{:dispatch [:biometric/authenticate {:on-fail on-biometric-auth-fail}]}))))
(rf/defn on-going-in-background
[{:keys [db now]}]
+2 -2
View File
@@ -164,7 +164,7 @@
{:MediaStates {}
:PlaybackCategories {}})
(def net-info #js {})
(def touchid #js {})
(def react-native-biometrics #js {:default {}})
(def react-native-image-viewing #js {:default {}})
(def react-native-static-safe-area-insets #js {:default {}})
@@ -391,7 +391,7 @@
"react-native-fetch-polyfill" fetch
"react-native-status-keycard" status-keycard
"react-native-keychain" keychain
"react-native-touch-id" touchid
"react-native-biometrics" react-native-biometrics
"@react-native-community/netinfo" net-info
"react-native-dialogs" dialogs
"react-native" react-native
@@ -182,7 +182,7 @@
(defn- view-internal
[{:keys [title title-icon type theme description blur? community-name community-logo button-icon
account-name emoji
account-name emoji context-tag-type
on-button-press
on-button-long-press
button-disabled? account-avatar-emoji account-avatar-type customization-color icon-avatar
@@ -214,6 +214,7 @@
:description description
:community-name community-name
:community-logo community-logo
:context-tag-type context-tag-type
:customization-color customization-color
:account-name account-name
:emoji emoji}]]
@@ -45,7 +45,7 @@
[:fiat-value :string]
[:token-value :string]
[:customization-color {:optional true} [:maybe :schema.common/customization-color]]
[:state [:enum :pressed :active :default]]
[:state {:optional true} [:enum :pressed :active :default]]
[:on-press {:optional true} [:maybe fn?]]
[:theme :schema.common/theme]]]]
:any])
@@ -2,7 +2,9 @@
(:require
[quo.components.markdown.text :as text]
[quo.components.profile.collectible.style :as style]
[react-native.core :as rn]))
[react-native.core :as rn]
[react-native.fast-image :as fast-image]
[react-native.svg :as svg]))
(defn remaining-tiles
[amount]
@@ -14,12 +16,21 @@
(str "+" amount)]])
(defn tile
[{:keys [style resource size]}]
(let [source (if (string? resource) {:uri resource} resource)]
[{:keys [style size resource]}]
(let [svg? (and (map? resource) (:svg? resource))
image-style (style/tile-style-by-size size)]
[rn/view {:style style}
[rn/image
{:style (style/tile-style-by-size size)
:source source}]]))
(if svg?
[rn/view
{:style {:border-radius (:border-radius image-style)
:overflow :hidden}}
[svg/svg-uri (assoc image-style :uri (:uri resource))]]
[fast-image/fast-image
{:style image-style
:source (if (string? resource)
{:uri resource
:priority :low}
resource)}])]))
(defn two-tiles
[{:keys [images size]}]
+1 -1
View File
@@ -27,7 +27,7 @@
9.213 11.877 8.436 C 11.787 7.866 11.649 7.313 11.468 6.781 Z"
:clip-path "url(#clip0_5514_84289)"}]
[svg/defs
[svg/clippath {:id "clip0_5514_84289"}
[svg/clip-path {:id "clip0_5514_84289"}
[svg/rect {:width width :height height :fill :none}]]]])
(defn- content
+1 -1
View File
@@ -15,7 +15,7 @@
[:token {:optional true} [:or keyword? string?]]
[:style {:optional true} map?]
;; Ignores `token` and uses this as parameter to `rn/image`'s source.
[:image-source {:optional true} [:or :schema.common/image-source :string]]]]
[:image-source {:optional true} [:maybe [:or :schema.common/image-source :string]]]]]
:any])
(defn- size->number
@@ -4,7 +4,7 @@
(defn container
[network state theme]
{:flex 1
{:width 136
:height 44
:border-width 1
:border-radius 12
@@ -10,8 +10,12 @@
[react-native.core :as rn]))
(defn network-bridge-add
[{:keys [network state theme]}]
[rn/view {:style (merge (style/container network state theme) (style/add-container theme))}
[{:keys [network state theme container-style on-press]}]
[rn/pressable
{:style (merge (style/container network state theme)
(style/add-container theme)
container-style)
:on-press on-press}
[icon/icon :i/add-circle {:size 12 :no-color true}]])
(defn- network->text
@@ -21,13 +25,14 @@
:else (string/capitalize (name network))))
(defn view-internal
[{:keys [theme network status amount container-style] :as args}]
[{:keys [theme network status amount container-style on-press] :as args}]
(if (= status :add)
[network-bridge-add args]
[rn/view
[rn/pressable
{:style (merge (style/container network status theme) container-style)
:accessible true
:accessibility-label :container}
:accessibility-label :container
:on-press on-press}
(if (= status :loading)
[rn/view
{:style (style/loading-skeleton theme)
+56 -49
View File
@@ -3,62 +3,69 @@
(:require
[quo.foundations.colors :as colors]
[quo.theme :as quo.theme]
[react-native.platform :as platform]))
[react-native.platform :as platform]
[utils.number]))
;; Set radius coefficient based on Android Version.
;; A good way to know is to check if shadow color is supported i.e API level 28 (Android 9) above
(def ^:private shadow-radius-coefficient (if platform/is-shadow-color-supported? 0.8 0.1))
(defn- get-shadow-color
"Calculates the shadow color based on a given color and opacity, with an optional coefficient.
- Arity [color opacity]: Uses a default coefficient value of 5 (empirically determined) to compute the shadow color.
- Arity [color opacity coefficient]: Uses the specified coefficient to compute the shadow color.
On Android platforms, the shadow color's alpha is adjusted based on the product of opacity and
coefficient, constrained between 0 and 1. Returns a map with :shadow-color and :shadow-opacity keys."
([color opacity]
(get-shadow-color color opacity 5))
([color opacity coefficient]
{:shadow-color (if platform/android?
(colors/alpha color (utils.number/value-in-range (* opacity coefficient) 0 1))
color)
:shadow-opacity opacity}))
(defn- get-shadow-radius
"Computes shadow radius and elevation properties based on a given radius, with an optional coefficient.
- Arity [radius]: Uses a default coefficient of 0.8 for API level 28 and above and 0.1 otherwise (empirically determined) to compute the elevation.
- Arity [radius coefficient]: Uses the specified coefficient to compute the elevation.
Returns a map with :elevation, computed as the product of radius and coefficient, and :shadow-radius keys."
([radius]
(get-shadow-radius radius shadow-radius-coefficient))
([radius coefficient]
{:elevation (* radius coefficient)
:shadow-radius radius}))
(def ^:private shadows
(let [dark-normal {1 {:shadow-color (when platform/ios?
(colors/alpha colors/neutral-100 0.5))
:shadow-offset {:width 0 :height 4}
:elevation 3
:shadow-opacity 1
:shadow-radius 20}
2 {:shadow-color (when platform/ios?
(colors/alpha colors/neutral-100 0.64))
:shadow-offset {:width 0 :height 4}
:elevation 4
:shadow-opacity 1
:shadow-radius 20}
3 {:shadow-color (when platform/ios?
(colors/alpha colors/neutral-100 0.64))
:shadow-offset {:width 0 :height 12}
:elevation 8
:shadow-opacity 1
:shadow-radius 20}
4 {:shadow-color (when platform/ios?
(colors/alpha colors/neutral-100 0.72))
:shadow-offset {:width 0 :height 16}
:shadow-opacity 1
:shadow-radius 20
:elevation 15}}
(let [dark-normal {1 (merge {:shadow-offset {:width 0 :height 4}}
(get-shadow-color colors/neutral-100 0.5)
(get-shadow-radius 20))
2 (merge {:shadow-offset {:width 0 :height 4}}
(get-shadow-color colors/neutral-100 0.64)
(get-shadow-radius 20))
3 (merge {:shadow-offset {:width 0 :height 12}}
(get-shadow-color colors/neutral-100 0.64)
(get-shadow-radius 20))
4 (merge {:shadow-offset {:width 0 :height 16}}
(get-shadow-color colors/neutral-100 0.72)
(get-shadow-radius 20))}
dark-normal-inverted (-> dark-normal
(update-in [:soft :shadow-offset :height] -)
(update-in [:medium :shadow-offset :height] -)
(update-in [:intense :shadow-offset :height] -)
(update-in [:strong :shadow-offset :height] -))
light-normal {1 {:shadow-color (when platform/ios?
(colors/alpha colors/neutral-100 0.04))
:shadow-offset {:width 0 :height 4}
:elevation 1
:shadow-opacity 1
:shadow-radius 16}
2 {:shadow-color (when platform/ios?
(colors/alpha colors/neutral-100 0.08))
:shadow-offset {:width 0 :height 4}
:elevation 6
:shadow-opacity 1
:shadow-radius 16}
3 {:shadow-color (when platform/ios?
(colors/alpha colors/neutral-100 0.12))
:shadow-offset {:width 0 :height 12}
:elevation 8
:shadow-opacity 1
:shadow-radius 16}
4 {:shadow-color (when platform/ios?
(colors/alpha colors/neutral-100 0.16))
:shadow-offset {:width 0 :height 16}
:shadow-opacity 1
:shadow-radius 16
:elevation 13}}
light-normal {1 (merge {:shadow-offset {:width 0 :height 4}}
(get-shadow-color colors/neutral-100 0.04)
(get-shadow-radius 16))
2 (merge {:shadow-offset {:width 0 :height 4}}
(get-shadow-color colors/neutral-100 0.08)
(get-shadow-radius 16))
3 (merge {:shadow-offset {:width 0 :height 12}}
(get-shadow-color colors/neutral-100 0.12)
(get-shadow-radius 16))
4 (merge {:shadow-offset {:width 0 :height 16}}
(get-shadow-color colors/neutral-100 0.16)
(get-shadow-radius 16))}
light-normal-inverted (-> light-normal
(update-in [:soft :shadow-offset :height] -)
(update-in [:medium :shadow-offset :height] -)
+76
View File
@@ -0,0 +1,76 @@
(ns react-native.biometrics
(:require
["react-native-biometrics" :default Biometrics]
[clojure.string :as string]
[oops.core :as oops]
[react-native.platform :as platform]
[schema.core :as schema]))
(def ^:private ^:const android-not-available-error-message "Biometric hardware unavailable")
(def ^:private ^:const android-not-enrolled-error-message "No fingerprints enrolled.")
(def ^:private ^:const ios-not-enrolled-error-message "No identities are enrolled")
(defn get-supported-type
"Returns a JS promise that resolves with the biometrics types supported by the
device, regardless of whether it's enabled or disabled.
Resolved values: `:Biometrics` `:FaceID` `:TouchID`"
[]
(-> (Biometrics.)
(.isSensorAvailable)
(.then (fn [result]
(-> result
(oops/oget :biometryType)
keyword)))
(.catch (constantly nil))))
(defn get-available
"Returns a JS promise that resolves to a boolean, which signifies whether
biometrics is enabled/disabled on the device."
[]
(-> (Biometrics.)
(.isSensorAvailable)
(.then (fn [result]
(oops/oget result :available)))))
;; NOTE: the react-native-biometrics package error codes/messages differ across platforms.
;; On android we get error messages while on iOS it's a stringified Obj-C error object.
(defn- convert-auth-error-message
[message]
(let [cause (if platform/android?
(condp = message
android-not-enrolled-error-message ::not-enrolled
android-not-available-error-message ::not-available
::unknown)
(condp #(string/includes? %2 %1) message
ios-not-enrolled-error-message ::not-enrolled
::unknown))]
(ex-info "Failed to authenticate with biometrics"
{:orig-error-message message}
cause)))
(defn authenticate
"Returns a JS promise that resolves with a boolean auth success state: `true` for
success and `false` when canceled by user."
[{:keys [prompt-message fallback-prompt-message cancel-button-text]}]
(-> (Biometrics.)
(.simplePrompt #js
{"promptMessage" prompt-message
"fallbackPromptMessage" fallback-prompt-message
"cancelButtonText" cancel-button-text})
(.then (fn [result]
(oops/oget result :success)))
(.catch (fn [error]
(-> (.-message error)
convert-auth-error-message
throw)))))
(schema/=> authenticate
[:=>
[:cat
[:map {:closed true}
[:prompt-message string?]
[:fallback-prompt-message {:optional true} string?]
[:cancel-button-text {:optional true} string?]]]
:any])
+2 -1
View File
@@ -20,7 +20,8 @@
(merge
props
{:source (if (string? source)
{:uri source}
{:uri source
:priority :high}
source)
:on-error (fn [e]
(when-let [on-error (:on-error props)]
+5 -3
View File
@@ -72,9 +72,11 @@
(defn get-credentials
"Gets the credentials for a specified server from the Keychain"
[server callback]
(-> (.getInternetCredentials ^js react-native-keychain (string/lower-case server))
(.then callback)))
([server]
(get-credentials server identity))
([server callback]
(-> (.getInternetCredentials ^js react-native-keychain (string/lower-case server))
(.then callback))))
(defn reset-credentials
[server]
+2
View File
@@ -14,3 +14,5 @@
(def low-device? (and android? (< version 29)))
(def is-below-android-13? (and android? (< version 33)))
(def is-shadow-color-supported? (and android? (> version 27)))
+3 -2
View File
@@ -6,10 +6,11 @@
(def svg (reagent/adapt-react-class Svg/default))
(def path (reagent/adapt-react-class Svg/Path))
(def rect (reagent/adapt-react-class Svg/Rect))
(def clippath (reagent/adapt-react-class Svg/ClipPath))
(def clip-path (reagent/adapt-react-class Svg/ClipPath))
(def defs (reagent/adapt-react-class Svg/Defs))
(def circle (reagent/adapt-react-class Svg/Circle))
(def svgxml (reagent/adapt-react-class Svg/SvgXml))
(def svg-xml (reagent/adapt-react-class Svg/SvgXml))
(def svg-uri (reagent/adapt-react-class Svg/SvgUri))
(def g (reagent/adapt-react-class Svg/G))
(def linear-gradient (reagent/adapt-react-class Svg/LinearGradient))
(def stop (reagent/adapt-react-class Svg/Stop))
-20
View File
@@ -1,20 +0,0 @@
(ns react-native.touch-id
(:require
["react-native-touch-id" :default touchid]))
;; currently, for android, react-native-touch-id
;; is not returning supported biometric type
;; defaulting to :fingerprint
(def android-default-support :fingerprint)
(defn get-supported-type
[callback]
(-> (.isSupported ^js touchid)
(.then #(callback (or (keyword %) android-default-support)))
(.catch #(callback nil))))
(defn authenticate
[{:keys [on-success on-fail reason options]}]
(-> (.authenticate ^js touchid reason (clj->js options))
(.then #(when on-success (on-success %)))
(.catch #(when on-fail (on-fail (aget % "code"))))))
+6 -1
View File
@@ -28,10 +28,15 @@
[:on-success [:or fn? [:cat keyword? [:* :any]]]]
[:on-error [:or fn? [:cat keyword? [:* :any]]]]]])
(def ^:private ?error
[:fn {:error/message "schema.common/error should be of type js/Error"}
(fn [v] (instance? js/Error v))])
(defn register-schemas
[]
(registry/register ::theme ?theme)
(registry/register ::customization-color ?customization-color)
(registry/register ::public-key ?public-key)
(registry/register ::image-source ?image-source)
(registry/register ::rpc-call ?rpc-call))
(registry/register ::rpc-call ?rpc-call)
(registry/register ::error ?error))
+10
View File
@@ -5,6 +5,16 @@
(def ^:private ?cofx
[:map])
(def ^:private ?event-fx
[:maybe
[:map {:closed true}
[:db {:optional true} [:maybe map?]]
[:fx {:optional true}
[:maybe
[:vector {:optional true}
[:vector :any]]]]]])
(defn register-schemas
[]
(registry/register ::event-fx ?event-fx)
(registry/register ::cofx ?cofx))
+101 -134
View File
@@ -1,157 +1,124 @@
(ns status-im.common.biometric.events
(:require
[native-module.core :as native-module]
[re-frame.core :as re-frame]
[react-native.async-storage :as async-storage]
[react-native.platform :as platform]
[react-native.touch-id :as touch-id]
[react-native.biometrics :as biometrics]
[schema.core :as schema]
[status-im.common.biometric.events-schema :as events-schema]
[status-im.common.biometric.utils :as utils]
[status-im.common.keychain.events :as keychain]
[status-im.constants :as constants]
[taoensso.timbre :as log]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(def android-device-blacklisted?
(= (:brand (native-module/get-device-model-info)) "bannedbrand"))
(defn get-supported-type
[callback]
(cond platform/ios? (touch-id/get-supported-type callback)
platform/android? (if android-device-blacklisted?
(callback nil)
(touch-id/get-supported-type callback))
:else (callback nil)))
(defn get-label-by-type
[biometric-type]
(condp = biometric-type
:fingerprint (i18n/label :t/biometric-fingerprint)
:FaceID (i18n/label :t/biometric-faceid)
(i18n/label :t/biometric-touchid)))
(defn get-icon-by-type
[biometric-type]
(condp = biometric-type
:FaceID :i/face-id
:i/touch-id))
(re-frame/reg-fx
:biometric/get-supported-biometric-type
(rf/reg-fx
:biometric/get-supported-type
(fn []
;;NOTE: if we can't save user password, we can't use biometric
(keychain/can-save-user-password?
(fn [can-save?]
(when can-save?
(get-supported-type #(rf/dispatch [:biometric/get-supported-biometric-type-success %])))))))
(when (and can-save? (not utils/android-device-blacklisted?))
(-> (biometrics/get-supported-type)
(.then (fn [type]
(rf/dispatch [:biometric/set-supported-type type])))))))))
(rf/defn get-supported-biometric-auth-success
{:events [:biometric/get-supported-biometric-type-success]}
[{:keys [db]} supported-type]
(defn set-supported-type
[{:keys [db]} [supported-type]]
{:db (assoc db :biometric/supported-type supported-type)})
(rf/defn show-message
{:events [:biometric/show-message]}
[_ code]
(let [handle-error? (and code
(not (contains? #{constants/biometric-error-user-canceled
constants/biometric-error-user-fallback}
code)))
content (if (#{constants/biometric-error-not-available
constants/biometric-error-not-enrolled}
code)
(i18n/label :t/grant-face-id-permissions)
(i18n/label :t/biometric-auth-error {:code code}))]
(when handle-error?
{:effects.utils/show-popup
{:title (i18n/label :t/biometric-auth-login-error-title)
:content content}})))
(schema/=> set-supported-type events-schema/?set-supported-type)
(rf/reg-event-fx :biometric/set-supported-type set-supported-type)
(defn- supress-biometry-error-key
[key-uid]
(keyword (str "biometric/supress-not-enrolled-error-" key-uid)))
(defn show-message
[_ [code]]
(let [content (if (#{::biometrics/not-enrolled
::biometrics/not-available}
code)
(i18n/label :t/grant-face-id-permissions)
(i18n/label :t/biometric-auth-error {:code code}))]
{:fx [[:effects.utils/show-popup
{:title (i18n/label :t/biometric-auth-login-error-title)
:content content}]]}))
;; NOTE: if the account had biometrics registered, but it's not enrolled at the moment,
;; we should show the error message only once and supress further "NOT_ENROLLED" errors
;; until biometry is enrolled again. Note that we can only know that when :biometric/authenticate
;; is dispatched and fails with "NOT_ENROLLED", since :biometric/get-supported-biometric-type
;; only tells us what kind of biometric is available on the device, but it doesn't know of its
;; enrollment status.
(re-frame/reg-fx
:biometric/supress-not-enrolled-error
(fn [[key-uid dispatch-event]]
(let [storage-key (supress-biometry-error-key key-uid)]
(-> (async-storage/get-item storage-key identity)
(.then (fn [item]
(when (not item)
(rf/dispatch dispatch-event)
(async-storage/set-item! storage-key true))))
(.catch (fn [err]
(log/error "Couldn't supress biometry NOT_ENROLLED error"
{:key-uid key-uid
:event :biometric/supress-not-enrolled-error
:error err})))))))
(schema/=> show-message events-schema/?show-message)
(rf/reg-event-fx :biometric/show-message show-message)
;; NOTE: when biometrics is re-enrolled, we erase the flag in async-storage to assure
;; the "NOT_ENROLLED" error message will be shown again if biometrics is un-enrolled
;; in the future.
(re-frame/reg-fx
:biometric/reset-not-enrolled-error
(fn [key-uid]
(let [storage-key (supress-biometry-error-key key-uid)]
(-> (async-storage/get-item storage-key identity)
(.then (fn [supress?]
(when supress?
(async-storage/set-item! storage-key nil))))
(.catch (fn [err]
(log/error "Couldn't reset supressing biometry NOT_ENROLLED error"
{:key-uid key-uid
:event :biometric/reset-not-enrolled-error
:error err})))))))
(re-frame/reg-fx
(rf/reg-fx
:biometric/authenticate
(fn [options]
(touch-id/authenticate
(merge
{:reason (i18n/label :t/biometric-auth-reason-login)
:options (merge
{:unifiedErrors true}
(when platform/ios?
{:passcodeFallback false
:fallbackLabel (i18n/label :t/biometric-auth-login-ios-fallback-label)})
(when platform/android?
{:title (i18n/label :t/biometric-auth-android-title)
:imageColor :blue
:imageErrorColor :red
:sensorDescription (i18n/label :t/biometric-auth-android-sensor-desc)
:sensorErrorDescription (i18n/label :t/biometric-auth-android-sensor-error-desc)
:cancelText (i18n/label :t/cancel)}))}
options))))
(fn [{:keys [on-success on-fail on-cancel prompt-message on-done]}]
(-> (biometrics/authenticate
{:prompt-message (or prompt-message (i18n/label :t/biometric-auth-reason-login))
:fallback-prompt-message (i18n/label
:t/biometric-auth-login-ios-fallback-label)
:cancel-button-text (i18n/label :t/cancel)})
(.then (fn [not-canceled?]
(utils/handle-cb on-done)
(if not-canceled?
(utils/handle-cb on-success)
(utils/handle-cb on-cancel))))
(.catch (fn [err]
(utils/handle-cb on-done)
(utils/handle-cb on-fail err))))))
(rf/defn authenticate
{:events [:biometric/authenticate]}
[_ opts]
{:biometric/authenticate opts})
(defn authenticate
[{:keys [db]} [opts]]
(let [pending? (get db :biometric/auth-pending?)]
;;NOTE: prompting biometric check while another one is pending triggers error
(when-not pending?
{:db (assoc db :biometric/auth-pending? true)
:fx [[:biometric/authenticate
(assoc opts :on-done [:set :biometric/auth-pending? false])]]})))
(rf/reg-event-fx
:biometric/on-enable-success
(fn [{:keys [db]} [password]]
(let [key-uid (get-in db [:profile/profile :key-uid])]
{:db (assoc db :auth-method constants/auth-method-biometric)
:dispatch [:keychain/save-password-and-auth-method
{:key-uid key-uid
:masked-password password}]})))
(schema/=> authenticate events-schema/?authenticate)
(rf/reg-event-fx :biometric/authenticate authenticate)
(rf/reg-event-fx
:biometric/enable
(fn [_ [password]]
{:dispatch [:biometric/authenticate
{:on-success #(rf/dispatch [:biometric/on-enable-success password])
:on-fail #(rf/dispatch [:biometric/show-message %])}]}))
(defn enable-biometrics
[{:keys [db]} [password]]
(let [key-uid (get-in db [:profile/profile :key-uid])]
{:db (assoc db :auth-method constants/auth-method-biometric)
:fx [[:dispatch
[:keychain/save-password-and-auth-method
{:key-uid key-uid
:masked-password password}]]]}))
(rf/reg-event-fx
:biometric/disable
(fn [{:keys [db]}]
(let [key-uid (get-in db [:profile/profile :key-uid])]
{:db (assoc db :auth-method constants/auth-method-none)
:keychain/clear-user-password key-uid})))
(schema/=> enable-biometrics events-schema/?enable-biometrics)
(rf/reg-event-fx :biometric/enable enable-biometrics)
(defn disable-biometrics
[{:keys [db]}]
(let [key-uid (get-in db [:profile/profile :key-uid])]
{:db (assoc db :auth-method constants/auth-method-none)
:fx [[:keychain/clear-user-password key-uid]]}))
(schema/=> disable-biometrics events-schema/?disable-biometrics)
(rf/reg-event-fx :biometric/disable disable-biometrics)
(defn check-if-biometrics-available
[{:keys [key-uid on-success on-fail]}]
(keychain/can-save-user-password?
(fn [can-save?]
(if-not can-save?
(utils/handle-cb on-fail
(ex-info "cannot-save-user-password"
{:fx :biometric/check-if-available}))
(-> (biometrics/get-available)
(.then (fn [available?]
(when-not available?
(throw (js/Error. "biometric-not-available")))))
(.then #(keychain/get-auth-method! key-uid))
(.then (fn [auth-method]
(when auth-method
(utils/handle-cb on-success auth-method))))
(.catch (fn [err]
(let [message (.-message err)]
(utils/handle-cb on-fail
(ex-info message
{:err err
:fx :biometric/check-if-available}))
(when-not (= message "biometric-not-available")
(log/error "Failed to check if biometrics is available"
{:error err
:key-uid key-uid
:event :profile.login/check-biometric}))))))))))
(schema/=> check-if-biometrics-available events-schema/?check-if-biometrics-available)
(rf/reg-fx :biometric/check-if-available check-if-biometrics-available)
@@ -0,0 +1,62 @@
(ns status-im.common.biometric.events-schema
(:require
[status-im.constants :as constants]
[utils.security.core :as security]))
(def ?set-supported-type
[:=>
[:catn
[:cofx :schema.re-frame/cofx]
[:args
[:tuple
[:enum
constants/biometrics-type-android
constants/biometrics-type-face-id
constants/biometrics-type-touch-id]]]]
:schema.re-frame/event-fx])
(def ?show-message
[:=>
[:catn
[:cofx :schema.re-frame/cofx]
[:args
[:tuple keyword?]]]
:schema.re-frame/event-fx])
(def ?authenticate
[:=>
[:catn
[:cofx :schema.re-frame/cofx]
[:args
[:tuple
[:map {:closed true}
[:on-success {:optional true} fn?]
[:on-fail {:optional true} fn?]
[:on-cancel {:optional true} fn?]
[:prompt-message {:optional true} :string]]]]]
:schema.re-frame/event-fx])
(def ?enable-biometrics
[:=>
[:catn
[:cofx :schema.re-frame/cofx]
[:args
[:tuple
[:fn {:error/message "Should be an instance of security/MaskedData"}
(fn [pw] (instance? security/MaskedData pw))]]]]
:schema.re-frame/event-fx])
(def ?disable-biometrics
[:=>
[:catn
[:cofx :schema.re-frame/cofx]]
:schema.re-frame/event-fx])
(def ?check-if-biometrics-available
[:=>
[:cat
[:map {:closed true}
[:key-uid string?]
[:on-success {:optional true} [:maybe fn?]]
[:on-fail {:optional true} [:maybe fn?]]]]
:any])
@@ -0,0 +1,80 @@
(ns status-im.common.biometric.events-test
(:require [cljs.test :refer [deftest testing is]]
matcher-combinators.test
[react-native.biometrics :as biometrics]
[status-im.common.biometric.events :as sut]
[status-im.constants :as constants]
[utils.i18n :as i18n]
[utils.security.core :as security]))
(deftest set-supported-biometrics-type-test
(testing "successfully setting supported biometrics type"
(let [cofx {:db {}}
supported-type constants/biometrics-type-face-id
expected {:db (assoc (:db cofx) :biometric/supported-type supported-type)}]
(is (match? expected (sut/set-supported-type cofx [supported-type])))))
(testing "throws error when setting unsupported biometrics type"
(let [cofx {:db {}}
supported-type :unsupported-type]
(is (thrown? js/Error (sut/set-supported-type cofx [supported-type]))))))
(deftest show-message-test
(testing "informs the user to enable biometrics from settings"
(let [cofx {:db {}}
expected {:fx [[:effects.utils/show-popup
{:title (i18n/label :t/biometric-auth-login-error-title)
:content (i18n/label :t/grant-face-id-permissions)}]]}]
(is (match? expected
(sut/show-message cofx
[::biometrics/not-available])))))
(testing "shows a generic error message"
(let [cofx {:db {}}
error-cause :test-error
expected {:fx [[:effects.utils/show-popup
{:title (i18n/label :t/biometric-auth-login-error-title)
:content (i18n/label :t/biometric-auth-error {:code error-cause})}]]}]
(is (match? expected
(sut/show-message cofx
[error-cause]))))))
(deftest authenticate-biometrics-test
(testing "passing the right args to authenticate"
(let [cofx {:db {}}
args {:on-success identity
:on-fail identity
:prompt-message "test"}
result (sut/authenticate cofx [args])]
(is (= (:prompt-message args) (get-in result [:fx 0 1 :prompt-message])))
(is (not (nil? (get-in result [:fx 0 1 :on-success]))))
(is (not (nil? (get-in result [:fx 0 1 :on-fail]))))))
(testing "skips biometric check if another one pending"
(let [cofx {:db {:biometric/auth-pending? true}}
result (sut/authenticate cofx [{}])]
(is (nil? result)))))
(deftest enable-biometrics-test
(testing "successfully enabling biometrics"
(let [key-uid "test-uid"
password (security/mask-data "test-pw")
cofx {:db {:profile/profile {:key-uid key-uid}}}
expected-db (assoc (:db cofx) :auth-method constants/auth-method-biometric)
result (sut/enable-biometrics cofx [password])]
(is (match? expected-db (:db result)))
(is (= password (get-in result [:fx 0 1 1 :masked-password])))))
(testing "throws error if raw password is passed"
(let [key-uid "test-uid"
password "test-password"
cofx {:db {:profile/profile {:key-uid key-uid}}}]
(is (thrown? js/Error (sut/enable-biometrics cofx [password]))))))
(deftest disable-biometrics-test
(testing "successfully disabling biometrics"
(let [key-uid "test-uid"
cofx {:db {:profile/profile {:key-uid key-uid}}}
expected {:db (assoc (:db cofx) :auth-method constants/auth-method-none)
:fx [[:keychain/clear-user-password key-uid]]}]
(is (match? expected (sut/disable-biometrics cofx))))))
+36
View File
@@ -0,0 +1,36 @@
(ns status-im.common.biometric.utils
(:require
[native-module.core :as native-module]
[react-native.platform :as platform]
[status-im.constants :as constants]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(def android-device-blacklisted?
(and platform/android? (= (:brand (native-module/get-device-model-info)) "bannedbrand")))
(defn get-label-by-type
[biometric-type]
(condp = biometric-type
constants/biometrics-type-android (i18n/label :t/biometric-fingerprint)
constants/biometrics-type-face-id (i18n/label :t/biometric-faceid)
(i18n/label :t/biometric-touchid)))
(defn get-icon-by-type
[biometric-type]
(condp = biometric-type
constants/biometrics-type-face-id :i/face-id
:i/touch-id))
;; NOTE: move to utils.re-frame?
(defn handle-cb
"Handles re-frame callbacks that are passed as anonymous fn or as dispatch vectors to effects.
e.g.:\n
* with dispatch vector - `:on-success [:my-ns/my-event]`\n
* with fn - `:on-success #(rf/dispatch [:my-ns/my-event])`"
[cb & args]
(when cb
(cond
(fn? cb) (apply cb args)
(vector? cb) (rf/dispatch (into cb args)))))
+8 -12
View File
@@ -70,17 +70,13 @@
{:db (assoc db :auth-method method)
:keychain/save-auth-method [key-uid method]})
(re-frame/reg-fx
:keychain/get-auth-method
(fn [[key-uid callback]]
(can-save-user-password?
(fn [can-save?]
(if can-save?
(keychain/get-credentials
(str key-uid "-auth")
(fn [value]
(callback (if value (oops/oget value "password") auth-method-none))))
(callback nil))))))
(defn get-auth-method!
[key-uid]
(-> (str key-uid "-auth")
(keychain/get-credentials)
(.then (fn [value]
(if value (oops/oget value "password") auth-method-none)))
(.catch (constantly auth-method-none))))
(defn save-user-password!
[key-uid password]
@@ -101,7 +97,7 @@
(get-user-password! key-uid callback)))
(rf/defn get-user-password
[_ key-uid callback]
[_ [key-uid callback]]
{:keychain/get-user-password [key-uid callback]})
(defn- password-migration-key-name
+2 -23
View File
@@ -9,7 +9,6 @@
[status-im.common.lightbox.animations :as anim]
[status-im.common.lightbox.constants :as constants]
[status-im.common.lightbox.style :as style]
[utils.i18n :as i18n]
[utils.re-frame :as rf]
[utils.url :as url]))
@@ -40,25 +39,6 @@
(anim/animate top-view-width screen-width)
(anim/animate top-view-bg colors/neutral-100-opa-0)))))
(defn drawer
[images index]
(let [{:keys [image]} (nth images index)
uri (url/replace-port image (rf/sub [:mediaserver/port]))]
[quo/action-drawer
[[{:icon :i/save
:accessibility-label :save-image
:label (i18n/label :t/save-image-library)
:on-press (fn []
(rf/dispatch [:hide-bottom-sheet])
(rf/dispatch
[:lightbox/save-image-to-gallery
uri
#(rf/dispatch [:toasts/upsert
{:id :random-id
:type :positive
:container-style {:bottom (when platform/android? 20)}
:text (i18n/label :t/photo-saved)}])]))}]]]))
(defn share-image
[images index]
(let [{:keys [image]} (nth images index)
@@ -66,7 +46,7 @@
(rf/dispatch [:lightbox/share-image uri])))
(defn top-view
[images insets index animations derived landscape? screen-width]
[images insets index animations derived landscape? screen-width on-options-press]
(let [{:keys [description header]} (nth images @index)
bg-color (if landscape?
colors/neutral-100-opa-70
@@ -113,7 +93,6 @@
[rn/touchable-opacity
{:active-opacity 1
:accessibility-label :image-options
:on-press #(rf/dispatch [:show-bottom-sheet
{:content (fn [] [drawer images @index])}])
:on-press #(on-options-press images @index)
:style style/close-container}
[quo/icon :options {:size 20 :color colors/white}]]]]))
+7 -4
View File
@@ -44,7 +44,8 @@
[rn/view {:style {:width constants/separator-width}}]])
(defn lightbox-content
[{:keys [props state animations derived images index handle-items-changed bottom-text-component]}]
[{:keys [props state animations derived images index handle-items-changed bottom-text-component
on-options-press]}]
(let [{:keys [data transparent? scroll-index
set-full-height?]} state
insets (safe-area/get-insets)
@@ -69,7 +70,7 @@
{:height screen-height})}
(when-not @transparent?
[:f> top-view/top-view images insets scroll-index animations derived landscape?
screen-width])
screen-width on-options-press])
[gesture/gesture-detector
{:gesture (utils/drag-gesture animations (and landscape? platform/ios?) set-full-height?)}
[reanimated/view
@@ -136,7 +137,8 @@
(defn- f-lightbox
[]
(let [{:keys [images index bottom-text-component]} (rf/sub [:get-screen-params])
(let [{:keys [images index bottom-text-component on-options-press]}
(rf/sub [:get-screen-params])
props
(utils/init-props)
state
@@ -160,7 +162,8 @@
:images images
:index index
:handle-items-changed handle-items-changed
:bottom-text-component bottom-text-component}]))))
:bottom-text-component bottom-text-component
:on-options-press on-options-press}]))))
(defn lightbox
[]
+2 -1
View File
@@ -26,7 +26,8 @@
:discover (js/require "../resources/images/ui2/discover.png")
:invite-friends (js/require "../resources/images/ui2/invite-friends.png")
:transaction-progress (js/require "../resources/images/ui2/transaction-progress.png")
:welcome-illustration (js/require "../resources/images/ui2/welcome_illustration.png")})
:welcome-illustration (js/require "../resources/images/ui2/welcome_illustration.png")
:notifications (js/require "../resources/images/ui2/notifications.png")})
(def ui-themed
{:angry-man
+2 -1
View File
@@ -4,6 +4,7 @@
[quo.core :as quo]
[react-native.core :as rn]
[react-native.reanimated :as reanimated]
[react-native.safe-area :as safe-area]
[reagent.core :as reagent]
[status-im.common.scroll-page.style :as style]
[utils.re-frame :as rf]))
@@ -59,7 +60,7 @@
[rn/view {:style {:margin-top 0}}
top-nav]
[quo/page-nav
(cond-> {:margin-top 44
(cond-> {:margin-top (safe-area/get-top)
:type :no-title
:background (if (= 1 (reanimated/get-shared-value opacity-animation))
:blur
@@ -6,47 +6,59 @@
[status-im.common.standard-authentication.password-input.view :as password-input]
[status-im.contexts.profile.utils :as profile.utils]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
[utils.re-frame :as rf]
[reagent.core :as reagent]
[utils.security.core :as security]))
(defn view
[{:keys [on-enter-password on-press-biometrics button-label button-icon-left]}]
(let [{:keys [key-uid customization-color] :as profile} (rf/sub [:profile/profile-with-image])
{:keys [error processing password]} (rf/sub [:profile/login])
sign-in-enabled? (rf/sub [:sign-in-enabled?])]
[:<>
[rn/view {:style style/enter-password-container}
[rn/view
[quo/text
{:accessibility-label :sync-code-generated
:weight :bold
:size :heading-1
:style {:margin-bottom 4}}
(i18n/label :t/enter-password)]
[rn/view
{:style style/context-tag}
[quo/context-tag
{:type :default
:blur? true
:profile-picture (profile.utils/photo profile)
:full-name (profile.utils/displayed-name profile)
:customization-color customization-color
:size 24}]]
[password-input/view
{:on-press-biometrics on-press-biometrics
:processing processing
:error error
:default-password password
:sign-in-enabled? sign-in-enabled?}]
[quo/button
{:size 40
:container-style style/enter-password-button
:type :primary
:customization-color (or customization-color :primary)
:accessibility-label :login-button
:icon-left button-icon-left
:disabled? (or (not sign-in-enabled?) processing)
:on-press (fn []
(rf/dispatch [:set-in [:profile/login :key-uid] key-uid])
(rf/dispatch [:profile.login/verify-database-password password
#(on-enter-password password)]))}
button-label]]]]))
[]
(let [password-value (reagent/atom nil)]
(fn [{:keys [on-enter-password on-press-biometrics button-label button-icon-left]}]
(let [{:keys [key-uid customization-color]
:as profile} (rf/sub [:profile/profile-with-image])
{:keys [error processing password]} (rf/sub [:profile/login])
sign-in-enabled? (rf/sub [:sign-in-enabled?])
on-change-password (fn [value]
(reset! password-value value)
(when (not= value (security/safe-unmask-data password))
(rf/dispatch [:set-in [:profile/login :password]
(security/mask-data value)])
(rf/dispatch [:set-in [:profile/login :error] ""])))]
[:<>
[rn/view {:style style/enter-password-container}
[rn/view
[quo/text
{:accessibility-label :sync-code-generated
:weight :bold
:size :heading-1
:style {:margin-bottom 4}}
(i18n/label :t/enter-password)]
[rn/view
{:style style/context-tag}
[quo/context-tag
{:type :default
:blur? true
:profile-picture (profile.utils/photo profile)
:full-name (profile.utils/displayed-name profile)
:customization-color customization-color
:size 24}]]
[password-input/view
{:on-press-biometrics on-press-biometrics
:processing processing
:error error
:password @password-value
:on-change-password on-change-password
:sign-in-enabled? sign-in-enabled?}]
[quo/button
{:size 40
:container-style style/enter-password-button
:type :primary
:customization-color (or customization-color :primary)
:accessibility-label :login-button
:icon-left button-icon-left
:disabled? (or (not sign-in-enabled?) processing)
:on-press (fn []
(rf/dispatch [:set-in [:profile/login :key-uid] key-uid])
(rf/dispatch [:profile.login/verify-database-password password
#(on-enter-password password)]))}
button-label]]]]))))
@@ -1,11 +1,86 @@
(ns status-im.common.standard-authentication.events
(:require
[utils.re-frame :as rf]))
[schema.core :as schema]
[status-im.common.standard-authentication.enter-password.view :as enter-password]
[status-im.common.standard-authentication.events-schema :as events-schema]
[taoensso.timbre :as log]
[utils.i18n :as i18n]
[utils.re-frame :as rf]
[utils.security.core :as security]))
(rf/reg-event-fx :standard-auth/on-biometric-success
(fn [{:keys [db]} [callback]]
(let [key-uid (get-in db [:profile/profile :key-uid])]
{:fx [[:keychain/get-user-password [key-uid callback]]]})))
(defn authorize
[{:keys [db]} [args]]
(let [key-uid (get-in db [:profile/profile :key-uid])]
{:fx [[:biometric/check-if-available
{:key-uid key-uid
:on-success [:standard-auth/authorize-with-biometric args]
:on-fail [:standard-auth/authorize-with-password args]}]]}))
(schema/=> authorize events-schema/?authorize)
(rf/reg-event-fx :standard-auth/authorize authorize)
(defn authorize-with-biometric
[_ [{:keys [on-auth-success on-auth-fail] :as args}]]
(let [args-with-biometric-btn
(assoc args
:on-press-biometric
#(rf/dispatch [:standard-auth/authorize-with-biometric args]))]
{:fx [[:dispatch [:dismiss-keyboard]]
[:dispatch
[:biometric/authenticate
{:prompt-message (i18n/label :t/biometric-auth-confirm-message)
:on-cancel [:standard-auth/authorize-with-password args-with-biometric-btn]
:on-success [:standard-auth/on-biometric-success on-auth-success]
:on-fail [:standard-auth/on-biometric-fail on-auth-fail]}]]]}))
(schema/=> authorize-with-biometric events-schema/?authorize-with-biometric)
(rf/reg-event-fx :standard-auth/authorize-with-biometric authorize-with-biometric)
(defn on-biometric-success
[{:keys [db]} [on-auth-success]]
(let [key-uid (get-in db [:profile/profile :key-uid])]
{:fx [[:keychain/get-user-password [key-uid on-auth-success]]]}))
(schema/=> on-biometric-success events-schema/?on-biometric-success)
(rf/reg-event-fx :standard-auth/on-biometric-success on-biometric-success)
(defn on-biometric-fail
[_ [on-auth-fail error]]
(when on-auth-fail
(on-auth-fail error))
(log/error (ex-message error)
(-> error
ex-data
(assoc :code (ex-cause error)
:event :standard-auth/on-biometric-fail)))
{:fx [[:dispatch [:biometric/show-message (ex-cause error)]]]})
(schema/=> on-biometric-fail events-schema/?on-biometrics-fail)
(rf/reg-event-fx :standard-auth/on-biometric-fail on-biometric-fail)
(defn- bottom-sheet-password-view
[{:keys [on-press-biometric on-auth-success auth-button-icon-left auth-button-label]}]
(fn []
(let [handle-password-success (fn [password]
(-> password security/hash-masked-password on-auth-success))]
[enter-password/view
{:on-enter-password handle-password-success
:on-press-biometrics on-press-biometric
:button-icon-left auth-button-icon-left
:button-label auth-button-label}])))
(defn authorize-with-password
[_ [{:keys [on-close theme blur?] :as args}]]
{:fx [[:dispatch [:standard-auth/reset-login-password]]
[:dispatch
[:show-bottom-sheet
{:on-close on-close
:theme theme
:shell? blur?
:content #(bottom-sheet-password-view args)}]]]})
(schema/=> authorize-with-password events-schema/?authorize-with-password)
(rf/reg-event-fx :standard-auth/authorize-with-password authorize-with-password)
(rf/reg-event-fx
:standard-auth/reset-login-password
@@ -0,0 +1,53 @@
(ns status-im.common.standard-authentication.events-schema)
(def ^:private ?authorize-map
[:map {:closed true}
[:on-auth-success fn?]
[:on-auth-fail {:optional true} [:maybe fn?]]
[:on-close {:optional true} [:maybe fn?]]
[:auth-button-label {:optional true} [:maybe string?]]
[:auth-button-icon-left {:optional true} [:maybe keyword?]]
[:blur? {:optional true} [:maybe boolean?]]
[:theme {:optional true} [:maybe :schema.common/theme]]])
(def ?authorize
[:=>
[:catn
[:cofx :schema.re-frame/cofx]
[:args
[:tuple ?authorize-map]]]
:schema.re-frame/event-fx])
(def ?authorize-with-biometric
[:=>
[:catn
[:cofx :schema.re-frame/cofx]
[:args
[:tuple ?authorize-map]]]
:schema.re-frame/event-fx])
(def ?on-biometric-success
[:=>
[:catn
[:cofx :schema.re-frame/cofx]
[:args
[:tuple fn?]]]
:schema.re-frame/event-fx])
(def ?on-biometrics-fail
[:=>
[:catn
[:cofx :schema.re-frame/cofx]
[:args
[:tuple
[:maybe fn?]
[:maybe :schema.common/error]]]]
:schema.re-frame/event-fx])
(def ?authorize-with-password
[:=>
[:catn
[:cofx :schema.re-frame/cofx]
[:args
[:tuple ?authorize-map]]]
:schema.re-frame/event-fx])
@@ -9,7 +9,8 @@
[status-im.common.standard-authentication.password-input.style :as style]
[utils.i18n :as i18n]
[utils.re-frame :as rf]
[utils.security.core :as security]))
[utils.security.core :as security]
[reagent.core :as reagent]))
(defn get-error-message
[error]
@@ -20,14 +21,8 @@
(i18n/label :t/oops-wrong-password)
error))
(defn- on-change-password
[entered-password]
(rf/dispatch [:set-in [:profile/login :password]
(security/mask-data entered-password)])
(rf/dispatch [:set-in [:profile/login :error] ""]))
(defn- view-internal
[{:keys [default-password theme shell? on-press-biometrics blur?]}]
[{:keys [password on-change-password theme shell? on-press-biometrics blur?]}]
(let [{:keys [error processing]} (rf/sub [:profile/login])
error-message (get-error-message error)
error? (boolean (seq error-message))]
@@ -43,7 +38,7 @@
:error? error?
:label (i18n/label :t/profile-password)
:on-change-text on-change-password
:default-value (security/safe-unmask-data default-password)}]
:value password}]
(when on-press-biometrics
[quo/button
{:container-style style/auth-button
@@ -1,63 +0,0 @@
(ns status-im.common.standard-authentication.standard-auth.authorize
(:require
[react-native.touch-id :as biometric]
[status-im.common.standard-authentication.enter-password.view :as enter-password]
[taoensso.timbre :as log]
[utils.i18n :as i18n]
[utils.re-frame :as rf]
[utils.security.core :as security]))
(defn reset-password
[]
(rf/dispatch [:set-in [:profile/login :password] nil])
(rf/dispatch [:set-in [:profile/login :error] ""]))
(defn authorize
[{:keys [biometric-auth? on-auth-success on-auth-fail on-close
auth-button-label theme blur? auth-button-icon-left]}]
(let [handle-auth-success (fn [biometric?]
(fn [entered-password]
(let [sha3-masked-password (if biometric?
entered-password
(security/hash-masked-password
entered-password))]
(on-auth-success sha3-masked-password))))
password-login (fn [{:keys [on-press-biometrics]}]
(rf/dispatch [:show-bottom-sheet
{:on-close on-close
:theme theme
:shell? blur?
:content (fn []
[enter-password/view
{:on-enter-password (handle-auth-success
false)
:on-press-biometrics on-press-biometrics
:button-icon-left auth-button-icon-left
:button-label auth-button-label}])}]))
; biometrics-login recursively passes itself as a parameter because if the user
; fails biometric auth they will be shown the password bottom sheet with an option
; to retrigger biometric auth, so they can endlessly repeat this cycle.
biometrics-login (fn [on-press-biometrics]
(rf/dispatch [:dismiss-keyboard])
(biometric/authenticate
{:reason (i18n/label :t/biometric-auth-confirm-message)
:on-success (fn [_response]
(on-close)
(rf/dispatch [:standard-auth/on-biometric-success
(handle-auth-success true)]))
:on-fail (fn [error]
(on-close)
(log/error "Authentication Failed. Error:" error)
(when on-auth-fail (on-auth-fail error))
(password-login {:on-press-biometrics
#(on-press-biometrics
on-press-biometrics)}))}))]
(if biometric-auth?
(biometric/get-supported-type
(fn [biometric-type]
(if biometric-type
(biometrics-login biometrics-login)
(do
(reset-password)
(password-login {})))))
(password-login {}))))
@@ -4,7 +4,6 @@
[quo.theme :as quo.theme]
[react-native.core :as rn]
[reagent.core :as reagent]
[status-im.common.standard-authentication.standard-auth.authorize :as authorize]
[status-im.constants :as constants]
[utils.re-frame :as rf]))
@@ -33,14 +32,15 @@
{:size size
:customization-color customization-color
:on-reset (when @reset-slider? #(reset! reset-slider? false))
:on-complete #(authorize/authorize {:on-close on-close
:auth-button-icon-left auth-button-icon-left
:theme theme
:blur? blur?
:biometric-auth? biometric-auth?
:on-auth-success on-auth-success
:on-auth-fail on-auth-fail
:auth-button-label auth-button-label})
:on-complete #(rf/dispatch [:standard-auth/authorize
{:on-close on-close
:auth-button-icon-left auth-button-icon-left
:theme theme
:blur? blur?
:biometric-auth? biometric-auth?
:on-auth-success on-auth-success
:on-auth-fail on-auth-fail
:auth-button-label auth-button-label}])
:track-icon (if biometric-auth? :i/face-id :password)
:track-text track-text}]])))
+5 -1
View File
@@ -160,5 +160,9 @@
(def default-kdf-iterations 3200)
(def community-accounts-selection-enabled? false)
(def community-accounts-selection-enabled? (enabled? (get-config :ACCOUNT_SELECTION_ENABLED "0")))
(def fetch-messages-enabled? (enabled? (get-config :FETCH_MESSAGES_ENABLED "1")))
(def wallet-feature-flags
{:edit-default-keypair false
:bridge-token false})
+9 -4
View File
@@ -153,6 +153,11 @@
(def ^:const community-token-permission-can-view-and-post-channel 4)
(def ^:const community-token-permission-become-token-master 5)
(def ^:const community-token-permission-become-token-owner 6)
(def ^:const community-role-permissions
#{community-token-permission-become-admin
community-token-permission-become-member
community-token-permission-become-token-master
community-token-permission-become-token-owner})
;; Community rules for joining
(def ^:const community-rule-ens-only "ens-only")
@@ -378,10 +383,10 @@
(def ^:const auth-method-biometric-prepare "biometric-prepare")
(def ^:const auth-method-none "none")
(def ^:const biometric-error-user-canceled "USER_CANCELED")
(def ^:const biometric-error-user-fallback "USER_USER_FALLBACK")
(def ^:const biometric-error-not-available "NOT_AVAILABLE")
(def ^:const biometric-error-not-enrolled "NOT_ENROLLED")
;; NOTE all android biometrics falls under :Biometrics
(def ^:const biometrics-type-android :Biometrics)
(def ^:const biometrics-type-touch-id :TouchID)
(def ^:const biometrics-type-face-id :FaceID)
(def ^:const onboarding-generating-keys-animation-duration-ms 7000)
(def ^:const onboarding-generating-keys-navigation-retry-ms 3000)
@@ -66,7 +66,12 @@
album-messages))
:bottom-text-component
[lightbox/bottom-text-for-lightbox
first-image]}])}
first-image]
:on-options-press (fn [images index]
(rf/dispatch [:show-bottom-sheet
{:content (fn [] [lightbox/drawer
images
index])}]))}])}
[fast-image/fast-image
{:style (style/image dimensions index portrait? images-count)
:source {:uri (url/replace-port (:image (:content item)) media-server-port)}
@@ -57,7 +57,13 @@
:index 0
:insets insets
:bottom-text-component
[lightbox/bottom-text-for-lightbox message]}])}
[lightbox/bottom-text-for-lightbox message]
:on-options-press (fn [images index]
(rf/dispatch [:show-bottom-sheet
{:content (fn []
[lightbox/drawer
images
index])}]))}])}
[fast-image/fast-image
{:source {:uri image-local-url}
:style (merge dimensions {:border-radius 12})
@@ -1,10 +1,15 @@
(ns status-im.contexts.chat.messenger.messages.content.lightbox.view
(:require
[oops.core :as oops]
[quo.core :as quo]
[react-native.platform :as platform]
[reagent.core :as reagent]
[status-im.common.lightbox.constants :as constants]
[status-im.contexts.chat.messenger.messages.content.lightbox.style :as style]
[status-im.contexts.chat.messenger.messages.content.text.view :as message-view]))
[status-im.contexts.chat.messenger.messages.content.text.view :as message-view]
[utils.i18n :as i18n]
[utils.re-frame :as rf]
[utils.url :as url]))
(defn bottom-text-for-lightbox
[_]
@@ -16,3 +21,22 @@
:chat-id chat-id
:style-override (style/bottom-text expandable-text?)
:on-layout #(reset! text-height (oops/oget % "nativeEvent.layout.height"))}]))))
(defn drawer
[images index]
(let [{:keys [image]} (nth images index)
uri (url/replace-port image (rf/sub [:mediaserver/port]))]
[quo/action-drawer
[[{:icon :i/save
:accessibility-label :save-image
:label (i18n/label :t/save-image-library)
:on-press (fn []
(rf/dispatch [:hide-bottom-sheet])
(rf/dispatch
[:lightbox/save-image-to-gallery
uri
#(rf/dispatch [:toasts/upsert
{:id :random-id
:type :positive
:container-style {:bottom (when platform/android? 20)}
:text (i18n/label :t/photo-saved)}])]))}]]]))
@@ -6,6 +6,7 @@
[legacy.status-im.chat.models.message :as models.message]
[legacy.status-im.data-store.activities :as data-store.activities]
[legacy.status-im.data-store.chats :as data-store.chats]
[legacy.status-im.data-store.communities :as data-store.communities]
[legacy.status-im.data-store.invitations :as data-store.invitations]
[legacy.status-im.group-chats.core :as models.group]
[legacy.status-im.multiaccounts.update.core :as update.core]
@@ -127,7 +128,7 @@
(seq requests-to-join-community)
(let [requests (->> requests-to-join-community
types/js->clj
(map communities/<-request-to-join-community-rpc))]
(map data-store.communities/<-request-to-join-community-rpc))]
(js-delete response-js "requestsToJoinCommunity")
(rf/merge cofx
(process-next response-js sync-handler)
@@ -6,25 +6,28 @@
[status-im.common.password-authentication.view :as password-authentication]
[status-im.contexts.communities.actions.accounts-selection.style :as style]
[status-im.contexts.communities.actions.community-rules.view :as community-rules]
[status-im.contexts.communities.utils :as communities.utils]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(defn- join-community-and-navigate-back
[id]
(rf/dispatch [:password-authentication/show
{:content (fn [] [password-authentication/view])}
(rf/dispatch [:password-authentication/show {:content (fn [] [password-authentication/view])}
{:label (i18n/label :t/join-open-community)
:on-press #(rf/dispatch [:communities/request-to-join-with-addresses
{:community-id id
:password %}])}])
{:community-id id :password %}])}])
(rf/dispatch [:navigate-back]))
(defn f-view-internal
[]
(let [{id :community-id} (rf/sub [:get-screen-params])
{:keys [name color images]} (rf/sub [:communities/community id])
airdrop-account (rf/sub [:communities/airdrop-account id])
selected-accounts (rf/sub [:communities/selected-permission-accounts id])]
(let [{id :community-id} (rf/sub [:get-screen-params])
{:keys [name color images]} (rf/sub [:communities/community id])
airdrop-account (rf/sub [:communities/airdrop-account id])
selected-accounts (rf/sub [:communities/selected-permission-accounts id])
{:keys [highest-permission-role]} (rf/sub [:community/token-gated-overview id])
highest-role-text (i18n/label (communities.utils/role->translation-key
highest-permission-role
:t/member))]
[rn/view {:style style/container}
[quo/page-nav
{:text-align :left
@@ -48,7 +51,7 @@
(i18n/label :t/address-to-share)]
[quo/category
{:list-type :settings
:data [{:title (i18n/label :t/join-as-a-member)
:data [{:title (i18n/label :t/join-as-a {:role highest-role-text})
:on-press #(rf/dispatch [:open-modal :addresses-for-permissions
{:community-id id}])
:description :text
@@ -13,3 +13,10 @@
:gap 4
:justify-content :center
:margin-bottom 8})
(def highest-role
{:flex-direction :row
:gap 4
:justify-content :center
:align-items :center
:margin-bottom 8})
@@ -4,6 +4,7 @@
[react-native.core :as rn]
[status-im.common.not-implemented :as not-implemented]
[status-im.contexts.communities.actions.addresses-for-permissions.style :as style]
[status-im.contexts.communities.utils :as communities.utils]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
@@ -22,14 +23,19 @@
(defn view
[]
(let [{id :community-id} (rf/sub [:get-screen-params])
(let [{id :community-id} (rf/sub [:get-screen-params])
{:keys [name color images]} (rf/sub [:communities/community id])
accounts (rf/sub [:wallet/accounts-with-customization-color])
selected-addresses (rf/sub [:communities/selected-permission-addresses id])]
{:keys [highest-permission-role]} (rf/sub [:community/token-gated-overview id])
accounts (rf/sub [:wallet/accounts-with-customization-color])
selected-addresses (rf/sub [:communities/selected-permission-addresses id])
highest-role-text
(i18n/label
(communities.utils/role->translation-key highest-permission-role))]
[rn/safe-area-view {:style style/container}
[quo/drawer-top
{:type :context-tag
:title (i18n/label :t/addresses-for-permissions)
:context-tag-type :community
:community-name name
:button-icon :i/info
:on-button-press not-implemented/alert
@@ -43,6 +49,19 @@
:key-fn :address
:data accounts}]
(when (and highest-permission-role (seq selected-addresses))
[rn/view
{:style style/highest-role}
[quo/text
{:size :paragraph-2
:style {:color colors/neutral-50}}
(i18n/label :t/eligible-to-join-as {:role ""})]
[quo/context-tag
{:type :icon
:icon :i/members
:size 24
:context highest-role-text}]])
(when (empty? selected-addresses)
[rn/view
{:style style/error-message}
@@ -26,6 +26,7 @@
[:<>
[quo/drawer-top
{:type :context-tag
:context-tag-type :community
:title (i18n/label :t/airdrop-addresses)
:community-name name
:button-icon :i/info
@@ -23,10 +23,8 @@
(defn- view-internal
[{:keys [theme]}]
(fn []
(let [{:keys [name
id
images]} (rf/sub [:get-screen-params])
{:keys [color]} (rf/sub [:communities/community id])]
(let [{:keys [id]} (rf/sub [:get-screen-params])
{:keys [color name images]} (rf/sub [:communities/community id])]
[rn/safe-area-view {:flex 1}
[gesture/scroll-view {:style style/container}
[rn/view style/page-container
@@ -1,13 +1,16 @@
(ns status-im.contexts.communities.discover.style
(:require
[react-native.platform :as platform]
[status-im.contexts.shell.jump-to.constants :as jump-to.constants]))
(def screen-title-container
{:height 56
(def header-height 56)
(defn screen-title-container
[safe-area-top]
{:height header-height
:padding-vertical 12
:justify-content :center
:margin-horizontal 20})
:margin-horizontal 20
:margin-top (+ header-height safe-area-top)})
(def featured-communities-header
{:flex-direction :row
@@ -40,7 +43,7 @@
[fixed?]
(merge
{:padding-vertical 12
:height 56
:height header-height
:background-color :transparent}
(when-not fixed?
{:margin-top 12
@@ -60,15 +63,12 @@
{:align-items :center
:justify-content :center})
(def render-communities-container
{:margin-top (if platform/ios? 57 104)})
(defn blur-tabs-header
[]
[safe-area-top]
{:padding-horizontal 20
:position :absolute
:top (if platform/ios? 100 104)
:height 56
:top (+ header-height safe-area-top)
:height header-height
:right 0
:left 0
:justify-content :center
@@ -5,6 +5,7 @@
[quo.foundations.colors :as colors]
[quo.theme :as quo.theme]
[react-native.core :as rn]
[react-native.safe-area :as safe-area]
[reagent.core :as reagent]
[status-im.common.scroll-page.view :as scroll-page]
[status-im.contexts.communities.actions.community-options.view :as options]
@@ -33,7 +34,7 @@
(defn screen-title
[]
[rn/view
{:style style/screen-title-container}
{:style (style/screen-title-container (safe-area/get-top))}
[quo/text
{:accessibility-label :communities-screen-title
:weight :semi-bold
@@ -183,7 +184,6 @@
view-type]
(fn []
[rn/view
{:style style/render-communities-container}
[discover-communities-header
{:selected-tab selected-tab
:view-type view-type
@@ -196,7 +196,7 @@
(fn []
(when (> @scroll-height 360)
[rn/view
{:style (style/blur-tabs-header)}
{:style (style/blur-tabs-header (safe-area/get-top))}
[discover-communities-segments selected-tab true]])))
(defn discover-screen-content
@@ -209,6 +209,7 @@
[scroll-page/scroll-page
{:theme theme
:on-scroll #(reset! scroll-height %)
:page-nav-props {:background :blur}
:navigate-back? :true
:height (if (> @scroll-height 360)
208
+133 -99
View File
@@ -1,96 +1,56 @@
(ns status-im.contexts.communities.events
(:require [clojure.set :as set]
[clojure.string :as string]
[clojure.walk :as walk]
[legacy.status-im.data-store.chats :as data-store.chats]
[legacy.status-im.mailserver.core :as mailserver]
[react-native.platform :as platform]
[react-native.share :as share]
[schema.core :as schema]
[status-im.constants :as constants]
[status-im.contexts.chat.messenger.messages.link-preview.events :as link-preview.events]
status-im.contexts.communities.actions.community-options.events
status-im.contexts.communities.actions.leave.events
[status-im.navigation.events :as navigation]
[taoensso.timbre :as log]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(:require
[clojure.string :as string]
[legacy.status-im.data-store.chats :as data-store.chats]
[legacy.status-im.data-store.communities :as data-store.communities]
[legacy.status-im.mailserver.core :as mailserver]
[react-native.platform :as platform]
[react-native.share :as share]
[schema.core :as schema]
[status-im.constants :as constants]
[status-im.contexts.chat.messenger.messages.link-preview.events :as link-preview.events]
status-im.contexts.communities.actions.community-options.events
status-im.contexts.communities.actions.leave.events
[status-im.navigation.events :as navigation]
[taoensso.timbre :as log]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(defn <-request-to-join-community-rpc
[r]
(set/rename-keys r
{:communityId :community-id
:publicKey :public-key
:chatId :chat-id}))
(defn handle-community
[{:keys [db]} [community-js]]
(when community-js
(let [{:keys [token-permissions
token-permissions-check joined id]
:as community} (data-store.communities/<-rpc community-js)
has-channel-perm? (fn [id-perm-tuple]
(let [{:keys [type]} (second id-perm-tuple)]
(or (= type constants/community-token-permission-can-view-channel)
(=
type
constants/community-token-permission-can-view-and-post-channel))))]
{:db (assoc-in db [:communities id] community)
:fx [[:dispatch [:communities/initialize-permission-addresses id]]
(when (not joined)
[:dispatch [:chat.ui/spectate-community id]])
(when (nil? token-permissions-check)
[:dispatch [:communities/check-permissions-to-join-community id]])
(when (some has-channel-perm? token-permissions)
[:dispatch [:communities/check-all-community-channels-permissions id]])
(when joined
[:dispatch [:communities/get-revealed-accounts id]])]})))
(defn <-requests-to-join-community-rpc
[requests key-fn]
(reduce #(assoc %1 (key-fn %2) (<-request-to-join-community-rpc %2)) {} requests))
(rf/reg-event-fx :communities/handle-community handle-community)
(defn <-chats-rpc
[chats]
(reduce-kv (fn [acc k v]
(assoc acc
(name k)
(-> v
(assoc :can-post? (:canPost v))
(dissoc :canPost)
(update :members walk/stringify-keys))))
{}
chats))
(defn <-categories-rpc
[categ]
(reduce-kv #(assoc %1 (name %2) %3) {} categ))
(defn <-rpc
[c]
(-> c
(set/rename-keys {:canRequestAccess :can-request-access?
:canManageUsers :can-manage-users?
:canDeleteMessageForEveryone :can-delete-message-for-everyone?
:canJoin :can-join?
:requestedToJoinAt :requested-to-join-at
:isMember :is-member?
:adminSettings :admin-settings
:tokenPermissions :token-permissions
:communityTokensMetadata :tokens-metadata
:introMessage :intro-message
:muteTill :muted-till})
(update :admin-settings
set/rename-keys
{:pinMessageAllMembersEnabled :pin-message-all-members-enabled?})
(update :members walk/stringify-keys)
(update :chats <-chats-rpc)
(update :token-permissions seq)
(update :categories <-categories-rpc)
(assoc :token-images
(reduce (fn [acc {sym :symbol image :image}]
(assoc acc sym image))
{}
(:communityTokensMetadata c)))))
(rf/reg-event-fx :communities/handle-community
(fn [{:keys [db]}
[community-js]]
(when community-js
(let [{:keys [token-permissions
token-permissions-check joined id]
:as community} (<-rpc community-js)
has-channel-perm? (fn [id-perm-tuple]
(let [{:keys [type]} (second id-perm-tuple)]
(or (= type constants/community-token-permission-can-view-channel)
(=
type
constants/community-token-permission-can-view-and-post-channel))))]
{:db (assoc-in db [:communities id] community)
:fx [[:dispatch [:communities/initialize-permission-addresses id]]
(when (not joined)
[:dispatch [:chat.ui/spectate-community id]])
(when (nil? token-permissions-check)
[:dispatch [:communities/check-permissions-to-join-community id]])
(when (some has-channel-perm? token-permissions)
[:dispatch [:communities/check-all-community-channels-permissions id]])]}))))
(schema/=> handle-community
[:=>
[:catn
[:cofx :schema.re-frame/cofx]
[:args
[:schema [:catn [:community-js map?]]]]]
[:maybe
[:map
[:db [:map [:communities map?]]]
[:fx vector?]]]])
(rf/defn handle-removed-chats
[{:keys [db]} chat-ids]
@@ -164,7 +124,7 @@
(fn [{:keys [db]} [requests]]
{:db (assoc db
:communities/my-pending-requests-to-join
(<-requests-to-join-community-rpc requests :communityId))}))
(data-store.communities/<-requests-to-join-community-rpc requests :communityId))}))
(rf/reg-event-fx :communities/get-user-requests-to-join
(fn [_]
@@ -240,12 +200,19 @@
(defn toggle-selected-permission-address
[{:keys [db]} [address community-id]]
{:db (update-in db
[:communities community-id :selected-permission-addresses]
(fn [selected-addresses]
(if (contains? selected-addresses address)
(disj selected-addresses address)
(conj selected-addresses address))))})
(let [selected-permission-addresses
(get-in db [:communities community-id :selected-permission-addresses])
updated-selected-permission-addresses
(if (contains? selected-permission-addresses address)
(disj selected-permission-addresses address)
(conj selected-permission-addresses address))]
{:db (assoc-in db
[:communities community-id :selected-permission-addresses]
updated-selected-permission-addresses)
:fx [(when community-id
[:dispatch
[:communities/check-permissions-to-join-community community-id
updated-selected-permission-addresses :based-on-client-selection]])]}))
(rf/reg-event-fx :communities/toggle-selected-permission-address
toggle-selected-permission-address)
@@ -255,7 +222,8 @@
(when community-id
{:db (assoc-in db
[:communities community-id :selected-permission-addresses]
(get-in db [:communities community-id :previous-permission-addresses]))})))
(get-in db [:communities community-id :previous-permission-addresses]))
:fx [[:dispatch [:communities/check-permissions-to-join-community community-id]]]})))
(rf/reg-event-fx :communities/share-community-channel-url-with-data
(fn [_ [chat-id]]
@@ -394,14 +362,80 @@
(rf/merge
cofx
{:fx [[:dispatch [:communities/fetch-community deserialized-key]]
[:dispatch [:navigate-to :community-overview deserialized-key]]]}
[:dispatch [:navigate-to :community-overview deserialized-key]]
[:dispatch [:communities/update-last-opened-at deserialized-key]]]}
(navigation/pop-to-root :shell-stack)))))
(rf/reg-event-fx :communities/navigate-to-community-chat
(fn [{:keys [db]} [chat-id pop-to-root?]]
(let [{:keys [community-id]} (get-in db [:chats chat-id])]
{:fx [(when community-id
[:dispatch [:communities/fetch-community community-id]])
[:dispatch [:communities/fetch-community community-id]]
[:dispatch [:communities/update-last-opened-at community-id]])
(if pop-to-root?
[:dispatch [:chat/pop-to-root-and-navigate-to-chat chat-id]]
[:dispatch [:chat/navigate-to-chat chat-id]])]})))
(defn get-revealed-accounts
[{:keys [db]} [community-id]]
(let [{:keys [joined fetching-revealed-accounts]
:as community} (get-in db [:communities community-id])]
(when (and community joined (not fetching-revealed-accounts))
{:db (assoc-in db [:communities community-id :fetching-revealed-accounts] true)
:json-rpc/call
[{:method "wakuext_getRevealedAccounts"
:params [community-id (get-in db [:profile/profile :public-key])]
:js-response true
:on-success [:communities/get-revealed-accounts-success community-id]
:on-error (fn [err]
(log/error {:message "failed to fetch revealed accounts"
:community-id community-id
:err err})
(rf/dispatch [:communities/get-revealed-accounts-failed community-id]))}]})))
(rf/reg-event-fx :communities/get-revealed-accounts get-revealed-accounts)
(schema/=> get-revealed-accounts
[:=>
[:catn
[:cofx :schema.re-frame/cofx]
[:args
[:schema [:catn [:community-id [:? :string]]]]]]
[:maybe
[:map
[:db map?]
[:json-rpc/call :schema.common/rpc-call]]]])
(rf/reg-event-fx :communities/get-revealed-accounts-success
(fn [{:keys [db]} [community-id revealed-accounts-js]]
(when-let [community (get-in db [:communities community-id])]
(let [revealed-accounts
(reduce
(fn [acc {:keys [address] :as revealed-account}]
(assoc acc address (dissoc revealed-account :address)))
{}
(data-store.communities/<-revealed-accounts-rpc revealed-accounts-js))
community-with-revealed-accounts
(-> community
(assoc :revealed-accounts revealed-accounts)
(dissoc :fetching-revealed-accounts))]
{:db (assoc-in db [:communities community-id] community-with-revealed-accounts)}))))
(rf/reg-event-fx :communities/get-revealed-accounts-failed
(fn [{:keys [db]} [community-id]]
(when (get-in db [:communities community-id])
{:db (update-in db [:communities community-id] dissoc :fetching-revealed-accounts)})))
(rf/reg-event-fx :communities/update-last-opened-at
(fn [_ [community-id]]
{:json-rpc/call [{:method "wakuext_communityUpdateLastOpenedAt"
:params [community-id]
:on-success #(rf/dispatch [:communities/update-last-opened-at-success community-id
%])
:on-error #(log/error (str "failed to update last opened at for community "
%))}]}))
(rf/reg-event-fx :communities/update-last-opened-at-success
(fn [{:keys [db]} [community-id last-opened-at]]
{:db (assoc-in db [:communities community-id :last-opened-at] last-opened-at)}))
@@ -2,6 +2,7 @@
(:require [cljs.test :refer [deftest is testing]]
[legacy.status-im.mailserver.core :as mailserver]
matcher-combinators.test
[status-im.constants :as constants]
[status-im.contexts.chat.messenger.messages.link-preview.events :as link-preview.events]
[status-im.contexts.communities.events :as events]))
@@ -193,3 +194,79 @@
(is (match?
nil
(events/spectate-community-success {} []))))))
(deftest get-revealed-accounts
(let [community {:id community-id}]
(testing "given a unjoined community"
(is (match?
nil
(events/get-revealed-accounts {:db {:communities {community-id community}}} [community-id]))))
(testing "given a already :fetching-revealed-accounts community"
(is (match?
nil
(events/get-revealed-accounts
{:db {:communities {community-id (assoc community :fetching-revealed-accounts true)}}}
[community-id]))))
(testing "given joined community"
(let [community (assoc community :joined true)
db {:communities {community-id community}
:profile/profile {:public-key "profile-public-key"}}
effects (events/get-revealed-accounts {:db db} [community-id])]
(is (match? (assoc-in db [:communities community-id :fetching-revealed-accounts] true)
(:db effects)))
(is (match? {:method "wakuext_getRevealedAccounts"
:params [community-id "profile-public-key"]}
(-> effects :json-rpc/call first (select-keys [:method :params]))))))))
(deftest handle-community
(let [community {:id community-id}]
(testing "given a unjoined community"
(let [effects (events/handle-community {} [community])]
(is (match? community-id
(-> effects :db :communities (get community-id) :id)))
(is (match?
[[:dispatch [:communities/initialize-permission-addresses community-id]]
[:dispatch [:chat.ui/spectate-community community-id]]
[:dispatch [:communities/check-permissions-to-join-community community-id]]]
(filter some? (:fx effects))))))
(testing "given a joined community"
(let [community (assoc community :joined true)
effects (events/handle-community {} [community])]
(is (match?
[[:dispatch [:communities/initialize-permission-addresses community-id]]
[:dispatch [:communities/check-permissions-to-join-community community-id]]
[:dispatch [:communities/get-revealed-accounts community-id]]]
(filter some? (:fx effects))))))
(testing "given a community with token-permissions-check"
(let [community (assoc community :token-permissions-check :fake-token-permissions-check)
effects (events/handle-community {} [community])]
(is (match?
[[:dispatch [:communities/initialize-permission-addresses community-id]]
[:dispatch [:chat.ui/spectate-community community-id]]]
(filter some? (:fx effects))))))
(testing "given a community with view channel permission"
(let [community (assoc community
:token-permissions
[["perm-id" {:type constants/community-token-permission-can-view-channel}]])
effects (events/handle-community {} [community])]
(is (match?
[[:dispatch [:communities/initialize-permission-addresses community-id]]
[:dispatch [:chat.ui/spectate-community community-id]]
[:dispatch [:communities/check-permissions-to-join-community community-id]]
[:dispatch
[:communities/check-all-community-channels-permissions community-id]]]
(filter some? (:fx effects))))))
(testing "given a community with post in channel permission"
(let [community (assoc community
:token-permissions
[["perm-id"
{:type constants/community-token-permission-can-view-and-post-channel}]])
effects (events/handle-community {} [community])]
(is (match?
[[:dispatch [:communities/initialize-permission-addresses community-id]]
[:dispatch [:chat.ui/spectate-community community-id]]
[:dispatch [:communities/check-permissions-to-join-community community-id]]
[:dispatch
[:communities/check-all-community-channels-permissions community-id]]]
(filter some? (:fx effects))))))))
@@ -34,26 +34,31 @@
:communities/check-all-community-channels-permissions}))}]]]})))
(rf/reg-event-fx :communities/check-permissions-to-join-community-success
(fn [{:keys [db]} [community-id result]]
{:db (-> db
(assoc-in [:communities community-id :checking-permissions?] false)
(assoc-in [:communities community-id :token-permissions-check] result))}))
(fn [{:keys [db]} [community-id based-on-client-selection? result]]
(let [token-permissions-check (cond-> result
based-on-client-selection? (assoc :based-on-client-selection? true))]
{:db (-> db
(assoc-in [:communities community-id :checking-permissions?] false)
(assoc-in [:communities community-id :token-permissions-check]
token-permissions-check))})))
(rf/reg-event-fx :communities/check-permissions-to-join-community-failed
(fn [{:keys [db]} [community-id]]
{:db (assoc-in db [:communities community-id :checking-permissions?] false)}))
(rf/reg-event-fx :communities/check-permissions-to-join-community
(fn [{:keys [db]} [community-id]]
(fn [{:keys [db]} [community-id addresses based-on-client-selection?]]
(when-let [community (get-in db [:communities community-id])]
(when-not (:checking-permissions? community)
{:db (-> db
(assoc-in [:communities community-id :checking-permissions?] true)
(assoc-in [:communities community-id :can-request-access?] false))
:json-rpc/call [{:method "wakuext_checkPermissionsToJoinCommunity"
:params [{:communityId community-id}]
:params [(cond-> {:communityId community-id}
addresses
(assoc :addresses addresses))]
:on-success [:communities/check-permissions-to-join-community-success
community-id]
community-id based-on-client-selection?]
:on-error (fn [err]
(rf/dispatch
[:communities/check-permissions-to-join-community-failed
@@ -7,7 +7,6 @@
[react-native.core :as rn]
[reagent.core :as reagent]
[status-im.common.home.actions.view :as actions]
[status-im.common.password-authentication.view :as password-authentication]
[status-im.common.scroll-page.style :as scroll-page.style]
[status-im.common.scroll-page.view :as scroll-page]
[status-im.config :as config]
@@ -15,37 +14,20 @@
[status-im.contexts.communities.actions.chat.view :as chat-actions]
[status-im.contexts.communities.actions.community-options.view :as options]
[status-im.contexts.communities.overview.style :as style]
[status-im.contexts.communities.overview.utils :as utils]
[status-im.contexts.communities.utils :as communities.utils]
[utils.debounce :as debounce]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(defn preview-user-list
[user-list]
(when (seq user-list)
[rn/view style/preview-user
[quo/preview-list
{:type :user
:number (count user-list)
:size :size-24}
user-list]
[quo/text
{:accessibility-label :communities-screen-title
:style {:margin-left 8}
:size :label}
(utils/join-existing-users-string user-list)]]))
(defn add-category-height
(defn- add-category-height
[categories-heights category height]
(swap! categories-heights
(fn [heights]
(assoc heights category height))))
(swap! categories-heights assoc category height))
(defn collapse-category
(defn- collapse-category
[community-id category-id collapsed?]
(rf/dispatch [:communities/toggle-collapsed-category community-id category-id (not collapsed?)]))
(defn layout-y
(defn- layout-y
[event]
(oops/oget event "nativeEvent.layout.y"))
@@ -76,7 +58,7 @@
{:on-press on-press
:on-long-press #(rf/dispatch [:show-bottom-sheet channel-sheet-data])})]]))
(defn channel-list-component
(defn- channel-list-component
[{:keys [on-category-layout community-id community-color on-first-channel-height-changed]}
channels-list]
[rn/view
@@ -103,7 +85,7 @@
^{:key (:id chat)}
[channel-chat-item community-id community-color chat])])])])
(defn get-access-type
(defn- get-access-type
[access]
(condp = access
constants/community-no-membership-access :open
@@ -111,17 +93,9 @@
constants/community-on-request-access :request-access
:unknown-access))
(defn join-gated-community
[id]
(rf/dispatch [:password-authentication/show
{:content (fn [] [password-authentication/view])}
{:label (i18n/label :t/join-open-community)
:on-press #(rf/dispatch [:communities/request-to-join
{:community-id id :password %}])}]))
(defn info-button
(defn- info-button
[]
[rn/touchable-without-feedback
[rn/pressable
{:on-press
#(rf/dispatch
[:show-bottom-sheet
@@ -136,112 +110,116 @@
[rn/view
[quo/icon :i/info {:no-color true}]]])
(defn token-gates
[]
(fn [{:keys [id color]}]
(let [{:keys [can-request-access?
number-of-hold-tokens tokens]} (rf/sub [:community/token-gated-overview id])]
[rn/view {:style (style/token-gated-container)}
[rn/view
{:style {:padding-horizontal 12
:flex-direction :row
:align-items :center
:justify-content :space-between
:flex 1}}
[quo/text {:weight :medium}
(if can-request-access?
(i18n/label :t/you-eligible-to-join)
(i18n/label :t/you-not-eligible-to-join))]
[info-button]]
(when (pos? number-of-hold-tokens)
[quo/text {:style {:padding-horizontal 12 :padding-bottom 18} :size :paragraph-2}
(if can-request-access?
(i18n/label :t/you-hold-number-of-hold-tokens-of-these
{:number-of-hold-tokens number-of-hold-tokens})
(i18n/label :t/you-must-hold))])
[quo/token-requirement-list
{:tokens tokens
:padding? true}]
[quo/button
{:on-press #(join-gated-community id)
:accessibility-label :join-community-button
:customization-color color
:container-style {:margin-horizontal 12 :margin-top 12 :margin-bottom 12}
:disabled? (not can-request-access?)
:icon-left (if can-request-access? :i/unlocked :i/locked)}
(i18n/label :t/join-open-community)]])))
(defn- token-requirements
[{:keys [id color]}]
(let [{:keys [can-request-access?
number-of-hold-tokens tokens
highest-permission-role]} (rf/sub [:community/token-gated-overview id])
highest-role-text
(i18n/label
(communities.utils/role->translation-key highest-permission-role :t/member))]
[rn/view {:style (style/token-gated-container)}
[rn/view
{:style {:padding-horizontal 12
:flex-direction :row
:align-items :center
:justify-content :space-between
:flex 1}}
[quo/text {:weight :medium}
(if can-request-access?
(i18n/label :t/you-eligible-to-join-as {:role highest-role-text})
(i18n/label :t/you-not-eligible-to-join))]
[info-button]]
(when (pos? number-of-hold-tokens)
[quo/text {:style {:padding-horizontal 12 :padding-bottom 18} :size :paragraph-2}
(if can-request-access?
(i18n/label :t/you-hold-number-of-hold-tokens-of-these
{:number-of-hold-tokens number-of-hold-tokens})
(i18n/label :t/you-must-hold))])
[quo/token-requirement-list
{:tokens tokens
:padding? true}]
[quo/button
{:on-press (if config/community-accounts-selection-enabled?
#(rf/dispatch [:open-modal :community-account-selection
{:community-id id}])
#(rf/dispatch [:open-modal :community-requests-to-join {:id id}]))
:accessibility-label :join-community-button
:customization-color color
:container-style {:margin-horizontal 12 :margin-top 12 :margin-bottom 12}
:disabled? (not can-request-access?)
:icon-left (if can-request-access? :i/unlocked :i/locked)}
(i18n/label :t/join-open-community)]]))
(defn join-community
[{:keys [joined color permissions token-permissions id] :as community}
pending?]
(let [access-type (get-access-type (:access permissions))
(defn- join-community
[{:keys [id color joined permissions role-permissions? can-join?] :as community}]
(let [pending? (rf/sub [:communities/my-pending-request-to-join id])
access-type (get-access-type (:access permissions))
unknown-access? (= access-type :unknown-access)
invite-only? (= access-type :invite-only)]
[:<>
(when-not (or joined pending? invite-only? unknown-access?)
(if (seq token-permissions)
[token-gates community]
(if role-permissions?
[token-requirements community]
[quo/button
{:on-press
(if config/community-accounts-selection-enabled?
#(rf/dispatch [:open-modal :community-account-selection {:community-id id}])
#(rf/dispatch [:open-modal :community-requests-to-join community]))
{:on-press (if config/community-accounts-selection-enabled?
#(rf/dispatch [:open-modal :community-account-selection
{:community-id id}])
#(rf/dispatch [:open-modal :community-requests-to-join {:id id}]))
:accessibility-label :show-request-to-join-screen-button
:customization-color color
:icon-left :i/communities}
(i18n/label :t/request-to-join-community)]))
(when (not (or joined pending? token-permissions))
:icon-left :i/communities}
(i18n/label :t/request-to-join)]))
(when (not (or pending? role-permissions? can-join?))
[quo/text
{:size :paragraph-2
:weight :regular
:style style/review-notice}
(i18n/label :t/community-admins-will-review-your-request)])]))
(defn status-tag
[pending? joined]
(when (or pending? joined)
[rn/view {:style {:position :absolute :top 12 :right 12}}
[quo/status-tag
{:status {:type (if joined :positive :pending)}
:label (if joined
(i18n/label :t/joined)
(i18n/label :t/pending))}]]))
(defn- status-tag
[community-id joined]
(let [pending? (rf/sub [:communities/my-pending-request-to-join community-id])]
(when (or pending? joined)
[rn/view {:style {:position :absolute :top 12 :right 12}}
[quo/status-tag
{:status {:type (if joined :positive :pending)}
:label (if joined
(i18n/label :t/joined)
(i18n/label :t/pending))}]])))
(defn add-handlers
(defn- add-handlers
[community-id
joined-or-spectated
{:keys [id locked?]
:or {locked? false}
:as chat}]
(merge
chat
(when (and (not locked?) id)
{:on-press (when joined-or-spectated
(fn []
(rf/dispatch [:dismiss-keyboard])
(debounce/dispatch-and-chill
[:communities/navigate-to-community-chat (str community-id id)]
1000)))
:on-long-press #(rf/dispatch
[:show-bottom-sheet
{:content (fn []
[chat-actions/actions chat false])}])
:community-id community-id})))
(cond-> chat
(and (not locked?) id)
(assoc :on-press (when joined-or-spectated
(fn []
(rf/dispatch [:dismiss-keyboard])
(debounce/dispatch-and-chill
[:communities/navigate-to-community-chat (str community-id id)]
1000)))
:on-long-press #(rf/dispatch
[:show-bottom-sheet
{:content (fn []
[chat-actions/actions chat false])}])
:community-id community-id)))
(defn add-handlers-to-chats
(defn- add-handlers-to-chats
[community-id joined-or-spectated chats]
(mapv (partial add-handlers community-id joined-or-spectated) chats))
(defn add-handlers-to-categorized-chats
(defn- add-handlers-to-categorized-chats
[community-id categorized-chats joined-or-spectated]
(let [add-on-press (partial add-handlers-to-chats community-id joined-or-spectated)]
(map (fn [[category v]]
[category (update v :chats add-on-press)])
categorized-chats)))
(defn community-header
(defn- community-header
[title logo description]
[quo/text-combinations
{:container-style
@@ -258,11 +236,11 @@
:title-accessibility-label :community-title
:description-accessibility-label :community-description}])
(defn community-content
[community]
(rf/dispatch [:communities/check-all-community-channels-permissions (:id community)])
(fn [{:keys [name description joined spectated images tags color id token-permissions] :as community}
pending?
(defn- community-content
[{:keys [id]}]
(rf/dispatch [:communities/check-all-community-channels-permissions id])
(fn [{:keys [name description joined spectated images tags color id membership-permissions?]
:as community}
{:keys [on-category-layout
collapsed?
on-first-channel-height-changed]}]
@@ -271,7 +249,7 @@
[:<>
[rn/view {:style style/community-content-container}
(when-not collapsed?
[status-tag pending? joined])
[status-tag id joined])
[community-header name (when collapsed? (get-in images [:thumbnail :uri]))
(when-not collapsed? description)]
(when (and (seq tags) (not collapsed?))
@@ -279,9 +257,8 @@
{:tags tags
:last-item-style style/last-community-tag
:container-style style/community-tag-container}])
[join-community community pending?]]
(when (or (and (seq token-permissions) joined)
(empty? token-permissions))
[join-community community]]
(when (or joined (not membership-permissions?))
[channel-list-component
{:on-category-layout on-category-layout
:community-id id
@@ -289,7 +266,7 @@
:on-first-channel-height-changed on-first-channel-height-changed}
(add-handlers-to-categorized-chats id chats-by-category joined-or-spectated)])])))
(defn sticky-category-header
(defn- sticky-category-header
[_]
(fn [{:keys [enabled label]}]
(when enabled
@@ -302,7 +279,7 @@
{:chevron :left}
label]])))
(defn page-nav-right-section-buttons
(defn- page-nav-right-section-buttons
[id]
[{:icon-name :i/options
:accessibility-label :community-options-for-community
@@ -310,7 +287,7 @@
[:show-bottom-sheet
{:content (fn [] [options/community-options-bottom-sheet id])}])}])
(defn pick-first-category-by-height
(defn- pick-first-category-by-height
[scroll-height first-channel-height categories-heights]
(->> categories-heights
(sort-by (comp - second))
@@ -318,7 +295,7 @@
(and (>= scroll-height (+ height first-channel-height))
category)))))
(defn community-scroll-page
(defn- community-scroll-page
[{:keys [joined]}]
(let [scroll-height (reagent/atom 0)
categories-heights (reagent/atom {})
@@ -328,7 +305,7 @@
;; from not collapsed to collapsed if the
;; user is on this page
initial-joined? joined]
(fn [{:keys [id name images] :as community} pending?]
(fn [{:keys [id name images] :as community}]
(let [cover {:uri (get-in images [:banner :uri])}
logo {:uri (get-in images [:thumbnail :uri])}
collapsed? (and initial-joined? (:joined community))
@@ -355,7 +332,6 @@
@categories-heights)}]}
[community-content
community
pending?
{:on-category-layout (partial add-category-height categories-heights)
:collapsed? collapsed?
:on-first-channel-height-changed
@@ -365,17 +341,16 @@
(swap! categories-heights select-keys categories)
(reset! first-channel-height height))}]]))))
(defn community-card-page-view
(defn- community-card-page-view
[id]
(let [{:keys [id joined]
:as community} (rf/sub [:communities/community id])
pending? (rf/sub [:communities/my-pending-request-to-join id])]
:as community} (rf/sub [:communities/community id])]
(when community
(when joined
(rf/dispatch [:activity-center.notifications/dismiss-community-overview id]))
[community-scroll-page community pending?])))
[community-scroll-page community])))
(defn overview
(defn view
[id]
(let [id (or id (rf/sub [:get-screen-params :community-overview]))
customization-color (rf/sub [:profile/customization-color])]
@@ -0,0 +1,13 @@
(ns status-im.contexts.communities.utils
(:require
[status-im.constants :as constants]))
(defn role->translation-key
([role] (role->translation-key role nil))
([role fallback-to]
(condp = role
constants/community-token-permission-become-token-owner :t/token-owner
constants/community-token-permission-become-token-master :t/token-master
constants/community-token-permission-become-admin :t/admin
constants/community-token-permission-become-member :t/member
fallback-to)))
@@ -3,7 +3,7 @@
[quo.core :as quo]
[react-native.core :as rn]
[react-native.safe-area :as safe-area]
[status-im.common.biometric.events :as biometric]
[status-im.common.biometric.utils :as biometric]
[status-im.common.parallax.view :as parallax]
[status-im.common.parallax.whitelist :as whitelist]
[status-im.common.resources :as resources]
@@ -2,7 +2,7 @@
(:require
[native-module.core :as native-module]
[re-frame.core :as re-frame]
[status-im.common.biometric.events :as biometric]
status-im.common.biometric.events
[status-im.constants :as constants]
[status-im.contexts.profile.create.events :as profile.create]
[status-im.contexts.profile.recover.events :as profile.recover]
@@ -32,8 +32,10 @@
(rf/defn enable-biometrics
{:events [:onboarding/enable-biometrics]}
[_]
{:biometric/authenticate {:on-success #(rf/dispatch [:onboarding/biometrics-done])
:on-fail #(rf/dispatch [:onboarding/biometrics-fail %])}})
{:fx [[:dispatch
[:biometric/authenticate
{:on-success #(rf/dispatch [:onboarding/biometrics-done])
:on-fail #(rf/dispatch [:onboarding/biometrics-fail %])}]]]})
(rf/defn navigate-to-enable-notifications
{:events [:onboarding/navigate-to-enable-notifications]}
@@ -51,10 +53,10 @@
[:onboarding/finalize-setup]
[:onboarding/create-account-and-login])}))
(rf/defn biometrics-fail
{:events [:onboarding/biometrics-fail]}
[cofx code]
(biometric/show-message cofx code))
(rf/reg-event-fx
:onboarding/biometrics-fail
(fn [_ [error]]
{:dispatch [:biometric/show-message (ex-cause error)]}))
(rf/defn create-account-and-login
{:events [:onboarding/create-account-and-login]}
@@ -16,7 +16,6 @@
[status-im.common.log :as logging]
[status-im.common.universal-links :as universal-links]
[status-im.config :as config]
[status-im.constants :as constants]
[status-im.contexts.chat.contacts.events :as contacts]
[status-im.contexts.chat.messenger.messages.link-preview.events :as link-preview]
[status-im.contexts.profile.config :as profile.config]
@@ -178,12 +177,14 @@
(rf/defn login-with-biometric-if-available
{:events [:profile.login/login-with-biometric-if-available]}
[_ key-uid]
{:keychain/get-auth-method [key-uid
#(rf/dispatch [:profile.login/get-auth-method-success % key-uid])]})
{:biometric/check-if-available {:key-uid key-uid
:on-success (fn [auth-method]
(rf/dispatch [:profile.login/check-biometric-success
key-uid auth-method]))}})
(rf/defn get-auth-method-success
{:events [:profile.login/get-auth-method-success]}
[{:keys [db]} auth-method key-uid]
(rf/defn check-biometric-success
{:events [:profile.login/check-biometric-success]}
[{:keys [db]} key-uid auth-method]
(merge {:db (assoc db :auth-method auth-method)}
(when (= auth-method keychain/auth-method-biometric)
{:keychain/password-hash-migration
@@ -194,7 +195,6 @@
:on-fail #(rf/dispatch
[:profile.login/biometric-auth-fail %])}]))}})))
;; result of :keychain/get-auth-method above
(rf/defn get-user-password-success
{:events [:profile.login/get-user-password-success]}
[{:keys [db] :as cofx} password]
@@ -209,22 +209,18 @@
:profile.login/biometric-success
(fn [{:keys [db]}]
(let [key-uid (get-in db [:profile/login :key-uid])]
{:db db
:fx [[:biometric/reset-not-enrolled-error key-uid]
[:keychain/get-user-password
[key-uid #(rf/dispatch [:profile.login/get-user-password-success %])]]]})))
{:keychain/get-user-password [key-uid
#(rf/dispatch [:profile.login/get-user-password-success %])]})))
(rf/reg-event-fx
:profile.login/biometric-auth-fail
(fn [{:keys [db]} [code]]
(let [key-uid (get-in db [:profile/login :key-uid])]
{:db db
:fx [(if (= code constants/biometric-error-not-enrolled)
[:biometric/supress-not-enrolled-error
[key-uid
[:biometric/show-message code]]]
[:dispatch [:biometric/show-message code]])]})))
(fn [_ [error]]
(log/error (ex-message error)
(-> error
ex-data
(assoc :code (ex-cause error)
:event :profile.login/biometric-auth-fail)))
{:dispatch [:biometric/show-message (ex-cause error)]}))
(rf/defn verify-database-password
{:events [:profile.login/verify-database-password]}
@@ -3,9 +3,8 @@
[quo.theme :as quo.theme]
[react-native.core :as rn]
[react-native.safe-area :as safe-area]
[status-im.common.biometric.events :as biometric]
[status-im.common.biometric.utils :as biometric]
[status-im.common.not-implemented :as not-implemented]
[status-im.common.standard-authentication.standard-auth.authorize :as authorize]
[status-im.constants :as constants]
[status-im.contexts.profile.settings.screens.password.style :as style]
[utils.i18n :as i18n]
@@ -14,16 +13,19 @@
(defn- on-press-biometric-enable
[button-label theme]
(fn []
(authorize/authorize
{:biometric-auth? false
:blur? true
:theme theme
:auth-button-label (i18n/label :t/biometric-enable-button {:bio-type-label button-label})
:on-close (fn [] (rf/dispatch [:standard-auth/reset-login-password]))
:on-auth-success (fn [password]
(rf/dispatch [:hide-bottom-sheet])
(rf/dispatch [:standard-auth/reset-login-password])
(rf/dispatch [:biometric/enable password]))})))
(rf/dispatch
[:standard-auth/authorize-with-password
{:blur? true
:theme theme
:auth-button-label (i18n/label :t/biometric-enable-button {:bio-type-label button-label})
:on-close (fn [] (rf/dispatch [:standard-auth/reset-login-password]))
:on-auth-success (fn [password]
(rf/dispatch [:hide-bottom-sheet])
(rf/dispatch [:standard-auth/reset-login-password])
(rf/dispatch
[:biometric/authenticate
{:on-success #(rf/dispatch [:biometric/enable password])
:on-fail #(rf/dispatch [:biometric/show-message (ex-cause %)])}]))}])))
(defn- get-biometric-item
[theme]
@@ -2,6 +2,7 @@
(:require
[quo.foundations.colors :as colors]
[react-native.platform :as platform]
[react-native.reanimated :as reanimated]
[status-im.contexts.shell.jump-to.utils :as utils]))
(defn bottom-tabs-container
@@ -28,10 +29,11 @@
(defn bottom-tabs-blur-overlay
[height]
[{:height height}
(reanimated/apply-animations-to-style
{:height height}
{:position :absolute
:left 0
:right 0
:bottom 0
:height (utils/bottom-tabs-container-height)
:background-color colors/neutral-100-opa-70-blur}])
:background-color colors/neutral-100-opa-70-blur}))
@@ -15,7 +15,7 @@
(def screens-map
{shell.constants/chat-screen chat/chat
shell.constants/community-screen communities.overview/overview
shell.constants/community-screen communities.overview/view
shell.constants/discover-communities-screen communities.discover/view})
(defn f-screen
@@ -15,12 +15,12 @@
(defn profile-tab
[]
(let [{:keys [emoji-hash
customization-color
universal-profile-url]
:as profile} (rf/sub [:profile/profile])
abbreviated-url (address/get-abbreviated-profile-url
universal-profile-url)
emoji-hash-string (string/join emoji-hash)]
:as profile} (rf/sub [:profile/profile-with-image])
customization-color (rf/sub [:profile/customization-color])
abbreviated-url (address/get-abbreviated-profile-url
universal-profile-url)
emoji-hash-string (string/join emoji-hash)]
[rn/scroll-view
{:content-container-style {:padding-bottom 16}}
[rn/view {:style style/qr-code-container}
@@ -0,0 +1,18 @@
(ns status-im.contexts.shell.share.wallet.style
(:require
[quo.foundations.colors :as colors]))
(defn indicator-wrapper-style
[active?]
{:width 8
:height 8
:border-radius 4
:background-color colors/white
:opacity (if active? 1.0 0.5)})
(def indicator-list-style
{:display :flex
:flex-direction :row
:align-items :center
:justify-content :center
:gap 8})
@@ -6,6 +6,7 @@
[react-native.share :as share]
[reagent.core :as reagent]
[status-im.contexts.shell.share.style :as style]
[status-im.contexts.shell.share.wallet.style :as wallet-style]
[status-im.contexts.wallet.common.sheets.network-preferences.view :as network-preferences]
[status-im.contexts.wallet.common.utils :as utils]
[utils.i18n :as i18n]
@@ -43,10 +44,11 @@
(rf/dispatch [:hide-bottom-sheet])
(reset! selected-networks (map #(get utils/id->network %)
chain-ids)))}])}]))
(defn wallet-qr-code-item
[account width index]
(let [selected-networks (reagent/atom [:ethereum :optimism :arbitrum])
wallet-type (reagent/atom :wallet-legacy)]
(defn- wallet-qr-code-item-internal
[props]
(let [{:keys [account width index]} props
selected-networks (reagent/atom [:ethereum :optimism :arbitrum])
wallet-type (reagent/atom :wallet-legacy)]
(fn []
(let [share-title (str (:name account) " " (i18n/label :t/address))
qr-url (utils/get-wallet-qr {:wallet-type @wallet-type
@@ -57,7 +59,7 @@
:port (rf/sub [:mediaserver/port])
:qr-size qr-size
:error-level :highest})]
[rn/view {:style {:width width :margin-left (if (zero? index) 0 -30)}}
[rn/view {:style {:height qr-size :width width :margin-left (if (zero? index) 0 -30)}}
[rn/view {:style style/qr-code-container}
[quo/share-qr-code
{:type @wallet-type
@@ -73,18 +75,54 @@
:on-legacy-press #(reset! wallet-type :wallet-legacy)
:on-settings-press #(open-preferences @selected-networks)}]]]))))
(def wallet-qr-code-item (memoize wallet-qr-code-item-internal))
(defn- indicator
[active?]
[rn/view
{:style (wallet-style/indicator-wrapper-style active?)}])
(defn- indicator-list
[indicator-count current-index]
[rn/view
{:style wallet-style/indicator-list-style}
(for [i (range indicator-count)]
(let [current-index (cond (<= current-index 0) 0
(>= current-index (dec indicator-count)) (dec indicator-count)
:else current-index)]
^{:key i} [indicator (= current-index i)]))])
(defn render-item
[item]
(let [width (rf/sub [:dimensions/window-width])]
[wallet-qr-code-item
{:account item
:index (:position item)
:width width}]))
(defn wallet-tab
[]
(let [accounts (rf/sub [:wallet/accounts])
width (rf/sub [:dimensions/window-width])]
[rn/flat-list
{:horizontal true
:deceleration-rate 0.9
:snap-to-alignment "start"
:snap-to-interval (- width 30)
:disable-interval-momentum true
:scroll-event-throttle 64
:data accounts
:directional-lock-enabled true
:render-fn (fn [account index]
(wallet-qr-code-item account width index))}]))
(let [accounts (rf/sub [:wallet/accounts])
width (rf/sub [:dimensions/window-width])
current-index (reagent/atom 0)]
(fn []
[rn/view
[rn/flat-list
{:horizontal true
:deceleration-rate 0.9
:snap-to-alignment :start
:snap-to-interval (- width 30)
:disable-interval-momentum true
:scroll-event-throttle 64
:data accounts
:directional-lock-enabled true
:shows-horizontal-scroll-indicator false
:on-scroll (fn [e]
(reset! current-index (js/Math.ceil
(/ e.nativeEvent.contentOffset.x
width))))
:render-fn render-item}]
(when (> (count accounts) 1)
[rn/view
{:style {:margin-top 20}}
(indicator-list (count accounts) @current-index)])])))
@@ -13,6 +13,14 @@
[item]
{:source (quo.resources/get-network (:network-name item))})
(defn- bridge-token-component
[]
(fn [token]
(let [on-press #(rf/dispatch [:wallet/select-bridge-to
{:token token
:stack-id :wallet-bridge}])]
[quo/token-network (assoc token :on-press on-press)])))
(defn view
[]
(let [networks (rf/sub [:wallet/network-details])
@@ -30,5 +38,5 @@
:placeholder (i18n/label :t/search-assets)}]
[rn/flat-list
{:data (temp/bridge-token-list networks-logos)
:render-fn quo/token-network
:render-fn bridge-token-component
:content-container-style style/list-content-container}]]))
@@ -0,0 +1,9 @@
(ns status-im.contexts.wallet.account.bridge-to.style)
(def header-container
{:padding-horizontal 20
:padding-vertical 12})
(def content-container
{:padding-horizontal 8})
@@ -0,0 +1,64 @@
(ns status-im.contexts.wallet.account.bridge-to.view
(:require
[clojure.string :as string]
[quo.core :as quo]
[quo.foundations.resources :as quo.resources]
[quo.theme :as quo.theme]
[react-native.core :as rn]
[status-im.contexts.wallet.account.bridge-to.style :as style]
[status-im.contexts.wallet.common.account-switcher.view :as account-switcher]
[status-im.contexts.wallet.common.utils :as utils]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(defn- bridge-token-component
[]
(fn [{:keys [chain-id network-name]} token]
(let [network (rf/sub [:wallet/network-details-by-chain-id chain-id])
currency (rf/sub [:profile/currency])
currency-symbol (rf/sub [:profile/currency-symbol])
all-balances (:balances-per-chain token)
balance-for-chain (utils/get-balance-for-chain all-balances chain-id)
crypto-formatted (or (:balance balance-for-chain) "0.00")
fiat-value (utils/token-fiat-value currency
(or (:balance balance-for-chain) 0)
token)
fiat-formatted (utils/get-standard-fiat-format crypto-formatted currency-symbol fiat-value)]
[quo/network-list
{:label (name network-name)
:network-image (quo.resources/get-network (:network-name network))
:token-value (str crypto-formatted " " (:symbol token))
:fiat-value fiat-formatted}])))
(defn- view-internal
[]
(let [send-bridge-data (rf/sub [:wallet/wallet-send])
network-details (rf/sub [:wallet/network-details])
account (rf/sub [:wallet/current-viewing-account])
token (:token send-bridge-data)
token-symbol (:symbol token)
tokens (:tokens account)
mainnet (first network-details)
layer-2-networks (rest network-details)
account-token (some #(when (= token-symbol (:symbol %)) %) tokens)]
[rn/view
[account-switcher/view
{:on-press #(rf/dispatch [:navigate-back-within-stack :wallet-bridge-to])
:icon-name :i/arrow-left
:accessibility-label :top-bar}]
[quo/text-combinations
{:container-style style/header-container
:title (i18n/label :t/bridge-to {:name (string/upper-case (str (:label token)))})}]
[rn/view style/content-container
[bridge-token-component (assoc mainnet :network-name :t/mainnet) account-token]]
[quo/divider-label (i18n/label :t/layer-2)]
[rn/flat-list
{:data layer-2-networks
:render-fn (fn [network]
[bridge-token-component network account-token])
:content-container-style style/content-container}]]))
(def view (quo.theme/with-theme view-internal))
@@ -3,6 +3,7 @@
[quo.core :as quo]
[react-native.core :as rn]
[reagent.core :as reagent]
[status-im.config :as config]
[status-im.contexts.wallet.account.style :as style]
[status-im.contexts.wallet.account.tabs.view :as tabs]
[status-im.contexts.wallet.common.account-switcher.view :as account-switcher]
@@ -52,7 +53,9 @@
:receive-action #(rf/dispatch [:open-modal :wallet-share-address {:status :receive}])
:buy-action #(rf/dispatch [:show-bottom-sheet
{:content buy-drawer}])
:bridge-action #(rf/dispatch [:open-modal :wallet-bridge])}])
:bridge-action (if (:bridge-token config/wallet-feature-flags)
#(rf/dispatch [:open-modal :wallet-bridge])
#(js/alert "feature disabled in config file"))}])
[quo/tabs
{:style style/tabs
:size 32
@@ -3,7 +3,6 @@
[quo.theme]
[react-native.core :as rn]
[status-im.contexts.wallet.collectible.tabs.about.style :as style]
[status-im.contexts.wallet.temp :as temp]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
@@ -14,7 +13,8 @@
(let [window-width (rf/sub [:dimensions/window-width])
item-width (- (/ window-width 2) link-card-space)
{:keys [collectible-data]} (rf/sub [:wallet/last-collectible-details])
link-card-container-style (style/link-card item-width)]
link-card-container-style (style/link-card item-width)
collectible-about {:cards []}]
[:<>
[rn/view {:style style/title}
[quo/text
@@ -25,12 +25,13 @@
[quo/text
{:size :paragraph-2}
(:description collectible-data)]]
[quo/section-label
{:container-style style/section-label
:section (i18n/label :t/on-the-web)}]
[rn/view {:style style/link-cards-container}
(for [item (:cards temp/collectible-about)]
^{:key (:title item)}
[quo/link-card (assoc item :container-style link-card-container-style)])]]))
(when (count collectible-about)
[quo/section-label
{:container-style style/section-label
:section (i18n/label :t/on-the-web)}]
[rn/view {:style style/link-cards-container}
(for [item (:cards collectible-about)]
^{:key (:title item)}
[quo/link-card (assoc item :container-style link-card-container-style)])])]))
(def view (quo.theme/with-theme view-internal))
@@ -1,7 +1,6 @@
(ns status-im.contexts.wallet.collectible.tabs.activity.view
(:require [quo.core :as quo]
[react-native.core :as rn]
[status-im.contexts.wallet.temp :as temp]))
[react-native.core :as rn]))
(defn activity-item
[item]
@@ -12,6 +11,6 @@
(defn view
[]
[rn/flat-list
{:data temp/collectible-activities
{:data nil
:style {:flex 1}
:render-fn activity-item}])
@@ -3,12 +3,15 @@
[quo.core :as quo]
[quo.theme :as quo.theme]
[react-native.core :as rn]
[react-native.platform :as platform]
[react-native.svg :as svg]
[reagent.core :as reagent]
[status-im.common.scroll-page.view :as scroll-page]
[status-im.contexts.wallet.collectible.style :as style]
[status-im.contexts.wallet.collectible.tabs.view :as tabs]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
[utils.re-frame :as rf]
[utils.url :as url]))
(defn header
[collectible-name collection-name collection-image-url]
@@ -70,19 +73,49 @@
:accessibility-label :share-details
:label (i18n/label :t/share-details)}]]])
(defn options-drawer
[images index]
(let [{:keys [image]} (nth images index)
uri (url/replace-port image (rf/sub [:mediaserver/port]))]
[quo/action-drawer
[[{:icon :i/link
:accessibility-label :view-on-etherscan
:label (i18n/label :t/view-on-eth)}]
[{:icon :i/save
:accessibility-label :save-image
:label (i18n/label :t/save-image-to-photos)
:on-press (fn []
(rf/dispatch [:hide-bottom-sheet])
(rf/dispatch
[:lightbox/save-image-to-gallery
uri
#(rf/dispatch [:toasts/upsert
{:id :random-id
:type :positive
:container-style {:bottom (when platform/android? 20)}
:text (i18n/label :t/photo-saved)}])]))}]
[{:icon :i/share
:accessibility-label :share-collectible
:label (i18n/label :t/share-collectible)
:right-icon :i/external}]]]))
(defn view-internal
[{:keys [theme] :as _props}]
(let [selected-tab (reagent/atom :overview)
on-tab-change #(reset! selected-tab %)]
(fn []
(let [collectible (rf/sub [:wallet/last-collectible-details])
animation-shared-element-id (rf/sub [:animation-shared-element-id])
{:keys [collectible-data preview-url
collection-data id]} collectible
token-id (:token-id id)
(let [collectible (rf/sub [:wallet/last-collectible-details])
animation-shared-element-id (rf/sub [:animation-shared-element-id])
{:keys [id
preview-url
collection-data
collectible-data]} collectible
{svg? :svg?
preview-uri :uri} preview-url
token-id (:token-id id)
{collection-image :image-url
collection-name :name} collection-data
{collectible-name :name} collectible-data]
collection-name :name} collection-data
{collectible-name :name} collectible-data]
[scroll-page/scroll-page
{:navigate-back? true
:height 148
@@ -94,29 +127,45 @@
[:show-bottom-sheet
{:content collectible-actions-sheet
:theme theme}])}]
:picture preview-url}}
:picture preview-uri}}
[rn/view {:style style/container}
[rn/view {:style style/preview-container}
[rn/touchable-opacity
{:active-opacity 1
:on-press #(rf/dispatch [:lightbox/navigate-to-lightbox
token-id
{:images [{:image preview-url
:image-width 300 ; collectibles don't have
; width/height but we need
; to pass something
:image-height 300 ; without it animation
; doesn't work smoothly and
; :border-radius not
; applied
:id token-id
:header collectible-name
:description collection-name}]
:index 0}])}
[rn/image
{:source preview-url
:style style/preview
:native-ID (when (= animation-shared-element-id token-id) :shared-element)}]]]
:on-press (fn []
(if svg?
(js/alert "Can't visualize SVG images in lightbox")
(rf/dispatch
[:lightbox/navigate-to-lightbox
token-id
{:images [{:image preview-uri
:image-width 300 ; collectibles don't have
; width/height but we need
; to pass something
:image-height 300 ; without it animation
; doesn't work smoothly
; and :border-radius not
; applied
:id token-id
:header collectible-name
:description collection-name}]
:index 0
:on-options-press (fn [images index]
(rf/dispatch [:show-bottom-sheet
{:content (fn []
[options-drawer
images
index])}]))}])))}
(if svg?
[rn/view
{:style (assoc style/preview :overflow :hidden)
:native-ID (when (= animation-shared-element-id token-id)
:shared-element)}
[svg/svg-uri (assoc style/preview :uri preview-uri)]]
[rn/image
{:source preview-uri
:style style/preview
:native-ID (when (= animation-shared-element-id token-id) :shared-element)}])]]
[header collectible-name collection-name collection-image]
[cta-buttons]
[quo/tabs
@@ -52,6 +52,7 @@
:fiat-value "€0.00"
:networks networks-list
:state :default
:symbol "STT"
:customization-color :blue}
{:token :eth
:label "Ethereum"
@@ -59,6 +60,7 @@
:fiat-value "€0.00"
:networks networks-list
:state :default
:symbol "ETH"
:customization-color :blue}
{:token :dai
:label "Dai"
@@ -66,6 +68,7 @@
:fiat-value "€0.00"
:networks networks-list
:state :default
:symbol "DAI"
:customization-color :blue}])
(def secret-phrase
@@ -41,10 +41,12 @@
(defn view
[item]
[quo/token-value
(merge item
{:on-long-press
#(rf/dispatch
[:show-bottom-sheet
{:content (fn [] [token-value-drawer item])
:selected-item (fn [] [quo/token-value item])}])})])
(let [{:keys [watch-only?]} (rf/sub [:wallet/current-viewing-account])]
[quo/token-value
(cond-> item
(not watch-only?)
(assoc :on-long-press
#(rf/dispatch
[:show-bottom-sheet
{:content (fn [] [token-value-drawer item])
:selected-item (fn [] [quo/token-value item])}])))]))
@@ -106,6 +106,16 @@
total-units-in-all-chains (total-token-units-in-all-chains token)]
(money/crypto->fiat total-units-in-all-chains price)))
(defn token-fiat-value
"Returns the fiat value for a single token on a given network."
[currency raw-balance {:keys [market-values-per-currency]}]
(let [price (or (get-in market-values-per-currency
[currency :price])
(get-in market-values-per-currency
[constants/profile-default-currency :price])
0)]
(money/crypto->fiat raw-balance price)))
(defn calculate-balance-for-account
[currency {:keys [tokens] :as _account}]
(->> tokens
@@ -185,6 +195,11 @@
constants/arbitrum-chain-id :arbitrum
constants/arbitrum-test-chain-id :arbitrum})
(def short-name->id
{:eth constants/mainnet-chain-id
:opt constants/optimism-chain-id
:arb1 constants/arbitrum-chain-id})
(defn get-standard-fiat-format
[crypto-value currency-symbol fiat-value]
(if (string/includes? crypto-value "<")
@@ -226,3 +241,7 @@
[input-string]
(let [split-result (string/split input-string #"0x")]
[(first split-result) (str "0x" (second split-result))]))
(defn get-balance-for-chain
[data chain-id]
(some #(when (= chain-id (:chain-id %)) %) (vals data)))
@@ -9,6 +9,7 @@
[reagent.core :as reagent]
[status-im.common.emoji-picker.utils :as emoji-picker.utils]
[status-im.common.standard-authentication.core :as standard-auth]
[status-im.config :as config]
[status-im.constants :as constants]
[status-im.contexts.wallet.common.utils :as utils]
[status-im.contexts.wallet.create-account.style :as style]
@@ -31,7 +32,9 @@
:size :xxs
:customization-color account-color}
:action :button
:action-props {:on-press #(rf/dispatch [:navigate-to :wallet-select-keypair])
:action-props {:on-press (if (:edit-default-keypair config/wallet-feature-flags)
#(rf/dispatch [:navigate-to :wallet-select-keypair])
#(js/alert "feature disabled in config file"))
:button-text (i18n/label :t/edit)
:alignment :flex-start}
:description :text
@@ -40,7 +43,7 @@
:image :icon
:image-props :i/derivated-path
:action :button
:action-props {:on-press #(js/alert "Button pressed!")
:action-props {:on-press #(js/alert "Coming soon!")
:button-text (i18n/label :t/edit)
:icon-left :i/placeholder
:alignment :flex-start}
+10 -21
View File
@@ -6,7 +6,6 @@
[status-im.contexts.wallet.data-store :as data-store]
[status-im.contexts.wallet.events.collectibles]
[status-im.contexts.wallet.item-types :as item-types]
[status-im.contexts.wallet.temp :as temp]
[taoensso.timbre :as log]
[utils.ethereum.chain :as chain]
[utils.ethereum.eip.eip55 :as eip55]
@@ -179,6 +178,11 @@
(first derived-address-details)]))]
{:fx [[:dispatch [:wallet/create-derived-addresses account-details on-success]]]})))
(rf/reg-event-fx :wallet/select-bridge-to
(fn [{:keys [db]} [{:keys [token stack-id]}]]
{:db (assoc-in db [:wallet :ui :send :token] token)
:fx [[:navigate-to-within-stack [:wallet-bridge-to stack-id]]]}))
(rf/reg-event-fx
:wallet/get-ethereum-chains
(fn [_]
@@ -242,30 +246,15 @@
(rf/reg-event-fx :wallet/fetch-address-suggestions
(fn [{:keys [db]} [address]]
(fn [{:keys [db]} [_address]]
{:db (assoc db
:wallet/local-suggestions
(cond
(= address
(get-in
temp/address-local-suggestion-saved-contact-address-mock
[:accounts 0 :address]))
[temp/address-local-suggestion-saved-contact-address-mock]
(= address
(get temp/address-local-suggestion-saved-address-mock
:address))
[temp/address-local-suggestion-saved-address-mock]
:else (temp/find-matching-addresses address))
:wallet/valid-ens-or-address?
false)}))
:wallet/local-suggestions nil
:wallet/valid-ens-or-address? false)}))
(rf/reg-event-fx :wallet/ens-validation-success
(fn [{:keys [db]} [ens]]
(fn [{:keys [db]} [_ens]]
{:db (assoc db
:wallet/local-suggestions (if (= ens
(:ens temp/ens-local-suggestion-saved-address-mock))
[temp/ens-local-suggestion-saved-address-mock]
[temp/ens-local-suggestion-mock])
:wallet/local-suggestions nil
:wallet/valid-ens-or-address? true)}))
(rf/reg-event-fx :wallet/address-validation-success
@@ -24,9 +24,11 @@
(defn displayable-collectible?
[collectible]
(let [{:keys [image-url animation-url]} (:collectible-data collectible)]
(let [{{:keys [image-url animation-url]} :collectible-data
{collection-image-url :image-url} :collection-data} collectible]
(or (not (string/blank? animation-url))
(not (string/blank? image-url)))))
(not (string/blank? image-url))
(not (string/blank? collection-image-url)))))
(defn- add-collectibles-to-accounts
[accounts collectibles]
+14 -3
View File
@@ -2,6 +2,7 @@
(:require
[camel-snake-kebab.core :as csk]
[camel-snake-kebab.extras :as cske]
[clojure.string :as string]
[status-im.constants :as constants]
[status-im.contexts.wallet.common.utils :as utils]
[status-im.contexts.wallet.send.utils :as send-utils]
@@ -57,16 +58,25 @@
(rf/reg-event-fx :wallet/select-send-address
(fn [{:keys [db]} [{:keys [address token recipient stack-id]}]]
(let [[prefix to-address] (utils/split-prefix-and-address address)]
(let [[prefix to-address] (utils/split-prefix-and-address address)
prefix-seq (string/split prefix #":")
selected-networks (->> prefix-seq
(remove string/blank?)
(mapv #(utils/short-name->id (keyword %))))]
{:db (-> db
(assoc-in [:wallet :ui :send :recipient] (or recipient address))
(assoc-in [:wallet :ui :send :to-address] to-address)
(assoc-in [:wallet :ui :send :address-prefix] prefix))
(assoc-in [:wallet :ui :send :address-prefix] prefix)
(assoc-in [:wallet :ui :send :selected-networks] selected-networks))
:fx [[:navigate-to-within-stack
(if token
[:wallet-send-input-amount stack-id]
[:wallet-select-asset stack-id])]]})))
(rf/reg-event-fx :wallet/update-receiver-networks
(fn [{:keys [db]} [selected-networks]]
{:db (assoc-in db [:wallet :ui :send :selected-networks] selected-networks)}))
(rf/reg-event-fx :wallet/send-select-token
(fn [{:keys [db]} [{:keys [token stack-id]}]]
{:db (assoc-in db [:wallet :ui :send :token] token)
@@ -92,10 +102,11 @@
(let [wallet-address (get-in db [:wallet :current-viewing-account-address])
token (get-in db [:wallet :ui :send :token])
account-address (get-in db [:wallet :ui :send :send-account-address])
selected-networks (get-in db [:wallet :ui :send :selected-networks])
to-address (or account-address (get-in db [:wallet :ui :send :to-address]))
token-decimal (:decimals token)
token-id (:symbol token)
network-preferences []
network-preferences selected-networks
gas-rates constants/gas-rate-medium
amount-in (send-utils/amount-in-hex amount token-decimal)
from-address wallet-address
@@ -44,7 +44,8 @@
:market-values-per-currency {:usd {:price 10}}}
:wallet/wallet-send-loading-suggested-routes? false
:wallet/wallet-send-route {:route []}
:wallet/wallet-send-suggested-routes {:candidates []}})
:wallet/wallet-send-suggested-routes {:candidates []}
:wallet/wallet-send-selected-networks []})
(h/describe "Send > input amount screen"
(h/setup-restorable-re-frame)
@@ -54,13 +54,6 @@
(normalize-input current v)
current))
(defn- find-affordable-networks
[{:keys [balances-per-chain]} input-value]
(->> balances-per-chain
(filter (fn [[_ {:keys [balance]}]]
(>= (js/parseFloat balance) input-value)))
(map first)))
(defn- reset-input-error
[new-value prev-value input-error]
(reset! input-error
@@ -129,21 +122,22 @@
(<= input-num-value 0)
(> input-num-value (:amount @current-limit)))
amount (str @input-value " " token-symbol)
{:keys [color]} (rf/sub [:wallet/current-viewing-account])]
{:keys [color]} (rf/sub [:wallet/current-viewing-account])
fetch-routes (fn []
(rf/dispatch [:wallet/clean-suggested-routes])
(when-not (or
(empty? @input-value)
(<= input-num-value 0)
(> input-num-value (:amount @current-limit)))
(debounce/debounce-and-dispatch [:wallet/get-suggested-routes
@input-value]
100)))]
(rn/use-effect
(fn []
(let [dismiss-keyboard-fn #(when (= % "active") (rn/dismiss-keyboard!))
app-keyboard-listener (.addEventListener rn/app-state "change" dismiss-keyboard-fn)]
#(.remove app-keyboard-listener))))
(rn/use-effect (fn []
(rf/dispatch [:wallet/clean-suggested-routes])
(when-not (or
(empty? @input-value)
(<= input-num-value 0)
(> input-num-value (:amount @current-limit)))
(debounce/debounce-and-dispatch [:wallet/get-suggested-routes @input-value]
100)))
[@input-value])
(rn/use-effect #(fetch-routes) [@input-value])
[rn/view
{:style style/screen
:accessibility-label (str "container" (when @input-error "-error"))}
@@ -166,10 +160,11 @@
:on-change-text (fn [text]
(handle-on-change text))}]
[routes/view
{:amount amount
:routes suggested-routes
:loading-networks (find-affordable-networks token @input-value)
:networks (:networks token)}]
{:amount amount
:routes suggested-routes
:token token
:input-value @input-value
:fetch-routes fetch-routes}]
[quo/bottom-actions
{:actions :1-action
:button-one-label (i18n/label :t/confirm)
@@ -1,4 +1,5 @@
(ns status-im.contexts.wallet.send.routes.style)
(ns status-im.contexts.wallet.send.routes.style
(:require [quo.foundations.colors :as colors]))
(def routes-container
{:padding-horizontal 20
@@ -30,3 +31,26 @@
{:flex-grow 1
:align-items :center
:justify-content :center})
(def add-network
{:margin-top 8
:align-self :flex-end
:left 12})
(defn warning-container
[color theme]
{:flex-direction :row
:border-width 1
:border-color (colors/resolve-color color theme 10)
:background-color (colors/resolve-color color theme 5)
:margin-horizontal 20
:margin-top 4
:margin-bottom 8
:padding-left 12
:padding-vertical 11
:border-radius 12})
(def warning-text
{:margin-left 8
:margin-right 12
:padding-right 12})
@@ -1,39 +1,134 @@
(ns status-im.contexts.wallet.send.routes.view
(:require
[clojure.string :as string]
[quo.core :as quo]
[quo.foundations.colors :as colors]
[quo.foundations.resources :as resources]
[quo.theme :as quo.theme]
[react-native.core :as rn]
[reagent.core :as reagent]
[status-im.contexts.wallet.common.utils :as utils]
[status-im.contexts.wallet.send.routes.style :as style]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(defn route-item
[{:keys [amount from-network to-network status]}]
[rn/view {:style style/routes-inner-container}
[quo/network-bridge
{:amount amount
:network from-network
:status status}]
(if (= status :default)
[quo/network-link
{:shape :linear
:source from-network
:destination to-network
:container-style style/network-link}]
[rn/view {:style {:width 73}}])
[quo/network-bridge
{:amount amount
:network to-network
:status status
:container-style {:right 12}}]])
(defn- find-affordable-networks
[{:keys [balances-per-chain]} input-value selected-networks]
(->> balances-per-chain
(filter (fn [[_ {:keys [balance chain-id]}]]
(and
(>= (js/parseFloat balance) input-value)
(some #(= % chain-id) selected-networks))))
(map first)))
(defn view
[{:keys [amount routes loading-networks]}]
(let [loading-suggested-routes? (rf/sub [:wallet/wallet-send-loading-suggested-routes?])
candidates (:candidates routes)]
(if (or (and (not-empty loading-networks) loading-suggested-routes?) (not-empty candidates))
(defn- make-network-item
[{:keys [network-name chain-id] :as _network}
{:keys [title color on-change network-preferences] :as _options}]
{:title (or title (string/capitalize (name network-name)))
:image :icon-avatar
:image-props {:icon (resources/get-network network-name)
:size :size-20}
:action :selector
:action-props {:type :checkbox
:customization-color color
:checked? (some #(= % chain-id) @network-preferences)
:on-change on-change}})
(defn networks-drawer
[{:keys [fetch-routes theme]}]
(let [network-details (rf/sub [:wallet/network-details])
{:keys [color]} (rf/sub [:wallet/current-viewing-account])
selected-networks (rf/sub [:wallet/wallet-send-selected-networks])
prefix (rf/sub [:wallet/wallet-send-address-prefix])
prefix-seq (string/split prefix #":")
grouped-details (group-by #(contains? (set prefix-seq) (:short-name %)) network-details)
preferred (get grouped-details true [])
not-preferred (get grouped-details false [])
network-preferences (reagent/atom selected-networks)
toggle-network (fn [{:keys [chain-id]}]
(swap! network-preferences
(fn [preferences]
(if (some #(= % chain-id) preferences)
(vec (remove #(= % chain-id) preferences))
(conj preferences chain-id)))))]
(fn []
[rn/view
[quo/drawer-top {:title (i18n/label :t/edit-receiver-networks)}]
[quo/category
{:list-type :settings
:label (i18n/label :t/preferred-by-receiver)
:data (mapv (fn [network]
(make-network-item network
{:color color
:network-preferences network-preferences
:on-change #(toggle-network network)}))
preferred)}]
(when (pos? (count not-preferred))
[quo/category
{:list-type :settings
:label (i18n/label :t/not-preferred-by-receiver)
:data (mapv (fn [network]
(make-network-item network
{:color color
:network-preferences network-preferences
:on-change #(toggle-network network)}))
not-preferred)}])
(when (not= selected-networks @network-preferences)
[rn/view {:style (style/warning-container color theme)}
[quo/icon :i/info {:color (colors/resolve-color color theme)}]
[quo/text
{:size :paragraph-2
:style style/warning-text} (i18n/label :t/receiver-networks-warning)]])
[quo/bottom-actions
{:button-one-label (i18n/label :t/apply-changes)
:button-one-props {:disabled? (= selected-networks @network-preferences)
:on-press (fn []
(rf/dispatch [:wallet/update-receiver-networks
@network-preferences])
(rf/dispatch [:hide-bottom-sheet])
(fetch-routes))
:customization-color color}}]])))
(defn route-item
[{:keys [amount from-network to-network status theme fetch-routes]}]
(if (= status :add)
[quo/network-bridge
{:status :add
:container-style style/add-network
:on-press #(rf/dispatch [:show-bottom-sheet
{:content (fn [] [networks-drawer
{:theme theme
:fetch-routes fetch-routes}])}])}]
[rn/view {:style style/routes-inner-container}
[quo/network-bridge
{:amount amount
:network from-network
:status status}]
(if (= status :default)
[quo/network-link
{:shape :linear
:source from-network
:destination to-network
:container-style style/network-link}]
[rn/view {:style {:width 73}}])
[quo/network-bridge
{:amount amount
:network to-network
:status status
:container-style {:right 12}}]]))
(defn- view-internal
[{:keys [amount routes token input-value theme fetch-routes]}]
(let [selected-networks (rf/sub [:wallet/wallet-send-selected-networks])
loading-networks (find-affordable-networks token input-value selected-networks)
loading-suggested-routes? (rf/sub [:wallet/wallet-send-loading-suggested-routes?])
best-routes (:best routes)
data (if loading-suggested-routes? loading-networks best-routes)]
(if (or (and (not-empty loading-networks) loading-suggested-routes?) (not-empty best-routes))
[rn/flat-list
{:data (if loading-suggested-routes? loading-networks candidates)
{:data (if (and (< (count data) 3) (pos? (count data)))
(concat data [{:status :add}])
data)
:content-container-style style/routes-container
:header [rn/view {:style style/routes-header-container}
[quo/section-label
@@ -45,7 +140,12 @@
:render-fn (fn [item]
[route-item
{:amount amount
:status (if loading-suggested-routes? :loading :default)
:theme theme
:fetch-routes fetch-routes
:status (cond
(= (:status item) :add) :add
loading-suggested-routes? :loading
:else :default)
:from-network (if loading-suggested-routes?
(utils/id->network item)
(utils/id->network (get-in item [:from :chain-id])))
@@ -54,5 +154,7 @@
(utils/id->network (get-in item
[:to :chain-id])))}])}]
[rn/view {:style style/empty-container}
(when (and (not (nil? candidates)) (not loading-suggested-routes?))
(when (and (not (nil? best-routes)) (not loading-suggested-routes?))
[quo/text (i18n/label :t/no-routes-found)])])))
(def view (quo.theme/with-theme view-internal))
@@ -168,14 +168,13 @@
[local-suggestions-list]]]
[:<>
[quo/tabs
{:style style/tabs
:container-style style/tabs-content
:size 32
:default-active selected-tab
:data tabs-data
:scrollable? true
:scroll-on-press? true
:on-change on-change-tab}]
{:style style/tabs
:container-style style/tabs-content
:size 32
:default-active selected-tab
:data tabs-data
:scrollable? true
:on-change on-change-tab}]
[tabs/view {:selected-tab selected-tab}]])]))))
(defn view
-124
View File
@@ -1,124 +0,0 @@
(ns status-im.contexts.wallet.temp
(:require [clojure.string :as string]
[quo.foundations.resources :as quo.resources]
[status-im.common.resources :as resources]
[status-im.contexts.wallet.item-types :as types]))
(def ens-local-suggestion-saved-address-mock
{:type types/saved-address
:name "Pedro"
:ens "pedro.eth"
:address "0x4732894732894738294783294723894723984"
:customization-color :purple
:networks [{:network-name :ethereum
:short-name "eth"}
{:network-name :optimism
:short-name "opt"}]})
(def ens-local-suggestion-mock
{:type types/address
:ens "pedro.eth"
:address "0x4732894732894738294783294723894723984"
:networks [{:network-name :ethereum
:short-name "eth"}
{:network-name :optimism
:short-name "opt"}]})
(def address-local-suggestion-saved-contact-address-mock
{:type types/saved-contact-address
:customization-color :blue
:accounts [{:name "New House"
:address "0x62cf6E0Ba4C4530735616e1Ee7ff5FbCB726fBd2"
:emoji "🍔"
:customization-color :blue}]
:contact-props {:full-name "Mark Libot"
:profile-picture (resources/get-mock-image :user-picture-male4)
:customization-color :purple}})
(def address-local-suggestion-saved-address-mock
{:type types/saved-address
:name "Peter Lamborginski"
:address "0x12FaBc34De56Ef78A9B0Cd12Ef3456AbC7D8E9F0"
:customization-color :magenta
:networks [{:network-name :ethereum
:short-name "eth"}
{:network-name :optimism
:short-name "opt"}]})
(def address-local-suggestion-mock
{:type types/address
:address "0x1233cD34De56Ef78A9B0Cd12Ef3456AbC7123dee"
:networks [{:network-name :ethereum
:short-name "eth"}
{:network-name :optimism
:short-name "opt"}]})
(defn find-matching-addresses
[substring]
(let [all-addresses [address-local-suggestion-saved-address-mock
address-local-suggestion-mock]]
(vec (filter #(string/starts-with? (:address %) substring) all-addresses))))
(def collectible-activities
[{:transaction :receive
:timestamp "Today 22:20"
:status :finalised
:counter 1
:first-tag {:size 24
:type :collectible
:collectible (resources/mock-images :collectible)
:collectible-name "Collectible"
:collectible-number "123"}
:second-tag-prefix :t/from
:second-tag {:size 24
:type :default
:full-name "Aretha Gosling"
:profile-picture (resources/mock-images :user-picture-female2)}
:third-tag-prefix :t/to
:third-tag {:size 24
:type :account
:account-name "Piggy bank"
:emoji "🐷"}
:fourth-tag-prefix :t/via
:fourth-tag {:size 24
:type :network
:network-logo (quo.resources/get-network :ethereum)
:network-name "Mainnet"}}
{:transaction :mint
:timestamp "Yesterday"
:status :finalised
:counter 1
:first-tag {:size 24
:type :collectible
:collectible (resources/mock-images :collectible)
:collectible-name "Collectible"
:collectible-number "123"}
:second-tag-prefix :t/at
:second-tag
{:size 24
:type :address
:address
"0x04fcf40c526b09ff9fb22f4a5dbd08490ef9b64af700870f8a0ba2133f4251d5607ed83cd9047b8c2796576bc83fa0de23a13a4dced07654b8ff137fe744047917"}
:third-tag-prefix :t/on
:third-tag {:size 24
:type :network
:network-logo (quo.resources/get-network :ethereum)
:network-name "Mainnet"}}])
(def collectible-about
{:cards [{:title "BAYC"
:icon :social/link
:address "boredapeyachtclub"
:customization-color :social/link
:on-press #(js/alert "pressed")}
{:title "Twitter"
:icon :social/twitter
:address "@BoredApeYC"
:customization-color :social/twitter
:on-press #(js/alert "pressed")}
{:title "Opensea"
:icon :social/opensea
:address "Bored Ape Yacht Club"
:customization-color :social/opensea
:on-press #(js/alert "pressed")}]})
+1 -1
View File
@@ -38,7 +38,7 @@
{:db db/app-db
:theme/init-theme nil
:network/listen-to-network-info nil
:biometric/get-supported-biometric-type nil
:biometric/get-supported-type nil
;;app starting flow continues in get-profiles-overview
:profile/get-profiles-overview #(rf/dispatch [:profile/get-profiles-overview-success %])
:effects.font/get-font-file-for-initials-avatar
@@ -0,0 +1,100 @@
(ns status-im.integration-test.standard-auth-test
(:require
[cljs.test :refer [deftest testing is use-fixtures]]
[day8.re-frame.test :as rf-test]
re-frame.core
[test-helpers.integration :as h]
[utils.re-frame :as rf]))
(defn fixture-re-frame
[]
(let [restore-re-frame (atom nil)]
{:before #(reset! restore-re-frame (re-frame.core/make-restore-fn))
:after #(@restore-re-frame)}))
(use-fixtures :each (fixture-re-frame))
(def default-args
{:on-auth-success identity
:on-auth-fail identity
:on-close identity
:auth-button-label "test"
:auth-button-icon-left :test-icon
:blur? false
:theme :light})
(deftest standard-auth-biometric-authorize-success
(testing "calling success callback when completing biometric authentication"
(h/log-headline :standard-auth-authorize-success)
(rf-test/run-test-async
(do
(rf/reg-fx :biometric/check-if-available
(fn [{:keys [on-success]}]
(rf/dispatch on-success)))
(rf/reg-event-fx :biometric/authenticate
(fn [_ [{:keys [on-success]}]]
(rf/dispatch on-success)))
(rf/reg-fx :keychain/get-user-password
(fn [[_ on-success]]
(on-success))))
(let [on-success-called? (atom false)
args (assoc default-args :on-auth-success #(reset! on-success-called? true))]
(rf/dispatch [:standard-auth/authorize args])
(rf-test/wait-for [:standard-auth/on-biometric-success]
(is @on-success-called?))))))
(deftest standard-auth-biometric-authorize-cancel
(testing "falling back to password authorization when biometrics canceled"
(h/log-headline :standard-auth-authorize-cancel)
(rf-test/run-test-async
(do
(rf/reg-fx :biometric/check-if-available
(fn [{:keys [on-success]}]
(rf/dispatch on-success)))
(rf/reg-event-fx :biometric/authenticate
(fn [_ [{:keys [on-cancel]}]]
(rf/dispatch on-cancel)))
(rf/reg-event-fx :show-bottom-sheet
(fn [_])))
(rf/dispatch [:standard-auth/authorize default-args])
(rf-test/wait-for [:show-bottom-sheet]
(is true)))))
(deftest standard-auth-biometric-authorize-fail
(testing "showing biometric error message when authorization failed"
(h/log-headline :standard-auth-authorize-fail)
(rf-test/run-test-async
(let [on-fail-called? (atom false)
expected-error-cause :bad-error
error (atom nil)
args (assoc default-args
:on-auth-fail
(fn [err]
(reset! on-fail-called? true)
(reset! error err)))]
(rf/reg-fx :biometric/check-if-available
(fn [{:keys [on-success]}]
(rf/dispatch on-success)))
(rf/reg-event-fx :biometric/authenticate
(fn [_ [{:keys [on-fail]}]]
(rf/dispatch (conj on-fail (ex-info "error" {} expected-error-cause)))))
(rf/reg-fx :biometric/show-message
(fn [_]))
(rf/dispatch [:standard-auth/authorize args])
(rf-test/wait-for [:biometric/show-message]
(is @on-fail-called?)
(is (= expected-error-cause (ex-cause @error))))))))
(deftest standard-auth-password-authorize-fallback
(testing "falling back to password when biometrics is not available"
(h/log-headline :standard-auth-password-authorize-fallback)
(rf-test/run-test-async
(do
(rf/reg-fx :biometric/check-if-available
(fn [{:keys [on-fail]}]
(rf/dispatch on-fail)))
(rf/reg-event-fx :show-bottom-sheet
(fn [_])))
(rf/dispatch [:standard-auth/authorize default-args])
(rf-test/wait-for [:standard-auth/authorize-with-password]
(is true)))))
+6 -1
View File
@@ -47,6 +47,7 @@
[status-im.contexts.syncing.scan-sync-code-page.view :as scan-sync-code-page]
[status-im.contexts.syncing.setup-syncing.view :as settings-setup-syncing]
[status-im.contexts.syncing.syncing-devices-list.view :as settings-syncing]
[status-im.contexts.wallet.account.bridge-to.view :as bridge-to]
[status-im.contexts.wallet.account.bridge.view :as bridge]
[status-im.contexts.wallet.account.view :as wallet-accounts]
[status-im.contexts.wallet.add-address-to-watch.confirm-address.view :as confirm-address-to-watch]
@@ -142,7 +143,7 @@
:component communities.discover/view}
{:name :community-overview
:component communities.overview/overview}
:component communities.overview/view}
{:name :settings
:options options/transparent-screen-options
@@ -322,6 +323,10 @@
:modalPresentationStyle :overCurrentContext}
:component bridge/view}
{:name :wallet-bridge-to
:options {:insets {:top? true}}
:component bridge-to/view}
{:name :wallet-edit-derivation-path
:component wallet-edit-derivation-path/view}
+48 -21
View File
@@ -1,6 +1,7 @@
(ns status-im.subs.communities
(:require
[clojure.string :as string]
[legacy.status-im.data-store.communities :as data-store]
[legacy.status-im.ui.screens.profile.visibility-status.utils :as visibility-status-utils]
[re-frame.core :as re-frame]
[status-im.constants :as constants]
@@ -297,32 +298,58 @@
(fn [collapsed-categories [_ community-id]]
(get collapsed-categories community-id)))
(defn- permission-id->permission-value
[token-permissions permission-id]
(get (into {} token-permissions) permission-id))
(re-frame/reg-sub
:community/token-gated-overview
(fn [[_ community-id]]
[(re-frame/subscribe [:communities/community community-id])])
(fn [[{:keys [token-permissions-check token-permissions checking-permissions? token-images]}] _]
{:can-request-access? (:satisfied token-permissions-check)
:number-of-hold-tokens (reduce
(fn [acc [_ {:keys [criteria]}]]
(reduce #(+ %1 (if %2 1 0)) acc criteria))
0
(:permissions token-permissions-check))
:tokens (->> token-permissions
(filter (fn [[_ {:keys [type]}]]
(= type constants/community-token-permission-become-member)))
(map (fn [[perm-key {:keys [token_criteria]}]]
(let [check-criteria (get-in token-permissions-check
[:permissions perm-key :criteria])]
(map
(fn [{sym :symbol amount :amount} sufficient?]
{:symbol sym
:sufficient? (when (seq check-criteria) sufficient?)
:loading? checking-permissions?
:amount amount
:img-src (get token-images sym)})
token_criteria
(or check-criteria token_criteria))))))}))
(let [can-request-access? (:satisfied token-permissions-check)
highest-permission-role
(when can-request-access?
(->> token-permissions-check
:permissions
(reduce-kv
(fn [highest-permission-role permission-id {:keys [criteria]}]
(if-let [permission-type
(and (first criteria)
(some #{(:type (permission-id->permission-value token-permissions
permission-id))}
constants/community-role-permissions))]
(if highest-permission-role
(min highest-permission-role permission-type)
permission-type)
highest-permission-role))
nil)))
highest-permission-role (if (and can-request-access? (nil? highest-permission-role))
constants/community-token-permission-become-member
highest-permission-role)]
{:can-request-access? can-request-access?
:highest-permission-role highest-permission-role
:number-of-hold-tokens (reduce
(fn [acc [_ {:keys [criteria]}]]
(reduce #(+ %1 (if %2 1 0)) acc criteria))
0
(:permissions token-permissions-check))
:tokens (->>
token-permissions
(filter (fn [[_ permission]]
(data-store/role-permission? permission)))
(map (fn [[perm-key {:keys [token_criteria]}]]
(let [check-criteria (get-in token-permissions-check
[:permissions perm-key :criteria])]
(map
(fn [{sym :symbol amount :amount} sufficient?]
{:symbol sym
:sufficient? (when (seq check-criteria) sufficient?)
:loading? checking-permissions?
:amount amount
:img-src (get token-images sym)})
token_criteria
(or check-criteria token_criteria))))))})))
(re-frame/reg-sub
:community/images
+41 -35
View File
@@ -1,6 +1,7 @@
(ns status-im.subs.communities-test
(:require
[cljs.test :refer [is testing]]
matcher-combinators.test
[re-frame.db :as rf-db]
[status-im.constants :as constants]
status-im.subs.communities
@@ -17,7 +18,7 @@
(swap! rf-db/app-db assoc
:communities
raw-communities)
(is (= raw-communities (rf/sub [sub-name]))))))
(is (match? raw-communities (rf/sub [sub-name]))))))
(h/deftest-sub :communities/section-list
[sub-name]
@@ -26,29 +27,29 @@
:communities
{"0x1" {:name "civilized monkeys"}
"0x2" {:name "Civilized rats"}})
(is (= [{:title "C"
:data [{:name "civilized monkeys"}
{:name "Civilized rats"}]}]
(rf/sub [sub-name]))))
(is (match? [{:title "C"
:data [{:name "civilized monkeys"}
{:name "Civilized rats"}]}]
(rf/sub [sub-name]))))
(testing "sorts by section ascending"
(swap! rf-db/app-db assoc
:communities
{"0x3" {:name "Memorable"}
"0x1" {:name "Civilized monkeys"}})
(is (= [{:title "C" :data [{:name "Civilized monkeys"}]}
{:title "M" :data [{:name "Memorable"}]}]
(rf/sub [sub-name]))))
(is (match? [{:title "C" :data [{:name "Civilized monkeys"}]}
{:title "M" :data [{:name "Memorable"}]}]
(rf/sub [sub-name]))))
(testing "builds default section for communities without a name"
(swap! rf-db/app-db assoc
:communities
{"0x2" {:id "0x2"}
"0x1" {:id "0x1"}})
(is (= [{:title ""
:data [{:id "0x2"}
{:id "0x1"}]}]
(rf/sub [sub-name])))))
(is (match? [{:title ""
:data [{:id "0x2"}
{:id "0x1"}]}]
(rf/sub [sub-name])))))
(h/deftest-sub :communities/unviewed-counts
[sub-name]
@@ -64,17 +65,17 @@
"0x102" {:community-id community-id
:unviewed-mentions-count 5
:unviewed-messages-count 1}})
(is (= {:unviewed-messages-count 3
:unviewed-mentions-count 8}
(rf/sub [sub-name community-id]))))
(is (match? {:unviewed-messages-count 3
:unviewed-mentions-count 8}
(rf/sub [sub-name community-id]))))
(testing "defaults to zero when count keys are not present"
(swap! rf-db/app-db assoc
:chats
{"0x100" {:community-id community-id}})
(is (= {:unviewed-messages-count 0
:unviewed-mentions-count 0}
(rf/sub [sub-name community-id])))))
(is (match? {:unviewed-messages-count 0
:unviewed-mentions-count 0}
(rf/sub [sub-name community-id])))))
(h/deftest-sub :communities/categorized-channels
[sub-name]
@@ -350,16 +351,16 @@
(swap! rf-db/app-db assoc
:communities/my-pending-requests-to-join
{})
(is (= {}
(rf/sub [sub-name]))))
(is (match? {}
(rf/sub [sub-name]))))
(testing "users requests to join different communities"
(swap! rf-db/app-db assoc
:communities/my-pending-requests-to-join
{:community-id-1 {:id :request-id-1}
:community-id-2 {:id :request-id-2}})
(is (= {:community-id-1 {:id :request-id-1}
:community-id-2 {:id :request-id-2}}
(rf/sub [sub-name])))))
(is (match? {:community-id-1 {:id :request-id-1}
:community-id-2 {:id :request-id-2}}
(rf/sub [sub-name])))))
(h/deftest-sub :communities/my-pending-request-to-join
[sub-name]
@@ -367,15 +368,15 @@
(swap! rf-db/app-db assoc
:communities/my-pending-requests-to-join
{})
(is (= nil
(rf/sub [sub-name :community-id-1]))))
(is (match? nil
(rf/sub [sub-name :community-id-1]))))
(testing "users request to join a specific communities"
(swap! rf-db/app-db assoc
:communities/my-pending-requests-to-join
{:community-id-1 {:id :request-id-1}
:community-id-2 {:id :request-id-2}})
(is (= :request-id-1
(rf/sub [sub-name :community-id-1])))))
(is (match? :request-id-1
(rf/sub [sub-name :community-id-1])))))
(h/deftest-sub :community/token-gated-overview
[sub-name]
@@ -385,6 +386,7 @@
community {:id community-id
:checking-permissions? checking-permissions?
:permissions {:access 3}
:highest-permission-role constants/community-token-permission-become-admin
:token-images {"ETH" token-image-eth}
:token-permissions [[:permission-id-01
{:id "permission-id-01"
@@ -451,14 +453,18 @@
:outroMessage "bla"
:verified false}]
(swap! rf-db/app-db assoc-in [:communities community-id] community)
(is (= {:can-request-access? true
:number-of-hold-tokens 2
:tokens [[{:symbol "ETH"
:amount "0.001"
:sufficient? nil
:loading? checking-permissions?
:img-src token-image-eth}]]}
(rf/sub [sub-name community-id])))))
(is (match? {:can-request-access? true
:number-of-hold-tokens 2
:tokens [[{:symbol "DAI"
:amount "5.0"
:sufficient? nil
:loading? checking-permissions?}]
[{:symbol "ETH"
:amount "0.001"
:sufficient? nil
:loading? checking-permissions?
:img-src token-image-eth}]]}
(rf/sub [sub-name community-id])))))
(h/deftest-sub :communities/airdrop-account
[sub-name]
+1
View File
@@ -55,6 +55,7 @@
(reg-root-key-sub :get-pairing-installations :pairing/installations)
(reg-root-key-sub :tooltips :tooltips)
(reg-root-key-sub :biometric/supported-type :biometric/supported-type)
(reg-root-key-sub :biometric/auth-pending? :biometric/auth-pending?)
(reg-root-key-sub :app-state :app-state)
(reg-root-key-sub :home-items-show-number :home-items-show-number)
(reg-root-key-sub :waku/v2-peer-stats :peer-stats)
+30 -8
View File
@@ -3,17 +3,39 @@
[clojure.string :as string]
[re-frame.core :as re-frame]))
(defn- svg-animation?
[url media-type]
(and (not (string/blank? url))
(string/includes? media-type "svg")))
(defn- animation?
[url media-type]
(and (not (string/blank? url))
(not (string/blank? media-type))))
(defn- preview-url
[{:keys [image-url animation-url animation-media-type]}]
(if (and (not (string/blank? animation-url))
(not= animation-media-type "image/svg+xml"))
animation-url
image-url))
[{{collectible-image-url :image-url
animation-url :animation-url
animation-media-type :animation-media-type} :collectible-data
{collection-image-url :image-url} :collection-data}]
(cond
(svg-animation? animation-url animation-media-type)
{:uri animation-url
:svg? true}
(animation? animation-url animation-media-type)
{:uri animation-url}
(not (string/blank? collectible-image-url))
{:uri collectible-image-url}
:else
{:uri collection-image-url}))
(defn add-collectibles-preview-url
[collectibles]
(map (fn [{:keys [collectible-data] :as collectible}]
(assoc collectible :preview-url (preview-url collectible-data)))
(map (fn [collectible]
(assoc collectible :preview-url (preview-url collectible)))
collectibles))
(re-frame/reg-sub
@@ -47,7 +69,7 @@
:<- [:wallet]
(fn [wallet]
(let [last-collectible (:last-collectible-details wallet)]
(assoc last-collectible :preview-url (preview-url (:collectible-data last-collectible))))))
(assoc last-collectible :preview-url (preview-url last-collectible)))))
(re-frame/reg-sub
:wallet/last-collectible-details-chain-id
+5
View File
@@ -48,6 +48,11 @@
:<- [:wallet/wallet-send]
:-> :address-prefix)
(rf/reg-sub
:wallet/wallet-send-selected-networks
:<- [:wallet/wallet-send]
:-> :selected-networks)
(rf/reg-sub
:wallet/wallet-send-route
:<- [:wallet/wallet-send]

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