Compare commits
32
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0dbee06436 | ||
|
|
31d2b115be | ||
|
|
e154ffe178 | ||
|
|
d129b37a6b | ||
|
|
413cde7468 | ||
|
|
d6d7c40f10 | ||
|
|
a2eebdf26b | ||
|
|
74c33967e2 | ||
|
|
3433bb68bc | ||
|
|
8e2a881aae | ||
|
|
45b4589c46 | ||
|
|
48cbe2dd87 | ||
|
|
4b7a9906b1 | ||
|
|
58d5041050 | ||
|
|
1a2089ba24 | ||
|
|
fd69436bc0 | ||
|
|
f026915228 | ||
|
|
9ede021d97 | ||
|
|
ebb110e6e3 | ||
|
|
ab973076eb | ||
|
|
c78bdda717 | ||
|
|
b7a138118a | ||
|
|
f03e11c877 | ||
|
|
6c5350573d | ||
|
|
521765e312 | ||
|
|
5f362f333f | ||
|
|
6aae68ba04 | ||
|
|
dbaaa54c83 | ||
|
|
e5913cc3ea | ||
|
|
0226a92c07 | ||
|
|
d7db401cb2 | ||
|
|
7e54aa0b0d |
@@ -72,7 +72,7 @@ public class MainApplication extends NavigationApplication {
|
||||
OkHttpClientProvider.setOkHttpClientFactory(new StatusOkHttpClientFactory());
|
||||
|
||||
WebView.setWebContentsDebuggingEnabled(BuildConfig.DEBUG_WEBVIEW == "1");
|
||||
initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
|
||||
//initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
|
||||
}
|
||||
/**
|
||||
* Loads Flipper in React Native templates. Call this in the onCreate method with something like
|
||||
|
||||
+62
-467
@@ -1859,21 +1859,6 @@
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"path": "com/android/databinding/baseLibrary/3.1.4",
|
||||
"repo": "https://dl.google.com/dl/android/maven2",
|
||||
"files": {
|
||||
"baseLibrary-3.1.4.pom": {
|
||||
"sha1": "b48baeaef73d7763fa92b847c4140f0e0ff71d99",
|
||||
"sha256": "16c6wpphs4b8373w7jdiynv48lgl8sj8sy5gp16cf3qgqgmai4qv"
|
||||
},
|
||||
"baseLibrary-3.1.4.jar": {
|
||||
"sha1": "df1e7638ba852152abe964e86f60fa4ce12e6a6a",
|
||||
"sha256": "0cn50bas33hndr7snlgwpj4vgr66dazkg7ybb04hgc0czdgl9adb"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"path": "com/android/databinding/baseLibrary/3.2.1",
|
||||
"repo": "https://dl.google.com/dl/android/maven2",
|
||||
@@ -1964,21 +1949,6 @@
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"path": "com/android/databinding/compilerCommon/3.1.4",
|
||||
"repo": "https://dl.google.com/dl/android/maven2",
|
||||
"files": {
|
||||
"compilerCommon-3.1.4.pom": {
|
||||
"sha1": "0fd23d31fe5e40ac6d203734dcc6b16328ba714c",
|
||||
"sha256": "0sb36alvbmxv05amnc02csm73cg6aib8s16fipjlgqri58cn5yd9"
|
||||
},
|
||||
"compilerCommon-3.1.4.jar": {
|
||||
"sha1": "11005423fee93309c0cd512a8783647702c20c27",
|
||||
"sha256": "0kxd2js2yk7bisiiy1j5i5zgd9h124qac10dan68y8swiddd4hlb"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"path": "com/android/signflinger/4.1.0",
|
||||
"repo": "https://dl.google.com/dl/android/maven2",
|
||||
@@ -2384,21 +2354,6 @@
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"path": "com/android/tools/analytics-library/protos/26.1.4",
|
||||
"repo": "https://dl.google.com/dl/android/maven2",
|
||||
"files": {
|
||||
"protos-26.1.4.pom": {
|
||||
"sha1": "0c9e7fe6c7c2b0156a87aa626f5463af34669f99",
|
||||
"sha256": "11wnpnlb0ixck525g1qi6lgrjcsca9281kpmwkm3m3r8y1fnl86c"
|
||||
},
|
||||
"protos-26.1.4.jar": {
|
||||
"sha1": "dc5876bb894d87d2088b0a4447b13fdc13ad82fc",
|
||||
"sha256": "1dy9pd8sjkhhip8xqz681i9q66m43iigmnwhdkmk6xm33j0d6cf7"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"path": "com/android/tools/analytics-library/protos/26.2.1",
|
||||
"repo": "https://dl.google.com/dl/android/maven2",
|
||||
@@ -2489,21 +2444,6 @@
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"path": "com/android/tools/analytics-library/shared/26.1.4",
|
||||
"repo": "https://dl.google.com/dl/android/maven2",
|
||||
"files": {
|
||||
"shared-26.1.4.pom": {
|
||||
"sha1": "18ef89a0e8844559433bf6c085b4b86faecb87b6",
|
||||
"sha256": "1m4g32q62mjwmg0z23fvzf40gaf4dgm0jb5cbcv4j36jpgp0yrmm"
|
||||
},
|
||||
"shared-26.1.4.jar": {
|
||||
"sha1": "02a285c67f4b421145e47849d4114f7534707156",
|
||||
"sha256": "08h7w0fwky1mr5j7v4yb4afa3kvvw56bnj4926m4zi62p1qfdxsn"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"path": "com/android/tools/analytics-library/shared/26.2.1",
|
||||
"repo": "https://dl.google.com/dl/android/maven2",
|
||||
@@ -2594,21 +2534,6 @@
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"path": "com/android/tools/analytics-library/tracker/26.1.4",
|
||||
"repo": "https://dl.google.com/dl/android/maven2",
|
||||
"files": {
|
||||
"tracker-26.1.4.pom": {
|
||||
"sha1": "0949ee22e49c32374aa3227b76efdf6b69a85cb0",
|
||||
"sha256": "0077291y8qj555nwqg1ssykdg7cjqgf8866hz9y7rw6sj95h9flw"
|
||||
},
|
||||
"tracker-26.1.4.jar": {
|
||||
"sha1": "fd48066d6c78b78abf5baa335dc2124060e8371c",
|
||||
"sha256": "1yggkx8f5a3w3z924rmc01y06vn4ppz5541s88y6qkd0xbxbdmb6"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"path": "com/android/tools/analytics-library/tracker/26.2.1",
|
||||
"repo": "https://dl.google.com/dl/android/maven2",
|
||||
@@ -2699,21 +2624,6 @@
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"path": "com/android/tools/annotations/26.1.4",
|
||||
"repo": "https://dl.google.com/dl/android/maven2",
|
||||
"files": {
|
||||
"annotations-26.1.4.pom": {
|
||||
"sha1": "d5e8ea57c56cd1f5b6e1e676ab0d489d88b59826",
|
||||
"sha256": "1i6qhh6b5nppvbc465hzjd29ip8j698cs1873yv42dhakc325cyz"
|
||||
},
|
||||
"annotations-26.1.4.jar": {
|
||||
"sha1": "817d5238d9ea07b4b26d04e29e9bada2aacb7245",
|
||||
"sha256": "102r2z2wh3pmaar7f0d3nxksk265m5plbd8cjjvbgll9jkw972k0"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"path": "com/android/tools/annotations/26.2.1",
|
||||
"repo": "https://dl.google.com/dl/android/maven2",
|
||||
@@ -2774,21 +2684,6 @@
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"path": "com/android/tools/build/aapt2-proto/0.1.0",
|
||||
"repo": "https://dl.google.com/dl/android/maven2",
|
||||
"files": {
|
||||
"aapt2-proto-0.1.0.pom": {
|
||||
"sha1": "d3492c6cfb99d5d556cf4840c2efd63493ce2ac1",
|
||||
"sha256": "1h9vlambl1k51nx86qm0yfyavpf9qfrh7gja1q3qsqj10jinb8kc"
|
||||
},
|
||||
"aapt2-proto-0.1.0.jar": {
|
||||
"sha1": "d1eb93a21a8d3590c3bfac574a8b6dffb2dbd21c",
|
||||
"sha256": "1x69zbk977hyc97hpc3bxmh19yiiq3hkl3hadjmwps08z4g13990"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"path": "com/android/tools/build/aapt2-proto/0.3.1",
|
||||
"repo": "https://dl.google.com/dl/android/maven2",
|
||||
@@ -2894,21 +2789,6 @@
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"path": "com/android/tools/build/apksig/3.1.4",
|
||||
"repo": "https://dl.google.com/dl/android/maven2",
|
||||
"files": {
|
||||
"apksig-3.1.4.pom": {
|
||||
"sha1": "a0d953c40691088ad3336fca80b5e2cd3fbd05ec",
|
||||
"sha256": "1jfg6giv1mkg7j72g3w7h5gjvbmpalb03ra7lbdwk350lz76jq23"
|
||||
},
|
||||
"apksig-3.1.4.jar": {
|
||||
"sha1": "e0c4d0059e68e9f64606dfa01e066f86dd07c6cb",
|
||||
"sha256": "0xa5hzkmfymz5pqnrgw7bx9h13rbfnwy3h7nmmnqcrbrlqvc7bar"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"path": "com/android/tools/build/apksig/3.2.1",
|
||||
"repo": "https://dl.google.com/dl/android/maven2",
|
||||
@@ -3059,21 +2939,6 @@
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"path": "com/android/tools/build/builder-model/3.1.4",
|
||||
"repo": "https://dl.google.com/dl/android/maven2",
|
||||
"files": {
|
||||
"builder-model-3.1.4.pom": {
|
||||
"sha1": "2cd8e9360a4114089d33a0ef98927f14d36c8562",
|
||||
"sha256": "0in1yb8n7m28ppj91k5hxclq60qc9141lwm4hyllqsjl2qdns5ys"
|
||||
},
|
||||
"builder-model-3.1.4.jar": {
|
||||
"sha1": "f026c31b8228a84b62bb2fe0ac0544143e9ab27d",
|
||||
"sha256": "0gqa2immwkl4kvg4c233ndxp2bg33ypdbmp6jah5ab0c5azqr3bf"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"path": "com/android/tools/build/builder-model/3.2.1",
|
||||
"repo": "https://dl.google.com/dl/android/maven2",
|
||||
@@ -3164,21 +3029,6 @@
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"path": "com/android/tools/build/builder-test-api/3.1.4",
|
||||
"repo": "https://dl.google.com/dl/android/maven2",
|
||||
"files": {
|
||||
"builder-test-api-3.1.4.pom": {
|
||||
"sha1": "e9843c965bd3ec945ad5e94feebbfe1d47aa5a3b",
|
||||
"sha256": "0adip5p8lvbhcqxhqrpahws9ia9f9q12dkzchf5kj44vgl0r7mbf"
|
||||
},
|
||||
"builder-test-api-3.1.4.jar": {
|
||||
"sha1": "e48338f64f1c8fbef8329eb6d899fb6378fca604",
|
||||
"sha256": "1qjgvj3jmwa7gxc910vfa56rijzin33zymqpb4ikfpsvhk7g2kqz"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"path": "com/android/tools/build/builder-test-api/3.2.1",
|
||||
"repo": "https://dl.google.com/dl/android/maven2",
|
||||
@@ -3269,21 +3119,6 @@
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"path": "com/android/tools/build/builder/3.1.4",
|
||||
"repo": "https://dl.google.com/dl/android/maven2",
|
||||
"files": {
|
||||
"builder-3.1.4.pom": {
|
||||
"sha1": "d33573f1d53514989682eaf85d2c2b98f37aeae2",
|
||||
"sha256": "064y4z05s3r7x74rlb26c8m7aq5pharw5l1yk1ca76h9k0lafslp"
|
||||
},
|
||||
"builder-3.1.4.jar": {
|
||||
"sha1": "afbcd4b7002c61fe898b1b4c50ed9e62386125d8",
|
||||
"sha256": "02wmahn5ibgnxqrk7nqzwdgc4j80iml01g17lmlghdhdmks3y9zy"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"path": "com/android/tools/build/builder/3.2.1",
|
||||
"repo": "https://dl.google.com/dl/android/maven2",
|
||||
@@ -3344,21 +3179,6 @@
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"path": "com/android/tools/build/bundletool/0.1.0-alpha01",
|
||||
"repo": "https://dl.google.com/dl/android/maven2",
|
||||
"files": {
|
||||
"bundletool-0.1.0-alpha01.pom": {
|
||||
"sha1": "834b735a36a399e2bb0276842ce97c55f6d6c072",
|
||||
"sha256": "1271sgv8jxdgsf60chx8yjc0jsfs38xd2jhdmdv8d8h4iwrpcrvc"
|
||||
},
|
||||
"bundletool-0.1.0-alpha01.jar": {
|
||||
"sha1": "f7c303e37818223bd98566fcbea29aa0964c4d06",
|
||||
"sha256": "05bgc6sh1cz4l8mbw6jyx78pq275szq011z5cgpjdkdbpzq5dnrv"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"path": "com/android/tools/build/bundletool/0.5.0",
|
||||
"repo": "https://dl.google.com/dl/android/maven2",
|
||||
@@ -3449,21 +3269,6 @@
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"path": "com/android/tools/build/gradle-api/3.1.4",
|
||||
"repo": "https://dl.google.com/dl/android/maven2",
|
||||
"files": {
|
||||
"gradle-api-3.1.4.pom": {
|
||||
"sha1": "e18ab0b7eee6fc63e65158b4f88bf5c7ce207524",
|
||||
"sha256": "0rjnchkvy8j8k3f12l060p4yg9c784l8j7ngdbphy6jwipvxfz2j"
|
||||
},
|
||||
"gradle-api-3.1.4.jar": {
|
||||
"sha1": "eb41dfb5596afd8933c804595ca8596952fad450",
|
||||
"sha256": "0qqsqjrgnamvzll97ylzw34f75hcp3cmh65dzksqhxgwcfcp9sni"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"path": "com/android/tools/build/gradle-api/3.2.1",
|
||||
"repo": "https://dl.google.com/dl/android/maven2",
|
||||
@@ -3554,21 +3359,6 @@
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"path": "com/android/tools/build/gradle-core/3.1.4",
|
||||
"repo": "https://dl.google.com/dl/android/maven2",
|
||||
"files": {
|
||||
"gradle-core-3.1.4.pom": {
|
||||
"sha1": "38efeb43831cda5d758c52cd62817c3c53ac4722",
|
||||
"sha256": "1kiij87ybp97q5m3w81pr9gy94fpf5jm59jp67ia9h7cz9dj0kv1"
|
||||
},
|
||||
"gradle-core-3.1.4.jar": {
|
||||
"sha1": "4c846d065331c2a11ed605619613833a842a7b8d",
|
||||
"sha256": "1nhx6sjfxfqq63yr59i5j09yvkm383fim93fcfkp6s711ma54pma"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"path": "com/android/tools/build/gradle/3.0.0",
|
||||
"repo": "https://dl.google.com/dl/android/maven2",
|
||||
@@ -3599,21 +3389,6 @@
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"path": "com/android/tools/build/gradle/3.1.4",
|
||||
"repo": "https://dl.google.com/dl/android/maven2",
|
||||
"files": {
|
||||
"gradle-3.1.4.pom": {
|
||||
"sha1": "920f69e56d872f11136254d329ccc6825ced29a1",
|
||||
"sha256": "1cs4sqfpwg0fhdhyqdpzq70gkyq9cy9xm11bmvpanfls2wcwyqi5"
|
||||
},
|
||||
"gradle-3.1.4.jar": {
|
||||
"sha1": "08f9a726f69c0c8fa3f447566717a21e6b394ed9",
|
||||
"sha256": "1dxp32ncbrvi8qd9pij9r0mzcn3l6qm7jr0rk86nq5xi0k06ak0g"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"path": "com/android/tools/build/gradle/3.2.1",
|
||||
"repo": "https://dl.google.com/dl/android/maven2",
|
||||
@@ -3824,21 +3599,6 @@
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"path": "com/android/tools/build/manifest-merger/26.1.4",
|
||||
"repo": "https://dl.google.com/dl/android/maven2",
|
||||
"files": {
|
||||
"manifest-merger-26.1.4.pom": {
|
||||
"sha1": "8b025ca5a54d8e27600470f841f87a77d0a93f56",
|
||||
"sha256": "0xxjj1frb9fqyv6d6kmfhxsy7xqjas8nkv7y0hpk1726q0kqi81v"
|
||||
},
|
||||
"manifest-merger-26.1.4.jar": {
|
||||
"sha1": "ddb4dcb3bb44c7053fa583967dfa9030f43f1c01",
|
||||
"sha256": "1cccgadv0varzj48cpwbk3c0y7hpkl5nxa7v7sds9xd2smkv8q9x"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"path": "com/android/tools/build/manifest-merger/26.2.1",
|
||||
"repo": "https://dl.google.com/dl/android/maven2",
|
||||
@@ -3929,21 +3689,6 @@
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"path": "com/android/tools/common/26.1.4",
|
||||
"repo": "https://dl.google.com/dl/android/maven2",
|
||||
"files": {
|
||||
"common-26.1.4.pom": {
|
||||
"sha1": "0ba42432d38a56a205e7a5f39a67701277c6d818",
|
||||
"sha256": "0xdgznbm17brc3x99p9y4jc082ql0svvxcm36yzlr840iywcl5iy"
|
||||
},
|
||||
"common-26.1.4.jar": {
|
||||
"sha1": "b70b6ef7188fe5a6ad6186f0efb22e536e483b9b",
|
||||
"sha256": "0irdsr5kppk7mw0wjnfpj8h5lixh2p7v4v1ly8z0np95wd6mfnrx"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"path": "com/android/tools/common/26.2.1",
|
||||
"repo": "https://dl.google.com/dl/android/maven2",
|
||||
@@ -4034,21 +3779,6 @@
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"path": "com/android/tools/ddms/ddmlib/26.1.4",
|
||||
"repo": "https://dl.google.com/dl/android/maven2",
|
||||
"files": {
|
||||
"ddmlib-26.1.4.pom": {
|
||||
"sha1": "e18f8f2897b429a9246e9a622608a8b347f73b94",
|
||||
"sha256": "0bq9rr7zwfssz1m6f9qs39s88chqy3siq3hgbfp7f7jc4hgfi1mr"
|
||||
},
|
||||
"ddmlib-26.1.4.jar": {
|
||||
"sha1": "c11fa14b583412aaa9262461299318207439156d",
|
||||
"sha256": "0zzzhjjsrry77yksjdvv5k3a1nhccpnwh9k6vfv51i8mh9mi58x3"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"path": "com/android/tools/ddms/ddmlib/26.2.1",
|
||||
"repo": "https://dl.google.com/dl/android/maven2",
|
||||
@@ -4139,21 +3869,6 @@
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"path": "com/android/tools/dvlib/26.1.4",
|
||||
"repo": "https://dl.google.com/dl/android/maven2",
|
||||
"files": {
|
||||
"dvlib-26.1.4.pom": {
|
||||
"sha1": "49d0672a46075d55b83d2e59e8a7c4af90c4e9f0",
|
||||
"sha256": "1xxdi7fb5ixv850zfjd340ww8gx8vkmlx9jm18ib9w5gj77w4w2s"
|
||||
},
|
||||
"dvlib-26.1.4.jar": {
|
||||
"sha1": "5d443b51ad041e9599cfdb278cd2f6c9d2ccdf28",
|
||||
"sha256": "1kh85j1spdpbd5bwcf2155hjyv7psn3b9qxry7lw0i4cldi862n5"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"path": "com/android/tools/dvlib/26.2.1",
|
||||
"repo": "https://dl.google.com/dl/android/maven2",
|
||||
@@ -4349,21 +4064,6 @@
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"path": "com/android/tools/layoutlib/layoutlib-api/26.1.4",
|
||||
"repo": "https://dl.google.com/dl/android/maven2",
|
||||
"files": {
|
||||
"layoutlib-api-26.1.4.pom": {
|
||||
"sha1": "de645341e6b3b77554bd2510f13fd04513d66324",
|
||||
"sha256": "09229jd3448xaci0xh740v902w1g8xgzrkq1py6949jidzfm814n"
|
||||
},
|
||||
"layoutlib-api-26.1.4.jar": {
|
||||
"sha1": "dad1158a9fc38b711339960b82fd9dcf32009e46",
|
||||
"sha256": "1a5zqp4y43jlqbdnqjw7sis2f4sqa3iixkcj31fq9s72gknwj4fr"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"path": "com/android/tools/layoutlib/layoutlib-api/26.2.1",
|
||||
"repo": "https://dl.google.com/dl/android/maven2",
|
||||
@@ -4514,21 +4214,6 @@
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"path": "com/android/tools/lint/lint-gradle-api/26.1.4",
|
||||
"repo": "https://dl.google.com/dl/android/maven2",
|
||||
"files": {
|
||||
"lint-gradle-api-26.1.4.pom": {
|
||||
"sha1": "8bc04a18da7f891ab4c13a010d422a14f99d8d6d",
|
||||
"sha256": "0b8z7fsfpba2bhx2m0jaca297jgyasy5zhfsx61s40dcp80j89ff"
|
||||
},
|
||||
"lint-gradle-api-26.1.4.jar": {
|
||||
"sha1": "cbc00782604b7d0ad50e9c50b84b074af79394f0",
|
||||
"sha256": "0nipwpq92wvzxnn2wzdff69v8ps9rznwcrj0xagwqfwd85hdkil6"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"path": "com/android/tools/lint/lint-gradle-api/26.2.1",
|
||||
"repo": "https://dl.google.com/dl/android/maven2",
|
||||
@@ -4694,21 +4379,6 @@
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"path": "com/android/tools/repository/26.1.4",
|
||||
"repo": "https://dl.google.com/dl/android/maven2",
|
||||
"files": {
|
||||
"repository-26.1.4.pom": {
|
||||
"sha1": "1b4c88b0253140647c018cce242b688d2ff98cc3",
|
||||
"sha256": "1yinybbnmqlkcw43bqpxi6pq5lwr7ppj8xxfwkx264jqni5phipa"
|
||||
},
|
||||
"repository-26.1.4.jar": {
|
||||
"sha1": "349dfc72ae53dedc32a17f5d47440838fe2527f1",
|
||||
"sha256": "0mskx9a3qm6499415mn0nzir9jvn807pnfwaf8wpymz4gsbfh45l"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"path": "com/android/tools/repository/26.2.1",
|
||||
"repo": "https://dl.google.com/dl/android/maven2",
|
||||
@@ -4799,21 +4469,6 @@
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"path": "com/android/tools/sdklib/26.1.4",
|
||||
"repo": "https://dl.google.com/dl/android/maven2",
|
||||
"files": {
|
||||
"sdklib-26.1.4.pom": {
|
||||
"sha1": "0e7ef3a225517e60891160d63467bc3572de7e58",
|
||||
"sha256": "00bgvi6pq59js519i0xi4zsz3pvvfn1l6dmi50b6k428jhdcljzh"
|
||||
},
|
||||
"sdklib-26.1.4.jar": {
|
||||
"sha1": "7424640f2bd3ca3faccb6f656e29547430cd464a",
|
||||
"sha256": "02p8gsmqk7azzvvnmjnhpc8n49v83yf3pfia2py89j1h5fy7x2bs"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"path": "com/android/tools/sdklib/26.2.1",
|
||||
"repo": "https://dl.google.com/dl/android/maven2",
|
||||
@@ -4904,21 +4559,6 @@
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"path": "com/android/tools/sdk-common/26.1.4",
|
||||
"repo": "https://dl.google.com/dl/android/maven2",
|
||||
"files": {
|
||||
"sdk-common-26.1.4.pom": {
|
||||
"sha1": "03b3158f1e0d5eb281d5a6a67435b97dc2d76c21",
|
||||
"sha256": "0a6jjz7fcbky2w2bv0v5qksppgr51nd7lhawr9lva3wg2gpk36mv"
|
||||
},
|
||||
"sdk-common-26.1.4.jar": {
|
||||
"sha1": "5dbdefb2dc6cb5ba1b4b059bf11c964a830c5755",
|
||||
"sha256": "1awy7i7q22avjs8lxys3i0k3b6qdi0kzvs03p2pxvwbm7lckv7bq"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"path": "com/android/tools/sdk-common/26.2.1",
|
||||
"repo": "https://dl.google.com/dl/android/maven2",
|
||||
@@ -7445,21 +7085,6 @@
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"path": "com/google/errorprone/error_prone_annotations/2.1.2",
|
||||
"repo": "https://repo.maven.apache.org/maven2",
|
||||
"files": {
|
||||
"error_prone_annotations-2.1.2.pom": {
|
||||
"sha1": "44f5d3b9781c31822991ff9f948d6cbfb8cdf055",
|
||||
"sha256": "04894gp1inj1cpgp68cjh0rzpv0svfzhv2spak2prvdlp25mh2hq"
|
||||
},
|
||||
"error_prone_annotations-2.1.2.jar": {
|
||||
"sha1": "6dcc08f90f678ac33e5ef78c3c752b6f59e63e0c",
|
||||
"sha256": "0akq6zj7fd6i0abyz5c0q5aikp7lldrbind4lbvn0q60blxqfg6y"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"path": "com/google/errorprone/error_prone_annotations/2.2.0",
|
||||
"repo": "https://repo.maven.apache.org/maven2",
|
||||
@@ -7531,17 +7156,6 @@
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"path": "com/google/errorprone/error_prone_parent/2.1.2",
|
||||
"repo": "https://repo.maven.apache.org/maven2",
|
||||
"files": {
|
||||
"error_prone_parent-2.1.2.pom": {
|
||||
"sha1": "ae2dd256d508d2ffc9d77fbec0414ee695973a8a",
|
||||
"sha256": "0hx1cf07n7kwcl2pwiab628fm8fmymgy7bwdkvr3nswgvcfxddn6"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"path": "com/google/errorprone/error_prone_parent/2.2.0",
|
||||
"repo": "https://repo.maven.apache.org/maven2",
|
||||
@@ -8474,16 +8088,16 @@
|
||||
},
|
||||
|
||||
{
|
||||
"path": "com/sun/istack/istack-commons-runtime/4.1.1",
|
||||
"path": "com/sun/istack/istack-commons-runtime/4.2.0",
|
||||
"repo": "https://repo.maven.apache.org/maven2",
|
||||
"files": {
|
||||
"istack-commons-runtime-4.1.1.pom": {
|
||||
"sha1": "35c136c863b9591c4d5374b76c724e871cbc57aa",
|
||||
"sha256": "17nvihq7f24xrvlqkzxq23qkb4g5f9sl0pq7wsvspl78gbv4ciq1"
|
||||
"istack-commons-runtime-4.2.0.pom": {
|
||||
"sha1": "e00df2d2db8d5459e86a5ef542269ed56c278c66",
|
||||
"sha256": "0wx5n7595af1n4a8rf5xcqmf6nwyhck0sq17yy94pr1f7pmrp20v"
|
||||
},
|
||||
"istack-commons-runtime-4.1.1.jar": {
|
||||
"sha1": "9b3769c76235bc283b060da4fae2318c6d53f07e",
|
||||
"sha256": "1lyw30wh3w1xazp0kzb4j5zvz01fz1rihk2kqkwfcnjxpz2li0by"
|
||||
"istack-commons-runtime-4.2.0.jar": {
|
||||
"sha1": "131351109ff27c4aa0958a988bb273e879687232",
|
||||
"sha256": "1xjzfa470birdrq8myd0b57c580gk7jip735vrs3zybf15x5n0i1"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -8511,12 +8125,12 @@
|
||||
},
|
||||
|
||||
{
|
||||
"path": "com/sun/istack/istack-commons/4.1.1",
|
||||
"path": "com/sun/istack/istack-commons/4.2.0",
|
||||
"repo": "https://repo.maven.apache.org/maven2",
|
||||
"files": {
|
||||
"istack-commons-4.1.1.pom": {
|
||||
"sha1": "645608b459500510bd8d75686cd4b3a9e9ee36a0",
|
||||
"sha256": "0303sa2xi5ln0ypnwpqizs6zrni8s0dr7wj0d41nkbrg6152fxnf"
|
||||
"istack-commons-4.2.0.pom": {
|
||||
"sha1": "ddebb110777b1340dae08ba3779042ea5b45144e",
|
||||
"sha256": "0z29v0lwwyy5gibffcb91ppjmikvrw90pg76m9l7pidjvcw6cwv6"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -8863,16 +8477,16 @@
|
||||
},
|
||||
|
||||
{
|
||||
"path": "jakarta/activation/jakarta.activation-api/2.1.1",
|
||||
"path": "jakarta/activation/jakarta.activation-api/2.1.2",
|
||||
"repo": "https://repo.maven.apache.org/maven2",
|
||||
"files": {
|
||||
"jakarta.activation-api-2.1.1.pom": {
|
||||
"sha1": "0c6e1dbee7b7faf7c9c8b7274a8b6279415cac6a",
|
||||
"sha256": "006awx3sv5lc6ngsnrvgij6m9dhhrxqwy1gkkf3p9agdxzw5jck9"
|
||||
"jakarta.activation-api-2.1.2.pom": {
|
||||
"sha1": "233dabc7d6b1784679925cbbfebd2e3dec692591",
|
||||
"sha256": "1phfr3r5gy10si0k7r750fbkvg1rdhxg62c3xv5mscfri87b189c"
|
||||
},
|
||||
"jakarta.activation-api-2.1.1.jar": {
|
||||
"sha1": "88c774ab863a21fb2fc4219af95379fafe499a31",
|
||||
"sha256": "010s9784kcs97whlpyy7pd2dp71m62hh5n41zix5mfrdy7qf7fik"
|
||||
"jakarta.activation-api-2.1.2.jar": {
|
||||
"sha1": "640c0d5aff45dbff1e1a1bc09673ff3a02b1ba12",
|
||||
"sha256": "1fwz95v2iygy0bcmvffw4d0zparqkb2ibqm4jp0p0hgbs26mfgzm"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -10387,16 +10001,16 @@
|
||||
},
|
||||
|
||||
{
|
||||
"path": "org/checkerframework/checker-qual/3.32.0",
|
||||
"path": "org/checkerframework/checker-qual/3.34.0",
|
||||
"repo": "https://repo.maven.apache.org/maven2",
|
||||
"files": {
|
||||
"checker-qual-3.32.0.pom": {
|
||||
"sha1": "69d7d01436d892d55b202ccec8a7066f0ac41f98",
|
||||
"sha256": "1kvxly5fpws3prsar57rmjqq6hcy2a0b5fpx60fgmpkf59jqhnkr"
|
||||
"checker-qual-3.34.0.pom": {
|
||||
"sha1": "0e3a886c77f8027c96dcbf9516356a42d5b95dad",
|
||||
"sha256": "0dg54xq0mjd4q2kxyg0z3kfi4d7bjnb7pf870r38qf7kqj8yjnca"
|
||||
},
|
||||
"checker-qual-3.32.0.jar": {
|
||||
"sha1": "54ebd61f46b58b862c779e034073a93489ab3faf",
|
||||
"sha256": "1k9wsy7wvh5304aaqb51hlgpfciahg5avzgmnzq8bgx6l1fh4vmn"
|
||||
"checker-qual-3.34.0.jar": {
|
||||
"sha1": "fd620da2920cdb0bfcbcde20e309f75940198ccf",
|
||||
"sha256": "1p96cdclxdvsxgd2bv8lscwqc1cd2ak6mvg7llb7mgbmwf1kxl2x"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -10643,27 +10257,27 @@
|
||||
},
|
||||
|
||||
{
|
||||
"path": "org/eclipse/angus/angus-activation-project/2.0.0",
|
||||
"path": "org/eclipse/angus/angus-activation-project/2.0.1",
|
||||
"repo": "https://repo.maven.apache.org/maven2",
|
||||
"files": {
|
||||
"angus-activation-project-2.0.0.pom": {
|
||||
"sha1": "6fafee47a73b1ee5dc0f533bcaebc55743bbee84",
|
||||
"sha256": "17ffihwphiw6vzwxb3gkrxbjcsby640wmadj43rbcfamn6icwrjx"
|
||||
"angus-activation-project-2.0.1.pom": {
|
||||
"sha1": "24682c09b455ad140ee080bd86752f0bf1957c55",
|
||||
"sha256": "1ddiingflsp4wdyaw1az6fm02iacn63imnkg82xnxh8ximcns5y3"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"path": "org/eclipse/angus/angus-activation/2.0.0",
|
||||
"path": "org/eclipse/angus/angus-activation/2.0.1",
|
||||
"repo": "https://repo.maven.apache.org/maven2",
|
||||
"files": {
|
||||
"angus-activation-2.0.0.pom": {
|
||||
"sha1": "87500cdbfdcb4758ece7ca2267469a590e2d9fb9",
|
||||
"sha256": "1sb92gyb9fk3fqysrsr021wdan191i6wgq845gkf4lnk4rbgcqsr"
|
||||
"angus-activation-2.0.1.pom": {
|
||||
"sha1": "b0b59e5f8caaf5afe94cde78d4e98aa1c0a50505",
|
||||
"sha256": "1vs0w1m3hqa0piqq144x3d9jl3bywzzdl0lg34dfl9gmyw7ypib7"
|
||||
},
|
||||
"angus-activation-2.0.0.jar": {
|
||||
"sha1": "72369f4e2314d38de2dcbb277141ef0226f73151",
|
||||
"sha256": "0iwi0y1ksir12z47gc0q7y7bfxnylf9yxdprix2sjnpkl0hx64is"
|
||||
"angus-activation-2.0.1.jar": {
|
||||
"sha1": "eaafaf4eb71b400e4136fc3a286f50e34a68ecb7",
|
||||
"sha256": "0cf1nhrkjqz0nihp0l484y627asl5mnixmy1cj4xz3l62lc7c9mj"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -10941,12 +10555,12 @@
|
||||
},
|
||||
|
||||
{
|
||||
"path": "org/jacoco/org.jacoco.build/0.8.8",
|
||||
"path": "org/jacoco/org.jacoco.build/0.8.10",
|
||||
"repo": "https://repo.maven.apache.org/maven2",
|
||||
"files": {
|
||||
"org.jacoco.build-0.8.8.pom": {
|
||||
"sha1": "b1ec2ce6fa11aa065c5c8cea04be7fa745c9fcbc",
|
||||
"sha256": "1vrarvwmzb8gg8k7fmpxx3fh8n9ik1r8ahigfxngq97xhl90pkpl"
|
||||
"org.jacoco.build-0.8.10.pom": {
|
||||
"sha1": "a129ae2c1a5138a8bdfcfaecde3d1c74cb6d4f23",
|
||||
"sha256": "0fvcpmk09b92985xsry4pdz2ii8jja0h68iw759i9apbipcv1mz3"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -10967,16 +10581,16 @@
|
||||
},
|
||||
|
||||
{
|
||||
"path": "org/jacoco/org.jacoco.core/0.8.8",
|
||||
"path": "org/jacoco/org.jacoco.core/0.8.10",
|
||||
"repo": "https://repo.maven.apache.org/maven2",
|
||||
"files": {
|
||||
"org.jacoco.core-0.8.8.pom": {
|
||||
"sha1": "887670d63e8ac0302fde83422824b5e39736e262",
|
||||
"sha256": "09g2zsc854m5qxy2byqfh20rpk384c1jcl531qybh8zqinjbbypm"
|
||||
"org.jacoco.core-0.8.10.pom": {
|
||||
"sha1": "e4acd57d7b22eab888cf7a5bac94a2798f6a23cb",
|
||||
"sha256": "12gaf5yl7p4328hvncsgph4ni40lg60k9gplca7b7vww2kayv84k"
|
||||
},
|
||||
"org.jacoco.core-0.8.8.jar": {
|
||||
"sha1": "fb1257ce77ec2fe326aad639b2253e76f481ea2e",
|
||||
"sha256": "0hqnc5jh8ga60d44hxp59f80ycwxnyng1nyz2d3r524xh0pphk27"
|
||||
"org.jacoco.core-0.8.10.jar": {
|
||||
"sha1": "669a338279c3f40b154a64c624bab625664a00e6",
|
||||
"sha256": "020fv0bdhl459nr9jqjl7gdcq6wspkxy92lpxqw3jl57jdynd2g7"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -12181,36 +11795,6 @@
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"path": "org/jetbrains/kotlin/kotlin-stdlib-jre7/1.2.0",
|
||||
"repo": "https://repo.maven.apache.org/maven2",
|
||||
"files": {
|
||||
"kotlin-stdlib-jre7-1.2.0.pom": {
|
||||
"sha1": "52d689e2aecf9c5ee2ca40c9512069ea77b4eb06",
|
||||
"sha256": "0j3ka2lfxqxb37dmx4nzm07q88a77yf5wf1mrqs7gayk49y42xr0"
|
||||
},
|
||||
"kotlin-stdlib-jre7-1.2.0.jar": {
|
||||
"sha1": "ec8b969e26fbcf2265a4d1a1539c4d1d4c5af380",
|
||||
"sha256": "09i91z5r1ynll65sa6v61hqkz875q7vaz049zrx7jdyla6whz8n7"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"path": "org/jetbrains/kotlin/kotlin-stdlib-jre8/1.2.0",
|
||||
"repo": "https://repo.maven.apache.org/maven2",
|
||||
"files": {
|
||||
"kotlin-stdlib-jre8-1.2.0.pom": {
|
||||
"sha1": "dd37e31bef41f48317214e93134ff54372bad406",
|
||||
"sha256": "0f5c4jjw8rs5jgyjb2d9j6h1nf5nqcj6aq61s7p5cw6546z78ykb"
|
||||
},
|
||||
"kotlin-stdlib-jre8-1.2.0.jar": {
|
||||
"sha1": "505f55b9619bbc5f5e26c77427dd24a6a441eef1",
|
||||
"sha256": "0an8j2wwpx0mapmpl179xqf242kvjbipxaqxrgvl26ggwvp28db3"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"path": "org/jetbrains/kotlin/kotlin-stdlib/1.1.3-2",
|
||||
"repo": "https://repo.maven.apache.org/maven2",
|
||||
@@ -12572,12 +12156,12 @@
|
||||
},
|
||||
|
||||
{
|
||||
"path": "org/junit/junit-bom/5.9.2",
|
||||
"path": "org/junit/junit-bom/5.9.3",
|
||||
"repo": "https://repo.maven.apache.org/maven2",
|
||||
"files": {
|
||||
"junit-bom-5.9.2.pom": {
|
||||
"sha1": "645a08cbe455cad14d8bfb25a35d7f594c53cafd",
|
||||
"sha256": "01gp6mpz7c4vcyrmm0drb05rvdan82d6qiw6d8rzacaihijpvl1f"
|
||||
"junit-bom-5.9.3.pom": {
|
||||
"sha1": "b1874b6a66656e4f5e4b492ab321249bcb749dc7",
|
||||
"sha256": "1mrf6kf0y6bic98n30w8s9gnxykgzv5j8mx1bh745wkjkv6jj0sd"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -12713,6 +12297,17 @@
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"path": "org/ow2/asm/asm-bom/9.5",
|
||||
"repo": "https://repo.maven.apache.org/maven2",
|
||||
"files": {
|
||||
"asm-bom-9.5.pom": {
|
||||
"sha1": "2b5d6f54150ef4cbef69c3b09b281353f42e1366",
|
||||
"sha256": "1grm2s0pqc0s2kl79mhbv3l5zcwbgq3z803gh0wbczc3vlsnnxbi"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"path": "org/ow2/asm/asm-commons/5.1",
|
||||
"repo": "https://repo.maven.apache.org/maven2",
|
||||
|
||||
@@ -118,7 +118,6 @@ com.airbnb.android:lottie:3.4.4
|
||||
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.1.4
|
||||
com.android.databinding:baseLibrary:3.2.1
|
||||
com.android.databinding:baseLibrary:3.3.1
|
||||
com.android.databinding:baseLibrary:3.5.4
|
||||
@@ -126,28 +125,24 @@ com.android.databinding:baseLibrary:4.1.0
|
||||
com.android.databinding:compilerCommon:1.0-rc5
|
||||
com.android.databinding:compilerCommon:3.0.0
|
||||
com.android.databinding:compilerCommon:3.0.1
|
||||
com.android.databinding:compilerCommon:3.1.4
|
||||
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:protos:26.0.0
|
||||
com.android.tools.analytics-library:protos:26.0.1
|
||||
com.android.tools.analytics-library:protos:26.1.4
|
||||
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:shared:26.0.0
|
||||
com.android.tools.analytics-library:shared:26.0.1
|
||||
com.android.tools.analytics-library:shared:26.1.4
|
||||
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:tracker:26.0.0
|
||||
com.android.tools.analytics-library:tracker:26.0.1
|
||||
com.android.tools.analytics-library:tracker:26.1.4
|
||||
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
|
||||
@@ -160,7 +155,6 @@ 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:aapt2-proto:0.1.0
|
||||
com.android.tools.build:aapt2-proto:0.3.1
|
||||
com.android.tools.build:aapt2-proto:0.4.0
|
||||
com.android.tools.build:aapt2-proto:4.1.0-6503028
|
||||
@@ -168,7 +162,6 @@ com.android.tools.build:aapt2-proto:4.1.0-alpha01-6193524
|
||||
com.android.tools.build:aaptcompiler:4.1.0
|
||||
com.android.tools.build:apksig:3.0.0
|
||||
com.android.tools.build:apksig:3.0.1
|
||||
com.android.tools.build:apksig:3.1.4
|
||||
com.android.tools.build:apksig:3.2.1
|
||||
com.android.tools.build:apksig:3.3.1
|
||||
com.android.tools.build:apksig:3.5.4
|
||||
@@ -182,7 +175,6 @@ com.android.tools.build:builder-model:1.3.1
|
||||
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.1.4
|
||||
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
|
||||
@@ -192,7 +184,6 @@ com.android.tools.build:builder-test-api:1.3.1
|
||||
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.1.4
|
||||
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
|
||||
@@ -202,19 +193,16 @@ com.android.tools.build:builder:1.3.1
|
||||
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.1.4
|
||||
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:bundletool:0.1.0-alpha01
|
||||
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:gradle-api:3.0.0
|
||||
com.android.tools.build:gradle-api:3.0.1
|
||||
com.android.tools.build:gradle-api:3.1.4
|
||||
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
|
||||
@@ -224,13 +212,11 @@ com.android.tools.build:gradle-core:1.3.1
|
||||
com.android.tools.build:gradle-core:1.5.0
|
||||
com.android.tools.build:gradle-core:3.0.0
|
||||
com.android.tools.build:gradle-core:3.0.1
|
||||
com.android.tools.build:gradle-core:3.1.4
|
||||
com.android.tools.build:gradle:1.1.3
|
||||
com.android.tools.build:gradle:1.3.1
|
||||
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.1.4
|
||||
com.android.tools.build:gradle:3.2.1
|
||||
com.android.tools.build:gradle:3.3.1
|
||||
com.android.tools.build:gradle:3.5.4
|
||||
@@ -240,7 +226,6 @@ com.android.tools.build:manifest-merger:24.3.1
|
||||
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.1.4
|
||||
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
|
||||
@@ -252,7 +237,6 @@ com.android.tools.ddms:ddmlib:24.3.1
|
||||
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.1.4
|
||||
com.android.tools.ddms:ddmlib:26.2.1
|
||||
com.android.tools.ddms:ddmlib:26.3.1
|
||||
com.android.tools.ddms:ddmlib:26.5.4
|
||||
@@ -272,7 +256,6 @@ com.android.tools.layoutlib:layoutlib-api:24.3.1
|
||||
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.1.4
|
||||
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
|
||||
@@ -289,7 +272,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-checks:27.1.0
|
||||
com.android.tools.lint:lint-gradle-api:26.1.4
|
||||
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
|
||||
@@ -307,7 +289,6 @@ com.android.tools:annotations:24.3.1
|
||||
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.1.4
|
||||
com.android.tools:annotations:26.2.1
|
||||
com.android.tools:annotations:26.3.1
|
||||
com.android.tools:annotations:26.5.4
|
||||
@@ -317,7 +298,6 @@ com.android.tools:common:24.3.1
|
||||
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.1.4
|
||||
com.android.tools:common:26.2.1
|
||||
com.android.tools:common:26.3.1
|
||||
com.android.tools:common:26.5.4
|
||||
@@ -327,14 +307,12 @@ com.android.tools:dvlib:24.3.1
|
||||
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.1.4
|
||||
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:repository:26.0.0
|
||||
com.android.tools:repository:26.0.1
|
||||
com.android.tools:repository:26.1.4
|
||||
com.android.tools:repository:26.2.1
|
||||
com.android.tools:repository:26.3.1
|
||||
com.android.tools:repository:26.5.4
|
||||
@@ -344,7 +322,6 @@ com.android.tools:sdklib:24.3.1
|
||||
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.1.4
|
||||
com.android.tools:sdklib:26.2.1
|
||||
com.android.tools:sdklib:26.3.1
|
||||
com.android.tools:sdklib:26.5.4
|
||||
@@ -354,7 +331,6 @@ com.android.tools:sdk-common:24.3.1
|
||||
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.1.4
|
||||
com.android.tools:sdk-common:26.2.1
|
||||
com.android.tools:sdk-common:26.3.1
|
||||
com.android.tools:sdk-common:26.5.4
|
||||
@@ -415,13 +391,11 @@ com.google.code.findbugs:jsr305:1.3.9
|
||||
com.google.code.findbugs:jsr305:3.0.2
|
||||
com.google.code.gson:gson:2.2.4
|
||||
com.google.code.gson:gson:2.3
|
||||
com.google.code.gson:gson:2.7
|
||||
com.google.code.gson:gson:2.8.0
|
||||
com.google.code.gson:gson:2.8.5
|
||||
com.google.code.gson:gson:2.8.6
|
||||
com.google.crypto.tink:tink:1.3.0-rc2
|
||||
com.google.errorprone:error_prone_annotations:2.0.18
|
||||
com.google.errorprone:error_prone_annotations:2.1.2
|
||||
com.google.errorprone:error_prone_annotations:2.2.0
|
||||
com.google.errorprone:error_prone_annotations:2.3.1
|
||||
com.google.errorprone:error_prone_annotations:2.3.2
|
||||
@@ -595,10 +569,7 @@ 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.10
|
||||
org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.5.30
|
||||
org.jetbrains.kotlin:kotlin-stdlib-jre7:1.2.0
|
||||
org.jetbrains.kotlin:kotlin-stdlib-jre8:1.2.0
|
||||
org.jetbrains.kotlin:kotlin-stdlib:1.1.3-2
|
||||
org.jetbrains.kotlin:kotlin-stdlib:1.2.0
|
||||
org.jetbrains.kotlin:kotlin-stdlib:1.2.71
|
||||
org.jetbrains.kotlin:kotlin-stdlib:1.3.20
|
||||
org.jetbrains.kotlin:kotlin-stdlib:1.3.50
|
||||
|
||||
+10
-37
@@ -122,14 +122,12 @@ https://dl.google.com/dl/android/maven2/android/arch/lifecycle/common/1.0.0/comm
|
||||
https://dl.google.com/dl/android/maven2/android/arch/lifecycle/runtime/1.0.0/runtime-1.0.0.pom
|
||||
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.1.4/baseLibrary-3.1.4.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/compilerCommon/3.0.0/compilerCommon-3.0.0.pom
|
||||
https://dl.google.com/dl/android/maven2/com/android/databinding/compilerCommon/3.0.1/compilerCommon-3.0.1.pom
|
||||
https://dl.google.com/dl/android/maven2/com/android/databinding/compilerCommon/3.1.4/compilerCommon-3.1.4.pom
|
||||
https://dl.google.com/dl/android/maven2/com/android/signflinger/4.1.0/signflinger-4.1.0.pom
|
||||
https://dl.google.com/dl/android/maven2/com/android/support/animated-vector-drawable/26.0.2/animated-vector-drawable-26.0.2.pom
|
||||
https://dl.google.com/dl/android/maven2/com/android/support/animated-vector-drawable/27.0.1/animated-vector-drawable-27.0.1.pom
|
||||
@@ -157,33 +155,28 @@ 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/crash/27.1.0/crash-27.1.0.pom
|
||||
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.1.4/protos-26.1.4.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/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.1.4/shared-26.1.4.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/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.1.4/tracker-26.1.4.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/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.1.4/annotations-26.1.4.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/build/aapt2-proto/0.1.0/aapt2-proto-0.1.0.pom
|
||||
https://dl.google.com/dl/android/maven2/com/android/tools/build/aapt2-proto/0.3.1/aapt2-proto-0.3.1.pom
|
||||
https://dl.google.com/dl/android/maven2/com/android/tools/build/aapt2-proto/0.4.0/aapt2-proto-0.4.0.pom
|
||||
https://dl.google.com/dl/android/maven2/com/android/tools/build/aapt2-proto/4.1.0-6503028/aapt2-proto-4.1.0-6503028.pom
|
||||
@@ -191,7 +184,6 @@ https://dl.google.com/dl/android/maven2/com/android/tools/build/aapt2-proto/4.1.
|
||||
https://dl.google.com/dl/android/maven2/com/android/tools/build/aaptcompiler/4.1.0/aaptcompiler-4.1.0.pom
|
||||
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.1.4/apksig-3.1.4.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
|
||||
@@ -202,43 +194,36 @@ https://dl.google.com/dl/android/maven2/com/android/tools/build/apkzlib/3.5.4/ap
|
||||
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/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.1.4/builder-model-3.1.4.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-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.1.4/builder-test-api-3.1.4.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/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.1.4/builder-3.1.4.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/bundletool/0.1.0-alpha01/bundletool-0.1.0-alpha01.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/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.1.4/gradle-api-3.1.4.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-core/3.0.0/gradle-core-3.0.0.pom
|
||||
https://dl.google.com/dl/android/maven2/com/android/tools/build/gradle-core/3.0.1/gradle-core-3.0.1.pom
|
||||
https://dl.google.com/dl/android/maven2/com/android/tools/build/gradle-core/3.1.4/gradle-core-3.1.4.pom
|
||||
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.1.4/gradle-3.1.4.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
|
||||
@@ -253,28 +238,24 @@ https://dl.google.com/dl/android/maven2/com/android/tools/build/jetifier/jetifie
|
||||
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/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.1.4/manifest-merger-26.1.4.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/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.1.4/common-26.1.4.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/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.1.4/ddmlib-26.1.4.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/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.1.4/dvlib-26.1.4.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
|
||||
@@ -288,7 +269,6 @@ https://dl.google.com/dl/android/maven2/com/android/tools/external/org-jetbrains
|
||||
https://dl.google.com/dl/android/maven2/com/android/tools/external/org-jetbrains/uast/27.1.0/uast-27.1.0.pom
|
||||
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.1.4/layoutlib-api-26.1.4.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
|
||||
@@ -299,7 +279,6 @@ https://dl.google.com/dl/android/maven2/com/android/tools/lint/lint-api/27.1.0/l
|
||||
https://dl.google.com/dl/android/maven2/com/android/tools/lint/lint-checks/26.0.0/lint-checks-26.0.0.pom
|
||||
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/27.1.0/lint-checks-27.1.0.pom
|
||||
https://dl.google.com/dl/android/maven2/com/android/tools/lint/lint-gradle-api/26.1.4/lint-gradle-api-26.1.4.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
|
||||
@@ -311,21 +290,18 @@ https://dl.google.com/dl/android/maven2/com/android/tools/lint/lint/26.0.1/lint-
|
||||
https://dl.google.com/dl/android/maven2/com/android/tools/lint/lint/27.1.0/lint-27.1.0.pom
|
||||
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.1.4/repository-26.1.4.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/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.1.4/sdklib-26.1.4.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/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.1.4/sdk-common-26.1.4.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
|
||||
@@ -496,13 +472,11 @@ https://repo.maven.apache.org/maven2/com/google/code/gson/gson/2.8.5/gson-2.8.5.
|
||||
https://repo.maven.apache.org/maven2/com/google/code/gson/gson/2.8.6/gson-2.8.6.pom
|
||||
https://repo.maven.apache.org/maven2/com/google/crypto/tink/tink/1.3.0-rc2/tink-1.3.0-rc2.pom
|
||||
https://repo.maven.apache.org/maven2/com/google/errorprone/error_prone_annotations/2.0.18/error_prone_annotations-2.0.18.pom
|
||||
https://repo.maven.apache.org/maven2/com/google/errorprone/error_prone_annotations/2.1.2/error_prone_annotations-2.1.2.pom
|
||||
https://repo.maven.apache.org/maven2/com/google/errorprone/error_prone_annotations/2.2.0/error_prone_annotations-2.2.0.pom
|
||||
https://repo.maven.apache.org/maven2/com/google/errorprone/error_prone_annotations/2.3.1/error_prone_annotations-2.3.1.pom
|
||||
https://repo.maven.apache.org/maven2/com/google/errorprone/error_prone_annotations/2.3.2/error_prone_annotations-2.3.2.pom
|
||||
https://repo.maven.apache.org/maven2/com/google/errorprone/error_prone_annotations/2.18.0/error_prone_annotations-2.18.0.pom
|
||||
https://repo.maven.apache.org/maven2/com/google/errorprone/error_prone_parent/2.0.18/error_prone_parent-2.0.18.pom
|
||||
https://repo.maven.apache.org/maven2/com/google/errorprone/error_prone_parent/2.1.2/error_prone_parent-2.1.2.pom
|
||||
https://repo.maven.apache.org/maven2/com/google/errorprone/error_prone_parent/2.2.0/error_prone_parent-2.2.0.pom
|
||||
https://repo.maven.apache.org/maven2/com/google/errorprone/error_prone_parent/2.3.1/error_prone_parent-2.3.1.pom
|
||||
https://repo.maven.apache.org/maven2/com/google/errorprone/error_prone_parent/2.3.2/error_prone_parent-2.3.2.pom
|
||||
@@ -572,10 +546,10 @@ https://repo.maven.apache.org/maven2/com/sun/activation/all/1.2.0/all-1.2.0.pom
|
||||
https://repo.maven.apache.org/maven2/com/sun/activation/javax.activation/1.2.0/javax.activation-1.2.0.pom
|
||||
https://repo.maven.apache.org/maven2/com/sun/istack/istack-commons-runtime/2.21/istack-commons-runtime-2.21.pom
|
||||
https://repo.maven.apache.org/maven2/com/sun/istack/istack-commons-runtime/3.0.7/istack-commons-runtime-3.0.7.pom
|
||||
https://repo.maven.apache.org/maven2/com/sun/istack/istack-commons-runtime/4.1.1/istack-commons-runtime-4.1.1.pom
|
||||
https://repo.maven.apache.org/maven2/com/sun/istack/istack-commons-runtime/4.2.0/istack-commons-runtime-4.2.0.pom
|
||||
https://repo.maven.apache.org/maven2/com/sun/istack/istack-commons/2.21/istack-commons-2.21.pom
|
||||
https://repo.maven.apache.org/maven2/com/sun/istack/istack-commons/3.0.7/istack-commons-3.0.7.pom
|
||||
https://repo.maven.apache.org/maven2/com/sun/istack/istack-commons/4.1.1/istack-commons-4.1.1.pom
|
||||
https://repo.maven.apache.org/maven2/com/sun/istack/istack-commons/4.2.0/istack-commons-4.2.0.pom
|
||||
https://repo.maven.apache.org/maven2/com/sun/xml/bind/jaxb-bom-ext/2.2.11/jaxb-bom-ext-2.2.11.pom
|
||||
https://repo.maven.apache.org/maven2/com/sun/xml/bind/jaxb-bom-ext/2.3.1/jaxb-bom-ext-2.3.1.pom
|
||||
https://repo.maven.apache.org/maven2/com/sun/xml/bind/jaxb-bom-ext/4.0.2/jaxb-bom-ext-4.0.2.pom
|
||||
@@ -603,7 +577,7 @@ https://repo.maven.apache.org/maven2/com/tunnelvisionlabs/antlr4/4.5/antlr4-4.5.
|
||||
https://repo.maven.apache.org/maven2/de/undercouch/gradle-download-task/3.4.3/gradle-download-task-3.4.3.pom
|
||||
https://repo.maven.apache.org/maven2/de/undercouch/gradle-download-task/4.0.2/gradle-download-task-4.0.2.pom
|
||||
https://repo.maven.apache.org/maven2/it/unimi/dsi/fastutil/7.2.0/fastutil-7.2.0.pom
|
||||
https://repo.maven.apache.org/maven2/jakarta/activation/jakarta.activation-api/2.1.1/jakarta.activation-api-2.1.1.pom
|
||||
https://repo.maven.apache.org/maven2/jakarta/activation/jakarta.activation-api/2.1.2/jakarta.activation-api-2.1.2.pom
|
||||
https://repo.maven.apache.org/maven2/jakarta/xml/bind/jakarta.xml.bind-api-parent/4.0.0/jakarta.xml.bind-api-parent-4.0.0.pom
|
||||
https://repo.maven.apache.org/maven2/jakarta/xml/bind/jakarta.xml.bind-api/4.0.0/jakarta.xml.bind-api-4.0.0.pom
|
||||
https://repo.maven.apache.org/maven2/javax/activation/activation/1.1/activation-1.1.pom
|
||||
@@ -719,7 +693,7 @@ https://repo.maven.apache.org/maven2/org/bouncycastle/bcprov-jdk15on/1.60/bcprov
|
||||
https://repo.maven.apache.org/maven2/org/checkerframework/checker-qual/2.5.2/checker-qual-2.5.2.pom
|
||||
https://repo.maven.apache.org/maven2/org/checkerframework/checker-qual/2.5.8/checker-qual-2.5.8.pom
|
||||
https://repo.maven.apache.org/maven2/org/checkerframework/checker-qual/2.8.1/checker-qual-2.8.1.pom
|
||||
https://repo.maven.apache.org/maven2/org/checkerframework/checker-qual/3.32.0/checker-qual-3.32.0.pom
|
||||
https://repo.maven.apache.org/maven2/org/checkerframework/checker-qual/3.34.0/checker-qual-3.34.0.pom
|
||||
https://repo.maven.apache.org/maven2/org/codehaus/codehaus-parent/4/codehaus-parent-4.pom
|
||||
https://repo.maven.apache.org/maven2/org/codehaus/groovy/groovy-all/2.4.15/groovy-all-2.4.15.pom
|
||||
https://repo.maven.apache.org/maven2/org/codehaus/mojo/animal-sniffer-annotations/1.14/animal-sniffer-annotations-1.14.pom
|
||||
@@ -739,8 +713,8 @@ https://repo.maven.apache.org/maven2/org/easymock/easymockclassextension/3.2/eas
|
||||
https://repo.maven.apache.org/maven2/org/easymock/easymock-parent/3.2/easymock-parent-3.2.pom
|
||||
https://repo.maven.apache.org/maven2/org/easymock/easymock-parent/5.1.0/easymock-parent-5.1.0.pom
|
||||
https://repo.maven.apache.org/maven2/org/easymock/easymock/5.1.0/easymock-5.1.0.pom
|
||||
https://repo.maven.apache.org/maven2/org/eclipse/angus/angus-activation-project/2.0.0/angus-activation-project-2.0.0.pom
|
||||
https://repo.maven.apache.org/maven2/org/eclipse/angus/angus-activation/2.0.0/angus-activation-2.0.0.pom
|
||||
https://repo.maven.apache.org/maven2/org/eclipse/angus/angus-activation-project/2.0.1/angus-activation-project-2.0.1.pom
|
||||
https://repo.maven.apache.org/maven2/org/eclipse/angus/angus-activation/2.0.1/angus-activation-2.0.1.pom
|
||||
https://repo.maven.apache.org/maven2/org/eclipse/ee4j/project/1.0.7/project-1.0.7.pom
|
||||
https://repo.maven.apache.org/maven2/org/eclipse/ee4j/project/1.0.8/project-1.0.8.pom
|
||||
https://repo.maven.apache.org/maven2/org/eclipse/jdt/core/compiler/ecj/4.4.2/ecj-4.4.2.pom
|
||||
@@ -761,9 +735,9 @@ https://repo.maven.apache.org/maven2/org/hamcrest/hamcrest-core/2.2/hamcrest-cor
|
||||
https://repo.maven.apache.org/maven2/org/hamcrest/hamcrest-parent/1.3/hamcrest-parent-1.3.pom
|
||||
https://repo.maven.apache.org/maven2/org/hamcrest/hamcrest/2.2/hamcrest-2.2.pom
|
||||
https://repo.maven.apache.org/maven2/org/jacoco/org.jacoco.build/0.7.4.201502262128/org.jacoco.build-0.7.4.201502262128.pom
|
||||
https://repo.maven.apache.org/maven2/org/jacoco/org.jacoco.build/0.8.8/org.jacoco.build-0.8.8.pom
|
||||
https://repo.maven.apache.org/maven2/org/jacoco/org.jacoco.build/0.8.10/org.jacoco.build-0.8.10.pom
|
||||
https://repo.maven.apache.org/maven2/org/jacoco/org.jacoco.core/0.7.4.201502262128/org.jacoco.core-0.7.4.201502262128.pom
|
||||
https://repo.maven.apache.org/maven2/org/jacoco/org.jacoco.core/0.8.8/org.jacoco.core-0.8.8.pom
|
||||
https://repo.maven.apache.org/maven2/org/jacoco/org.jacoco.core/0.8.10/org.jacoco.core-0.8.10.pom
|
||||
https://repo.maven.apache.org/maven2/org/jacoco/org.jacoco.report/0.7.4.201502262128/org.jacoco.report-0.7.4.201502262128.pom
|
||||
https://repo.maven.apache.org/maven2/org/jdom/jdom2/2.0.6/jdom2-2.0.6.pom
|
||||
https://repo.maven.apache.org/maven2/org/jetbrains/annotations/13.0/annotations-13.0.pom
|
||||
@@ -844,8 +818,6 @@ https://repo.maven.apache.org/maven2/org/jetbrains/kotlin/kotlin-stdlib-jdk8/1.3
|
||||
https://repo.maven.apache.org/maven2/org/jetbrains/kotlin/kotlin-stdlib-jdk8/1.4.10/kotlin-stdlib-jdk8-1.4.10.pom
|
||||
https://repo.maven.apache.org/maven2/org/jetbrains/kotlin/kotlin-stdlib-jdk8/1.5.30/kotlin-stdlib-jdk8-1.5.30.pom
|
||||
https://repo.maven.apache.org/maven2/org/jetbrains/kotlin/kotlin-stdlib-jdk8/1.8.0/kotlin-stdlib-jdk8-1.8.0.pom
|
||||
https://repo.maven.apache.org/maven2/org/jetbrains/kotlin/kotlin-stdlib-jre7/1.2.0/kotlin-stdlib-jre7-1.2.0.pom
|
||||
https://repo.maven.apache.org/maven2/org/jetbrains/kotlin/kotlin-stdlib-jre8/1.2.0/kotlin-stdlib-jre8-1.2.0.pom
|
||||
https://repo.maven.apache.org/maven2/org/jetbrains/kotlin/kotlin-stdlib/1.1.3-2/kotlin-stdlib-1.1.3-2.pom
|
||||
https://repo.maven.apache.org/maven2/org/jetbrains/kotlin/kotlin-stdlib/1.2.0/kotlin-stdlib-1.2.0.pom
|
||||
https://repo.maven.apache.org/maven2/org/jetbrains/kotlin/kotlin-stdlib/1.2.20/kotlin-stdlib-1.2.20.pom
|
||||
@@ -870,7 +842,7 @@ https://repo.maven.apache.org/maven2/org/jetbrains/kotlin/kotlin-util-klib/1.4.3
|
||||
https://repo.maven.apache.org/maven2/org/jetbrains/trove4j/trove4j/20160824/trove4j-20160824.pom
|
||||
https://repo.maven.apache.org/maven2/org/json/json/20180813/json-20180813.pom
|
||||
https://repo.maven.apache.org/maven2/org/json/json/20230227/json-20230227.pom
|
||||
https://repo.maven.apache.org/maven2/org/junit/junit-bom/5.9.2/junit-bom-5.9.2.pom
|
||||
https://repo.maven.apache.org/maven2/org/junit/junit-bom/5.9.3/junit-bom-5.9.3.pom
|
||||
https://repo.maven.apache.org/maven2/org/jvnet/staxex/stax-ex/1.7.7/stax-ex-1.7.7.pom
|
||||
https://repo.maven.apache.org/maven2/org/jvnet/staxex/stax-ex/1.8/stax-ex-1.8.pom
|
||||
https://repo.maven.apache.org/maven2/org/jvnet/staxex/stax-ex/2.1.0/stax-ex-2.1.0.pom
|
||||
@@ -880,6 +852,7 @@ https://repo.maven.apache.org/maven2/org/ow2/asm/asm-analysis/5.0.3/asm-analysis
|
||||
https://repo.maven.apache.org/maven2/org/ow2/asm/asm-analysis/5.1/asm-analysis-5.1.pom
|
||||
https://repo.maven.apache.org/maven2/org/ow2/asm/asm-analysis/6.0/asm-analysis-6.0.pom
|
||||
https://repo.maven.apache.org/maven2/org/ow2/asm/asm-analysis/7.0/asm-analysis-7.0.pom
|
||||
https://repo.maven.apache.org/maven2/org/ow2/asm/asm-bom/9.5/asm-bom-9.5.pom
|
||||
https://repo.maven.apache.org/maven2/org/ow2/asm/asm-commons/5.1/asm-commons-5.1.pom
|
||||
https://repo.maven.apache.org/maven2/org/ow2/asm/asm-commons/6.0/asm-commons-6.0.pom
|
||||
https://repo.maven.apache.org/maven2/org/ow2/asm/asm-commons/7.0/asm-commons-7.0.pom
|
||||
|
||||
@@ -30,9 +30,9 @@ react-native-orientation-locker
|
||||
react-native-permissions
|
||||
react-native-randombytes
|
||||
react-native-reanimated
|
||||
react-native-safe-area-context
|
||||
react-native-shake
|
||||
react-native-share
|
||||
react-native-static-safe-area-insets
|
||||
react-native-status
|
||||
react-native-status-keycard
|
||||
react-native-svg
|
||||
|
||||
@@ -46,7 +46,7 @@ function fetch_and_template_file() {
|
||||
OBJ_URL="${REPO_URL}/${PKG_PATH}/${FILENAME}"
|
||||
if ! OBJ_NIX_FETCH_OUT=$(nix_fetch "${OBJ_URL}"); then
|
||||
echo " ! Failed to fetch: ${OBJ_URL}" >&2
|
||||
exit 1
|
||||
return 1
|
||||
fi
|
||||
|
||||
OBJ_NAME="${FILENAME}"
|
||||
@@ -58,6 +58,10 @@ function fetch_and_template_file() {
|
||||
}"
|
||||
}
|
||||
|
||||
function fetch_and_template_file_no_fail() {
|
||||
fetch_and_template_file "${1}" 2>/dev/null || true
|
||||
}
|
||||
|
||||
if [[ -z "${1}" ]]; then
|
||||
echo "Required POM URL argument not given!" >&2
|
||||
exit 1
|
||||
@@ -111,7 +115,7 @@ echo -ne "
|
||||
}"
|
||||
|
||||
# Some deps are just POMs, in which case there is no JAR to fetch.
|
||||
[[ "${OBJ_TYPE}" == "" ]] && fetch_and_template_file "${PKG_NAME}.jar"
|
||||
[[ "${OBJ_TYPE}" == "" ]] && fetch_and_template_file_no_fail "${PKG_NAME}.jar"
|
||||
[[ "${OBJ_TYPE}" == "jar" ]] && fetch_and_template_file "${PKG_NAME}.jar"
|
||||
[[ "${OBJ_TYPE}" == "bundle" ]] && fetch_and_template_file "${PKG_NAME}.jar"
|
||||
[[ "${OBJ_TYPE}" =~ aar* ]] && fetch_and_template_file "${PKG_NAME}.aar"
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 271 B |
Binary file not shown.
|
After Width: | Height: | Size: 367 B |
Binary file not shown.
|
After Width: | Height: | Size: 363 B |
Binary file not shown.
|
After Width: | Height: | Size: 524 B |
@@ -11,7 +11,7 @@
|
||||
:inner 44
|
||||
:status-indicator 12
|
||||
:status-indicator-border 2
|
||||
:font-size :paragraph-1}
|
||||
:font-size :heading-2}
|
||||
:small {:outer 32
|
||||
:inner 28
|
||||
:status-indicator 12
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
(ns quo2.components.buttons.predictive-keyboard.component-spec
|
||||
(:require [quo2.components.buttons.predictive-keyboard.view :as predictive-keyboard]
|
||||
[test-helpers.component :as h]))
|
||||
|
||||
(h/describe "predictive-keyboard"
|
||||
(h/test "basic render"
|
||||
(h/render [predictive-keyboard/view {:type :error :text "Error message"}])
|
||||
(h/is-truthy (h/get-by-label-text :predictive-keyboard)))
|
||||
(h/test "rendered with correct text"
|
||||
(h/render [predictive-keyboard/view {:type :info :text "Error message"}])
|
||||
(h/is-truthy (h/get-by-text "Error message")))
|
||||
(h/test "rendered with correct words"
|
||||
(h/render [predictive-keyboard/view {:type :words :words ["lab" "label"]}])
|
||||
(h/is-truthy (h/get-by-text "lab"))
|
||||
(h/is-truthy (h/get-by-text "label")))
|
||||
(h/test "word press event"
|
||||
(let [event (h/mock-fn)]
|
||||
(h/render [predictive-keyboard/view {:type :words :words ["lab" "label"] :on-press #(event %)}])
|
||||
(h/fire-event :press (h/get-by-text "lab"))
|
||||
(h/was-called event))))
|
||||
@@ -0,0 +1,11 @@
|
||||
(ns quo2.components.buttons.predictive-keyboard.style)
|
||||
|
||||
(defn wrapper
|
||||
[type]
|
||||
{:flex 1
|
||||
:min-height 48
|
||||
:padding-vertical 8
|
||||
:justify-content :center
|
||||
:padding-horizontal (if (= type :words) 0 20)})
|
||||
|
||||
(def word-list {:align-items :center :padding-horizontal 20})
|
||||
@@ -0,0 +1,71 @@
|
||||
(ns quo2.components.buttons.predictive-keyboard.view
|
||||
(:require [react-native.core :as rn]
|
||||
[quo2.components.buttons.predictive-keyboard.style :as style]
|
||||
[quo2.components.info.info-message :as info-message]
|
||||
[react-native.linear-gradient :as linear-gradient]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[quo2.components.buttons.button :as button]))
|
||||
|
||||
(def ^:private gradients
|
||||
{:light [(colors/alpha colors/neutral-40 0.05) (colors/alpha colors/neutral-40 0)]
|
||||
:dark [(colors/alpha colors/neutral-80 0.7) (colors/alpha colors/neutral-80 0)]
|
||||
:blur [colors/white-opa-5 colors/white-opa-0]})
|
||||
|
||||
(defn- word-component
|
||||
[word _ _ {:keys [blur? on-press]}]
|
||||
[button/button
|
||||
(merge {:type :blur-bg
|
||||
:size 32
|
||||
:on-press #(on-press word)}
|
||||
(when blur? {:override-theme :dark}))
|
||||
word])
|
||||
|
||||
(defn- separator
|
||||
[]
|
||||
[rn/view {:style {:width 8}}])
|
||||
|
||||
(defn view
|
||||
"Options
|
||||
- `type` `:words`/`:error`/`:info`/`:empty`.
|
||||
- `blur?` Boolean to enable blur background support.
|
||||
- `text` error/info text.
|
||||
- `words` List of words to display in the keyboard.
|
||||
- `on-press` Callback called when a word is pressed `(fn [word])`."
|
||||
[{:keys [type blur? text words on-press]}]
|
||||
[linear-gradient/linear-gradient
|
||||
{:style {:flex-direction :row}
|
||||
:accessibility-label :predictive-keyboard
|
||||
:colors (if blur?
|
||||
(gradients :blur)
|
||||
(colors/theme-colors (gradients :light) (gradients :dark)))}
|
||||
[rn/view {:style (style/wrapper type)}
|
||||
(case type
|
||||
:words
|
||||
[rn/flat-list
|
||||
{:data words
|
||||
:content-container-style style/word-list
|
||||
:render-fn word-component
|
||||
:render-data {:blur? blur?
|
||||
:on-press on-press}
|
||||
:shows-horizontal-scroll-indicator false
|
||||
:separator [separator]
|
||||
:horizontal true
|
||||
:key-fn str}]
|
||||
|
||||
:error
|
||||
[info-message/info-message
|
||||
{:icon :i/info
|
||||
:size :default
|
||||
:type :error}
|
||||
text]
|
||||
|
||||
:info
|
||||
[info-message/info-message
|
||||
(merge {:icon :i/info
|
||||
:size :default
|
||||
:type (if (= type :error) :error :default)}
|
||||
(when blur?
|
||||
{:text-color colors/white-opa-70
|
||||
:icon-color colors/white-opa-70}))
|
||||
text]
|
||||
nil)]])
|
||||
@@ -0,0 +1,30 @@
|
||||
(ns quo2.components.drawers.documentation-drawers.component-spec
|
||||
(:require [quo2.components.drawers.documentation-drawers.view :as documentation-drawers]
|
||||
[test-helpers.component :as h]))
|
||||
|
||||
(h/describe "Documentation drawers component"
|
||||
(h/test "render component without button"
|
||||
(h/render [documentation-drawers/view {:title "Documentation"} "Content"])
|
||||
(-> (h/expect (h/get-by-label-text :documentation-drawer-title))
|
||||
(.toBeTruthy))
|
||||
(-> (h/expect (h/get-by-label-text :documentation-drawer-content))
|
||||
(.toBeTruthy)))
|
||||
(h/test "render component with button"
|
||||
(h/render [documentation-drawers/view
|
||||
{:title "Documentation" :show-button? true :button-label "Read more"} "Content"])
|
||||
(-> (h/expect (h/get-by-label-text :documentation-drawer-title))
|
||||
(.toBeTruthy))
|
||||
(-> (h/expect (h/get-by-label-text :documentation-drawer-content))
|
||||
(.toBeTruthy))
|
||||
(-> (h/expect (h/get-by-label-text :documentation-drawer-button))
|
||||
(.toBeTruthy)))
|
||||
(h/test "button is pressed"
|
||||
(let [event (h/mock-fn)]
|
||||
(h/render
|
||||
[documentation-drawers/view
|
||||
{:title "Documentation" :show-button? true :button-label "Read more" :on-press-button event}
|
||||
"Content"])
|
||||
(h/fire-event :press (h/get-by-label-text :documentation-drawer-button))
|
||||
(-> (h/expect event)
|
||||
(.toHaveBeenCalled)))))
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
(ns quo2.components.drawers.documentation-drawers.style)
|
||||
|
||||
(def container
|
||||
{:align-items :flex-start
|
||||
:padding 20})
|
||||
|
||||
(def content
|
||||
{:margin-top 12
|
||||
:margin-bottom 16})
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
(ns quo2.components.drawers.documentation-drawers.view
|
||||
(:require [quo2.components.markdown.text :as text]
|
||||
[quo2.components.drawers.documentation-drawers.style :as style]
|
||||
[react-native.core :as rn]
|
||||
[react-native.gesture :as gesture]
|
||||
[quo2.components.buttons.button :as button]
|
||||
[quo2.foundations.colors :as colors]))
|
||||
|
||||
(defn view
|
||||
"Options
|
||||
- `title` Title text
|
||||
- `show-button?` Show button
|
||||
- `button-label` button label
|
||||
- `button-icon` button icon
|
||||
- `on-press-button` On press handler for the button
|
||||
- `shell?` use shell theme
|
||||
|
||||
`content` Content of the drawer
|
||||
"
|
||||
[{:keys [title show-button? on-press-button button-label button-icon shell?]} content]
|
||||
[gesture/scroll-view
|
||||
[rn/view {:style style/container}
|
||||
[text/text
|
||||
{:size :heading-2
|
||||
:accessibility-label :documentation-drawer-title
|
||||
:style {:color (colors/theme-colors colors/neutral-100
|
||||
colors/white
|
||||
(when shell? :dark))}
|
||||
:weight :semi-bold} title]
|
||||
[rn/view {:style style/content :accessibility-label :documentation-drawer-content}
|
||||
content]
|
||||
(when show-button?
|
||||
[button/button
|
||||
(merge {:size 24
|
||||
:type (if shell? :blur-bg-outline :outline)
|
||||
:on-press on-press-button
|
||||
:accessibility-label :documentation-drawer-button
|
||||
:after button-icon}
|
||||
(when shell? {:override-theme :dark})) button-label])]])
|
||||
|
||||
@@ -6,10 +6,10 @@
|
||||
[react-native.core :as rn]))
|
||||
|
||||
(def themes
|
||||
{:light {:default colors/neutral-40
|
||||
{:light {:default colors/neutral-50
|
||||
:success colors/success-50
|
||||
:error colors/danger-50}
|
||||
:dark {:default colors/neutral-60
|
||||
:dark {:default colors/neutral-40
|
||||
:success colors/success-60
|
||||
:error colors/danger-60}})
|
||||
|
||||
@@ -27,18 +27,20 @@
|
||||
:icon-color colors/white ;; icon color override
|
||||
:no-icon-color? false ;; disable tint color for icon"
|
||||
[{:keys [type size icon text-color icon-color no-icon-color? style]} message]
|
||||
(let [weight (if (= size :default) :regular :medium)
|
||||
size (if (= size :default) :paragraph-2 :label)
|
||||
text-color (or text-color (get-color type))
|
||||
icon-color (or icon-color text-color)]
|
||||
(let [weight (if (= size :default) :regular :medium)
|
||||
icon-size (if (= size :default) 16 12)
|
||||
icon-margin-top (if (= size :default) 2 3)
|
||||
size (if (= size :default) :paragraph-2 :label)
|
||||
text-color (or text-color (get-color type))
|
||||
icon-color (or icon-color text-color)]
|
||||
[rn/view
|
||||
{:style (merge {:flex-direction :row}
|
||||
style)}
|
||||
[quo2.icons/icon icon
|
||||
{:color icon-color
|
||||
:no-color no-icon-color?
|
||||
:size 12
|
||||
:container-style {:margin-top 3}}]
|
||||
:size icon-size
|
||||
:container-style {:margin-top icon-margin-top}}]
|
||||
[text/text
|
||||
{:size size
|
||||
:weight weight
|
||||
|
||||
@@ -522,7 +522,7 @@
|
||||
seeking-audio?]
|
||||
[:f> soundtrack/f-soundtrack
|
||||
{:audio-current-time-ms audio-current-time-ms
|
||||
:player-ref player-ref
|
||||
:player-ref @player-ref
|
||||
:seeking-audio? seeking-audio?}]])
|
||||
(when (or @recording? @reviewing-audio?)
|
||||
[:f> f-time-counter @recording? @recording-length-ms @ready-to-delete? @reviewing-audio?
|
||||
|
||||
+4
-4
@@ -19,7 +19,7 @@
|
||||
(let [player-ref (reagent/atom {})
|
||||
audio-current-time-ms (reagent/atom 0)]
|
||||
(h/render [:f> soundtrack/f-soundtrack
|
||||
{:player-ref player-ref
|
||||
{:player-ref @player-ref
|
||||
:audio-current-time-ms audio-current-time-ms}])
|
||||
(-> (h/expect (h/get-by-test-id "soundtrack"))
|
||||
(.toBeTruthy)))))
|
||||
@@ -31,7 +31,7 @@
|
||||
audio-current-time-ms (reagent/atom 0)]
|
||||
(h/render [:f> soundtrack/f-soundtrack
|
||||
{:seeking-audio? seeking-audio?
|
||||
:player-ref player-ref
|
||||
:player-ref @player-ref
|
||||
:audio-current-time-ms audio-current-time-ms}])
|
||||
(h/fire-event
|
||||
:on-sliding-start
|
||||
@@ -47,7 +47,7 @@
|
||||
audio-current-time-ms (reagent/atom 0)]
|
||||
(h/render [:f> soundtrack/f-soundtrack
|
||||
{:seeking-audio? seeking-audio?
|
||||
:player-ref player-ref
|
||||
:player-ref @player-ref
|
||||
:audio-current-time-ms audio-current-time-ms}])
|
||||
(h/fire-event
|
||||
:on-sliding-start
|
||||
@@ -69,7 +69,7 @@
|
||||
audio-current-time-ms (reagent/atom 0)]
|
||||
(h/render [:f> soundtrack/f-soundtrack
|
||||
{:seeking-audio? seeking-audio?
|
||||
:player-ref player-ref
|
||||
:player-ref @player-ref
|
||||
:audio-current-time-ms audio-current-time-ms}])
|
||||
(h/fire-event
|
||||
:on-sliding-start
|
||||
|
||||
@@ -10,12 +10,14 @@
|
||||
(def ^:private thumb-dark (js/require "../resources/images/icons2/12x12/thumb-dark.png"))
|
||||
|
||||
(defn f-soundtrack
|
||||
[{:keys [audio-current-time-ms player-ref seeking-audio?]}]
|
||||
(let [audio-duration-ms (audio/get-player-duration @player-ref)]
|
||||
[{:keys [audio-current-time-ms player-ref style seeking-audio?]}]
|
||||
(let [audio-duration-ms (audio/get-player-duration player-ref)]
|
||||
[:<>
|
||||
[slider/slider
|
||||
{:test-ID "soundtrack"
|
||||
:style (style/player-slider-container)
|
||||
:style (merge
|
||||
(style/player-slider-container)
|
||||
(or style {}))
|
||||
:minimum-value 0
|
||||
:maximum-value audio-duration-ms
|
||||
:value @audio-current-time-ms
|
||||
@@ -23,7 +25,7 @@
|
||||
:on-sliding-complete (fn [seek-time]
|
||||
(reset! seeking-audio? false)
|
||||
(audio/seek-player
|
||||
@player-ref
|
||||
player-ref
|
||||
seek-time
|
||||
#(log/debug "[record-audio] on seek - seek time: " seek-time)
|
||||
#(log/error "[record-audio] on seek - error: " %)))
|
||||
|
||||
+10
-2
@@ -10,6 +10,7 @@
|
||||
quo2.components.banners.banner.view
|
||||
quo2.components.buttons.button
|
||||
quo2.components.buttons.dynamic-button
|
||||
quo2.components.buttons.predictive-keyboard.view
|
||||
quo2.components.colors.color-picker.view
|
||||
quo2.components.community.community-card-view
|
||||
quo2.components.community.community-list-view
|
||||
@@ -24,6 +25,7 @@
|
||||
quo2.components.dividers.new-messages
|
||||
quo2.components.dividers.strength-divider.view
|
||||
quo2.components.drawers.action-drawers.view
|
||||
quo2.components.drawers.documentation-drawers.view
|
||||
quo2.components.drawers.drawer-buttons.view
|
||||
quo2.components.drawers.permission-context.view
|
||||
quo2.components.dropdowns.dropdown
|
||||
@@ -62,6 +64,7 @@
|
||||
quo2.components.profile.select-profile.view
|
||||
quo2.components.reactions.reaction
|
||||
quo2.components.record-audio.record-audio.view
|
||||
quo2.components.record-audio.soundtrack.view
|
||||
quo2.components.selectors.disclaimer.view
|
||||
quo2.components.selectors.filter.view
|
||||
quo2.components.selectors.selectors.view
|
||||
@@ -81,8 +84,6 @@
|
||||
quo2.components.tags.token-tag
|
||||
quo2.components.text-combinations.title.view))
|
||||
|
||||
(def button quo2.components.buttons.button/button)
|
||||
(def dynamic-button quo2.components.buttons.dynamic-button/dynamic-button)
|
||||
(def text quo2.components.markdown.text/text)
|
||||
(def icon quo2.components.icon/icon)
|
||||
(def separator quo2.components.separator/separator)
|
||||
@@ -118,6 +119,11 @@
|
||||
;;;; BANNER
|
||||
(def banner quo2.components.banners.banner.view/banner)
|
||||
|
||||
;;;; BUTTONS
|
||||
(def button quo2.components.buttons.button/button)
|
||||
(def dynamic-button quo2.components.buttons.dynamic-button/dynamic-button)
|
||||
(def predictive-keyboard quo2.components.buttons.predictive-keyboard.view/view)
|
||||
|
||||
;;;; CARDS
|
||||
(def small-option-card quo2.components.onboarding.small-option-card.view/small-option-card)
|
||||
|
||||
@@ -151,6 +157,7 @@
|
||||
|
||||
;;;; DRAWERS
|
||||
(def action-drawer quo2.components.drawers.action-drawers.view/action-drawer)
|
||||
(def documentation-drawers quo2.components.drawers.documentation-drawers.view/view)
|
||||
(def drawer-buttons quo2.components.drawers.drawer-buttons.view/view)
|
||||
(def permission-context quo2.components.drawers.permission-context.view/view)
|
||||
|
||||
@@ -184,6 +191,7 @@
|
||||
|
||||
;;;; RECORD AUDIO
|
||||
(def record-audio quo2.components.record-audio.record-audio.view/record-audio)
|
||||
(def soundtrack quo2.components.record-audio.soundtrack.view/f-soundtrack)
|
||||
|
||||
;;;; SETTINGS
|
||||
(def privacy-option quo2.components.settings.privacy-option/card)
|
||||
|
||||
@@ -3,12 +3,14 @@
|
||||
[quo2.components.avatars.user-avatar.component-spec]
|
||||
[quo2.components.banners.banner.component-spec]
|
||||
[quo2.components.buttons.--tests--.buttons-component-spec]
|
||||
[quo2.components.buttons.predictive-keyboard.component-spec]
|
||||
[quo2.components.colors.color-picker.component-spec]
|
||||
[quo2.components.counter.--tests--.counter-component-spec]
|
||||
[quo2.components.counter.step.component-spec]
|
||||
[quo2.components.dividers.--tests--.divider-label-component-spec]
|
||||
[quo2.components.dividers.strength-divider.component-spec]
|
||||
[quo2.components.drawers.action-drawers.component-spec]
|
||||
[quo2.components.drawers.documentation-drawers.component-spec]
|
||||
[quo2.components.drawers.drawer-buttons.component-spec]
|
||||
[quo2.components.drawers.permission-context.component-spec]
|
||||
[quo2.components.inputs.input.component-spec]
|
||||
|
||||
@@ -130,6 +130,9 @@
|
||||
(when (exists? (.-NativeModules ^js react-native))
|
||||
(.-RNSelectableTextInputManager ^js (.-NativeModules ^js react-native))))
|
||||
|
||||
;; TODO: iOS native implementation https://github.com/status-im/status-mobile/issues/14137
|
||||
(defonce selectable-text-input
|
||||
(reagent/adapt-react-class
|
||||
(.requireNativeComponent ^js react-native "RNSelectableTextInput")))
|
||||
(if platform/android?
|
||||
(reagent/adapt-react-class
|
||||
(.requireNativeComponent ^js react-native "RNSelectableTextInput"))
|
||||
view))
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
[status-im.chat.models.mentions :as mentions]
|
||||
[status-im.chat.models.message :as chat.message]
|
||||
[status-im.chat.models.message-content :as message-content]
|
||||
[status-im2.config :as config]
|
||||
[status-im2.constants :as constants]
|
||||
[utils.re-frame :as rf]
|
||||
[utils.i18n :as i18n]
|
||||
@@ -35,9 +34,12 @@
|
||||
"Set input text for current-chat. Takes db and input text and cofx
|
||||
as arguments and returns new fx. Always clear all validation messages."
|
||||
{:events [:chat.ui/set-chat-input-text]}
|
||||
[{db :db} new-input chat-id]
|
||||
[{:keys [db] :as cofx} new-input chat-id]
|
||||
(let [current-chat-id (or chat-id (:current-chat-id db))]
|
||||
{:db (assoc-in db [:chat/inputs current-chat-id :input-text] (text->emoji new-input))}))
|
||||
(rf/merge cofx
|
||||
{:db (assoc-in db [:chat/inputs current-chat-id :input-text] (text->emoji new-input))}
|
||||
(when (empty? new-input)
|
||||
(mentions/clear-mentions)))))
|
||||
|
||||
(rf/defn set-input-content-height
|
||||
{:events [:chat.ui/set-input-content-height]}
|
||||
@@ -111,8 +113,7 @@
|
||||
(update-in [:chat/inputs current-chat-id :metadata]
|
||||
dissoc
|
||||
:sending-image))
|
||||
:dispatch (when-not config/new-composer-enabled?
|
||||
[:mention/to-input-field text current-chat-id])}))
|
||||
:dispatch [:mention/to-input-field text current-chat-id]}))
|
||||
|
||||
(rf/defn show-contact-request-input
|
||||
"Sets reference to previous chat message and focuses on input"
|
||||
@@ -164,10 +165,7 @@
|
||||
:image-path (utils/safe-replace resized-uri #"file://" "")
|
||||
:image-width width
|
||||
:image-height height
|
||||
;; TODO: message not received if text field is
|
||||
;; nil or empty, issue:
|
||||
;; https://github.com/status-im/status-mobile/issues/14754
|
||||
:text (or input-text "placeholder")
|
||||
:text input-text
|
||||
:response-to message-id})
|
||||
images)))
|
||||
|
||||
@@ -187,8 +185,6 @@
|
||||
[{:keys [db] :as cofx}]
|
||||
(let [current-chat-id (:current-chat-id db)]
|
||||
(rf/merge cofx
|
||||
(when-not config/new-composer-enabled?
|
||||
{:set-text-input-value [current-chat-id ""]})
|
||||
(clean-input current-chat-id)
|
||||
(mentions/clear-mentions))))
|
||||
|
||||
|
||||
@@ -98,10 +98,9 @@
|
||||
[{:keys [db]} result]
|
||||
(log/debug "[mentions] on-to-input-field-success" {:result result})
|
||||
(let [{:keys [input-segments state chat-id new-text]} (transfer-mention-result result)]
|
||||
{:set-text-input-value [chat-id new-text]
|
||||
:db (-> db
|
||||
(assoc-in [:chats/mentions chat-id :mentions] state)
|
||||
(assoc-in [:chat/inputs-with-mentions chat-id] input-segments))}))
|
||||
{:db (-> db
|
||||
(assoc-in [:chats/mentions chat-id :mentions] state)
|
||||
(assoc-in [:chat/inputs-with-mentions chat-id] input-segments))}))
|
||||
|
||||
(rf/defn on-change-text
|
||||
{:events [:mention/on-change-text]}
|
||||
@@ -162,22 +161,11 @@
|
||||
:match match
|
||||
:searched-text searched-text
|
||||
:public-key public-key})
|
||||
(let [{:keys [new-text state chat-id]} (transfer-mention-result result)
|
||||
{:keys [at-sign-idx]} state
|
||||
cursor (+ at-sign-idx (count primary-name) 2)]
|
||||
(let [{:keys [new-text chat-id]} (transfer-mention-result result)]
|
||||
(rf/merge
|
||||
cofx
|
||||
{:db (-> db
|
||||
(assoc-in [:chats/mention-suggestions chat-id] nil))
|
||||
:set-text-input-value [chat-id new-text text-input-ref]
|
||||
:dispatch [:chat.ui/set-chat-input-text new-text chat-id]}
|
||||
;; NOTE(rasom): Some keyboards do not react on selection property passed to
|
||||
;; text input (specifically Samsung keyboard with predictive text set on).
|
||||
;; In this case, if the user continues typing after the programmatic change,
|
||||
;; the new text is added to the last known cursor position before
|
||||
;; programmatic change. By calling `reset-text-input-cursor` we force the
|
||||
;; keyboard's cursor position to be changed before the next input.
|
||||
(reset-text-input-cursor text-input-ref cursor)
|
||||
{:db (assoc-in db [:chats/mention-suggestions chat-id] nil)
|
||||
:dispatch [:chat.ui/set-chat-input-text new-text chat-id]}
|
||||
(recheck-at-idxs public-key))))
|
||||
|
||||
(rf/defn clear-suggestions
|
||||
|
||||
@@ -91,10 +91,16 @@
|
||||
:chat-type (.-chatType chat)
|
||||
:unviewed-messages-count (.-unviewedMessagesCount chat)
|
||||
:unviewed-mentions-count (.-unviewedMentionsCount chat)
|
||||
:last-message {:content {:text (.-text chat)
|
||||
:parsed-text (types/js->clj (.-parsedText chat))}
|
||||
:content-type (.-contentType chat)
|
||||
:community-id (.-contentCommunityId chat)}
|
||||
:last-message {:content {:text (.-text chat)
|
||||
:parsed-text (types/js->clj (.-parsedText chat))
|
||||
:response-to (.-responseTo chat)}
|
||||
:content-type (.-contentType chat)
|
||||
:community-id (.-contentCommunityId chat)
|
||||
:outgoing (boolean (.-outgoingStatus chat))
|
||||
:album-images-count (.-albumImagesCount chat)
|
||||
:from (.-from chat)
|
||||
:deleted? (.-deleted chat)
|
||||
:deleted-for-me? (.-deletedForMe chat)}
|
||||
:last-clock-value (.-lastClockValue chat)
|
||||
:profile-public-key (.-profile chat)
|
||||
:highlight (.-highlight chat)
|
||||
|
||||
@@ -42,7 +42,8 @@
|
||||
:imageWidth :image-width
|
||||
:imageHeight :image-height
|
||||
:new :new?
|
||||
:albumImagesCount :album-images-count})
|
||||
:albumImagesCount :album-images-count
|
||||
:displayName :display-name})
|
||||
|
||||
(update :quoted-message
|
||||
set/rename-keys
|
||||
|
||||
@@ -148,7 +148,8 @@
|
||||
|
||||
(rf/defn on-return-from-background
|
||||
[{:keys [db now] :as cofx}]
|
||||
(let [app-in-background-since (get db :app-in-background-since)
|
||||
(let [new-account? (get db :onboarding-2/new-account?)
|
||||
app-in-background-since (get db :app-in-background-since)
|
||||
signed-up? (get-in db [:multiaccount :signed-up?])
|
||||
biometric-auth? (= (:auth-method db) "biometric")
|
||||
requires-bio-auth (and
|
||||
@@ -161,7 +162,8 @@
|
||||
{:db (dissoc db :app-in-background-since)}
|
||||
(mailserver/process-next-messages-request)
|
||||
(wallet/restart-wallet-service-after-background app-in-background-since)
|
||||
(universal-links/process-stored-event)
|
||||
(when-not new-account?
|
||||
(universal-links/process-stored-event))
|
||||
#(when-let [chat-id (:current-chat-id db)]
|
||||
{:dispatch [:chat/mark-all-as-read chat-id]})
|
||||
#(when requires-bio-auth
|
||||
|
||||
@@ -45,11 +45,13 @@
|
||||
{:events [::messenger-started]}
|
||||
[{:keys [db] :as cofx} {:keys [mailservers] :as response}]
|
||||
(log/info "Messenger started")
|
||||
(rf/merge cofx
|
||||
{:db (-> db
|
||||
(assoc :messenger/started? true)
|
||||
(add-mailservers mailservers))}
|
||||
(fetch-node-info-fx)
|
||||
(pairing/init)
|
||||
(stickers/load-packs)
|
||||
(universal-links/process-stored-event)))
|
||||
(let [new-account? (get db :onboarding-2/new-account?)]
|
||||
(rf/merge cofx
|
||||
{:db (-> db
|
||||
(assoc :messenger/started? true)
|
||||
(add-mailservers mailservers))}
|
||||
(fetch-node-info-fx)
|
||||
(pairing/init)
|
||||
(stickers/load-packs)
|
||||
(when-not new-account?
|
||||
(universal-links/process-stored-event)))))
|
||||
|
||||
@@ -195,7 +195,7 @@
|
||||
|
||||
;;CHAT
|
||||
{:name :start-a-new-chat
|
||||
:options {:sheet? true :insets {:top? true}}
|
||||
:options {:sheet? true}
|
||||
:component new-chat-aio/contact-selection-list}
|
||||
|
||||
{:name :group-chat-profile
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
(ns status-im.ui2.screens.chat.components.edit.style)
|
||||
|
||||
(def container
|
||||
{:flex-direction :row
|
||||
:height 24})
|
||||
|
||||
(def content-container
|
||||
{:padding-horizontal 10
|
||||
:flex 1
|
||||
:flex-direction :row})
|
||||
|
||||
(def icon-container
|
||||
{:position :absolute
|
||||
:left 10
|
||||
:bottom -4
|
||||
:width 16
|
||||
:height 16})
|
||||
|
||||
(def text-container
|
||||
{:position :absolute
|
||||
:left 36
|
||||
:right 54
|
||||
:top 3
|
||||
:flex-direction :row
|
||||
:align-items :center})
|
||||
@@ -1,33 +0,0 @@
|
||||
(ns status-im.ui2.screens.chat.components.edit.view
|
||||
(:require [utils.i18n :as i18n]
|
||||
[quo2.core :as quo]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[re-frame.core :as rf]
|
||||
[react-native.core :as rn]
|
||||
[status-im.ui2.screens.chat.components.edit.style :as style]))
|
||||
|
||||
(defn edit-message
|
||||
[on-cancel]
|
||||
[rn/view
|
||||
{:style style/container
|
||||
:accessibility-label :edit-message}
|
||||
[rn/view {:style style/content-container}
|
||||
[quo/icon :i/connector
|
||||
{:size 16
|
||||
:color (colors/theme-colors colors/neutral-40 colors/neutral-60)
|
||||
:container-style style/icon-container}]
|
||||
[rn/view {:style style/text-container}
|
||||
[quo/text
|
||||
{:weight :medium
|
||||
:size :paragraph-2}
|
||||
(i18n/label :t/editing-message)]]]
|
||||
[quo/button
|
||||
{:width 24
|
||||
:size 24
|
||||
:accessibility-label :reply-cancel-button
|
||||
:on-press #(do (on-cancel)
|
||||
(rf/dispatch [:chat.ui/cancel-message-edit]))
|
||||
:type :outline}
|
||||
[quo/icon :i/close
|
||||
{:size 16
|
||||
:color (colors/theme-colors colors/neutral-100 colors/neutral-40)}]]])
|
||||
@@ -1,37 +0,0 @@
|
||||
(ns status-im.ui2.screens.chat.components.reply.style)
|
||||
|
||||
(defn reply-content
|
||||
[pin?]
|
||||
{:padding-horizontal (when-not pin? 10)
|
||||
:flex 1
|
||||
:flex-direction :row})
|
||||
|
||||
(defn quoted-message
|
||||
[pin? in-chat-input?]
|
||||
(merge {:flex-direction :row
|
||||
:flex 1
|
||||
:align-items :center
|
||||
:width (if in-chat-input? "100%" "45%")}
|
||||
(when-not pin?
|
||||
{:left 22
|
||||
:margin-right 22})))
|
||||
|
||||
(def reply-from
|
||||
{:flex-direction :row
|
||||
:align-items :center})
|
||||
|
||||
(def message-author-text
|
||||
{:margin-left 4})
|
||||
|
||||
(def message-text
|
||||
{:text-transform :none
|
||||
:margin-left 4
|
||||
:margin-top 2
|
||||
:flex 1})
|
||||
|
||||
(def gradient
|
||||
{:position :absolute
|
||||
:right 0
|
||||
:top 0
|
||||
:bottom 0
|
||||
:width "50%"})
|
||||
@@ -1,142 +0,0 @@
|
||||
(ns status-im.ui2.screens.chat.components.reply.view
|
||||
(:require [clojure.string :as string]
|
||||
[utils.i18n :as i18n]
|
||||
[quo.react-native :as rn]
|
||||
[quo2.components.buttons.button :as quo2.button]
|
||||
[quo2.components.icon :as quo2.icon]
|
||||
[quo2.components.markdown.text :as quo2.text]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[status-im2.constants :as constants]
|
||||
[status-im.ethereum.stateofus :as stateofus]
|
||||
[status-im.ui.components.icons.icons :as icons]
|
||||
[status-im2.contexts.chat.messages.avatar.view :as avatar]
|
||||
[utils.re-frame :as rf]
|
||||
[status-im.ui2.screens.chat.components.reply.style :as style]
|
||||
[react-native.linear-gradient :as linear-gradient]))
|
||||
|
||||
(defn get-quoted-text-with-mentions
|
||||
[parsed-text]
|
||||
(string/join
|
||||
(mapv (fn [{:keys [type literal children]}]
|
||||
(cond
|
||||
(= type "paragraph")
|
||||
(get-quoted-text-with-mentions children)
|
||||
|
||||
(= type "mention")
|
||||
(rf/sub [:messages/resolve-mention literal])
|
||||
|
||||
(seq children)
|
||||
(get-quoted-text-with-mentions children)
|
||||
|
||||
:else
|
||||
literal))
|
||||
parsed-text)))
|
||||
|
||||
(defn format-author
|
||||
[contact-name]
|
||||
(let [author (if (or (= (aget contact-name 0) "@")
|
||||
;; in case of replies
|
||||
(= (aget contact-name 1) "@"))
|
||||
(or (stateofus/username contact-name)
|
||||
(subs contact-name 0 81))
|
||||
contact-name)]
|
||||
author))
|
||||
|
||||
(defn format-reply-author
|
||||
[from username current-public-key]
|
||||
(or (and (= from current-public-key)
|
||||
(i18n/label :t/You))
|
||||
(when username (format-author username))))
|
||||
|
||||
(defn reply-deleted-message
|
||||
[]
|
||||
[rn/view
|
||||
{:style {:flex-direction :row
|
||||
:align-items :center}}
|
||||
[quo2.icon/icon :sad-face {:size 16}]
|
||||
[quo2.text/text
|
||||
{:number-of-lines 1
|
||||
:size :label
|
||||
:weight :regular
|
||||
:accessibility-label :quoted-message
|
||||
:style {:text-transform :none
|
||||
:margin-left 4
|
||||
:margin-top 2}}
|
||||
(i18n/label :t/message-deleted)]])
|
||||
|
||||
(defn reply-from
|
||||
[{:keys [from contact-name current-public-key]}]
|
||||
[rn/view {:style style/reply-from}
|
||||
[avatar/avatar from :xxxs]
|
||||
[quo2.text/text
|
||||
{:weight :semi-bold
|
||||
:size :paragraph-2
|
||||
:number-of-lines 1
|
||||
:style style/message-author-text}
|
||||
(format-reply-author from contact-name current-public-key)]])
|
||||
|
||||
(defn reply-message
|
||||
[{:keys [from identicon content-type contentType parsed-text content deleted? deleted-for-me?
|
||||
album-images-count]}
|
||||
in-chat-input? pin? recording-audio?]
|
||||
(let [contact-name (rf/sub [:contacts/contact-name-by-identity from])
|
||||
current-public-key (rf/sub [:multiaccount/public-key])
|
||||
content-type (or content-type contentType)]
|
||||
[rn/view
|
||||
{:style {:flex-direction :row
|
||||
:height (when-not pin? 24)
|
||||
:accessibility-label :reply-message}}
|
||||
[rn/view {:style (style/reply-content pin?)}
|
||||
(when-not pin?
|
||||
;;TODO quo2 icon should be used
|
||||
[icons/icon :main-icons/connector
|
||||
{:color (colors/theme-colors colors/neutral-40 colors/neutral-60)
|
||||
:container-style {:position :absolute :left 10 :bottom -4 :width 16 :height 16}}])
|
||||
(if (or deleted? deleted-for-me?)
|
||||
[rn/view {:style (style/quoted-message pin? in-chat-input?)}
|
||||
[reply-deleted-message]]
|
||||
[rn/view {:style (style/quoted-message pin? in-chat-input?)}
|
||||
[reply-from
|
||||
{:from from
|
||||
:identicon identicon
|
||||
:contact-name contact-name
|
||||
:current-public-key current-public-key}]
|
||||
[quo2.text/text
|
||||
{:number-of-lines 1
|
||||
:size :label
|
||||
:weight :regular
|
||||
:accessibility-label :quoted-message
|
||||
:ellipsize-mode :tail
|
||||
:style (merge
|
||||
style/message-text
|
||||
(when (or (= constants/content-type-image content-type)
|
||||
(= constants/content-type-sticker content-type)
|
||||
(= constants/content-type-audio content-type))
|
||||
{:color (colors/theme-colors colors/neutral-50 colors/neutral-40)}))}
|
||||
(case (or content-type contentType)
|
||||
constants/content-type-image (if album-images-count
|
||||
(i18n/label :t/images-albums-count
|
||||
{:album-images-count album-images-count})
|
||||
(i18n/label :t/image))
|
||||
constants/content-type-sticker (i18n/label :t/sticker)
|
||||
constants/content-type-audio (i18n/label :t/audio)
|
||||
(get-quoted-text-with-mentions (or parsed-text (:parsed-text content))))]])]
|
||||
(when (and in-chat-input? (not recording-audio?))
|
||||
[quo2.button/button
|
||||
{:width 24
|
||||
:size 24
|
||||
:type :outline
|
||||
:accessibility-label :reply-cancel-button
|
||||
:on-press #(rf/dispatch [:chat.ui/cancel-message-reply])}
|
||||
;;TODO quo2 icon should be used
|
||||
[icons/icon :main-icons/close
|
||||
{:width 16
|
||||
:height 16
|
||||
:color (colors/theme-colors colors/neutral-100 colors/neutral-40)}]])
|
||||
(when (and in-chat-input? recording-audio?)
|
||||
[linear-gradient/linear-gradient
|
||||
{:colors [(colors/theme-colors colors/white-opa-0 colors/neutral-90-opa-0)
|
||||
(colors/theme-colors colors/white colors/neutral-90)]
|
||||
:start {:x 0 :y 0}
|
||||
:end {:x 0.7 :y 0}
|
||||
:style style/gradient}])]))
|
||||
@@ -1,5 +0,0 @@
|
||||
(ns status-im.ui2.screens.chat.composer.edit.style)
|
||||
|
||||
(def container
|
||||
{:padding-horizontal 15
|
||||
:padding-vertical 8})
|
||||
@@ -1,23 +0,0 @@
|
||||
(ns status-im.ui2.screens.chat.composer.edit.view
|
||||
(:require [react-native.core :as rn]
|
||||
[status-im.ui2.screens.chat.components.edit.view :as edit]
|
||||
[status-im.ui2.screens.chat.composer.edit.style :as style]
|
||||
[status-im.ui2.screens.chat.composer.input :as input]))
|
||||
|
||||
(defn- focus-input-on-edit
|
||||
[edit had-edit text-input-ref]
|
||||
;;when we show edit we focus input
|
||||
(when-not (= edit @had-edit)
|
||||
(reset! had-edit edit)
|
||||
(when edit
|
||||
;; A setTimeout of 0 is necessary to ensure the statement is enqueued and will get executed ASAP.
|
||||
(js/setTimeout #(input/input-focus text-input-ref) 0))))
|
||||
|
||||
(defn edit-message-auto-focus-wrapper
|
||||
[text-input-ref _]
|
||||
(let [had-edit (atom nil)]
|
||||
(fn [_ edit on-cancel]
|
||||
(focus-input-on-edit edit had-edit text-input-ref)
|
||||
(when edit
|
||||
[rn/view {:style style/container}
|
||||
[edit/edit-message on-cancel]]))))
|
||||
@@ -1,11 +0,0 @@
|
||||
(ns status-im.ui2.screens.chat.composer.images.style)
|
||||
|
||||
(def remove-photo-container
|
||||
{:position :absolute
|
||||
:top 5
|
||||
:right 5})
|
||||
|
||||
(def small-image
|
||||
{:width 56
|
||||
:height 56
|
||||
:border-radius 8})
|
||||
@@ -1,35 +0,0 @@
|
||||
(ns status-im.ui2.screens.chat.composer.images.view
|
||||
(:require [quo2.core :as quo]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[re-frame.core :as rf]
|
||||
[react-native.core :as rn]
|
||||
[status-im.ui2.screens.chat.composer.images.style :as style]))
|
||||
|
||||
(defn image
|
||||
[item]
|
||||
;; there is a bug on Android https://github.com/facebook/react-native/issues/12534
|
||||
;; so we need some magic here with paddings so close button isn't cut
|
||||
[rn/view {:padding-top 12 :padding-bottom 8 :padding-right 12}
|
||||
[rn/image
|
||||
{:source {:uri (:resized-uri (val item))}
|
||||
:style style/small-image}]
|
||||
[rn/touchable-opacity
|
||||
{:on-press (fn [] (rf/dispatch [:chat.ui/image-unselected (val item)]))
|
||||
:style style/remove-photo-container
|
||||
:hit-slop {:right 5
|
||||
:left 5
|
||||
:top 10
|
||||
:bottom 10}}
|
||||
[quo/icon :i/clear
|
||||
{:size 20
|
||||
:color (colors/theme-colors colors/neutral-50 colors/neutral-60)}]]])
|
||||
|
||||
(defn images-list
|
||||
[images]
|
||||
(when (seq images)
|
||||
[rn/flat-list
|
||||
{:key-fn first
|
||||
:render-fn image
|
||||
:data images
|
||||
:horizontal true
|
||||
:keyboard-should-persist-taps :handled}]))
|
||||
@@ -1,383 +0,0 @@
|
||||
(ns status-im.ui2.screens.chat.composer.input
|
||||
(:require [clojure.string :as string]
|
||||
[oops.core :as oops]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[re-frame.core :as re-frame]
|
||||
[reagent.core :as reagent]
|
||||
[status-im2.constants :as chat.constants]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]
|
||||
[utils.transforms :as transforms]
|
||||
[quo2.foundations.typography :as typography]
|
||||
[react-native.background-timer :as background-timer]
|
||||
[react-native.platform :as platform]
|
||||
[react-native.core :as rn]
|
||||
[react-native.clipboard :as clipboard]
|
||||
[quo.react :as quo.react]))
|
||||
|
||||
(defonce input-texts (atom {}))
|
||||
(defonce input-text-content-heights (atom {}))
|
||||
(defonce mentions-enabled? (reagent/atom {}))
|
||||
(defonce chat-input-key (reagent/atom 1))
|
||||
(defonce text-input-ref (reagent/atom nil))
|
||||
(defonce recording-audio? (reagent/atom false))
|
||||
(defonce reviewing-audio? (reagent/atom false))
|
||||
(defonce reviewing-audio-filepath (atom {}))
|
||||
(defonce record-audio-permission-granted (reagent/atom false))
|
||||
(defonce record-audio-reset-fn (atom nil))
|
||||
|
||||
(declare selectable-text-input)
|
||||
|
||||
(re-frame/reg-fx
|
||||
:chat.ui/clear-inputs
|
||||
(fn []
|
||||
(reset! input-texts {})
|
||||
(reset! input-text-content-heights {})
|
||||
(reset! mentions-enabled? {})
|
||||
(reset! chat-input-key 1)))
|
||||
|
||||
(defn input-focus
|
||||
[text-input-ref]
|
||||
(some-> ^js (quo.react/current-ref text-input-ref)
|
||||
.focus))
|
||||
|
||||
(defn show-send
|
||||
[{:keys [actions-ref send-ref sticker-ref record-ref]} chat-id]
|
||||
(when (and (or @recording-audio?
|
||||
(get @reviewing-audio-filepath chat-id))
|
||||
@record-audio-reset-fn)
|
||||
(@record-audio-reset-fn)
|
||||
(swap! reviewing-audio-filepath dissoc chat-id))
|
||||
(when actions-ref
|
||||
(quo.react/set-native-props actions-ref #js {:width 0 :left -88}))
|
||||
(quo.react/set-native-props send-ref #js {:width nil :right nil})
|
||||
(quo.react/set-native-props record-ref #js {:right nil :left -1000})
|
||||
(when sticker-ref
|
||||
(quo.react/set-native-props sticker-ref #js {:width 0 :right -100})))
|
||||
|
||||
(defn hide-send
|
||||
[{:keys [actions-ref send-ref sticker-ref record-ref]}]
|
||||
(when actions-ref
|
||||
(quo.react/set-native-props actions-ref #js {:width nil :left nil}))
|
||||
(quo.react/set-native-props send-ref #js {:width 0 :right -100})
|
||||
(quo.react/set-native-props record-ref #js {:left 0 :right 0})
|
||||
(when sticker-ref
|
||||
(quo.react/set-native-props sticker-ref #js {:width nil :right nil})))
|
||||
|
||||
(defn reset-input
|
||||
[refs chat-id]
|
||||
(some-> ^js (quo.react/current-ref (:text-input-ref refs))
|
||||
.clear)
|
||||
(swap! mentions-enabled? update :render not)
|
||||
(swap! input-texts dissoc chat-id)
|
||||
(swap! input-text-content-heights dissoc chat-id))
|
||||
|
||||
(defn clear-input
|
||||
[chat-id refs]
|
||||
(hide-send refs)
|
||||
(if (get @mentions-enabled? chat-id)
|
||||
(do
|
||||
(swap! mentions-enabled? dissoc chat-id)
|
||||
;;we need this timeout, because if we clear text input and first index was a mention object with
|
||||
;;blue color,
|
||||
;;after clearing text will be typed with this blue color, so we render white text first and then
|
||||
;;clear it
|
||||
(js/setTimeout #(reset-input refs chat-id) 50))
|
||||
(reset-input refs chat-id)))
|
||||
|
||||
(defn on-text-change
|
||||
[val chat-id]
|
||||
(swap! input-texts assoc chat-id val)
|
||||
;;we still store it in app-db for mentions, we don't have reactions in views
|
||||
(rf/dispatch [:chat.ui/set-chat-input-text val]))
|
||||
|
||||
(defn on-selection-change
|
||||
[timeout-id last-text-change args]
|
||||
(let [selection (.-selection ^js (.-nativeEvent ^js args))
|
||||
start (.-start selection)
|
||||
end (.-end selection)]
|
||||
;; NOTE(rasom): on iOS we do not dispatch this event immediately
|
||||
;; because it is needed only in case if selection is changed without
|
||||
;; typing. Timeout might be canceled on `on-change`.
|
||||
(when platform/ios?
|
||||
(reset!
|
||||
timeout-id
|
||||
(background-timer/set-timeout
|
||||
#(rf/dispatch [:mention/on-selection-change
|
||||
{:start start
|
||||
:end end}])
|
||||
50)))
|
||||
;; NOTE(rasom): on Android we dispatch event only in case if there
|
||||
;; was no text changes during last 50ms. `on-selection-change` is
|
||||
;; dispatched after `on-change`, that's why there is no another way
|
||||
;; to know whether selection was changed without typing.
|
||||
(when (and platform/android?
|
||||
(or (not @last-text-change)
|
||||
(< 50 (- (js/Date.now) @last-text-change))))
|
||||
(rf/dispatch [:mention/on-selection-change
|
||||
{:start start
|
||||
:end end}]))))
|
||||
|
||||
(defn on-change
|
||||
[last-text-change timeout-id refs chat-id sending-image args]
|
||||
(let [text (.-text ^js (.-nativeEvent ^js args))
|
||||
prev-text (get @input-texts chat-id)]
|
||||
(when (and (seq prev-text) (empty? text) (not sending-image))
|
||||
(hide-send refs))
|
||||
(when (and (empty? prev-text) (or (seq text) sending-image))
|
||||
(show-send refs chat-id)
|
||||
(reset! recording-audio? false)
|
||||
(swap! reviewing-audio-filepath dissoc chat-id))
|
||||
|
||||
(when (and (not (get @mentions-enabled? chat-id)) (string/index-of text "@"))
|
||||
(swap! mentions-enabled? assoc chat-id true))
|
||||
|
||||
;; NOTE(rasom): on iOS `on-selection-change` is canceled in case if it
|
||||
;; happens during typing because it is not needed for mention
|
||||
;; suggestions calculation
|
||||
(when (and platform/ios? @timeout-id)
|
||||
(background-timer/clear-timeout @timeout-id))
|
||||
(when platform/android?
|
||||
(reset! last-text-change (js/Date.now)))
|
||||
|
||||
(on-text-change text chat-id)
|
||||
|
||||
(rf/dispatch [:mention/on-change-text text])))
|
||||
|
||||
(defn on-text-input
|
||||
[chat-id args]
|
||||
(let [native-event (.-nativeEvent ^js args)
|
||||
text (.-text ^js native-event)]
|
||||
(when (and (not (get @mentions-enabled? chat-id)) (string/index-of text "@"))
|
||||
(swap! mentions-enabled? assoc chat-id true))))
|
||||
|
||||
(defn text-input-style
|
||||
[chat-id]
|
||||
(merge typography/font-regular
|
||||
typography/paragraph-1
|
||||
{:flex 1
|
||||
:min-height 34
|
||||
:margin 0
|
||||
:flex-shrink 1
|
||||
:color (colors/theme-colors colors/neutral-100 colors/white)
|
||||
:margin-horizontal 20}
|
||||
(if platform/android?
|
||||
{:padding-vertical 8
|
||||
:text-align-vertical :top}
|
||||
{:margin-top 8
|
||||
:margin-bottom 8})
|
||||
(when (or @recording-audio? (get @reviewing-audio-filepath chat-id))
|
||||
{:display :none})))
|
||||
|
||||
(defn text-input
|
||||
[{:keys [refs chat-id sending-image on-content-size-change]}]
|
||||
(let [cooldown-enabled? (rf/sub [:chats/current-chat-cooldown-enabled?])
|
||||
timeout-id (reagent/atom nil)
|
||||
last-text-change (reagent/atom nil)
|
||||
mentions-enabled? (get @mentions-enabled? chat-id)
|
||||
props
|
||||
{:style (text-input-style chat-id)
|
||||
:ref (:text-input-ref refs)
|
||||
:max-font-size-multiplier 1
|
||||
:accessibility-label :chat-message-input
|
||||
:text-align-vertical :center
|
||||
:multiline true
|
||||
:editable (not cooldown-enabled?)
|
||||
:blur-on-submit false
|
||||
:auto-focus false
|
||||
:max-length chat.constants/max-text-size
|
||||
:placeholder-text-color (colors/theme-colors colors/neutral-40 colors/white-opa-30)
|
||||
:placeholder (if cooldown-enabled?
|
||||
(i18n/label :cooldown/text-input-disabled)
|
||||
(i18n/label :t/type-a-message))
|
||||
:default-value (get @input-texts chat-id)
|
||||
:underline-color-android :transparent
|
||||
:auto-capitalize :sentences
|
||||
:auto-correct false
|
||||
:spell-check false
|
||||
:on-content-size-change on-content-size-change
|
||||
:on-selection-change (partial on-selection-change
|
||||
timeout-id
|
||||
last-text-change)
|
||||
:on-change
|
||||
(partial on-change last-text-change timeout-id refs chat-id sending-image)
|
||||
:on-text-input (partial on-text-input chat-id)}
|
||||
input-with-mentions (rf/sub [:chat/input-with-mentions])
|
||||
children (fn []
|
||||
(if mentions-enabled?
|
||||
(map-indexed
|
||||
(fn [index [mention-type text]]
|
||||
^{:key (str index "_" mention-type "_" text)}
|
||||
[rn/text (when (= mention-type :mention) {:style {:color colors/primary-50}})
|
||||
text])
|
||||
input-with-mentions)
|
||||
(get @input-texts chat-id)))]
|
||||
(reset! text-input-ref (:text-input-ref refs))
|
||||
;when ios implementation for selectable-text-input is ready, we need remove this condition and use
|
||||
;selectable-text-input directly.
|
||||
(if platform/android?
|
||||
[selectable-text-input chat-id props children]
|
||||
[rn/text-input props
|
||||
children])))
|
||||
|
||||
(declare first-level-menu-items second-level-menu-items)
|
||||
|
||||
(defn update-input-text
|
||||
[{:keys [text-input chat-id]} text]
|
||||
(on-text-change text chat-id)
|
||||
(.setNativeProps ^js text-input (clj->js {:text text})))
|
||||
|
||||
(re-frame/reg-fx
|
||||
:set-text-input-value
|
||||
(fn [[chat-id text local-text-input-ref]]
|
||||
(when local-text-input-ref
|
||||
(reset! text-input-ref local-text-input-ref))
|
||||
(on-text-change text chat-id)
|
||||
(if platform/ios?
|
||||
(.setNativeProps ^js (quo.react/current-ref @text-input-ref) (clj->js {:text text}))
|
||||
(if (string/blank? text)
|
||||
(.clear ^js (quo.react/current-ref @text-input-ref))
|
||||
(.setNativeProps ^js (quo.react/current-ref @text-input-ref) (clj->js {:text text}))))))
|
||||
|
||||
(defn calculate-input-text
|
||||
[{:keys [full-text selection-start selection-end]} content]
|
||||
(let [head (subs full-text 0 selection-start)
|
||||
tail (subs full-text selection-end)]
|
||||
(str head content tail)))
|
||||
|
||||
(defn update-selection
|
||||
[text-input-handle selection-start selection-end]
|
||||
;to avoid something disgusting like this
|
||||
;https://lightrun.com/answers/facebook-react-native-textinput-controlled-selection-broken-on-both-ios-and-android
|
||||
;use native invoke instead! do not use setNativeProps! e.g. (.setNativeProps ^js text-input (clj->js
|
||||
;{:selection {:start selection-start :end selection-end}}))
|
||||
(let [manager (rn/selectable-text-input-manager)]
|
||||
(oops/ocall manager :setSelection text-input-handle selection-start selection-end)))
|
||||
|
||||
(def first-level-menus
|
||||
{:cut (fn [{:keys [content] :as params}]
|
||||
(let [new-text (calculate-input-text params "")]
|
||||
(clipboard/set-string content)
|
||||
(update-input-text params new-text)))
|
||||
|
||||
:copy-to-clipboard (fn [{:keys [content]}]
|
||||
(clipboard/set-string content))
|
||||
|
||||
:paste (fn [params]
|
||||
(let [callback (fn [paste-content]
|
||||
(let [content (string/trim paste-content)
|
||||
new-text (calculate-input-text params content)]
|
||||
(update-input-text params new-text)))]
|
||||
(clipboard/get-string callback)))
|
||||
|
||||
:biu (fn [{:keys [first-level text-input-handle menu-items selection-start
|
||||
selection-end]}]
|
||||
(reset! first-level false)
|
||||
(reset! menu-items second-level-menu-items)
|
||||
(update-selection text-input-handle selection-start selection-end))})
|
||||
|
||||
(def first-level-menu-items (map i18n/label (keys first-level-menus)))
|
||||
|
||||
(defn reset-to-first-level-menu
|
||||
[first-level menu-items]
|
||||
(reset! first-level true)
|
||||
(reset! menu-items first-level-menu-items))
|
||||
|
||||
(defn append-markdown-char
|
||||
[{:keys [first-level menu-items content selection-start selection-end text-input-handle
|
||||
selection-event]
|
||||
:as params} wrap-chars]
|
||||
(let [content (str wrap-chars content wrap-chars)
|
||||
new-text (calculate-input-text params content)
|
||||
len-wrap-chars (count wrap-chars)
|
||||
selection-start (+ selection-start len-wrap-chars)
|
||||
selection-end (+ selection-end len-wrap-chars)]
|
||||
;don't update selection directly here, process it within on-selection-change instead
|
||||
;so that we can avoid java.lang.IndexOutOfBoundsException: setSpan..
|
||||
(reset! selection-event {:start selection-start
|
||||
:end selection-end
|
||||
:text-input-handle text-input-handle})
|
||||
(update-input-text params new-text)
|
||||
(reset-to-first-level-menu first-level menu-items)))
|
||||
|
||||
(def second-level-menus
|
||||
{:bold #(append-markdown-char % "**")
|
||||
|
||||
:italic #(append-markdown-char % "*")
|
||||
|
||||
:strikethrough #(append-markdown-char % "~~")})
|
||||
|
||||
(def second-level-menu-items (map i18n/label (keys second-level-menus)))
|
||||
|
||||
(defn on-menu-item-touched
|
||||
[{:keys [first-level event-type] :as params}]
|
||||
(let [menus (if @first-level first-level-menus second-level-menus)
|
||||
menu-item-key (nth (keys menus) event-type)
|
||||
action (get menus menu-item-key)]
|
||||
(action params)))
|
||||
|
||||
(defn selectable-text-input
|
||||
[_ _ _]
|
||||
(let [text-input-ref (reagent/atom nil)
|
||||
menu-items (reagent/atom first-level-menu-items)
|
||||
first-level (reagent/atom true)
|
||||
selection-event (atom nil)
|
||||
manager (rn/selectable-text-input-manager)]
|
||||
(reagent/create-class
|
||||
{:component-did-mount
|
||||
(fn [this]
|
||||
(when @text-input-ref
|
||||
(let [selectable-text-input-handle (rn/find-node-handle this)
|
||||
text-input-handle (rn/find-node-handle @text-input-ref)]
|
||||
(oops/ocall manager :setupMenuItems selectable-text-input-handle text-input-handle))))
|
||||
|
||||
:component-did-update (fn [_ _ _ _]
|
||||
(when (not @first-level)
|
||||
(let [text-input-handle (rn/find-node-handle @text-input-ref)]
|
||||
(oops/ocall manager :startActionMode text-input-handle))))
|
||||
|
||||
:reagent-render
|
||||
(fn [chat-id {:keys [style ref on-selection-change] :as props} children]
|
||||
(let [ref #(do (reset! text-input-ref %)
|
||||
(when ref
|
||||
(quo.react/set-ref-val! ref %)))
|
||||
on-selection-change (fn [args]
|
||||
(let [selection (.-selection ^js (.-nativeEvent ^js args))
|
||||
start (.-start selection)
|
||||
end (.-end selection)
|
||||
no-selection (<= (- end start) 0)]
|
||||
(when (and no-selection (not @first-level))
|
||||
(oops/ocall manager :hideLastActionMode)
|
||||
(reset-to-first-level-menu first-level menu-items)))
|
||||
(when on-selection-change
|
||||
(on-selection-change args))
|
||||
(when @selection-event
|
||||
(let [{:keys [start end text-input-handle]} @selection-event]
|
||||
(update-selection text-input-handle start end)
|
||||
(reset! selection-event nil))))
|
||||
on-selection
|
||||
(fn [^js event]
|
||||
(let [native-event (.-nativeEvent event)
|
||||
native-event (transforms/js->clj native-event)
|
||||
{:keys [eventType content selectionStart
|
||||
selectionEnd]} native-event
|
||||
full-text (:input-text (rf/sub [:chats/current-chat-input]))]
|
||||
(on-menu-item-touched {:first-level first-level
|
||||
:event-type eventType
|
||||
:content content
|
||||
:selection-start selectionStart
|
||||
:selection-end selectionEnd
|
||||
:text-input @text-input-ref
|
||||
:text-input-handle (rn/find-node-handle @text-input-ref)
|
||||
:full-text full-text
|
||||
:menu-items menu-items
|
||||
:chat-id chat-id
|
||||
:selection-event selection-event})))
|
||||
props (merge props
|
||||
{:ref ref
|
||||
:style (dissoc style :margin-horizontal)
|
||||
:on-selection-change on-selection-change
|
||||
:on-selection on-selection})]
|
||||
[rn/selectable-text-input {:menuItems @menu-items :style style}
|
||||
[rn/text-input props
|
||||
children]]))})))
|
||||
@@ -1,2 +0,0 @@
|
||||
(ns status-im.ui2.screens.chat.composer.mentions)
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
(ns status-im.ui2.screens.chat.composer.reply
|
||||
(:require [quo.react-native :as rn]
|
||||
[status-im.ui2.screens.chat.components.reply.view :as reply]
|
||||
[status-im.ui2.screens.chat.composer.input :as input]))
|
||||
|
||||
(defn focus-input-on-reply
|
||||
[reply had-reply text-input-ref]
|
||||
;;when we show reply we focus input
|
||||
(when-not (= reply @had-reply)
|
||||
(reset! had-reply reply)
|
||||
(when reply
|
||||
;; A setTimeout of 0 is necessary to ensure the statement is enqueued and will get executed ASAP.
|
||||
(js/setTimeout #(input/input-focus text-input-ref) 0))))
|
||||
|
||||
(defn reply-message-auto-focus-wrapper
|
||||
[text-input-ref _]
|
||||
(let [had-reply (atom nil)]
|
||||
(fn [_ reply]
|
||||
(focus-input-on-reply reply had-reply text-input-ref)
|
||||
(when reply
|
||||
[rn/view
|
||||
{:style (merge
|
||||
{:padding-horizontal 15
|
||||
:padding-vertical 8}
|
||||
(when @input/recording-audio?
|
||||
{:position :absolute
|
||||
:top 12
|
||||
:left 0
|
||||
:right 0
|
||||
;;When recording an audio and replying at the same time,
|
||||
;;text input is overlapped by the reply component but
|
||||
;;text input still have priority over touches, so we need
|
||||
;;to force the reply component to receive the touches in this
|
||||
;;scenario, thus we increase its z-index
|
||||
:z-index 1}))}
|
||||
[reply/reply-message reply true false
|
||||
(and @input/recording-audio? (not @input/reviewing-audio?))]]))))
|
||||
@@ -18,7 +18,6 @@
|
||||
[status-im.ui.screens.chat.styles.message.message :as style]
|
||||
[status-im.ui.screens.chat.utils :as chat.utils]
|
||||
[status-im.ui.screens.communities.icon :as communities.icon]
|
||||
[status-im.ui2.screens.chat.components.reply.view :as components.reply]
|
||||
[status-im.utils.utils :as utils]
|
||||
[status-im2.constants :as constants]
|
||||
[status-im2.contexts.chat.home.chat-list-item.view :as home.chat-list-item]
|
||||
@@ -144,9 +143,8 @@
|
||||
(:parsed-text content))))
|
||||
|
||||
(defn quoted-message
|
||||
[quoted-message pin?]
|
||||
[rn/view {:style (when-not pin? (style/quoted-message-container))}
|
||||
[components.reply/reply-message quoted-message false pin?]])
|
||||
[_ pin?]
|
||||
[rn/view {:style (when-not pin? (style/quoted-message-container))}])
|
||||
|
||||
(defn message-not-sent-text
|
||||
[chat-id message-id]
|
||||
|
||||
@@ -184,6 +184,7 @@
|
||||
|
||||
(rf/defn process-stored-event
|
||||
"Return an event description for processing a url if in the database"
|
||||
{:events [:universal-links/process-stored-event]}
|
||||
[{:keys [db] :as cofx}]
|
||||
(when-let [url (:universal-links/url db)]
|
||||
(rf/merge cofx
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
:margin-vertical 8})
|
||||
|
||||
(defn sheet
|
||||
[{:keys [top bottom]} window-height override-theme]
|
||||
[{:keys [top bottom]} window-height override-theme shell?]
|
||||
{:position :absolute
|
||||
:max-height (- window-height top 20)
|
||||
:z-index 1
|
||||
@@ -21,9 +21,20 @@
|
||||
:right 0
|
||||
:border-top-left-radius 20
|
||||
:border-top-right-radius 20
|
||||
:overflow :hidden
|
||||
:flex 1
|
||||
:padding-bottom (max 20 bottom)
|
||||
:background-color (colors/theme-colors colors/white colors/neutral-90 override-theme)})
|
||||
:background-color (if shell?
|
||||
:transparent
|
||||
(colors/theme-colors colors/white colors/neutral-90 override-theme))})
|
||||
|
||||
(def shell-bg
|
||||
{:position :absolute
|
||||
:background-color colors/white-opa-5
|
||||
:left 0
|
||||
:right 0
|
||||
:top 0
|
||||
:bottom 0})
|
||||
|
||||
(defn selected-item
|
||||
[override-theme]
|
||||
|
||||
@@ -6,7 +6,8 @@
|
||||
[status-im2.common.bottom-sheet.styles :as styles]
|
||||
[react-native.gesture :as gesture]
|
||||
[oops.core :as oops]
|
||||
[react-native.hooks :as hooks]))
|
||||
[react-native.hooks :as hooks]
|
||||
[react-native.blur :as blur]))
|
||||
|
||||
(def duration 450)
|
||||
(def timing-options #js {:duration duration})
|
||||
@@ -49,7 +50,7 @@
|
||||
(hide translate-y bg-opacity window-height))))))
|
||||
|
||||
(defn view
|
||||
[{:keys [hide? insets]} {:keys [content override-theme selected-item]}]
|
||||
[{:keys [hide? insets]} {:keys [content override-theme selected-item shell?]}]
|
||||
(let [{window-height :height} (rn/get-window)
|
||||
bg-opacity (reanimated/use-shared-value 0)
|
||||
translate-y (reanimated/use-shared-value window-height)
|
||||
@@ -69,7 +70,11 @@
|
||||
[reanimated/view
|
||||
{:style (reanimated/apply-animations-to-style
|
||||
{:transform [{:translateY translate-y}]}
|
||||
(styles/sheet insets window-height override-theme))}
|
||||
(styles/sheet insets window-height override-theme shell?))}
|
||||
|
||||
(when shell?
|
||||
[blur/view
|
||||
{:style styles/shell-bg}])
|
||||
|
||||
(when selected-item
|
||||
[rn/view
|
||||
|
||||
@@ -158,5 +158,3 @@
|
||||
["enrtree://AOGECG2SPND25EEFMAJ5WF3KSGJNSGV356DSTL2YVLLZWIV6SAYBM@test.waku.nodes.status.im"]})
|
||||
|
||||
(def default-kdf-iterations 3200)
|
||||
|
||||
(def ^:const new-composer-enabled? false)
|
||||
|
||||
@@ -263,7 +263,6 @@
|
||||
2 5000
|
||||
3 10000})
|
||||
|
||||
(def ^:const max-text-size 4096)
|
||||
;; any message that comes after this amount of ms will be grouped separately
|
||||
(def ^:const group-ms 300000)
|
||||
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
(ns status-im2.contexts.chat.bottom-sheet-composer.gradients.view
|
||||
(:require
|
||||
[react-native.core :as rn]
|
||||
[react-native.linear-gradient :as linear-gradient]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[status-im2.contexts.chat.bottom-sheet-composer.gradients.style :as style]))
|
||||
|
||||
|
||||
(defn view
|
||||
[{:keys [input-ref]}
|
||||
{:keys [gradient-z-index]}
|
||||
{:keys [gradient-opacity]}
|
||||
show-bottom-gradient?]
|
||||
[:f>
|
||||
(fn []
|
||||
[:<>
|
||||
[reanimated/linear-gradient (style/top-gradient gradient-opacity @gradient-z-index)]
|
||||
(when show-bottom-gradient?
|
||||
[rn/touchable-without-feedback
|
||||
{:on-press #(when @input-ref (.focus ^js @input-ref))
|
||||
:accessibility-label :bottom-gradient}
|
||||
[linear-gradient/linear-gradient (style/bottom-gradient)]])])])
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
(ns status-im2.contexts.chat.bottom-sheet-composer.images.view
|
||||
(:require [quo2.core :as quo]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[react-native.core :as rn]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[status-im2.contexts.chat.bottom-sheet-composer.images.style :as style]
|
||||
[utils.re-frame :as rf]
|
||||
[status-im2.contexts.chat.bottom-sheet-composer.constants :as constants]))
|
||||
|
||||
(defn image
|
||||
[item]
|
||||
[rn/view style/image-container
|
||||
[rn/image
|
||||
{:source {:uri (:resized-uri (val item))}
|
||||
:style style/small-image}]
|
||||
[rn/touchable-opacity
|
||||
{:on-press #(rf/dispatch [:chat.ui/image-unselected (val item)])
|
||||
:style style/remove-photo-container
|
||||
:hit-slop {:right 5
|
||||
:left 5
|
||||
:top 10
|
||||
:bottom 10}}
|
||||
[quo/icon :i/close {:color colors/white :size 12}]]])
|
||||
|
||||
(defn images-list
|
||||
[]
|
||||
[:f>
|
||||
(fn []
|
||||
(let [images (rf/sub [:chats/sending-image])
|
||||
height (reanimated/use-shared-value (if (seq images) constants/images-container-height 0))]
|
||||
(rn/use-effect (fn []
|
||||
(reanimated/animate height
|
||||
(if (seq images) constants/images-container-height 0)))
|
||||
[images])
|
||||
[reanimated/view {:style (reanimated/apply-animations-to-style {:height height} {})}
|
||||
[rn/flat-list
|
||||
{:key-fn first
|
||||
:render-fn image
|
||||
:data images
|
||||
:horizontal true
|
||||
:keyboard-should-persist-taps :handled}]]))])
|
||||
@@ -1,18 +0,0 @@
|
||||
(ns status-im2.contexts.chat.bottom-sheet-composer.sub-view
|
||||
(:require
|
||||
[react-native.blur :as blur]
|
||||
[react-native.core :as rn]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[status-im2.contexts.chat.bottom-sheet-composer.style :as style]))
|
||||
|
||||
(defn bar
|
||||
[]
|
||||
[rn/view {:style style/bar-container}
|
||||
[rn/view {:style (style/bar)}]])
|
||||
|
||||
(defn blur-view
|
||||
[layout-height]
|
||||
[:f>
|
||||
(fn []
|
||||
[reanimated/view {:style (style/blur-container layout-height)}
|
||||
[blur/view (style/blur-view)]])])
|
||||
@@ -1,92 +0,0 @@
|
||||
(ns status-im2.contexts.chat.bottom-sheet-composer.utils
|
||||
(:require
|
||||
[oops.core :as oops]
|
||||
[react-native.platform :as platform]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[status-im2.contexts.chat.bottom-sheet-composer.constants :as constants]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn bounded-val
|
||||
[val min-val max-val]
|
||||
(max min-val (min val max-val)))
|
||||
|
||||
(defn get-min-height
|
||||
[lines]
|
||||
(if (> lines 1) constants/multiline-minimized-height constants/input-height))
|
||||
|
||||
(defn calc-reopen-height
|
||||
[text-value min-height content-height saved-height]
|
||||
(if (empty? @text-value)
|
||||
min-height
|
||||
(Math/min @content-height (reanimated/get-shared-value saved-height))))
|
||||
|
||||
(defn update-height?
|
||||
[content-size height max-height maximized?]
|
||||
(when-not @maximized?
|
||||
(let [diff (Math/abs (- content-size (reanimated/get-shared-value height)))]
|
||||
(and (not= (reanimated/get-shared-value height) max-height)
|
||||
(> diff constants/content-change-threshold)))))
|
||||
|
||||
(defn show-top-gradient?
|
||||
[y lines max-lines gradient-opacity focused?]
|
||||
(and
|
||||
(> y constants/line-height)
|
||||
(>= lines max-lines)
|
||||
(= (reanimated/get-shared-value gradient-opacity) 0)
|
||||
@focused?))
|
||||
|
||||
(defn hide-top-gradient?
|
||||
[y gradient-opacity]
|
||||
(and
|
||||
(<= y constants/line-height)
|
||||
(= (reanimated/get-shared-value gradient-opacity) 1)))
|
||||
|
||||
(defn show-bottom-gradient?
|
||||
[{:keys [text-value focused?]} {:keys [lines]}]
|
||||
(and (not-empty @text-value) (not @focused?) (> lines 2)))
|
||||
|
||||
(defn show-background?
|
||||
[saved-height max-height new-height]
|
||||
(or (= (reanimated/get-shared-value saved-height) max-height)
|
||||
(> new-height (* constants/background-threshold max-height))))
|
||||
|
||||
(defn update-blur-height?
|
||||
[event lock-layout? layout-height]
|
||||
(or (not @lock-layout?)
|
||||
(> (reanimated/get-shared-value layout-height) (oops/oget event "nativeEvent.layout.height"))))
|
||||
|
||||
(defn calc-lines
|
||||
[height]
|
||||
(let [lines (Math/round (/ height constants/line-height))]
|
||||
(if platform/ios? lines (dec lines))))
|
||||
|
||||
(defn calc-max-height
|
||||
[window-height kb-height insets images? reply? edit?]
|
||||
(let [margin-top (if platform/ios? (:top insets) (+ 10 (:top insets)))
|
||||
max-height (- window-height
|
||||
margin-top
|
||||
kb-height
|
||||
constants/bar-container-height
|
||||
constants/actions-container-height)
|
||||
max-height (if images? (- max-height constants/images-container-height) max-height)
|
||||
max-height (if reply? (- max-height constants/reply-container-height) max-height)
|
||||
max-height (if edit? (- max-height constants/edit-container-height) max-height)]
|
||||
max-height))
|
||||
|
||||
(defn empty-input?
|
||||
[text images reply? audio?]
|
||||
(and (empty? text) (empty? images) (not reply?) (not audio?)))
|
||||
|
||||
(defn android-elevation?
|
||||
[lines images reply? edit?]
|
||||
(or (> lines 1) (seq images) reply? edit?))
|
||||
|
||||
(defn cancel-edit-message
|
||||
[{:keys [text-value maximized?]}
|
||||
{:keys [height saved-height last-height]}]
|
||||
(when-not @maximized?
|
||||
(reanimated/animate height constants/input-height)
|
||||
(reanimated/set-shared-value saved-height constants/input-height)
|
||||
(reanimated/set-shared-value last-height constants/input-height))
|
||||
(reset! text-value "")
|
||||
(rf/dispatch [:chat.ui/set-input-content-height constants/input-height]))
|
||||
@@ -1,163 +0,0 @@
|
||||
(ns status-im2.contexts.chat.bottom-sheet-composer.view
|
||||
(:require
|
||||
[quo2.foundations.colors :as colors]
|
||||
[react-native.core :as rn]
|
||||
[react-native.gesture :as gesture]
|
||||
[react-native.hooks :as hooks]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[reagent.core :as reagent]
|
||||
[utils.i18n :as i18n]
|
||||
[status-im2.contexts.chat.bottom-sheet-composer.style :as style]
|
||||
[status-im2.contexts.chat.bottom-sheet-composer.images.view :as images]
|
||||
[status-im2.contexts.chat.bottom-sheet-composer.reply.view :as reply]
|
||||
[utils.re-frame :as rf]
|
||||
[status-im2.contexts.chat.bottom-sheet-composer.edit.view :as edit]
|
||||
[status-im2.contexts.chat.bottom-sheet-composer.utils :as utils]
|
||||
[status-im2.contexts.chat.bottom-sheet-composer.constants :as constants]
|
||||
[status-im2.contexts.chat.bottom-sheet-composer.actions.view :as actions]
|
||||
[status-im2.contexts.chat.bottom-sheet-composer.keyboard :as kb]
|
||||
[status-im2.contexts.chat.bottom-sheet-composer.sub-view :as sub-view]
|
||||
[status-im2.contexts.chat.bottom-sheet-composer.effects :as effects]
|
||||
[status-im2.contexts.chat.bottom-sheet-composer.gesture :as drag-gesture]
|
||||
[status-im2.contexts.chat.bottom-sheet-composer.handlers :as handler]
|
||||
[status-im2.contexts.chat.bottom-sheet-composer.gradients.view :as gradients]))
|
||||
|
||||
(defn sheet
|
||||
[insets window-height blur-height opacity background-y]
|
||||
[:f>
|
||||
(fn []
|
||||
(let [props {:input-ref (atom nil)
|
||||
:keyboard-show-listener (atom nil)
|
||||
:keyboard-frame-listener (atom nil)
|
||||
:keyboard-hide-listener (atom nil)
|
||||
:emoji-kb-extra-height (atom nil)
|
||||
:saved-emoji-kb-extra-height (atom nil)
|
||||
:replying? (atom nil)
|
||||
:sending-images? (atom nil)
|
||||
:editing? (atom nil)
|
||||
:record-permission? (atom nil)
|
||||
:record-reset-fn (atom nil)}
|
||||
state {:text-value (reagent/atom "")
|
||||
:cursor-position (reagent/atom 0)
|
||||
:saved-cursor-position (reagent/atom 0)
|
||||
:gradient-z-index (reagent/atom 0)
|
||||
:kb-default-height (reagent/atom nil)
|
||||
:gesture-enabled? (reagent/atom true)
|
||||
:lock-selection? (reagent/atom true)
|
||||
:focused? (reagent/atom false)
|
||||
:lock-layout? (reagent/atom false)
|
||||
:maximized? (reagent/atom false)
|
||||
:recording? (reagent/atom false)}]
|
||||
[:f>
|
||||
(fn []
|
||||
(let [images (rf/sub [:chats/sending-image])
|
||||
audio (rf/sub [:chats/sending-audio])
|
||||
reply (rf/sub [:chats/reply-message])
|
||||
edit (rf/sub [:chats/edit-message])
|
||||
{:keys [input-text input-content-height]
|
||||
:as chat-input} (rf/sub [:chats/current-chat-input])
|
||||
content-height (reagent/atom (or input-content-height
|
||||
constants/input-height))
|
||||
{:keys [keyboard-shown keyboard-height]} (hooks/use-keyboard)
|
||||
kb-height (kb/get-kb-height keyboard-height
|
||||
@(:kb-default-height state))
|
||||
max-height (utils/calc-max-height window-height
|
||||
kb-height
|
||||
insets
|
||||
(seq images)
|
||||
reply
|
||||
edit)
|
||||
lines (utils/calc-lines @content-height)
|
||||
max-lines (utils/calc-lines max-height)
|
||||
initial-height (if (> lines 1)
|
||||
constants/multiline-minimized-height
|
||||
constants/input-height)
|
||||
animations {:gradient-opacity (reanimated/use-shared-value
|
||||
0)
|
||||
:container-opacity (reanimated/use-shared-value
|
||||
(if (utils/empty-input?
|
||||
input-text
|
||||
images
|
||||
reply
|
||||
audio)
|
||||
0.7
|
||||
1))
|
||||
:height (reanimated/use-shared-value
|
||||
initial-height)
|
||||
:saved-height (reanimated/use-shared-value
|
||||
initial-height)
|
||||
:last-height (reanimated/use-shared-value
|
||||
(utils/bounded-val
|
||||
@content-height
|
||||
constants/input-height
|
||||
max-height))
|
||||
:opacity opacity
|
||||
:background-y background-y}
|
||||
dimensions {:content-height content-height
|
||||
:max-height max-height
|
||||
:window-height window-height
|
||||
:lines lines
|
||||
:max-lines max-lines}
|
||||
show-bottom-gradient? (utils/show-bottom-gradient? state dimensions)]
|
||||
(effects/initialize props
|
||||
state
|
||||
animations
|
||||
dimensions
|
||||
chat-input
|
||||
keyboard-height
|
||||
(seq images)
|
||||
reply
|
||||
edit
|
||||
audio)
|
||||
[gesture/gesture-detector
|
||||
{:gesture (drag-gesture/drag-gesture props state animations dimensions keyboard-shown)}
|
||||
[reanimated/view
|
||||
{:style (style/sheet-container insets state animations)
|
||||
:on-layout #(handler/layout % state blur-height)}
|
||||
[sub-view/bar]
|
||||
[reply/view state]
|
||||
[edit/view edit #(utils/cancel-edit-message state animations)]
|
||||
[reanimated/touchable-opacity
|
||||
{:active-opacity 1
|
||||
:on-press (when @(:input-ref props) #(.focus ^js @(:input-ref props)))
|
||||
:style (style/input-container (:height animations) max-height)
|
||||
:accessibility-label :message-input-container}
|
||||
[rn/text-input
|
||||
{:ref #(reset! (:input-ref props) %)
|
||||
:default-value @(:text-value state)
|
||||
:on-focus #(handler/focus props state animations dimensions)
|
||||
:on-blur #(handler/blur state animations dimensions images reply)
|
||||
:on-content-size-change #(handler/content-size-change %
|
||||
state
|
||||
animations
|
||||
dimensions
|
||||
(or keyboard-shown edit))
|
||||
:on-scroll #(handler/scroll % state animations dimensions)
|
||||
:on-change-text #(handler/change-text % props state)
|
||||
:on-selection-change #(handler/selection-change % state)
|
||||
:max-height max-height
|
||||
:max-font-size-multiplier 1
|
||||
:multiline true
|
||||
:placeholder (i18n/label :t/type-something)
|
||||
:placeholder-text-color (colors/theme-colors colors/neutral-40 colors/neutral-50)
|
||||
:style (style/input props state)
|
||||
:accessibility-label :chat-message-input}]
|
||||
[gradients/view props state animations show-bottom-gradient?]]
|
||||
[images/images-list]
|
||||
[actions/view props state animations window-height insets (seq images)]]]))]))])
|
||||
|
||||
(defn f-bottom-sheet-composer
|
||||
[insets]
|
||||
(let [window-height (rf/sub [:dimensions/window-height])
|
||||
opacity (reanimated/use-shared-value 0)
|
||||
background-y (reanimated/use-shared-value (- window-height))
|
||||
blur-height (reanimated/use-shared-value (+ constants/composer-default-height
|
||||
(:bottom insets)))]
|
||||
[rn/view
|
||||
[reanimated/view {:style (style/background opacity background-y window-height)}]
|
||||
[sub-view/blur-view blur-height]
|
||||
[sheet insets window-height blur-height opacity background-y]]))
|
||||
|
||||
(defn bottom-sheet-composer
|
||||
[insets]
|
||||
[:f> f-bottom-sheet-composer insets])
|
||||
+2
-2
@@ -1,8 +1,8 @@
|
||||
(ns status-im2.contexts.chat.bottom-sheet-composer.actions.style
|
||||
(ns status-im2.contexts.chat.composer.actions.style
|
||||
(:require
|
||||
[quo2.foundations.colors :as colors]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[status-im2.contexts.chat.bottom-sheet-composer.constants :as constants]))
|
||||
[status-im2.contexts.chat.composer.constants :as constants]))
|
||||
|
||||
(def actions-container
|
||||
{:height constants/actions-container-height
|
||||
+43
-40
@@ -1,4 +1,4 @@
|
||||
(ns status-im2.contexts.chat.bottom-sheet-composer.actions.view
|
||||
(ns status-im2.contexts.chat.composer.actions.view
|
||||
(:require
|
||||
[quo2.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
@@ -7,11 +7,11 @@
|
||||
[react-native.reanimated :as reanimated]
|
||||
[reagent.core :as reagent]
|
||||
[status-im2.common.alert.events :as alert]
|
||||
[status-im2.contexts.chat.bottom-sheet-composer.constants :as constants]
|
||||
[status-im2.contexts.chat.composer.constants :as constants]
|
||||
[status-im2.contexts.chat.messages.list.view :as messages.list]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]
|
||||
[status-im2.contexts.chat.bottom-sheet-composer.actions.style :as style]))
|
||||
[status-im2.contexts.chat.composer.actions.style :as style]))
|
||||
|
||||
(defn send-message
|
||||
[{:keys [text-value focused? maximized?]}
|
||||
@@ -34,45 +34,45 @@
|
||||
(reset! text-value "")
|
||||
(messages.list/scroll-to-bottom))
|
||||
|
||||
(defn send-button
|
||||
(defn f-send-button
|
||||
[{:keys [text-value] :as state}
|
||||
animations
|
||||
window-height
|
||||
images?]
|
||||
[:f>
|
||||
(fn []
|
||||
(let [btn-opacity (reanimated/use-shared-value 0)
|
||||
z-index (reagent/atom 0)]
|
||||
[:f>
|
||||
(fn []
|
||||
(rn/use-effect (fn []
|
||||
(if (or (not-empty @text-value) images?)
|
||||
(when-not (= @z-index 1)
|
||||
(reset! z-index 1)
|
||||
(js/setTimeout #(reanimated/animate btn-opacity 1) 50))
|
||||
(when-not (= @z-index 0)
|
||||
(reanimated/animate btn-opacity 0)
|
||||
(js/setTimeout #(reset! z-index 0) 300))))
|
||||
[(and (empty? @text-value) (not images?))])
|
||||
[reanimated/view
|
||||
{:style (style/send-button btn-opacity @z-index)}
|
||||
[quo/button
|
||||
{:icon true
|
||||
:size 32
|
||||
:accessibility-label :send-message-button
|
||||
:on-press #(send-message state animations window-height)}
|
||||
:i/arrow-up]])]))])
|
||||
animations window-height images?
|
||||
btn-opacity z-index]
|
||||
(rn/use-effect (fn []
|
||||
(if (or (seq @text-value) images?)
|
||||
(when (or (not= @z-index 1) (not= (reanimated/get-shared-value btn-opacity) 1))
|
||||
(reset! z-index 1)
|
||||
(js/setTimeout #(reanimated/animate btn-opacity 1) 50))
|
||||
(when (or (not= @z-index 0) (not= (reanimated/get-shared-value btn-opacity) 0))
|
||||
(reanimated/animate btn-opacity 0)
|
||||
(js/setTimeout #(when (and (empty? @text-value) (not images?)) (reset! z-index 0))
|
||||
300))))
|
||||
[(and (empty? @text-value) (not images?))])
|
||||
[reanimated/view
|
||||
{:style (style/send-button btn-opacity @z-index)}
|
||||
[quo/button
|
||||
{:icon true
|
||||
:size 32
|
||||
:accessibility-label :send-message-button
|
||||
:on-press #(send-message state animations window-height)}
|
||||
:i/arrow-up]])
|
||||
|
||||
(defn send-button
|
||||
[state animations window-height images?]
|
||||
(let [btn-opacity (reanimated/use-shared-value 0)
|
||||
z-index (reagent/atom 0)]
|
||||
[:f> f-send-button state animations window-height images? btn-opacity z-index]))
|
||||
|
||||
(defn audio-button
|
||||
[{:keys [record-permission? record-reset-fn]}
|
||||
{:keys [recording? gesture-enabled?]}
|
||||
[{:keys [record-reset-fn]}
|
||||
{:keys [record-permission? recording? gesture-enabled? focused?]}
|
||||
{:keys [container-opacity]}]
|
||||
(let [audio (rf/sub [:chats/sending-audio])]
|
||||
[rn/view
|
||||
{:style (style/record-audio-container)
|
||||
:pointer-events :box-none}
|
||||
[quo/record-audio
|
||||
{:record-audio-permission-granted record-permission?
|
||||
{:record-audio-permission-granted @record-permission?
|
||||
:on-init (fn [reset-fn]
|
||||
(reset! record-reset-fn reset-fn))
|
||||
:on-start-recording (fn []
|
||||
@@ -86,15 +86,17 @@
|
||||
(reset! recording? false)
|
||||
(reset! gesture-enabled? true)
|
||||
(rf/dispatch [:chat/send-audio file-path duration])
|
||||
(reanimated/animate container-opacity
|
||||
constants/empty-opacity)
|
||||
(when-not @focused?
|
||||
(reanimated/animate container-opacity
|
||||
constants/empty-opacity))
|
||||
(rf/dispatch [:chat.ui/set-input-audio nil]))
|
||||
:on-cancel (fn []
|
||||
(when @recording?
|
||||
(reset! recording? false)
|
||||
(reset! gesture-enabled? true)
|
||||
(reanimated/animate container-opacity
|
||||
constants/empty-opacity)
|
||||
(when-not @focused?
|
||||
(reanimated/animate container-opacity
|
||||
constants/empty-opacity))
|
||||
(rf/dispatch [:chat.ui/set-input-audio nil])))
|
||||
:on-check-audio-permissions (fn []
|
||||
(permissions/permission-granted?
|
||||
@@ -174,7 +176,7 @@
|
||||
:i/format])
|
||||
|
||||
(defn view
|
||||
[props state animations window-height insets images? audio]
|
||||
[props state animations window-height insets edit? images?]
|
||||
[rn/view {:style style/actions-container}
|
||||
[rn/view
|
||||
{:style {:flex-direction :row
|
||||
@@ -183,5 +185,6 @@
|
||||
[image-button props animations insets]
|
||||
[reaction-button]
|
||||
[format-button]]
|
||||
[send-button state animations window-height images?]
|
||||
[audio-button props state animations audio]])
|
||||
[:f> send-button state animations window-height images?]
|
||||
(when (and (not edit?) (not images?))
|
||||
[audio-button props state animations])])
|
||||
+6
-2
@@ -1,4 +1,4 @@
|
||||
(ns status-im2.contexts.chat.bottom-sheet-composer.constants
|
||||
(ns status-im2.contexts.chat.composer.constants
|
||||
(:require
|
||||
[quo2.foundations.typography :as typography]
|
||||
[react-native.platform :as platform]))
|
||||
@@ -21,14 +21,18 @@
|
||||
|
||||
(def ^:const edit-container-height 32)
|
||||
|
||||
(def ^:const mentions-max-height 240)
|
||||
|
||||
(def ^:const extra-content-offset (if platform/ios? 6 0))
|
||||
|
||||
(def ^:const content-change-threshold 10)
|
||||
|
||||
(def ^:const drag-threshold 30)
|
||||
|
||||
(def ^:const velocity-threshold -1000)
|
||||
(def ^:const velocity-threshold (if platform/ios? -1000 -500))
|
||||
|
||||
(def ^:const background-threshold 0.75)
|
||||
|
||||
(def ^:const line-height (:line-height typography/paragraph-1))
|
||||
|
||||
(def ^:const max-text-size 4096)
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
(ns status-im2.contexts.chat.bottom-sheet-composer.edit.style)
|
||||
(ns status-im2.contexts.chat.composer.edit.style)
|
||||
|
||||
(def container
|
||||
{:flex-direction :row
|
||||
+13
-11
@@ -1,16 +1,17 @@
|
||||
(ns status-im2.contexts.chat.bottom-sheet-composer.edit.view
|
||||
(ns status-im2.contexts.chat.composer.edit.view
|
||||
(:require
|
||||
[react-native.reanimated :as reanimated]
|
||||
[status-im2.contexts.chat.bottom-sheet-composer.constants :as constants]
|
||||
[status-im2.contexts.chat.composer.constants :as constants]
|
||||
[status-im2.contexts.chat.composer.utils :as utils]
|
||||
[utils.i18n :as i18n]
|
||||
[quo2.core :as quo]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[re-frame.core :as rf]
|
||||
[react-native.core :as rn]
|
||||
[status-im2.contexts.chat.bottom-sheet-composer.edit.style :as style]))
|
||||
[status-im2.contexts.chat.composer.edit.style :as style]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn edit-message
|
||||
[cancel]
|
||||
[state]
|
||||
[rn/view
|
||||
{:style style/container
|
||||
:accessibility-label :edit-message}
|
||||
@@ -30,7 +31,7 @@
|
||||
:size 24
|
||||
:accessibility-label :edit-cancel-button
|
||||
:on-press (fn []
|
||||
(cancel)
|
||||
(utils/cancel-edit-message state)
|
||||
(rf/dispatch [:chat.ui/cancel-message-edit]))
|
||||
:type :outline}
|
||||
[quo/icon :i/close
|
||||
@@ -38,12 +39,13 @@
|
||||
:color (colors/theme-colors colors/neutral-100 colors/neutral-40)}]]])
|
||||
|
||||
(defn- f-view
|
||||
[edit cancel]
|
||||
(let [height (reanimated/use-shared-value (if edit constants/edit-container-height 0))]
|
||||
[state]
|
||||
(let [edit (rf/sub [:chats/edit-message])
|
||||
height (reanimated/use-shared-value (if edit constants/edit-container-height 0))]
|
||||
(rn/use-effect #(reanimated/animate height (if edit constants/edit-container-height 0)) [edit])
|
||||
[reanimated/view {:style (reanimated/apply-animations-to-style {:height height} {})}
|
||||
(when edit [edit-message cancel])]))
|
||||
(when edit [edit-message state])]))
|
||||
|
||||
(defn view
|
||||
[edit cancel]
|
||||
[:f> f-view edit cancel])
|
||||
[state]
|
||||
[:f> f-view state])
|
||||
+80
-28
@@ -1,11 +1,14 @@
|
||||
(ns status-im2.contexts.chat.bottom-sheet-composer.effects
|
||||
(ns status-im2.contexts.chat.composer.effects
|
||||
(:require
|
||||
[react-native.platform :as platform]
|
||||
[status-im.async-storage.core :as async-storage]
|
||||
[react-native.core :as rn]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[status-im2.contexts.chat.bottom-sheet-composer.constants :as constants]
|
||||
[status-im2.contexts.chat.bottom-sheet-composer.keyboard :as kb]
|
||||
[utils.number :as utils.number]))
|
||||
[status-im2.contexts.chat.composer.constants :as constants]
|
||||
[status-im2.contexts.chat.composer.keyboard :as kb]
|
||||
[utils.number :as utils.number]
|
||||
[oops.core :as oops]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn reenter-screen-effect
|
||||
[{:keys [text-value saved-cursor-position maximized?]}
|
||||
@@ -48,35 +51,43 @@
|
||||
(reanimated/set-shared-value background-y 0)
|
||||
(reanimated/animate opacity 1)))
|
||||
|
||||
(defn images-or-reply-effect
|
||||
[{:keys [container-opacity]}
|
||||
{:keys [replying? sending-images? input-ref]}
|
||||
images? reply?]
|
||||
(when (or images? reply?)
|
||||
(defn images-effect
|
||||
[{:keys [sending-images? input-ref]}
|
||||
{:keys [container-opacity]}
|
||||
images?]
|
||||
(when images?
|
||||
(reanimated/animate container-opacity 1))
|
||||
(when (and (not @sending-images?) images? @input-ref)
|
||||
(.focus ^js @input-ref)
|
||||
(reset! sending-images? true))
|
||||
(when (and (not @replying?) reply? @input-ref)
|
||||
(.focus ^js @input-ref)
|
||||
(reset! replying? true))
|
||||
(when-not images?
|
||||
(reset! sending-images? false))
|
||||
(when-not reply?
|
||||
(reset! replying? false)))
|
||||
(reset! sending-images? false)))
|
||||
|
||||
(defn edit-effect
|
||||
[{:keys [text-value saved-cursor-position]}
|
||||
{:keys [editing? input-ref]}
|
||||
[{:keys [input-ref]}
|
||||
{:keys [text-value saved-cursor-position]}
|
||||
edit]
|
||||
(let [edit-text (get-in edit [:content :text])]
|
||||
(when (and (not @editing?) edit @input-ref)
|
||||
(.focus ^js @input-ref)
|
||||
(reset! editing? true)
|
||||
(reset! text-value edit-text)
|
||||
(reset! saved-cursor-position (count edit-text)))
|
||||
(when-not edit-text
|
||||
(reset! editing? false))))
|
||||
(rn/use-effect
|
||||
(fn []
|
||||
(let [edit-text (get-in edit [:content :text])]
|
||||
(when (and edit @input-ref)
|
||||
(.focus ^js @input-ref)
|
||||
(.setNativeProps ^js @input-ref (clj->js {:text edit-text}))
|
||||
(reset! text-value edit-text)
|
||||
(reset! saved-cursor-position (count edit-text)))))
|
||||
[(:message-id edit)]))
|
||||
|
||||
(defn reply-effect
|
||||
[{:keys [input-ref]}
|
||||
{:keys [container-opacity]}
|
||||
reply]
|
||||
(rn/use-effect
|
||||
(fn []
|
||||
(when reply
|
||||
(reanimated/animate container-opacity 1))
|
||||
(when (and reply @input-ref)
|
||||
(.focus ^js @input-ref)))
|
||||
[(:message-id reply)]))
|
||||
|
||||
(defn audio-effect
|
||||
[{:keys [recording? gesture-enabled?]}
|
||||
@@ -105,7 +116,7 @@
|
||||
|
||||
(defn initialize
|
||||
[props state animations {:keys [max-height] :as dimensions} chat-input keyboard-height images? reply?
|
||||
edit audio]
|
||||
audio]
|
||||
(rn/use-effect
|
||||
(fn []
|
||||
(maximized-effect state animations dimensions chat-input)
|
||||
@@ -113,10 +124,51 @@
|
||||
(layout-effect state)
|
||||
(kb-default-height-effect state)
|
||||
(background-effect state animations dimensions chat-input)
|
||||
(images-or-reply-effect animations props images? reply?)
|
||||
(edit-effect state props edit)
|
||||
(images-effect props animations images?)
|
||||
(audio-effect state animations audio)
|
||||
(empty-effect state animations images? reply? audio)
|
||||
(kb/add-kb-listeners props state animations dimensions keyboard-height)
|
||||
#(component-will-unmount props))
|
||||
[max-height]))
|
||||
|
||||
(defn edit-mentions
|
||||
[{:keys [input-ref]} {:keys [text-value cursor-position]} input-with-mentions]
|
||||
(rn/use-effect (fn []
|
||||
(let [input-text (reduce (fn [acc item]
|
||||
(str acc (second item)))
|
||||
""
|
||||
input-with-mentions)]
|
||||
(reset! text-value input-text)
|
||||
(reset! cursor-position (count input-text))
|
||||
(js/setTimeout #(when @input-ref
|
||||
(.setNativeProps ^js @input-ref
|
||||
(clj->js {:selection {:start (count input-text)
|
||||
:end (count
|
||||
input-text)}})))
|
||||
300)))
|
||||
[(some #(= :mention (first %)) (seq input-with-mentions))]))
|
||||
|
||||
(defn update-input-mention
|
||||
[{:keys [input-ref]}
|
||||
{:keys [text-value]}
|
||||
input-text]
|
||||
(rn/use-effect
|
||||
(fn []
|
||||
(when (and input-text (not= @text-value input-text))
|
||||
(when @input-ref
|
||||
(.setNativeProps ^js @input-ref (clj->js {:text input-text})))
|
||||
(reset! text-value input-text)
|
||||
(rf/dispatch [:mention/on-change-text input-text])))
|
||||
[input-text]))
|
||||
|
||||
(defn did-mount
|
||||
[{:keys [selectable-input-ref input-ref selection-manager]}]
|
||||
(rn/use-effect
|
||||
(fn []
|
||||
(when platform/android?
|
||||
(let [selectable-text-input-handle (rn/find-node-handle @selectable-input-ref)
|
||||
text-input-handle (rn/find-node-handle @input-ref)]
|
||||
(oops/ocall selection-manager
|
||||
:setupMenuItems
|
||||
selectable-text-input-handle
|
||||
text-input-handle))))))
|
||||
+31
-21
@@ -1,10 +1,10 @@
|
||||
(ns status-im2.contexts.chat.bottom-sheet-composer.gesture
|
||||
(ns status-im2.contexts.chat.composer.gesture
|
||||
(:require
|
||||
[react-native.gesture :as gesture]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[oops.core :as oops]
|
||||
[status-im2.contexts.chat.bottom-sheet-composer.constants :as constants]
|
||||
[status-im2.contexts.chat.bottom-sheet-composer.utils :as utils]
|
||||
[status-im2.contexts.chat.composer.constants :as constants]
|
||||
[status-im2.contexts.chat.composer.utils :as utils]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn set-opacity
|
||||
@@ -35,10 +35,12 @@
|
||||
(rf/dispatch [:chat.ui/set-input-maximized true]))
|
||||
|
||||
(defn minimize
|
||||
[{:keys [input-ref emoji-kb-extra-height saved-emoji-kb-extra-height]}]
|
||||
[{:keys [input-ref emoji-kb-extra-height saved-emoji-kb-extra-height]}
|
||||
{:keys [maximized?]}]
|
||||
(when @emoji-kb-extra-height
|
||||
(reset! saved-emoji-kb-extra-height @emoji-kb-extra-height)
|
||||
(reset! emoji-kb-extra-height nil))
|
||||
(reset! maximized? false)
|
||||
(rf/dispatch [:chat.ui/set-input-maximized false])
|
||||
(when @input-ref
|
||||
(.blur ^js @input-ref)))
|
||||
@@ -54,7 +56,7 @@
|
||||
|
||||
(defn drag-gesture
|
||||
[{:keys [input-ref] :as props}
|
||||
{:keys [gesture-enabled?] :as state}
|
||||
{:keys [gesture-enabled? text-value] :as state}
|
||||
{:keys [height saved-height last-height opacity background-y container-opacity] :as animations}
|
||||
{:keys [max-height lines] :as dimensions}
|
||||
keyboard-shown]
|
||||
@@ -65,6 +67,7 @@
|
||||
(gesture/on-start (fn [event]
|
||||
(if-not keyboard-shown
|
||||
(do ; focus and end
|
||||
(reset! text-value (str (oops/oget event "velocityY")))
|
||||
(when (< (oops/oget event "velocityY") constants/velocity-threshold)
|
||||
(reanimated/set-shared-value container-opacity 1)
|
||||
(reanimated/set-shared-value last-height max-height))
|
||||
@@ -74,21 +77,26 @@
|
||||
(do ; else, will start gesture
|
||||
(reanimated/set-shared-value background-y 0)
|
||||
(reset! expanding? (neg? (oops/oget event "velocityY")))))))
|
||||
(gesture/on-update (fn [event]
|
||||
(let [translation (oops/oget event "translationY")
|
||||
min-height (utils/get-min-height lines)
|
||||
new-height (- (reanimated/get-shared-value saved-height) translation)
|
||||
new-height (utils/bounded-val new-height min-height max-height)]
|
||||
(when keyboard-shown
|
||||
(reanimated/set-shared-value height new-height)
|
||||
(set-opacity (oops/oget event "velocityY")
|
||||
opacity
|
||||
translation
|
||||
@expanding?
|
||||
min-height
|
||||
max-height
|
||||
new-height
|
||||
saved-height)))))
|
||||
(gesture/on-update
|
||||
(fn [event]
|
||||
(let [translation (oops/oget event "translationY")
|
||||
min-height (utils/get-min-height lines)
|
||||
new-height (- (reanimated/get-shared-value saved-height) translation)
|
||||
bounded-height (utils/bounded-val new-height min-height max-height)]
|
||||
(when keyboard-shown
|
||||
(if (>= new-height min-height)
|
||||
(do ; expand sheet
|
||||
(reanimated/set-shared-value height bounded-height)
|
||||
(set-opacity (oops/oget event "velocityY")
|
||||
opacity
|
||||
translation
|
||||
@expanding?
|
||||
min-height
|
||||
max-height
|
||||
bounded-height
|
||||
saved-height))
|
||||
(when @input-ref ; sheet at min-height, collapse keyboard
|
||||
(.blur ^js @input-ref)))))))
|
||||
(gesture/on-end (fn []
|
||||
(let [diff (- (reanimated/get-shared-value height)
|
||||
(reanimated/get-shared-value saved-height))]
|
||||
@@ -98,6 +106,8 @@
|
||||
(maximize state animations dimensions)
|
||||
(bounce-back animations dimensions starting-opacity))
|
||||
(if (> (Math/abs diff) constants/drag-threshold)
|
||||
(minimize props)
|
||||
(minimize props state)
|
||||
(bounce-back animations dimensions starting-opacity)))
|
||||
(reset! gesture-enabled? true))))))))
|
||||
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
(ns status-im2.contexts.chat.bottom-sheet-composer.gradients.style
|
||||
(ns status-im2.contexts.chat.composer.gradients.style
|
||||
(:require
|
||||
[quo2.foundations.colors :as colors]
|
||||
[quo2.foundations.typography :as typography]
|
||||
@@ -0,0 +1,24 @@
|
||||
(ns status-im2.contexts.chat.composer.gradients.view
|
||||
(:require
|
||||
[react-native.core :as rn]
|
||||
[react-native.linear-gradient :as linear-gradient]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[status-im2.contexts.chat.composer.gradients.style :as style]))
|
||||
|
||||
|
||||
(defn f-view
|
||||
[{:keys [input-ref]}
|
||||
{:keys [gradient-z-index]}
|
||||
{:keys [gradient-opacity]}
|
||||
show-bottom-gradient?]
|
||||
[:<>
|
||||
[reanimated/linear-gradient (style/top-gradient gradient-opacity @gradient-z-index)]
|
||||
(when show-bottom-gradient?
|
||||
[rn/touchable-without-feedback
|
||||
{:on-press #(when @input-ref (.focus ^js @input-ref))
|
||||
:accessibility-label :bottom-gradient}
|
||||
[linear-gradient/linear-gradient (style/bottom-gradient)]])])
|
||||
(defn view
|
||||
[props state animations show-bottom-gradient?]
|
||||
[:f> f-view props state animations show-bottom-gradient?])
|
||||
|
||||
+37
-14
@@ -1,11 +1,14 @@
|
||||
(ns status-im2.contexts.chat.bottom-sheet-composer.handlers
|
||||
(:require [react-native.reanimated :as reanimated]
|
||||
[reagent.core :as reagent]
|
||||
[oops.core :as oops]
|
||||
[status-im2.contexts.chat.bottom-sheet-composer.constants :as constants]
|
||||
[status-im2.contexts.chat.bottom-sheet-composer.keyboard :as kb]
|
||||
[status-im2.contexts.chat.bottom-sheet-composer.utils :as utils]
|
||||
[utils.re-frame :as rf]))
|
||||
(ns status-im2.contexts.chat.composer.handlers
|
||||
(:require
|
||||
[react-native.core :as rn]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[reagent.core :as reagent]
|
||||
[oops.core :as oops]
|
||||
[status-im2.contexts.chat.composer.constants :as constants]
|
||||
[status-im2.contexts.chat.composer.keyboard :as kb]
|
||||
[status-im2.contexts.chat.composer.utils :as utils]
|
||||
[status-im2.contexts.chat.composer.selection :as selection]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn focus
|
||||
[{:keys [input-ref] :as props}
|
||||
@@ -53,7 +56,8 @@
|
||||
(reset! saved-cursor-position @cursor-position)
|
||||
(reset! gradient-z-index (if (= (reanimated/get-shared-value gradient-opacity) 1) -1 0))
|
||||
(when (not= reopen-height max-height)
|
||||
(reset! maximized? false))))
|
||||
(reset! maximized? false)
|
||||
(rf/dispatch [:chat.ui/set-input-maximized false]))))
|
||||
|
||||
(defn content-size-change
|
||||
[event
|
||||
@@ -70,7 +74,8 @@
|
||||
(reanimated/animate height new-height)
|
||||
(reanimated/set-shared-value saved-height new-height))
|
||||
(when (= new-height max-height)
|
||||
(reset! maximized? true))
|
||||
(reset! maximized? true)
|
||||
(rf/dispatch [:chat.ui/set-input-maximized true]))
|
||||
(if (utils/show-background? saved-height max-height new-height)
|
||||
(do
|
||||
(reanimated/set-shared-value background-y 0)
|
||||
@@ -82,10 +87,12 @@
|
||||
|
||||
(defn scroll
|
||||
[event
|
||||
{:keys [scroll-y]}
|
||||
{:keys [gradient-z-index focused?]}
|
||||
{:keys [gradient-opacity]}
|
||||
{:keys [lines max-lines]}]
|
||||
(let [y (oops/oget event "nativeEvent.contentOffset.y")]
|
||||
(reset! scroll-y y)
|
||||
(when (utils/show-top-gradient? y lines max-lines gradient-opacity focused?)
|
||||
(reset! gradient-z-index 1)
|
||||
(js/setTimeout #(reanimated/animate gradient-opacity 1) 0))
|
||||
@@ -105,12 +112,28 @@
|
||||
(when @recording?
|
||||
(@record-reset-fn)
|
||||
(reset! recording? false))
|
||||
(rf/dispatch [:chat.ui/set-chat-input-text text]))
|
||||
(rf/dispatch [:chat.ui/set-chat-input-text text])
|
||||
(rf/dispatch [:mention/on-change-text text]))
|
||||
|
||||
(defn selection-change
|
||||
[event {:keys [lock-selection? cursor-position]}]
|
||||
(when-not @lock-selection?
|
||||
(reset! cursor-position (oops/oget event "nativeEvent.selection.end"))))
|
||||
[event
|
||||
{:keys [input-ref selection-event selection-manager]}
|
||||
{:keys [lock-selection? cursor-position first-level? menu-items]}]
|
||||
(let [start (oops/oget event "nativeEvent.selection.start")
|
||||
end (oops/oget event "nativeEvent.selection.end")
|
||||
selection? (not= start end)
|
||||
text-input-handle (rn/find-node-handle @input-ref)]
|
||||
(when-not @lock-selection?
|
||||
(reset! cursor-position end))
|
||||
(when (and selection? (not @first-level?))
|
||||
(js/setTimeout #(oops/ocall selection-manager :startActionMode text-input-handle) 500))
|
||||
(when (and (not selection?) (not @first-level?))
|
||||
(oops/ocall selection-manager :hideLastActionMode)
|
||||
(selection/reset-to-first-level-menu first-level? menu-items))
|
||||
(when @selection-event
|
||||
(let [{:keys [start end text-input-handle]} @selection-event]
|
||||
(selection/update-selection text-input-handle start end)
|
||||
(reset! selection-event nil)))))
|
||||
|
||||
(defn layout
|
||||
[event
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
(ns status-im2.contexts.chat.bottom-sheet-composer.images.style
|
||||
(ns status-im2.contexts.chat.composer.images.style
|
||||
(:require [quo2.foundations.colors :as colors]))
|
||||
|
||||
(def image-container
|
||||
@@ -0,0 +1,47 @@
|
||||
(ns status-im2.contexts.chat.composer.images.view
|
||||
(:require [quo2.core :as quo]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[react-native.core :as rn]
|
||||
[react-native.gesture :as gesture]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[status-im2.contexts.chat.composer.images.style :as style]
|
||||
[utils.re-frame :as rf]
|
||||
[status-im2.contexts.chat.composer.constants :as constants]))
|
||||
|
||||
(defn image
|
||||
[item]
|
||||
[rn/view style/image-container
|
||||
[rn/image
|
||||
{:source {:uri (:resized-uri (val item))}
|
||||
:style style/small-image}]
|
||||
[rn/touchable-opacity
|
||||
{:on-press #(rf/dispatch [:chat.ui/image-unselected (val item)])
|
||||
:style style/remove-photo-container
|
||||
:hit-slop {:right 5
|
||||
:left 5
|
||||
:top 10
|
||||
:bottom 10}}
|
||||
[quo/icon :i/close {:color colors/white :size 12}]]])
|
||||
|
||||
(defn f-images-list
|
||||
[]
|
||||
(let [images (rf/sub [:chats/sending-image])
|
||||
height (reanimated/use-shared-value (if (seq images) constants/images-container-height 0))]
|
||||
(rn/use-effect (fn []
|
||||
(reanimated/animate height
|
||||
(if (seq images) constants/images-container-height 0)))
|
||||
[images])
|
||||
[reanimated/view
|
||||
{:style (reanimated/apply-animations-to-style {:height height} {:margin-horizontal -20})}
|
||||
[gesture/flat-list
|
||||
{:key-fn first
|
||||
:render-fn image
|
||||
:data images
|
||||
:content-container-style {:padding-horizontal 20}
|
||||
:horizontal true
|
||||
:shows-horizontal-scroll-indicator false
|
||||
:keyboard-should-persist-taps :handled}]]))
|
||||
|
||||
(defn images-list
|
||||
[]
|
||||
[:f> f-images-list])
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
(ns status-im2.contexts.chat.bottom-sheet-composer.keyboard
|
||||
(ns status-im2.contexts.chat.composer.keyboard
|
||||
(:require [oops.core :as oops]
|
||||
[status-im.async-storage.core :as async-storage]
|
||||
[react-native.core :as rn]
|
||||
@@ -0,0 +1,30 @@
|
||||
(ns status-im2.contexts.chat.composer.mentions.style
|
||||
(:require [quo2.foundations.colors :as colors]
|
||||
[react-native.platform :as platform]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[status-im2.contexts.chat.composer.constants :as constants]))
|
||||
|
||||
|
||||
(defn shadow
|
||||
[]
|
||||
(if platform/ios?
|
||||
{:shadow-radius (colors/theme-colors 30 50)
|
||||
:shadow-opacity (colors/theme-colors 0.1 0.7)
|
||||
:shadow-color colors/neutral-100
|
||||
:shadow-offset {:width 0 :height (colors/theme-colors 8 12)}}
|
||||
{:elevation 10}))
|
||||
|
||||
(defn container
|
||||
[opacity bottom]
|
||||
(reanimated/apply-animations-to-style
|
||||
{:opacity opacity}
|
||||
(merge
|
||||
{:position :absolute
|
||||
:bottom bottom
|
||||
:left 8
|
||||
:right 8
|
||||
:border-radius 16
|
||||
:z-index 4
|
||||
:max-height constants/mentions-max-height
|
||||
:background-color (colors/theme-colors colors/white colors/neutral-95)}
|
||||
(shadow))))
|
||||
@@ -0,0 +1,67 @@
|
||||
(ns status-im2.contexts.chat.composer.mentions.view
|
||||
(:require
|
||||
[react-native.hooks :as hooks]
|
||||
[react-native.platform :as platform]
|
||||
[react-native.safe-area :as safe-area]
|
||||
[reagent.core :as reagent]
|
||||
[status-im2.contexts.chat.composer.utils :as utils]
|
||||
[utils.re-frame :as rf]
|
||||
[react-native.core :as rn]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[status-im2.common.contact-list-item.view :as contact-list-item]
|
||||
[status-im2.contexts.chat.composer.mentions.style :as style]))
|
||||
|
||||
(defn update-cursor
|
||||
[user {:keys [cursor-position input-ref]}]
|
||||
(when platform/android?
|
||||
(let [new-cursor-pos (+ (count (:primary-name user)) @cursor-position 1)]
|
||||
(reset! cursor-position new-cursor-pos)
|
||||
(reagent/next-tick #(when @input-ref
|
||||
(.setNativeProps ^js @input-ref
|
||||
(clj->js {:selection {:start new-cursor-pos
|
||||
:end
|
||||
new-cursor-pos}})))))))
|
||||
|
||||
(defn mention-item
|
||||
[user _ _ render-data]
|
||||
[contact-list-item/contact-list-item
|
||||
{:on-press (fn []
|
||||
(rf/dispatch [:chat.ui/select-mention nil user])
|
||||
(update-cursor user render-data))}
|
||||
user])
|
||||
|
||||
(defn- f-view
|
||||
[suggestions-atom props state animations max-height cursor-pos]
|
||||
(let [{:keys [keyboard-height]} (hooks/use-keyboard)
|
||||
suggestions (rf/sub [:chat/mention-suggestions])
|
||||
opacity (reanimated/use-shared-value (if (seq suggestions) 1 0))
|
||||
size (count suggestions)
|
||||
data {:keyboard-height keyboard-height
|
||||
:insets (safe-area/get-insets)
|
||||
:curr-height (reanimated/get-shared-value (:height animations))
|
||||
:window-height (rf/sub [:dimensions/window-height])
|
||||
:reply (rf/sub [:chats/reply-message])
|
||||
:edit (rf/sub [:chats/edit-message])}
|
||||
mentions-pos (utils/calc-suggestions-position cursor-pos max-height size state data)]
|
||||
(rn/use-effect
|
||||
(fn []
|
||||
(if (seq suggestions)
|
||||
(reset! suggestions-atom suggestions)
|
||||
(js/setTimeout #(reset! suggestions-atom suggestions) 300))
|
||||
(reanimated/animate opacity (if (seq suggestions) 1 0)))
|
||||
[(seq suggestions)])
|
||||
[reanimated/view
|
||||
{:style (style/container opacity mentions-pos)}
|
||||
[rn/flat-list
|
||||
{:keyboard-should-persist-taps :always
|
||||
:data (vals @suggestions-atom)
|
||||
:key-fn :key
|
||||
:render-fn mention-item
|
||||
:render-data {:cursor-position (:cursor-position state)
|
||||
:input-ref (:input-ref props)}
|
||||
:accessibility-label :mentions-list}]]))
|
||||
|
||||
(defn view
|
||||
[props state animations max-height cursor-pos]
|
||||
(let [suggestions-atom (reagent/atom {})]
|
||||
[:f> f-view suggestions-atom props state animations max-height cursor-pos]))
|
||||
+8
-1
@@ -1,5 +1,12 @@
|
||||
(ns status-im2.contexts.chat.bottom-sheet-composer.reply.style)
|
||||
(ns status-im2.contexts.chat.composer.reply.style)
|
||||
|
||||
|
||||
(defn container
|
||||
[pin? in-chat-input?]
|
||||
{:flex-direction :row
|
||||
:height (when-not pin? 24)
|
||||
:margin-left (when (and (not in-chat-input?) (not pin?)) 26)
|
||||
:margin-bottom (when (and (not in-chat-input?) (not pin?)) 8)})
|
||||
(defn reply-content
|
||||
[pin?]
|
||||
{:padding-right (when-not pin? 10)
|
||||
+7
-8
@@ -1,15 +1,15 @@
|
||||
(ns status-im2.contexts.chat.bottom-sheet-composer.reply.view
|
||||
(ns status-im2.contexts.chat.composer.reply.view
|
||||
(:require [clojure.string :as string]
|
||||
[react-native.core :as rn]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[status-im2.contexts.chat.bottom-sheet-composer.constants :as constants]
|
||||
[status-im2.contexts.chat.composer.constants :as constants]
|
||||
[utils.i18n :as i18n]
|
||||
[quo2.core :as quo]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[status-im2.constants :as constant]
|
||||
[status-im.ethereum.stateofus :as stateofus]
|
||||
[utils.re-frame :as rf]
|
||||
[status-im2.contexts.chat.bottom-sheet-composer.reply.style :as style]
|
||||
[status-im2.contexts.chat.composer.reply.style :as style]
|
||||
[react-native.linear-gradient :as linear-gradient]))
|
||||
|
||||
(defn get-quoted-text-with-mentions
|
||||
@@ -78,7 +78,7 @@
|
||||
:style style/message-author-text}
|
||||
(format-reply-author from contact-name current-public-key)]]))
|
||||
|
||||
(defn reply-message
|
||||
(defn quoted-message
|
||||
[{:keys [from identicon content-type contentType parsed-text content deleted? deleted-for-me?
|
||||
album-images-count]}
|
||||
in-chat-input? pin? recording-audio?]
|
||||
@@ -86,9 +86,8 @@
|
||||
current-public-key (rf/sub [:multiaccount/public-key])
|
||||
content-type (or content-type contentType)]
|
||||
[rn/view
|
||||
{:style {:flex-direction :row
|
||||
:height (when-not pin? 24)
|
||||
:accessibility-label :reply-message}}
|
||||
{:style (style/container pin? in-chat-input?)
|
||||
:accessibility-label :reply-message}
|
||||
[rn/view {:style (style/reply-content pin?)}
|
||||
(when-not pin?
|
||||
[quo/icon :i/connector
|
||||
@@ -148,7 +147,7 @@
|
||||
height (reanimated/use-shared-value (if reply constants/reply-container-height 0))]
|
||||
(rn/use-effect #(reanimated/animate height (if reply constants/reply-container-height 0)) [reply])
|
||||
[reanimated/view {:style (reanimated/apply-animations-to-style {:height height} {})}
|
||||
(when reply [reply-message reply true false recording?])]))
|
||||
(when reply [quoted-message reply true false recording?])]))
|
||||
|
||||
(defn view
|
||||
[{:keys [recording?]}]
|
||||
@@ -0,0 +1,109 @@
|
||||
(ns status-im2.contexts.chat.composer.selection
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[react-native.clipboard :as clipboard]
|
||||
[react-native.core :as rn]
|
||||
[oops.core :as oops]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(declare first-level-menu-items second-level-menu-items)
|
||||
|
||||
(defn update-input-text
|
||||
[{:keys [text-input]} text]
|
||||
(rf/dispatch [:chat.ui/set-chat-input-text text])
|
||||
(.setNativeProps ^js text-input (clj->js {:text text})))
|
||||
|
||||
(defn calculate-input-text
|
||||
[{:keys [full-text selection-start selection-end]} content]
|
||||
(let [head (subs full-text 0 selection-start)
|
||||
tail (subs full-text selection-end)]
|
||||
(str head content tail)))
|
||||
|
||||
(defn update-selection
|
||||
[text-input-handle selection-start selection-end]
|
||||
;; to avoid something like this
|
||||
;; https://lightrun.com/answers/facebook-react-native-textinput-controlled-selection-broken-on-both-ios-and-android
|
||||
;; use native invoke instead! do not use setNativeProps! e.g. (.setNativeProps ^js text-input (clj->js
|
||||
;; {:selection {:start selection-start :end selection-end}}))
|
||||
(let [manager (rn/selectable-text-input-manager)]
|
||||
(oops/ocall manager :setSelection text-input-handle selection-start selection-end)))
|
||||
|
||||
(defn reset-to-first-level-menu
|
||||
[first-level? menu-items]
|
||||
(reset! first-level? true)
|
||||
(reset! menu-items first-level-menu-items))
|
||||
|
||||
(defn append-markdown-char
|
||||
[{:keys [first-level? menu-items content selection-start selection-end text-input-handle
|
||||
selection-event]
|
||||
:as params} wrap-chars]
|
||||
(let [content (str wrap-chars content wrap-chars)
|
||||
new-text (calculate-input-text params content)
|
||||
len-wrap-chars (count wrap-chars)
|
||||
selection-start (+ selection-start len-wrap-chars)
|
||||
selection-end (+ selection-end len-wrap-chars)]
|
||||
;; don't update selection directly here, process it within on-selection-change instead
|
||||
;; so that we can avoid java.lang.IndexOutOfBoundsException: setSpan..
|
||||
(reset! selection-event {:start selection-start
|
||||
:end selection-end
|
||||
:text-input-handle text-input-handle})
|
||||
(update-input-text params new-text)
|
||||
(reset-to-first-level-menu first-level? menu-items)))
|
||||
|
||||
(def first-level-menus
|
||||
{:cut (fn [{:keys [content] :as params}]
|
||||
(let [new-text (calculate-input-text params "")]
|
||||
(clipboard/set-string content)
|
||||
(update-input-text params new-text)))
|
||||
|
||||
:copy-to-clipboard (fn [{:keys [content]}]
|
||||
(clipboard/set-string content))
|
||||
|
||||
:paste (fn [params]
|
||||
(let [callback (fn [paste-content]
|
||||
(let [content (string/trim paste-content)
|
||||
new-text (calculate-input-text params content)]
|
||||
(update-input-text params new-text)))]
|
||||
(clipboard/get-string callback)))
|
||||
|
||||
:biu (fn [{:keys [first-level? text-input-handle menu-items selection-start
|
||||
selection-end]}]
|
||||
(reset! first-level? false)
|
||||
(reset! menu-items second-level-menu-items)
|
||||
(update-selection text-input-handle selection-start selection-end))})
|
||||
|
||||
(def first-level-menu-items (map i18n/label (keys first-level-menus)))
|
||||
(def second-level-menus
|
||||
{:bold #(append-markdown-char % "**")
|
||||
|
||||
:italic #(append-markdown-char % "*")
|
||||
|
||||
:strikethrough #(append-markdown-char % "~~")})
|
||||
|
||||
(def second-level-menu-items (map i18n/label (keys second-level-menus)))
|
||||
|
||||
(defn on-menu-item-touched
|
||||
[{:keys [first-level? event-type] :as params}]
|
||||
(let [menus (if @first-level? first-level-menus second-level-menus)
|
||||
menu-item-key (nth (keys menus) event-type)
|
||||
action (get menus menu-item-key)]
|
||||
(action params)))
|
||||
|
||||
(defn on-selection
|
||||
[event
|
||||
{:keys [input-ref selection-event]}
|
||||
{:keys [first-level? menu-items]}]
|
||||
(let [{:strs [eventType content selectionStart
|
||||
selectionEnd]} (js->clj (oops/oget event "nativeEvent"))
|
||||
full-text (:input-text (rf/sub [:chats/current-chat-input]))]
|
||||
(on-menu-item-touched {:first-level? first-level?
|
||||
:event-type eventType
|
||||
:content content
|
||||
:selection-start selectionStart
|
||||
:selection-end selectionEnd
|
||||
:text-input @input-ref
|
||||
:text-input-handle (rn/find-node-handle @input-ref)
|
||||
:full-text full-text
|
||||
:menu-items menu-items
|
||||
:selection-event selection-event})))
|
||||
+18
-15
@@ -1,9 +1,9 @@
|
||||
(ns status-im2.contexts.chat.bottom-sheet-composer.style
|
||||
(ns status-im2.contexts.chat.composer.style
|
||||
(:require [quo2.foundations.colors :as colors]
|
||||
[quo2.foundations.typography :as typography]
|
||||
[react-native.platform :as platform]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[status-im2.contexts.chat.bottom-sheet-composer.constants :as constants]))
|
||||
[status-im2.contexts.chat.composer.constants :as constants]))
|
||||
|
||||
(defn shadow
|
||||
[focused?]
|
||||
@@ -54,20 +54,23 @@
|
||||
{:max-height max-height
|
||||
:overflow :hidden}))
|
||||
|
||||
(defn input
|
||||
(defn input-view
|
||||
[{:keys [saved-emoji-kb-extra-height]}
|
||||
{:keys [focused? recording?]}]
|
||||
{:z-index 1
|
||||
:position (if @saved-emoji-kb-extra-height :relative :absolute)
|
||||
:top 0
|
||||
:left 0
|
||||
:right (when (or focused? platform/ios?) 0)
|
||||
:flex 1
|
||||
:display (if @recording? :none :flex)
|
||||
:min-height constants/input-height})
|
||||
|
||||
(defn input-text
|
||||
[]
|
||||
(merge typography/paragraph-1
|
||||
{:min-height constants/input-height
|
||||
:color (colors/theme-colors :black :white)
|
||||
:text-align-vertical :top
|
||||
:flex 1
|
||||
:z-index 1
|
||||
:position (if @saved-emoji-kb-extra-height :relative :absolute)
|
||||
:top 0
|
||||
:left 0
|
||||
:right (when (or focused? platform/ios?) 0)
|
||||
:display (if @recording? :none :flex)}))
|
||||
{:color (colors/theme-colors :black :white)
|
||||
:text-align-vertical :top}))
|
||||
(defn background
|
||||
[opacity background-y window-height]
|
||||
(reanimated/apply-animations-to-style
|
||||
@@ -82,11 +85,11 @@
|
||||
:z-index 1}))
|
||||
|
||||
(defn blur-container
|
||||
[height]
|
||||
[height focused?]
|
||||
(reanimated/apply-animations-to-style
|
||||
{:height height}
|
||||
{:position :absolute
|
||||
:elevation 10
|
||||
:elevation (if-not @focused? 10 0)
|
||||
:left 0
|
||||
:right 0
|
||||
:bottom 0
|
||||
@@ -0,0 +1,19 @@
|
||||
(ns status-im2.contexts.chat.composer.sub-view
|
||||
(:require
|
||||
[react-native.blur :as blur]
|
||||
[react-native.core :as rn]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[status-im2.contexts.chat.composer.style :as style]))
|
||||
|
||||
(defn bar
|
||||
[]
|
||||
[rn/view {:style style/bar-container}
|
||||
[rn/view {:style (style/bar)}]])
|
||||
|
||||
(defn f-blur-view
|
||||
[layout-height focused?]
|
||||
[reanimated/view {:style (style/blur-container layout-height focused?)}
|
||||
[blur/view (style/blur-view)]])
|
||||
(defn blur-view
|
||||
[layout-height focused?]
|
||||
[:f> f-blur-view layout-height focused?])
|
||||
@@ -0,0 +1,190 @@
|
||||
(ns status-im2.contexts.chat.composer.utils
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[oops.core :as oops]
|
||||
[react-native.core :as rn]
|
||||
[react-native.platform :as platform]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[reagent.core :as reagent]
|
||||
[status-im2.contexts.chat.composer.constants :as constants]
|
||||
[status-im2.contexts.chat.composer.selection :as selection]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn bounded-val
|
||||
[val min-val max-val]
|
||||
(max min-val (min val max-val)))
|
||||
|
||||
(defn get-min-height
|
||||
[lines]
|
||||
(if (> lines 1) constants/multiline-minimized-height constants/input-height))
|
||||
|
||||
(defn calc-reopen-height
|
||||
[text-value min-height content-height saved-height]
|
||||
(if (empty? @text-value)
|
||||
min-height
|
||||
(Math/min @content-height (reanimated/get-shared-value saved-height))))
|
||||
|
||||
(defn update-height?
|
||||
[content-size height max-height maximized?]
|
||||
(when-not @maximized?
|
||||
(let [diff (Math/abs (- content-size (reanimated/get-shared-value height)))]
|
||||
(and (not= (reanimated/get-shared-value height) max-height)
|
||||
(> diff constants/content-change-threshold)))))
|
||||
|
||||
(defn show-top-gradient?
|
||||
[y lines max-lines gradient-opacity focused?]
|
||||
(and
|
||||
(> y constants/line-height)
|
||||
(>= lines max-lines)
|
||||
(= (reanimated/get-shared-value gradient-opacity) 0)
|
||||
@focused?))
|
||||
|
||||
(defn hide-top-gradient?
|
||||
[y gradient-opacity]
|
||||
(and
|
||||
(<= y constants/line-height)
|
||||
(= (reanimated/get-shared-value gradient-opacity) 1)))
|
||||
|
||||
(defn show-bottom-gradient?
|
||||
[{:keys [text-value focused?]} {:keys [lines]}]
|
||||
(and (not-empty @text-value) (not @focused?) (> lines 2)))
|
||||
|
||||
(defn show-background?
|
||||
[saved-height max-height new-height]
|
||||
(or (= (reanimated/get-shared-value saved-height) max-height)
|
||||
(> new-height (* constants/background-threshold max-height))))
|
||||
|
||||
(defn update-blur-height?
|
||||
[event lock-layout? layout-height]
|
||||
(or (not @lock-layout?)
|
||||
(> (reanimated/get-shared-value layout-height) (oops/oget event "nativeEvent.layout.height"))))
|
||||
|
||||
(defn calc-lines
|
||||
[height]
|
||||
(let [lines (Math/round (/ height constants/line-height))]
|
||||
(if platform/ios? lines (dec lines))))
|
||||
|
||||
(defn calc-max-height
|
||||
[window-height kb-height insets images? reply? edit?]
|
||||
(let [margin-top (if platform/ios? (:top insets) (+ 10 (:top insets)))
|
||||
max-height (- window-height
|
||||
margin-top
|
||||
kb-height
|
||||
constants/bar-container-height
|
||||
constants/actions-container-height)
|
||||
max-height (if images? (- max-height constants/images-container-height) max-height)
|
||||
max-height (if reply? (- max-height constants/reply-container-height) max-height)
|
||||
max-height (if edit? (- max-height constants/edit-container-height) max-height)]
|
||||
max-height))
|
||||
|
||||
(defn empty-input?
|
||||
[text images reply? audio?]
|
||||
(and (empty? text) (empty? images) (not reply?) (not audio?)))
|
||||
|
||||
(defn android-elevation?
|
||||
[lines images reply? edit?]
|
||||
(or (> lines 1) (seq images) reply? edit?))
|
||||
|
||||
(defn cancel-edit-message
|
||||
[{:keys [text-value]}]
|
||||
(reset! text-value "")
|
||||
(rf/dispatch [:chat.ui/set-input-content-height constants/input-height]))
|
||||
|
||||
(defn count-lines
|
||||
[s]
|
||||
(-> s
|
||||
(string/split #"\n" -1)
|
||||
(butlast)
|
||||
count))
|
||||
|
||||
(defn cursor-y-position-relative-to-container
|
||||
[{:keys [scroll-y]}
|
||||
{:keys [cursor-position text-value]}]
|
||||
(let [sub-text (subs @text-value 0 @cursor-position)
|
||||
sub-text-lines (count-lines sub-text)
|
||||
scrolled-lines (Math/round (/ @scroll-y constants/line-height))
|
||||
sub-text-lines-in-view (- sub-text-lines scrolled-lines)]
|
||||
(* sub-text-lines-in-view constants/line-height)))
|
||||
|
||||
(defn calc-suggestions-position
|
||||
[cursor-pos max-height size
|
||||
{:keys [maximized?]}
|
||||
{:keys [insets curr-height window-height keyboard-height edit reply]}]
|
||||
(let [base (+ constants/composer-default-height (:bottom insets) 8)
|
||||
base (+ base (- curr-height constants/input-height))
|
||||
base (if edit
|
||||
(+ base constants/edit-container-height)
|
||||
base)
|
||||
base (if reply
|
||||
(+ base constants/reply-container-height)
|
||||
base)
|
||||
view-height (- window-height keyboard-height (:top insets))
|
||||
container-height (bounded-val
|
||||
(* (/ constants/mentions-max-height 4) size)
|
||||
(/ constants/mentions-max-height 4)
|
||||
constants/mentions-max-height)]
|
||||
(if @maximized?
|
||||
(if (< (+ cursor-pos container-height) max-height)
|
||||
(+ constants/actions-container-height (:bottom insets))
|
||||
(+ constants/actions-container-height (:bottom insets) (- max-height cursor-pos) 18))
|
||||
(if (< (+ base container-height) view-height)
|
||||
base
|
||||
(+ constants/actions-container-height (:bottom insets) (- curr-height cursor-pos) 18)))))
|
||||
|
||||
|
||||
(defn init-props
|
||||
[]
|
||||
{:input-ref (atom nil)
|
||||
:selectable-input-ref (atom nil)
|
||||
:keyboard-show-listener (atom nil)
|
||||
:keyboard-frame-listener (atom nil)
|
||||
:keyboard-hide-listener (atom nil)
|
||||
:emoji-kb-extra-height (atom nil)
|
||||
:saved-emoji-kb-extra-height (atom nil)
|
||||
:sending-images? (atom false)
|
||||
:record-reset-fn (atom nil)
|
||||
:scroll-y (atom 0)
|
||||
:selection-event (atom nil)
|
||||
:selection-manager (rn/selectable-text-input-manager)})
|
||||
|
||||
(defn init-state
|
||||
[]
|
||||
{:text-value (reagent/atom "")
|
||||
:cursor-position (reagent/atom 0)
|
||||
:saved-cursor-position (reagent/atom 0)
|
||||
:gradient-z-index (reagent/atom 0)
|
||||
:kb-default-height (reagent/atom nil)
|
||||
:gesture-enabled? (reagent/atom true)
|
||||
:lock-selection? (reagent/atom true)
|
||||
:focused? (reagent/atom false)
|
||||
:lock-layout? (reagent/atom false)
|
||||
:maximized? (reagent/atom false)
|
||||
:record-permission? (reagent/atom true)
|
||||
:recording? (reagent/atom false)
|
||||
:first-level? (reagent/atom true)
|
||||
:menu-items (reagent/atom selection/first-level-menu-items)})
|
||||
(defn init-animations
|
||||
[lines input-text images reply audio content-height max-height opacity background-y]
|
||||
(let [initial-height (if (> lines 1)
|
||||
constants/multiline-minimized-height
|
||||
constants/input-height)]
|
||||
{:gradient-opacity (reanimated/use-shared-value 0)
|
||||
:container-opacity (reanimated/use-shared-value
|
||||
(if (empty-input?
|
||||
input-text
|
||||
images
|
||||
reply
|
||||
audio)
|
||||
0.7
|
||||
1))
|
||||
:height (reanimated/use-shared-value
|
||||
initial-height)
|
||||
:saved-height (reanimated/use-shared-value
|
||||
initial-height)
|
||||
:last-height (reanimated/use-shared-value
|
||||
(bounded-val
|
||||
@content-height
|
||||
constants/input-height
|
||||
max-height))
|
||||
:opacity opacity
|
||||
:background-y background-y}))
|
||||
@@ -0,0 +1,144 @@
|
||||
(ns status-im2.contexts.chat.composer.view
|
||||
(:require
|
||||
[quo2.foundations.colors :as colors]
|
||||
[react-native.core :as rn]
|
||||
[react-native.gesture :as gesture]
|
||||
[react-native.hooks :as hooks]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[reagent.core :as reagent]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]
|
||||
[status-im2.contexts.chat.composer.style :as style]
|
||||
[status-im2.contexts.chat.composer.images.view :as images]
|
||||
[status-im2.contexts.chat.composer.reply.view :as reply]
|
||||
[status-im2.contexts.chat.composer.edit.view :as edit]
|
||||
[status-im2.contexts.chat.composer.mentions.view :as mentions]
|
||||
[status-im2.contexts.chat.composer.utils :as utils]
|
||||
[status-im2.contexts.chat.composer.constants :as constants]
|
||||
[status-im2.contexts.chat.composer.actions.view :as actions]
|
||||
[status-im2.contexts.chat.composer.keyboard :as kb]
|
||||
[status-im2.contexts.chat.composer.sub-view :as sub-view]
|
||||
[status-im2.contexts.chat.composer.effects :as effects]
|
||||
[status-im2.contexts.chat.composer.gesture :as drag-gesture]
|
||||
[status-im2.contexts.chat.composer.handlers :as handler]
|
||||
[status-im2.contexts.chat.composer.gradients.view :as gradients]
|
||||
[status-im2.contexts.chat.composer.selection :as selection]))
|
||||
|
||||
(defn sheet-component
|
||||
[{:keys [insets window-height blur-height opacity background-y]} props state]
|
||||
(let [images (rf/sub [:chats/sending-image])
|
||||
audio (rf/sub [:chats/sending-audio])
|
||||
reply (rf/sub [:chats/reply-message])
|
||||
edit (rf/sub [:chats/edit-message])
|
||||
input-with-mentions (rf/sub [:chat/input-with-mentions])
|
||||
{:keys [input-text input-content-height]
|
||||
:as chat-input} (rf/sub [:chats/current-chat-input])
|
||||
content-height (reagent/atom (or input-content-height
|
||||
constants/input-height))
|
||||
{:keys [keyboard-shown keyboard-height]} (hooks/use-keyboard)
|
||||
kb-height (kb/get-kb-height keyboard-height
|
||||
@(:kb-default-height state))
|
||||
max-height (utils/calc-max-height window-height
|
||||
kb-height
|
||||
insets
|
||||
(boolean (seq images))
|
||||
reply
|
||||
edit)
|
||||
lines (utils/calc-lines @content-height)
|
||||
max-lines (utils/calc-lines max-height)
|
||||
animations (utils/init-animations
|
||||
lines
|
||||
input-text
|
||||
images
|
||||
reply
|
||||
audio
|
||||
content-height
|
||||
max-height
|
||||
opacity
|
||||
background-y)
|
||||
dimensions {:content-height content-height
|
||||
:max-height max-height
|
||||
:window-height window-height
|
||||
:lines lines
|
||||
:max-lines max-lines}
|
||||
show-bottom-gradient? (utils/show-bottom-gradient? state dimensions)
|
||||
cursor-pos (utils/cursor-y-position-relative-to-container props
|
||||
state)]
|
||||
(effects/did-mount props)
|
||||
(effects/initialize props
|
||||
state
|
||||
animations
|
||||
dimensions
|
||||
chat-input
|
||||
keyboard-height
|
||||
(boolean (seq images))
|
||||
reply
|
||||
audio)
|
||||
(effects/edit-effect props state edit)
|
||||
(effects/reply-effect props animations reply)
|
||||
(effects/update-input-mention props state input-text)
|
||||
(effects/edit-mentions props state input-with-mentions)
|
||||
[:<>
|
||||
[mentions/view props state animations max-height cursor-pos]
|
||||
[gesture/gesture-detector
|
||||
{:gesture (drag-gesture/drag-gesture props state animations dimensions keyboard-shown)}
|
||||
[reanimated/view
|
||||
{:style (style/sheet-container insets state animations)
|
||||
:on-layout #(handler/layout % state blur-height)}
|
||||
[sub-view/bar]
|
||||
[reply/view state]
|
||||
[edit/view state]
|
||||
[reanimated/touchable-opacity
|
||||
{:active-opacity 1
|
||||
:on-press (when @(:input-ref props) #(.focus ^js @(:input-ref props)))
|
||||
:style (style/input-container (:height animations) max-height)
|
||||
:accessibility-label :message-input-container}
|
||||
[rn/selectable-text-input
|
||||
{:ref #(reset! (:selectable-input-ref props) %)
|
||||
:menu-items @(:menu-items state)
|
||||
:style (style/input-view props state)}
|
||||
[rn/text-input
|
||||
{:ref #(reset! (:input-ref props) %)
|
||||
:default-value @(:text-value state)
|
||||
:on-focus #(handler/focus props state animations dimensions)
|
||||
:on-blur #(handler/blur state animations dimensions images reply)
|
||||
:on-content-size-change #(handler/content-size-change %
|
||||
state
|
||||
animations
|
||||
dimensions
|
||||
(or keyboard-shown edit))
|
||||
:on-scroll #(handler/scroll % props state animations dimensions)
|
||||
:on-change-text #(handler/change-text % props state)
|
||||
:on-selection-change #(handler/selection-change % props state)
|
||||
:on-selection #(selection/on-selection % props state)
|
||||
:max-height max-height
|
||||
:max-font-size-multiplier 1
|
||||
:multiline true
|
||||
:placeholder (i18n/label :t/type-something)
|
||||
:placeholder-text-color (colors/theme-colors colors/neutral-40 colors/neutral-50)
|
||||
:style (style/input-text)
|
||||
:max-length constants/max-text-size
|
||||
:accessibility-label :chat-message-input}]]
|
||||
[gradients/view props state animations show-bottom-gradient?]]
|
||||
[images/images-list]
|
||||
[actions/view props state animations window-height insets edit
|
||||
(boolean (seq images))]]]]))
|
||||
|
||||
(defn composer
|
||||
[insets]
|
||||
(let [window-height (rf/sub [:dimensions/window-height])
|
||||
opacity (reanimated/use-shared-value 0)
|
||||
background-y (reanimated/use-shared-value (- window-height))
|
||||
blur-height (reanimated/use-shared-value (+ constants/composer-default-height
|
||||
(:bottom insets)))
|
||||
extra-params {:insets insets
|
||||
:window-height window-height
|
||||
:blur-height blur-height
|
||||
:opacity opacity
|
||||
:background-y background-y}
|
||||
props (utils/init-props)
|
||||
state (utils/init-state)]
|
||||
[rn/view
|
||||
[reanimated/view {:style (style/background opacity background-y window-height)}]
|
||||
[sub-view/blur-view blur-height (:focused? state)]
|
||||
[:f> sheet-component extra-params props state]]))
|
||||
@@ -1,12 +1,14 @@
|
||||
(ns status-im2.contexts.chat.home.chat-list-item.view
|
||||
(:require [clojure.string :as string]
|
||||
[quo2.core :as quo]
|
||||
(:require [quo2.core :as quo]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[react-native.core :as rn]
|
||||
[utils.datetime :as datetime]
|
||||
[status-im2.common.home.actions.view :as actions] ;;TODO move to status-im2
|
||||
[status-im2.common.home.actions.view :as actions]
|
||||
[status-im2.contexts.chat.home.chat-list-item.style :as style]
|
||||
[utils.re-frame :as rf]))
|
||||
[utils.re-frame :as rf]
|
||||
[status-im2.constants :as constants]
|
||||
[clojure.string :as string]
|
||||
[utils.i18n :as i18n]))
|
||||
|
||||
(def max-subheader-length 50)
|
||||
|
||||
@@ -16,61 +18,149 @@
|
||||
(rf/dispatch [:dismiss-keyboard])
|
||||
(rf/dispatch [:chat/navigate-to-chat chat-id])))
|
||||
|
||||
(defn truncate-literal
|
||||
[literal]
|
||||
(when literal
|
||||
(let [size (min max-subheader-length (.-length literal))]
|
||||
{:components (.substring literal 0 size)
|
||||
:length size})))
|
||||
|
||||
(defn add-parsed-to-subheader
|
||||
[acc {:keys [type destination literal children]}]
|
||||
(let [result (case type
|
||||
"paragraph"
|
||||
(reduce
|
||||
(fn [{:keys [_ length] :as acc-paragraph} parsed-child]
|
||||
(if (>= length max-subheader-length)
|
||||
(reduced acc-paragraph)
|
||||
(add-parsed-to-subheader acc-paragraph parsed-child)))
|
||||
{:components [quo/text]
|
||||
:length 0}
|
||||
children)
|
||||
|
||||
"mention"
|
||||
{:components [quo/text (rf/sub [:messages/resolve-mention literal])]
|
||||
:length 4} ;; we can't predict name length so take the
|
||||
;; smallest possible
|
||||
|
||||
"status-tag"
|
||||
(truncate-literal (str "#" literal))
|
||||
|
||||
"link"
|
||||
(truncate-literal destination)
|
||||
|
||||
(truncate-literal literal))]
|
||||
{:components (conj (:components acc) (:components result))
|
||||
:length (+ (:length acc) (:length result))}))
|
||||
|
||||
(defn render-subheader
|
||||
"Render the preview of a last message to a maximum of max-subheader-length characters"
|
||||
(defn parsed-text-to-one-line
|
||||
[parsed-text]
|
||||
(let [result
|
||||
(reduce
|
||||
(fn [{:keys [_ length] :as acc-text} new-text-chunk]
|
||||
(if (>= length max-subheader-length)
|
||||
(reduced acc-text)
|
||||
(add-parsed-to-subheader acc-text new-text-chunk)))
|
||||
{:components [quo/text
|
||||
{:size :paragraph-2
|
||||
:style {:color (colors/theme-colors colors/neutral-50
|
||||
colors/neutral-40)
|
||||
:width "90%"}
|
||||
:number-of-lines 1
|
||||
:ellipsize-mode :tail
|
||||
:accessibility-label :chat-message-text}]
|
||||
:length 0}
|
||||
parsed-text)]
|
||||
(:components result)))
|
||||
(reduce
|
||||
(fn [acc {:keys [type literal children destination]}]
|
||||
(case type
|
||||
"paragraph"
|
||||
(str acc (parsed-text-to-one-line children) " ")
|
||||
|
||||
"mention"
|
||||
(str acc "@" (rf/sub [:messages/resolve-mention literal]))
|
||||
|
||||
"status-tag"
|
||||
(str acc literal)
|
||||
|
||||
"link"
|
||||
(str acc destination)
|
||||
|
||||
(str acc (string/replace literal #"\n" " "))))
|
||||
""
|
||||
parsed-text))
|
||||
|
||||
(defn extract-text-from-message
|
||||
[{:keys [content]}]
|
||||
(let [{:keys [parsed-text text]} content]
|
||||
(if parsed-text
|
||||
(parsed-text-to-one-line parsed-text)
|
||||
(if text
|
||||
(string/replace text #"\n" " ")
|
||||
text))))
|
||||
|
||||
(defn preview-text-from-content
|
||||
[group-chat primary-name {:keys [content-type album-images-count content outgoing] :as message}]
|
||||
(let [content-text (extract-text-from-message message)
|
||||
reply? (not (string/blank? (:response-to content)))
|
||||
author (if outgoing
|
||||
:you
|
||||
(if group-chat
|
||||
:other-person
|
||||
:dont-show))
|
||||
preview-text
|
||||
(case content-type
|
||||
constants/content-type-text
|
||||
(if reply?
|
||||
(case author
|
||||
:you (str (i18n/label :t/you-replied) ": " content-text)
|
||||
:other-person (str (i18n/label :t/user-replied {:user primary-name}) ": " content-text)
|
||||
:dont-show (str (i18n/label :t/replied) ": " content-text)
|
||||
(str (i18n/label :t/replied) ": " content-text))
|
||||
(case author
|
||||
:you (str (i18n/label :t/You) ": " content-text)
|
||||
:other-person (str primary-name ": " content-text)
|
||||
:dont-show content-text
|
||||
content-text))
|
||||
|
||||
constants/content-type-emoji
|
||||
(case author
|
||||
:you (str (i18n/label :t/You) ": " content-text)
|
||||
:other-person (str primary-name ": " content-text)
|
||||
:dont-show content-text
|
||||
content-text)
|
||||
|
||||
constants/content-type-system-text
|
||||
(case author
|
||||
:you (i18n/label :t/you-pinned-a-message)
|
||||
:other-person (i18n/label :t/user-pinned-a-message {:user primary-name})
|
||||
:dont-show (i18n/label :t/Pinned-a-message)
|
||||
(i18n/label :t/Pinned-a-message))
|
||||
|
||||
constants/content-type-sticker
|
||||
(case author
|
||||
:you (i18n/label :t/you-sent-a-sticker)
|
||||
:other-person (i18n/label :t/user-sent-a-sticker {:user primary-name})
|
||||
:dont-show (i18n/label :t/sent-a-sticker)
|
||||
(i18n/label :t/sent-a-sticker))
|
||||
|
||||
constants/content-type-image
|
||||
(let [sent-photos (if album-images-count
|
||||
(case author
|
||||
:you (i18n/label :t/you-sent-n-photos
|
||||
{:number album-images-count})
|
||||
:other-person (i18n/label :t/user-sent-n-photos
|
||||
{:number album-images-count
|
||||
:user primary-name})
|
||||
:dont-show (i18n/label :t/sent-n-photos {:number album-images-count})
|
||||
(i18n/label :t/sent-n-photos {:number album-images-count}))
|
||||
(case author
|
||||
:you (i18n/label :t/you-sent-a-photo)
|
||||
:other-person (i18n/label :t/user-sent-a-photo {:user primary-name})
|
||||
:dont-show (i18n/label :t/sent-a-photo)
|
||||
(i18n/label :t/sent-a-photo)))]
|
||||
(if (not (string/blank? content-text))
|
||||
(str sent-photos ": " content-text)
|
||||
sent-photos))
|
||||
|
||||
constants/content-type-audio
|
||||
(case author
|
||||
:you (i18n/label :t/you-sent-audio-message)
|
||||
:other-person (i18n/label :t/user-sent-audio-message {:user primary-name})
|
||||
:dont-show (i18n/label :t/sent-audio-message)
|
||||
(i18n/label :t/sent-audio-message))
|
||||
|
||||
constants/content-type-gif
|
||||
(case author
|
||||
:you (i18n/label :t/you-sent-a-gif)
|
||||
:other-person (i18n/label :t/user-sent-audio-message {:user primary-name})
|
||||
:dont-show (i18n/label :t/sent-a-gif)
|
||||
(i18n/label :t/sent-a-gif))
|
||||
|
||||
constants/content-type-community
|
||||
(case author
|
||||
:you (i18n/label :t/you-shared-a-community)
|
||||
:other-person (i18n/label :t/user-shared-a-community {:user primary-name})
|
||||
:dont-show (i18n/label :t/shared-a-community)
|
||||
(i18n/label :t/shared-a-community))
|
||||
|
||||
"")]
|
||||
(subs preview-text 0 (min (count preview-text) max-subheader-length))))
|
||||
|
||||
|
||||
(defn last-message-preview
|
||||
"Render the preview of a last message to a maximum of max-subheader-length characters"
|
||||
[group-chat {:keys [deleted? outgoing from deleted-for-me?] :as message}]
|
||||
(let [[primary-name _] (rf/sub [:contacts/contact-two-names-by-identity from])
|
||||
preview-text (if deleted-for-me?
|
||||
(i18n/label :t/you-deleted-a-message)
|
||||
(if deleted?
|
||||
(if outgoing
|
||||
(i18n/label :t/you-deleted-a-message)
|
||||
(if group-chat
|
||||
(i18n/label :t/user-deleted-a-message {:user primary-name})
|
||||
(i18n/label :t/this-message-was-deleted)))
|
||||
(preview-text-from-content group-chat primary-name message)))]
|
||||
[quo/text
|
||||
{:size :paragraph-2
|
||||
:style {:color (colors/theme-colors colors/neutral-50
|
||||
colors/neutral-40)
|
||||
:flex 1
|
||||
:margin-right 20}
|
||||
:number-of-lines 1
|
||||
:ellipsize-mode :tail
|
||||
:accessibility-label :chat-message-text}
|
||||
preview-text]))
|
||||
|
||||
|
||||
(defn verified-or-contact-icon
|
||||
[{:keys [ens-verified added?]}]
|
||||
@@ -136,12 +226,7 @@
|
||||
:color color}]
|
||||
[rn/view {:style {:margin-left 8}}
|
||||
[name-view display-name contact timestamp]
|
||||
(if (string/blank? (get-in last-message [:content :parsed-text]))
|
||||
[quo/text
|
||||
{:size :paragraph-2
|
||||
:style {:color (colors/theme-colors colors/neutral-50 colors/neutral-40)}}
|
||||
(get-in last-message [:content :text])]
|
||||
[render-subheader (get-in last-message [:content :parsed-text])])]
|
||||
[last-message-preview group-chat last-message]]
|
||||
(when-not muted
|
||||
(if (> unviewed-mentions-count 0)
|
||||
[quo/info-count {:style {:top 16}}
|
||||
|
||||
@@ -56,8 +56,7 @@
|
||||
:start {:x 0 :y 1}
|
||||
:end {:x 0 :y 0}
|
||||
:style (style/gradient-container insets animations derived)}
|
||||
(when (not= text "placeholder")
|
||||
[rn/text {:style style/text-style} text])
|
||||
[rn/text {:style style/text-style} text]
|
||||
[rn/flat-list
|
||||
{:ref #(reset! (:small-list-ref atoms) %)
|
||||
:key-fn :message-id
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
(ns status-im2.contexts.chat.messages.composer.controls.style
|
||||
(:require [quo2.foundations.colors :as colors]))
|
||||
|
||||
(defn controls
|
||||
[bottom-inset]
|
||||
{:padding-horizontal 20
|
||||
:z-index 3
|
||||
:position :absolute
|
||||
:background-color (colors/theme-colors colors/white colors/neutral-90)
|
||||
:padding-bottom (+ 12 bottom-inset)
|
||||
:bottom 0
|
||||
:left 0
|
||||
:right 0})
|
||||
|
||||
(def buttons-container
|
||||
{:flex-direction :row
|
||||
:margin-top 12
|
||||
:min-height 32})
|
||||
|
||||
(defn record-audio-container
|
||||
[bottom-inset]
|
||||
{:align-items :center
|
||||
:background-color :transparent
|
||||
:flex-direction :row
|
||||
:position :absolute
|
||||
:left 0
|
||||
:right 0
|
||||
:bottom (- bottom-inset 7)})
|
||||
@@ -1,127 +0,0 @@
|
||||
(ns status-im2.contexts.chat.messages.composer.controls.view
|
||||
(:require [react-native.core :as rn]
|
||||
[react-native.background-timer :as background-timer]
|
||||
[utils.re-frame :as rf]
|
||||
[utils.i18n :as i18n]
|
||||
[quo2.core :as quo]
|
||||
[status-im2.common.not-implemented :as not-implemented]
|
||||
[status-im2.contexts.chat.messages.composer.controls.style :as style]
|
||||
[status-im2.contexts.chat.messages.list.view :as messages.list]
|
||||
[status-im.ui2.screens.chat.composer.images.view :as composer-images]
|
||||
[status-im.utils.utils :as utils-old]
|
||||
[status-im.ui2.screens.chat.composer.input :as input]
|
||||
[status-im2.common.alert.events :as alert]
|
||||
[react-native.permissions :as permissions]
|
||||
[quo.react :as quo.react]))
|
||||
|
||||
(defn send-button
|
||||
[send-ref {:keys [chat-id images]} on-send]
|
||||
[rn/view
|
||||
{:ref send-ref
|
||||
:style (when-not (or (seq (get @input/input-texts chat-id)) (seq images))
|
||||
{:width 0
|
||||
:right -100})}
|
||||
[quo/button
|
||||
{:icon true
|
||||
:size 32
|
||||
:accessibility-label :send-message-button
|
||||
:on-press (fn []
|
||||
(on-send)
|
||||
(messages.list/scroll-to-bottom)
|
||||
(rf/dispatch [:chat.ui/send-current-message]))}
|
||||
:i/arrow-up]])
|
||||
|
||||
(defn reactions-button
|
||||
[]
|
||||
[not-implemented/not-implemented
|
||||
[quo/button
|
||||
{:icon true
|
||||
:type :outline
|
||||
:size 32} :i/reaction]])
|
||||
|
||||
(defn image-button
|
||||
[insets]
|
||||
[quo/button
|
||||
{:on-press (fn []
|
||||
(permissions/request-permissions
|
||||
{:permissions [:read-external-storage :write-external-storage]
|
||||
:on-allowed #(rf/dispatch [:open-modal :photo-selector {:insets insets}])
|
||||
:on-denied (fn []
|
||||
(background-timer/set-timeout
|
||||
#(utils-old/show-popup (i18n/label :t/error)
|
||||
(i18n/label
|
||||
:t/external-storage-denied))
|
||||
50))}))
|
||||
:icon true
|
||||
:type :outline
|
||||
:size 32}
|
||||
:i/image])
|
||||
|
||||
(defn record-audio
|
||||
[record-ref chat-id bottom-inset]
|
||||
[rn/view
|
||||
{:ref record-ref
|
||||
:style (style/record-audio-container bottom-inset)
|
||||
:pointer-events :box-none}
|
||||
[quo/record-audio
|
||||
{:record-audio-permission-granted @input/record-audio-permission-granted
|
||||
:on-init (fn [init-fn]
|
||||
(reset! input/record-audio-reset-fn init-fn)
|
||||
(reset! input/recording-audio?
|
||||
(some? (get @input/reviewing-audio-filepath chat-id)))
|
||||
(when (seq (get @input/input-texts chat-id))
|
||||
(js/setTimeout #(quo.react/set-native-props
|
||||
record-ref
|
||||
#js {:right nil :left -1000}))))
|
||||
:on-start-recording #(reset! input/recording-audio? true)
|
||||
:audio-file (get @input/reviewing-audio-filepath chat-id)
|
||||
:on-reviewing-audio (fn [audio-file]
|
||||
(swap! input/reviewing-audio-filepath assoc
|
||||
chat-id
|
||||
audio-file)
|
||||
(reset! input/reviewing-audio? true))
|
||||
:on-send (fn
|
||||
[{:keys [file-path duration]}]
|
||||
(rf/dispatch [:chat/send-audio file-path duration])
|
||||
(reset! input/recording-audio? false)
|
||||
(reset! input/reviewing-audio? false)
|
||||
(swap! input/reviewing-audio-filepath dissoc chat-id))
|
||||
:on-cancel (fn []
|
||||
(reset! input/recording-audio? false)
|
||||
(reset! input/reviewing-audio? false)
|
||||
(swap! input/reviewing-audio-filepath dissoc chat-id))
|
||||
:on-check-audio-permissions (fn []
|
||||
(permissions/permission-granted?
|
||||
:record-audio
|
||||
#(reset! input/record-audio-permission-granted %)
|
||||
#(reset! input/record-audio-permission-granted false)))
|
||||
:on-request-record-audio-permission (fn []
|
||||
(rf/dispatch
|
||||
[:request-permissions
|
||||
{:permissions [:record-audio]
|
||||
:on-allowed
|
||||
#(reset! input/record-audio-permission-granted true)
|
||||
:on-denied
|
||||
#(js/setTimeout
|
||||
(fn []
|
||||
(alert/show-popup
|
||||
(i18n/label :t/audio-recorder-error)
|
||||
(i18n/label
|
||||
:t/audio-recorder-permissions-error)))
|
||||
50)}]))}]])
|
||||
|
||||
(defn view
|
||||
[send-ref record-ref params bottom-inset chat-id images edit on-send]
|
||||
[rn/view {:style (style/controls bottom-inset)}
|
||||
[composer-images/images-list images]
|
||||
[rn/view {:style style/buttons-container}
|
||||
(when (and (not @input/recording-audio?)
|
||||
(nil? (get @input/reviewing-audio-filepath chat-id)))
|
||||
[:<>
|
||||
[image-button {:bottom bottom-inset}]
|
||||
[rn/view {:width 12}]
|
||||
[reactions-button]
|
||||
[rn/view {:flex 1}]
|
||||
[send-button send-ref params on-send]])]
|
||||
(when (and (not edit) (not (seq images)))
|
||||
[record-audio record-ref chat-id bottom-inset])])
|
||||
@@ -1,35 +0,0 @@
|
||||
(ns status-im2.contexts.chat.messages.composer.mentions.view
|
||||
(:require [utils.re-frame :as rf]
|
||||
[react-native.core :as rn]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[status-im2.common.contact-list-item.view :as contact-list-item]))
|
||||
|
||||
(defn mention-item
|
||||
[user _ _ text-input-ref]
|
||||
[contact-list-item/contact-list-item
|
||||
{:on-press #(rf/dispatch [:chat.ui/select-mention text-input-ref user])} user])
|
||||
|
||||
(defn f-mentions
|
||||
[{:keys [refs suggestions max-y]} bottom-inset]
|
||||
(let [translate-y (reanimated/use-shared-value 0)]
|
||||
(rn/use-effect
|
||||
(fn []
|
||||
(reanimated/set-shared-value translate-y
|
||||
(reanimated/with-timing (if (seq suggestions) 0 200)))))
|
||||
[reanimated/view
|
||||
{:style (reanimated/apply-animations-to-style
|
||||
{:transform [{:translateY translate-y}]}
|
||||
{:bottom (or bottom-inset 0)
|
||||
:position :absolute
|
||||
:left 0
|
||||
:right 0
|
||||
:z-index 5
|
||||
:elevation 5
|
||||
:max-height (/ max-y 2)})}
|
||||
[rn/flat-list
|
||||
{:keyboard-should-persist-taps :always
|
||||
:data (vals suggestions)
|
||||
:key-fn :key
|
||||
:render-fn mention-item
|
||||
:render-data (:text-input-ref refs)
|
||||
:accessibility-label :mentions-list}]]))
|
||||
@@ -1,42 +0,0 @@
|
||||
(ns status-im2.contexts.chat.messages.composer.style
|
||||
(:require [quo2.foundations.colors :as colors]
|
||||
[status-im.utils.platform :as platform]))
|
||||
|
||||
(defn input-bottom-sheet
|
||||
[window-height]
|
||||
(merge {:border-top-left-radius 20
|
||||
:border-top-right-radius 20
|
||||
:position :absolute
|
||||
:left 0
|
||||
:right 0
|
||||
:bottom (- window-height)
|
||||
:height window-height
|
||||
:flex 1
|
||||
:background-color (colors/theme-colors colors/white colors/neutral-90)
|
||||
:z-index 2}
|
||||
(if platform/ios?
|
||||
{:shadow-radius 16
|
||||
:shadow-opacity 1
|
||||
:shadow-color "rgba(9, 16, 28, 0.04)"
|
||||
:shadow-offset {:width 0 :height -2}}
|
||||
{:elevation 4})))
|
||||
|
||||
(defn bottom-sheet-handle
|
||||
[]
|
||||
{:width 32
|
||||
:height 4
|
||||
:background-color (colors/theme-colors colors/neutral-100 colors/white)
|
||||
:opacity 0.05
|
||||
:border-radius 100
|
||||
:align-self :center
|
||||
:margin-top 8})
|
||||
|
||||
(defn bottom-sheet-background
|
||||
[window-height]
|
||||
{:position :absolute
|
||||
:left 0
|
||||
:right 0
|
||||
:bottom 0
|
||||
:height window-height
|
||||
:background-color colors/neutral-95-opa-70
|
||||
:z-index 1})
|
||||
@@ -1,241 +0,0 @@
|
||||
(ns status-im2.contexts.chat.messages.composer.view
|
||||
(:require [clojure.string :as string]
|
||||
[oops.core :refer [oget]]
|
||||
[react-native.core :as rn]
|
||||
[react-native.hooks :as hooks]
|
||||
[react-native.gesture :as gesture]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[react-native.background-timer :as background-timer]
|
||||
[utils.re-frame :as rf]
|
||||
[status-im2.contexts.chat.messages.composer.style :as style]
|
||||
[status-im2.contexts.chat.messages.composer.controls.view :as controls]
|
||||
[status-im2.contexts.chat.messages.composer.mentions.view :as mentions]
|
||||
[status-im.ui2.screens.chat.composer.edit.view :as edit]
|
||||
[status-im.ui2.screens.chat.composer.input :as input]
|
||||
[status-im.ui2.screens.chat.composer.reply :as reply]
|
||||
[quo.react :refer [set-native-props]]))
|
||||
|
||||
(def initial-content-height (atom nil))
|
||||
(def keyboard-hiding? (atom false))
|
||||
|
||||
(defn minimize
|
||||
[{:keys [min-y set-bg-opacity set-translate-y set-parent-height refs chat-id]}]
|
||||
(set-bg-opacity 0)
|
||||
(set-translate-y (- min-y))
|
||||
(set-parent-height min-y)
|
||||
(when-not (seq (get @input/input-texts chat-id))
|
||||
(set-native-props (:record-ref refs) #js {:right 0 :left 0})))
|
||||
|
||||
(defn maximize
|
||||
[{:keys [max-y set-bg-opacity set-translate-y set-parent-height max-parent-height refs]}]
|
||||
(set-bg-opacity 1)
|
||||
(set-translate-y (- max-y))
|
||||
(set-parent-height max-parent-height)
|
||||
(set-native-props (:record-ref refs) #js {:right nil :left -1000}))
|
||||
|
||||
(defn clean-and-minimize
|
||||
[{:keys [chat-id refs] :as params}]
|
||||
(input/clear-input chat-id refs)
|
||||
(minimize params))
|
||||
|
||||
(def gesture-values (atom {}))
|
||||
|
||||
(defn get-bottom-sheet-gesture
|
||||
[{:keys [translate-y refs keyboard-shown min-y max-y] :as params}]
|
||||
(let [{:keys [text-input-ref]} refs]
|
||||
(-> (gesture/gesture-pan)
|
||||
(gesture/on-start
|
||||
(fn [_]
|
||||
(if (and keyboard-shown (not @input/recording-audio?))
|
||||
(swap! gesture-values assoc :pan-y (reanimated/get-shared-value translate-y))
|
||||
(input/input-focus text-input-ref))))
|
||||
(gesture/on-update
|
||||
(fn [evt]
|
||||
(when (and keyboard-shown (not @input/recording-audio?))
|
||||
(let [tY (oget evt "translationY")]
|
||||
(swap! gesture-values assoc :dy (- tY (:pdy @gesture-values)))
|
||||
(swap! gesture-values assoc :pdy tY)
|
||||
(reanimated/set-shared-value
|
||||
translate-y
|
||||
(max (min (+ tY (:pan-y @gesture-values)) (- min-y)) (- max-y)))))))
|
||||
(gesture/on-end
|
||||
(fn [_]
|
||||
(when (and keyboard-shown (not @input/recording-audio?))
|
||||
(if (< (:dy @gesture-values) 0)
|
||||
(maximize params)
|
||||
(do
|
||||
(reset! keyboard-hiding? true)
|
||||
(minimize params)
|
||||
(background-timer/set-timeout #(rf/dispatch [:dismiss-keyboard]) 200)))))))))
|
||||
|
||||
(defn update-y
|
||||
[{:keys [max-parent-height set-bg-opacity keyboard-shown max-y set-translate-y set-parent-height
|
||||
min-y chat-id]
|
||||
:as params}]
|
||||
(let [content-height (get @input/input-text-content-heights chat-id)
|
||||
new-y (+ min-y
|
||||
(if (and content-height @initial-content-height)
|
||||
(- content-height
|
||||
@initial-content-height)
|
||||
0))]
|
||||
(if (< new-y max-y)
|
||||
(when keyboard-shown
|
||||
(if (> new-y max-parent-height)
|
||||
(set-bg-opacity 1)
|
||||
(set-bg-opacity 0))
|
||||
(set-translate-y (- new-y))
|
||||
(set-parent-height (min new-y max-parent-height)))
|
||||
(if keyboard-shown
|
||||
(maximize params)
|
||||
(set-bg-opacity 0)))))
|
||||
|
||||
(defn get-input-content-change
|
||||
[{:keys [chat-id] :as params}]
|
||||
(fn [evt]
|
||||
(let [new-height (oget evt "nativeEvent.contentSize.height")]
|
||||
(swap! input/input-text-content-heights assoc chat-id new-height)
|
||||
(if @initial-content-height
|
||||
(do
|
||||
;;on Android when last symbol removed, height value is wrong, like 300px
|
||||
(when (string/blank? (get @input/input-texts chat-id))
|
||||
(swap! input/input-text-content-heights assoc chat-id @initial-content-height))
|
||||
(update-y params))
|
||||
(reset! initial-content-height new-height)))))
|
||||
|
||||
(defn effect!
|
||||
[{:keys [keyboard-shown reply edit suggestions images] :as params}]
|
||||
(rn/use-effect
|
||||
(fn []
|
||||
(when (or (not @keyboard-hiding?)
|
||||
(and @keyboard-hiding? (not keyboard-shown)))
|
||||
(reset! keyboard-hiding? false)
|
||||
(if (not keyboard-shown)
|
||||
(minimize params)
|
||||
(update-y params))))
|
||||
[reply edit suggestions images]))
|
||||
|
||||
(defn prepare-params
|
||||
[[refs window-height translate-y bg-opacity bg-bottom min-y max-y parent-height
|
||||
max-parent-height chat-id suggestions reply edit images keyboard-shown]]
|
||||
{:chat-id chat-id
|
||||
:translate-y translate-y
|
||||
:min-y min-y
|
||||
:max-y max-y
|
||||
:max-parent-height max-parent-height
|
||||
:parent-height parent-height
|
||||
:suggestions suggestions
|
||||
:reply reply
|
||||
:edit edit
|
||||
:images images
|
||||
:refs refs
|
||||
:keyboard-shown keyboard-shown
|
||||
:bg-opacity bg-opacity
|
||||
:bg-bottom bg-bottom
|
||||
:window-height window-height
|
||||
:set-bg-opacity (fn [value]
|
||||
(reanimated/set-shared-value bg-bottom (if (= value 1) 0 (- window-height)))
|
||||
(reanimated/set-shared-value bg-opacity (reanimated/with-timing value)))
|
||||
:set-translate-y (fn [value]
|
||||
(reanimated/set-shared-value translate-y (reanimated/with-timing value)))
|
||||
:set-parent-height (fn [value]
|
||||
(reanimated/set-shared-value parent-height (reanimated/with-timing value)))})
|
||||
|
||||
;; IMPORTANT! PLEASE READ BEFORE MAKING CHANGES
|
||||
|
||||
;; 1) insets are not stable so we can't rely on the first values and we have to use it from render
|
||||
;; function, so effect will be triggered a few times, for example first time it will be 0 and second
|
||||
;; time 38 on ios, and 400 and 0 on Android
|
||||
;; 2) for keyboard we use hooks, for some reason it triggers effect a few times with the same values,
|
||||
;; also it changes value only when keyboard completely closed or opened, that's why its not visually
|
||||
;; smooth, there is a small visible delay between keyboard and sheet animations
|
||||
;; 3) when we minimize sheet and hide keyboard in `sheet-gesture` function, keyboard hook triggers
|
||||
;; effect and there is a visual glitch when we have more than one line of text, so we use
|
||||
;; `keyboard-hiding?` flag
|
||||
;; 4) we store input content height in `input/input-text-content-heights` atom , we need it when chat
|
||||
;; screen is reopened
|
||||
(defn f-composer
|
||||
[_ _]
|
||||
(let [text-input-ref (rn/create-ref)
|
||||
send-ref (rn/create-ref)
|
||||
record-ref (rn/create-ref)
|
||||
refs {:send-ref send-ref
|
||||
:text-input-ref text-input-ref
|
||||
:record-ref record-ref}]
|
||||
(fn [chat-id insets]
|
||||
(let [reply (rf/sub [:chats/reply-message])
|
||||
edit (rf/sub [:chats/edit-message])
|
||||
suggestions (rf/sub [:chat/mention-suggestions])
|
||||
images (rf/sub [:chats/sending-image])
|
||||
|
||||
bottom-inset (max 20 (:bottom insets))
|
||||
{window-height :height} (rn/get-window)
|
||||
{:keys [keyboard-shown keyboard-height]} (hooks/use-keyboard)
|
||||
translate-y (reanimated/use-shared-value 0)
|
||||
bg-opacity (reanimated/use-shared-value 0)
|
||||
bg-bottom (reanimated/use-shared-value (- window-height))
|
||||
|
||||
suggestions? (and (seq suggestions)
|
||||
keyboard-shown
|
||||
(not @keyboard-hiding?))
|
||||
|
||||
max-y (- window-height
|
||||
(- (if (> keyboard-height 0)
|
||||
keyboard-height
|
||||
360)
|
||||
bottom-inset)
|
||||
46)
|
||||
|
||||
min-y (+ 108
|
||||
bottom-inset
|
||||
(if suggestions?
|
||||
(min (/ max-y 2)
|
||||
(+ 16
|
||||
(* 46 (dec (count suggestions)))))
|
||||
(+ 0
|
||||
(when (and
|
||||
(or edit reply)
|
||||
(not @input/recording-audio?))
|
||||
38)
|
||||
(when (seq images) 80))))
|
||||
|
||||
parent-height (reanimated/use-shared-value min-y)
|
||||
max-parent-height (Math/abs (- max-y 110 bottom-inset))
|
||||
|
||||
params
|
||||
(prepare-params
|
||||
[refs window-height translate-y bg-opacity bg-bottom min-y max-y parent-height
|
||||
max-parent-height chat-id suggestions reply edit images keyboard-shown])
|
||||
|
||||
input-content-change (get-input-content-change params)
|
||||
bottom-sheet-gesture (get-bottom-sheet-gesture params)]
|
||||
(effect! params)
|
||||
[reanimated/view
|
||||
{:style (reanimated/apply-animations-to-style
|
||||
{:height parent-height}
|
||||
{})}
|
||||
;;;;input
|
||||
[gesture/gesture-detector {:gesture bottom-sheet-gesture}
|
||||
[reanimated/view
|
||||
{:style (reanimated/apply-animations-to-style
|
||||
{:transform [{:translateY translate-y}]}
|
||||
(style/input-bottom-sheet window-height))}
|
||||
[rn/view {:style (style/bottom-sheet-handle)}]
|
||||
[edit/edit-message-auto-focus-wrapper text-input-ref edit #(clean-and-minimize params)]
|
||||
[reply/reply-message-auto-focus-wrapper text-input-ref reply]
|
||||
[rn/view
|
||||
{:style {:height (- max-y (- min-y 38))}}
|
||||
[input/text-input
|
||||
{:chat-id chat-id
|
||||
:on-content-size-change input-content-change
|
||||
:sending-image (seq images)
|
||||
:refs refs}]]]]
|
||||
(if suggestions?
|
||||
[:f> mentions/f-mentions (select-keys params [:refs :suggestions :max-y]) bottom-inset]
|
||||
[controls/view send-ref record-ref params bottom-inset chat-id images
|
||||
edit #(clean-and-minimize params)])
|
||||
;;;;black background
|
||||
[reanimated/view
|
||||
{:style (reanimated/apply-animations-to-style
|
||||
{:opacity bg-opacity
|
||||
:transform [{:translateY bg-bottom}]}
|
||||
(style/bottom-sheet-background window-height))}]]))))
|
||||
@@ -29,12 +29,10 @@
|
||||
images-count (count (:album message))
|
||||
;; album images are always square, except when we have 3 images, then they must be rectangular
|
||||
;; (portrait or landscape)
|
||||
portrait? (and (= images-count rectangular-style-count) (= album-style :portrait))
|
||||
text (:text (:content first-image))]
|
||||
portrait? (and (= images-count rectangular-style-count) (= album-style :portrait))]
|
||||
(if (and albumize? (> images-count 1))
|
||||
[:<>
|
||||
(when (not= text "placeholder")
|
||||
[rn/view {:style {:margin-bottom 10}} [text/text-content first-image context]])
|
||||
[rn/view {:style {:margin-bottom 10}} [text/text-content first-image context]]
|
||||
[rn/view
|
||||
{:style (style/album-container portrait?)}
|
||||
(map-indexed
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
(ns status-im2.contexts.chat.messages.content.audio.component-spec
|
||||
(:require [status-im2.contexts.chat.messages.content.audio.view :as audio-message]
|
||||
[test-helpers.component :as h]
|
||||
[react-native.audio-toolkit :as audio]
|
||||
[re-frame.core :as re-frame]))
|
||||
|
||||
(def message
|
||||
{:audio-duration-ms 5000
|
||||
:message-id "message-id"})
|
||||
|
||||
(def context
|
||||
{:in-pinned-view? false})
|
||||
|
||||
(defn setup-subs
|
||||
[subs]
|
||||
(doseq [keyval subs]
|
||||
(re-frame/reg-sub
|
||||
(key keyval)
|
||||
(fn [_] (val keyval)))))
|
||||
|
||||
(h/describe "audio message"
|
||||
(h/before-each
|
||||
#(setup-subs {:mediaserver/port 1000}))
|
||||
|
||||
(h/test "renders correctly"
|
||||
(h/render [audio-message/audio-message message context])
|
||||
(h/is-truthy (h/get-by-label-text :audio-message-container)))
|
||||
|
||||
(h/test "press play calls audio/toggle-playpause-player"
|
||||
(with-redefs [audio/toggle-playpause-player (js/jest.fn)
|
||||
audio/new-player (fn [_ _ _] {})
|
||||
audio/destroy-player #()
|
||||
audio/prepare-player (fn [_ on-success _] (on-success))
|
||||
audio-message/download-audio-http (fn [_ on-success] (on-success "audio-uri"))]
|
||||
(h/render [audio-message/audio-message message context])
|
||||
(h/fire-event
|
||||
:on-press
|
||||
(h/get-by-label-text :play-pause-audio-message-button))
|
||||
(-> (h/expect audio/toggle-playpause-player)
|
||||
(.toHaveBeenCalledTimes 1))))
|
||||
|
||||
(h/test "press play renders error"
|
||||
(h/render [audio-message/audio-message message context])
|
||||
(with-redefs [audio/toggle-playpause-player (fn [_ _ _ on-error] (on-error))
|
||||
audio/new-player (fn [_ _ _] {})
|
||||
audio/destroy-player #()
|
||||
audio/prepare-player (fn [_ on-success _] (on-success))
|
||||
audio-message/download-audio-http (fn [_ on-success] (on-success "audio-uri"))]
|
||||
(h/fire-event
|
||||
:on-press
|
||||
(h/get-by-label-text :play-pause-audio-message-button))
|
||||
(h/wait-for #(h/is-truthy (h/get-by-label-text :audio-error-label))))))
|
||||
@@ -0,0 +1,41 @@
|
||||
(ns status-im2.contexts.chat.messages.content.audio.style
|
||||
(:require [quo2.foundations.colors :as colors]
|
||||
[quo2.theme :as theme]))
|
||||
|
||||
(defn container
|
||||
[]
|
||||
{:width 295
|
||||
:height 56
|
||||
:border-radius 12
|
||||
:border-width 1
|
||||
:padding 12
|
||||
:flex-direction :row
|
||||
:align-items :center
|
||||
:justify-content :space-between
|
||||
:border-color (colors/theme-colors colors/neutral-20 colors/neutral-80)
|
||||
:background-color (colors/theme-colors colors/neutral-5 colors/neutral-80-opa-40)})
|
||||
|
||||
(def play-pause-slider-container
|
||||
{:flex-direction :row
|
||||
:align-items :center})
|
||||
|
||||
(def slider-container
|
||||
{:position :absolute
|
||||
:left 60
|
||||
:right 71
|
||||
:bottom nil})
|
||||
|
||||
(defn play-pause-container
|
||||
[]
|
||||
{:background-color (get-in colors/customization [:blue (if (theme/dark?) 60 50)])
|
||||
:width 32
|
||||
:height 32
|
||||
:border-radius 16
|
||||
:align-items :center
|
||||
:justify-content :center})
|
||||
|
||||
(def timestamp
|
||||
{:margin-left 4})
|
||||
|
||||
(def error-label
|
||||
{:margin-bottom 16})
|
||||
@@ -0,0 +1,204 @@
|
||||
(ns status-im2.contexts.chat.messages.content.audio.view
|
||||
(:require ["react-native-blob-util" :default ReactNativeBlobUtil]
|
||||
[goog.string :as gstring]
|
||||
[reagent.core :as reagent]
|
||||
[react-native.audio-toolkit :as audio]
|
||||
[status-im2.contexts.chat.messages.content.audio.style :as style]
|
||||
[react-native.platform :as platform]
|
||||
[taoensso.timbre :as log]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[quo2.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[utils.re-frame :as rf]
|
||||
[utils.i18n :as i18n]))
|
||||
|
||||
(def ^:const media-server-uri-prefix "https://localhost:")
|
||||
(def ^:const audio-path "/messages/audio")
|
||||
(def ^:const uri-param "?messageId=")
|
||||
|
||||
(defonce active-players (atom {}))
|
||||
(defonce audio-uris (atom {}))
|
||||
(defonce progress-timer (atom nil))
|
||||
(defonce current-player-key (reagent/atom nil))
|
||||
|
||||
(defn get-player-key
|
||||
[message-id in-pinned-view?]
|
||||
(str in-pinned-view? message-id))
|
||||
|
||||
(defn destroy-player
|
||||
[player-key]
|
||||
(when-let [player (@active-players player-key)]
|
||||
(audio/destroy-player player)
|
||||
(swap! active-players dissoc player-key)))
|
||||
|
||||
(defn update-state
|
||||
[state new-state]
|
||||
(when-not (= @state new-state)
|
||||
(reset! state new-state)))
|
||||
|
||||
(defn seek-player
|
||||
[player-key player-state value on-success]
|
||||
(when-let [player (@active-players player-key)]
|
||||
(audio/seek-player
|
||||
player
|
||||
value
|
||||
#(when on-success (on-success))
|
||||
#(update-state player-state :error))
|
||||
(update-state player-state :seeking)))
|
||||
|
||||
(defn download-audio-http
|
||||
[base64-uri on-success]
|
||||
(-> (.config ReactNativeBlobUtil (clj->js {:trusty platform/ios?}))
|
||||
(.fetch "GET" (str base64-uri))
|
||||
(.then #(on-success (.base64 ^js %)))
|
||||
(.catch #(log/error "could not fetch audio " base64-uri))))
|
||||
|
||||
(defn create-player
|
||||
[{:keys [progress player-state player-key]} audio-url on-success]
|
||||
(download-audio-http
|
||||
audio-url
|
||||
(fn [base64-data]
|
||||
(let [player (audio/new-player
|
||||
(str "data:audio/acc;base64," base64-data)
|
||||
{:autoDestroy false
|
||||
:continuesToPlayInBackground false}
|
||||
(fn []
|
||||
(update-state player-state :ready-to-play)
|
||||
(reset! progress 0)
|
||||
(when (and @progress-timer (= @current-player-key player-key))
|
||||
(js/clearInterval @progress-timer)
|
||||
(reset! progress-timer nil))))]
|
||||
(swap! active-players assoc player-key player)
|
||||
(audio/prepare-player
|
||||
player
|
||||
#(when on-success (on-success))
|
||||
#(update-state player-state :error)))))
|
||||
(update-state player-state :preparing))
|
||||
|
||||
(defn play-pause-player
|
||||
[{:keys [player-key player-state progress message-id audio-duration-ms seeking-audio?
|
||||
user-interaction?]
|
||||
:as params}]
|
||||
(let [mediaserver-port (rf/sub [:mediaserver/port])
|
||||
audio-uri (str media-server-uri-prefix
|
||||
mediaserver-port
|
||||
audio-path
|
||||
uri-param
|
||||
message-id)
|
||||
player (@active-players player-key)
|
||||
playing? (= @player-state :playing)]
|
||||
(when-not playing?
|
||||
(reset! current-player-key player-key))
|
||||
(if (and player
|
||||
(= (@audio-uris player-key) audio-uri))
|
||||
(audio/toggle-playpause-player
|
||||
player
|
||||
(fn []
|
||||
(update-state player-state :playing)
|
||||
(when @progress-timer
|
||||
(js/clearInterval @progress-timer))
|
||||
(reset! progress-timer
|
||||
(js/setInterval
|
||||
(fn []
|
||||
(let [player (@active-players player-key)
|
||||
current-time (audio/get-player-current-time player)
|
||||
playing? (= @player-state :playing)]
|
||||
(when (and playing? (not @seeking-audio?) (> current-time 0))
|
||||
(reset! progress current-time))))
|
||||
100)))
|
||||
(fn []
|
||||
(update-state player-state :ready-to-play)
|
||||
(when (and @progress-timer user-interaction?)
|
||||
(js/clearInterval @progress-timer)
|
||||
(reset! progress-timer nil)))
|
||||
#(update-state player-state :error))
|
||||
(do
|
||||
(swap! audio-uris assoc player-key audio-uri)
|
||||
(destroy-player player-key)
|
||||
(create-player params
|
||||
audio-uri
|
||||
(fn []
|
||||
(reset! seeking-audio? false)
|
||||
(if (> @progress 0)
|
||||
(let [seek-time (* audio-duration-ms @progress)
|
||||
checked-seek-time (min audio-duration-ms seek-time)]
|
||||
(seek-player
|
||||
player-key
|
||||
player-state
|
||||
checked-seek-time
|
||||
#(play-pause-player params)))
|
||||
(play-pause-player params))))))))
|
||||
|
||||
(defn f-audio-message
|
||||
[player-state progress seeking-audio? {:keys [audio-duration-ms message-id]}
|
||||
{:keys [in-pinned-view?]}]
|
||||
(let [player-key (get-player-key message-id in-pinned-view?)
|
||||
player (@active-players player-key)
|
||||
duration (if (and player (not (#{:preparing :not-loaded :error} @player-state)))
|
||||
(audio/get-player-duration player)
|
||||
audio-duration-ms)
|
||||
time-secs (quot
|
||||
(if (or @seeking-audio? (#{:playing :seeking} @player-state))
|
||||
(if (<= @progress 1) (* duration @progress) @progress)
|
||||
duration)
|
||||
1000)]
|
||||
(rn/use-effect (fn [] #(destroy-player player-key)))
|
||||
(rn/use-effect
|
||||
(fn []
|
||||
(when (and (some? @current-player-key)
|
||||
(not= @current-player-key player-key)
|
||||
(= @player-state :playing))
|
||||
(play-pause-player {:player-key player-key
|
||||
:player-state player-state
|
||||
:progress progress
|
||||
:message-id message-id
|
||||
:audio-duration-ms duration
|
||||
:seeking-audio? seeking-audio?
|
||||
:user-interaction? false})))
|
||||
[@current-player-key])
|
||||
(if (= @player-state :error)
|
||||
[quo/text
|
||||
{:style style/error-label
|
||||
:accessibility-label :audio-error-label
|
||||
:weight :medium
|
||||
:size :paragraph-2}
|
||||
(i18n/label :error-loading-audio)]
|
||||
[rn/view
|
||||
{:accessibility-label :audio-message-container
|
||||
:style (style/container)}
|
||||
[rn/touchable-opacity
|
||||
{:accessibility-label :play-pause-audio-message-button
|
||||
:on-press #(play-pause-player {:player-key player-key
|
||||
:player-state player-state
|
||||
:progress progress
|
||||
:message-id message-id
|
||||
:audio-duration-ms duration
|
||||
:seeking-audio? seeking-audio?
|
||||
:user-interaction? true})
|
||||
:style (style/play-pause-container)}
|
||||
[quo/icon
|
||||
(case @player-state
|
||||
:preparing :i/loading
|
||||
:playing :i/pause-audio
|
||||
:i/play-audio)
|
||||
{:size 20
|
||||
:color colors/white}]]
|
||||
[:f> quo/soundtrack
|
||||
{:style style/slider-container
|
||||
:audio-current-time-ms progress
|
||||
:player-ref (@active-players player-key)
|
||||
:seeking-audio? seeking-audio?}]
|
||||
[quo/text
|
||||
{:style style/timestamp
|
||||
:accessibility-label :audio-duration-label
|
||||
:weight :medium
|
||||
:size :paragraph-2}
|
||||
(gstring/format "%02d:%02d" (quot time-secs 60) (mod time-secs 60))]])))
|
||||
|
||||
(defn audio-message
|
||||
[message context]
|
||||
(let [player-state (reagent/atom :not-loaded)
|
||||
progress (reagent/atom 0)
|
||||
seeking-audio? (reagent/atom false)]
|
||||
(fn []
|
||||
[:f> f-audio-message player-state progress seeking-audio? message context])))
|
||||
@@ -16,8 +16,7 @@
|
||||
(defn image-message
|
||||
[index {:keys [content image-width image-height message-id] :as message} context on-long-press]
|
||||
(let [insets (safe-area/get-insets)
|
||||
dimensions (calculate-dimensions (or image-width 1000) (or image-height 1000))
|
||||
text (:text content)]
|
||||
dimensions (calculate-dimensions (or image-width 1000) (or image-height 1000))]
|
||||
(fn []
|
||||
(let [shared-element-id (rf/sub [:shared-element-id])]
|
||||
[rn/touchable-opacity
|
||||
@@ -30,7 +29,7 @@
|
||||
{:messages [message]
|
||||
:index 0
|
||||
:insets insets}])}
|
||||
(when (and (not= text "placeholder") (= index 0))
|
||||
(when (= index 0)
|
||||
[rn/view {:style {:margin-bottom 10}} [text/text-content message context]])
|
||||
[fast-image/fast-image
|
||||
{:source {:uri (:image content)}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
(ns status-im2.contexts.chat.messages.content.pin.view
|
||||
(:require [react-native.core :as rn]
|
||||
[status-im2.contexts.chat.composer.reply.view :as reply]
|
||||
[status-im2.contexts.chat.messages.content.pin.style :as style]
|
||||
[quo2.core :as quo]
|
||||
[quo2.foundations.colors :as colors]
|
||||
@@ -53,4 +54,4 @@
|
||||
(old-style/message-timestamp-text))
|
||||
:accessibility-label :message-timestamp}
|
||||
timestamp-str]]
|
||||
[old-message/quoted-message quoted-message true]]])
|
||||
[reply/quoted-message quoted-message false true]]])
|
||||
|
||||
@@ -1,26 +1,29 @@
|
||||
(ns status-im2.contexts.chat.messages.content.view
|
||||
(:require [react-native.core :as rn]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[react-native.platform :as platform]
|
||||
[status-im2.contexts.chat.messages.content.style :as style]
|
||||
[status-im2.contexts.chat.messages.content.pin.view :as pin]
|
||||
[status-im2.constants :as constants]
|
||||
[status-im2.contexts.chat.messages.content.unknown.view :as content.unknown]
|
||||
[status-im2.contexts.chat.messages.content.text.view :as content.text]
|
||||
[status-im2.contexts.chat.messages.drawers.view :as drawers]
|
||||
[status-im2.contexts.chat.messages.content.reactions.view :as reactions]
|
||||
[status-im2.contexts.chat.messages.content.status.view :as status]
|
||||
[status-im2.contexts.chat.messages.content.system.text.view :as system.text]
|
||||
[status-im2.contexts.chat.messages.content.album.view :as album]
|
||||
[status-im2.contexts.chat.messages.avatar.view :as avatar]
|
||||
[status-im2.contexts.chat.messages.content.image.view :as image]
|
||||
[quo2.core :as quo]
|
||||
[utils.re-frame :as rf]
|
||||
[status-im.ui2.screens.chat.messages.message :as old-message]
|
||||
[status-im2.common.not-implemented :as not-implemented]
|
||||
[utils.datetime :as datetime]
|
||||
[reagent.core :as reagent]
|
||||
[utils.address :as address]))
|
||||
(:require
|
||||
[react-native.core :as rn]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[react-native.platform :as platform]
|
||||
[status-im2.contexts.chat.messages.content.style :as style]
|
||||
[status-im2.contexts.chat.messages.content.pin.view :as pin]
|
||||
[status-im2.constants :as constants]
|
||||
[status-im2.contexts.chat.messages.content.unknown.view :as content.unknown]
|
||||
[status-im2.contexts.chat.messages.content.text.view :as content.text]
|
||||
[status-im2.contexts.chat.messages.drawers.view :as drawers]
|
||||
[status-im2.contexts.chat.messages.content.reactions.view :as reactions]
|
||||
[status-im2.contexts.chat.messages.content.status.view :as status]
|
||||
[status-im2.contexts.chat.messages.content.system.text.view :as system.text]
|
||||
[status-im2.contexts.chat.messages.content.album.view :as album]
|
||||
[status-im2.contexts.chat.messages.avatar.view :as avatar]
|
||||
[status-im2.contexts.chat.messages.content.image.view :as image]
|
||||
[status-im2.contexts.chat.messages.content.audio.view :as audio]
|
||||
[quo2.core :as quo]
|
||||
[utils.re-frame :as rf]
|
||||
[status-im.ui2.screens.chat.messages.message :as old-message]
|
||||
[status-im2.contexts.chat.composer.reply.view :as reply]
|
||||
[status-im2.common.not-implemented :as not-implemented]
|
||||
[utils.datetime :as datetime]
|
||||
[reagent.core :as reagent]
|
||||
[utils.address :as address]))
|
||||
|
||||
(def delivery-state-showing-time-ms 3000)
|
||||
|
||||
@@ -108,7 +111,7 @@
|
||||
:on-long-press #(on-long-press message-data context)}
|
||||
[rn/view {:style {:padding-vertical 8}}
|
||||
(when (and (seq response-to) quoted-message)
|
||||
[old-message/quoted-message quoted-message])
|
||||
[reply/quoted-message quoted-message])
|
||||
[rn/view
|
||||
{:style {:padding-horizontal 12
|
||||
:flex-direction :row}}
|
||||
@@ -128,7 +131,7 @@
|
||||
[not-implemented/not-implemented [old-message/sticker message-data]]
|
||||
|
||||
constants/content-type-audio
|
||||
[not-implemented/not-implemented [old-message/audio message-data]]
|
||||
[audio/audio-message message-data context]
|
||||
|
||||
constants/content-type-image
|
||||
[image/image-message 0 message-data context on-long-press]
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
(:require [quo2.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[status-im.ui.components.react :as react]
|
||||
[status-im.ui2.screens.chat.components.reply.view :as components.reply]
|
||||
[status-im2.contexts.chat.composer.reply.view :as reply]
|
||||
[status-im2.common.not-implemented :as not-implemented]
|
||||
[status-im2.constants :as constants]
|
||||
[utils.i18n :as i18n]
|
||||
@@ -44,11 +44,10 @@
|
||||
:icon :i/reply
|
||||
:id :reply}])
|
||||
(when (and (not (or deleted? deleted-for-me?))
|
||||
(not= (get content :text) "placeholder")
|
||||
(not= content-type constants/content-type-audio))
|
||||
[{:type :main
|
||||
:on-press #(react/copy-to-clipboard
|
||||
(components.reply/get-quoted-text-with-mentions
|
||||
(reply/get-quoted-text-with-mentions
|
||||
(get content :parsed-text)))
|
||||
:label (i18n/label :t/copy-text)
|
||||
:icon :i/copy
|
||||
|
||||
@@ -1,211 +0,0 @@
|
||||
(ns status-im2.contexts.chat.messages.list.new-temp-view
|
||||
(:require [oops.core :as oops]
|
||||
[quo2.core :as quo]
|
||||
[react-native.background-timer :as background-timer]
|
||||
[react-native.core :as rn]
|
||||
[react-native.platform :as platform]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[reagent.core :as reagent]
|
||||
[status-im.ui.screens.chat.group :as chat.group]
|
||||
[status-im.ui.screens.chat.message.gap :as message.gap]
|
||||
[status-im2.common.not-implemented :as not-implemented]
|
||||
[status-im2.constants :as constants]
|
||||
[status-im2.contexts.chat.bottom-sheet-composer.utils :as utils]
|
||||
[status-im2.contexts.chat.messages.content.deleted.view :as content.deleted]
|
||||
[status-im2.contexts.chat.messages.content.view :as message]
|
||||
[status-im2.contexts.chat.messages.list.state :as state]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]
|
||||
[status-im2.contexts.chat.bottom-sheet-composer.constants :as composer.constants]))
|
||||
|
||||
(defonce messages-list-ref (atom nil))
|
||||
|
||||
(defn list-key-fn [{:keys [message-id value]}] (or message-id value))
|
||||
(defn list-ref [ref] (reset! messages-list-ref ref))
|
||||
|
||||
(defn scroll-to-bottom
|
||||
[]
|
||||
(some-> ^js @messages-list-ref
|
||||
(.scrollToOffset #js {:y 0 :animated true})))
|
||||
|
||||
(defonce ^:const threshold-percentage-to-show-floating-scroll-down-button 75)
|
||||
(defonce show-floating-scroll-down-button (reagent/atom false))
|
||||
|
||||
(defn on-scroll
|
||||
[evt]
|
||||
(let [y (oops/oget evt "nativeEvent.contentOffset.y")
|
||||
layout-height (oops/oget evt "nativeEvent.layoutMeasurement.height")
|
||||
threshold-height (* (/ layout-height 100)
|
||||
threshold-percentage-to-show-floating-scroll-down-button)
|
||||
reached-threshold? (> y threshold-height)]
|
||||
(when (not= reached-threshold? @show-floating-scroll-down-button)
|
||||
(rn/configure-next (:ease-in-ease-out rn/layout-animation-presets))
|
||||
(reset! show-floating-scroll-down-button reached-threshold?))))
|
||||
|
||||
(defn on-viewable-items-changed
|
||||
[evt]
|
||||
(when @messages-list-ref
|
||||
(reset! state/first-not-visible-item
|
||||
(when-let [last-visible-element (aget (oops/oget evt "viewableItems")
|
||||
(dec (oops/oget evt "viewableItems.length")))]
|
||||
(let [index (oops/oget last-visible-element "index")
|
||||
;; Get first not visible element, if it's a datemark/gap
|
||||
;; we might unnecessarely add messages on receiving as
|
||||
;; they do not have a clock value, but most of the times
|
||||
;; it will be a message
|
||||
first-not-visible (aget (oops/oget @messages-list-ref "props.data") (inc index))]
|
||||
(when (and first-not-visible
|
||||
(= :message (:type first-not-visible)))
|
||||
first-not-visible))))))
|
||||
|
||||
;;TODO this is not really working in pair with inserting new messages because we stop inserting new
|
||||
;;messages
|
||||
;;if they outside the viewarea, but we load more here because end is reached,so its slowdown UI because
|
||||
;;we
|
||||
;;load and render 20 messages more, but we can't prevent this , because otherwise :on-end-reached will
|
||||
;;work wrong
|
||||
(defn list-on-end-reached
|
||||
[]
|
||||
(if @state/scrolling
|
||||
(rf/dispatch [:chat.ui/load-more-messages-for-current-chat])
|
||||
(background-timer/set-timeout #(rf/dispatch [:chat.ui/load-more-messages-for-current-chat])
|
||||
(if platform/low-device? 700 200))))
|
||||
|
||||
(defonce messages-view-height (reagent/atom 0))
|
||||
|
||||
(defn on-messages-view-layout
|
||||
[evt]
|
||||
(reset! messages-view-height (oops/oget evt "nativeEvent.layout.height")))
|
||||
|
||||
(defn list-footer
|
||||
[{:keys [chat-id]}]
|
||||
(let [loading-messages? (rf/sub [:chats/loading-messages? chat-id])
|
||||
all-loaded? (rf/sub [:chats/all-loaded? chat-id])]
|
||||
(when (or loading-messages? (not chat-id) (not all-loaded?))
|
||||
[rn/view {:style (when platform/android? {:scaleY -1})}
|
||||
[quo/skeleton @messages-view-height]])))
|
||||
|
||||
(defn list-header
|
||||
[{:keys [chat-id chat-type invitation-admin]}]
|
||||
(when (= chat-type constants/private-group-chat-type)
|
||||
[rn/view {:style (when platform/android? {:scaleY -1})}
|
||||
[chat.group/group-chat-footer chat-id invitation-admin]]))
|
||||
|
||||
(defn render-fn
|
||||
[{:keys [type value deleted? deleted-for-me? content-type] :as message-data} _ _
|
||||
{:keys [context keyboard-shown]}]
|
||||
[rn/view {:style (when platform/android? {:scaleY -1})}
|
||||
(if (= type :datemark)
|
||||
[quo/divider-date value]
|
||||
(if (= content-type constants/content-type-gap)
|
||||
[not-implemented/not-implemented
|
||||
[message.gap/gap message-data]]
|
||||
[rn/view {:padding-horizontal 8}
|
||||
(if (or deleted? deleted-for-me?)
|
||||
[content.deleted/deleted-message message-data context]
|
||||
[message/message-with-reactions message-data context keyboard-shown])]))])
|
||||
|
||||
(defn calc-shell-position
|
||||
[y]
|
||||
(let [{:keys [input-content-height focused?]} (rf/sub [:chats/current-chat-input])
|
||||
reply (rf/sub [:chats/reply-message])
|
||||
edit (rf/sub [:chats/edit-message])
|
||||
lines (utils/calc-lines input-content-height)
|
||||
base (if (or reply edit)
|
||||
(- composer.constants/edit-container-height)
|
||||
0)]
|
||||
(if (not focused?)
|
||||
(if (> lines 1) (+ -18 base) base)
|
||||
(if (> lines 12)
|
||||
(reanimated/get-shared-value y)
|
||||
(if (> lines 1) (- (- input-content-height composer.constants/input-height base)) base)))))
|
||||
|
||||
(defn shell-button
|
||||
[insets]
|
||||
(let [y (reanimated/use-shared-value 0)
|
||||
shell-position (calc-shell-position y)]
|
||||
(rn/use-effect (fn []
|
||||
(reanimated/animate y shell-position))
|
||||
[shell-position])
|
||||
[reanimated/view
|
||||
{:style (reanimated/apply-animations-to-style
|
||||
{:transform [{:translate-y y}]}
|
||||
{:bottom (+ composer.constants/composer-default-height (:bottom insets) 6)
|
||||
:position :absolute
|
||||
:left 0
|
||||
:right 0})}
|
||||
[quo/floating-shell-button
|
||||
(merge {:jump-to
|
||||
{:on-press #(do
|
||||
(rf/dispatch [:chat/close true])
|
||||
(rf/dispatch [:shell/navigate-to-jump-to]))
|
||||
:label (i18n/label :t/jump-to)
|
||||
:style {:align-self :center}}}
|
||||
(when @show-floating-scroll-down-button
|
||||
{:scroll-to-bottom {:on-press scroll-to-bottom}}))
|
||||
{}]]))
|
||||
|
||||
|
||||
(defn messages-list-content
|
||||
[{:keys [chat-id] :as chat} insets keyboard-shown]
|
||||
(fn []
|
||||
(let [context (rf/sub [:chats/current-chat-message-list-view-context])
|
||||
messages (rf/sub [:chats/raw-chat-messages-stream chat-id])]
|
||||
[rn/view
|
||||
{:style {:flex 1}}
|
||||
;; NOTE: DO NOT use anonymous functions for handlers
|
||||
[rn/flat-list
|
||||
{:key-fn list-key-fn
|
||||
:ref list-ref
|
||||
:header [list-header chat]
|
||||
:footer [list-footer chat]
|
||||
:data messages
|
||||
:render-data {:context context
|
||||
:keyboard-shown keyboard-shown}
|
||||
:render-fn render-fn
|
||||
:on-viewable-items-changed on-viewable-items-changed
|
||||
:on-end-reached list-on-end-reached
|
||||
:on-scroll-to-index-failed identity ; don't remove this
|
||||
:content-container-style {:padding-top (+ composer.constants/composer-default-height
|
||||
(:bottom insets)
|
||||
32)
|
||||
:padding-bottom 16}
|
||||
:scroll-indicator-insets {:top (+ composer.constants/composer-default-height
|
||||
(:bottom insets))}
|
||||
:keyboard-dismiss-mode :interactive
|
||||
:keyboard-should-persist-taps :handled
|
||||
:on-momentum-scroll-begin state/start-scrolling
|
||||
:on-momentum-scroll-end state/stop-scrolling
|
||||
:scroll-event-throttle 16
|
||||
:on-scroll on-scroll
|
||||
;; TODO https://github.com/facebook/react-native/issues/30034
|
||||
:inverted (when platform/ios? true)
|
||||
:style (when platform/android? {:scaleY -1})
|
||||
:on-layout on-messages-view-layout}]
|
||||
[:f> shell-button insets]])))
|
||||
|
||||
|
||||
(defn use-keyboard-visibility
|
||||
[]
|
||||
(let [show-listener (atom nil)
|
||||
hide-listener (atom nil)
|
||||
shown? (atom nil)]
|
||||
(rn/use-effect
|
||||
(fn []
|
||||
(reset! show-listener
|
||||
(.addListener rn/keyboard "keyboardWillShow" #(reset! shown? true)))
|
||||
(reset! hide-listener
|
||||
(.addListener rn/keyboard "keyboardWillHide" #(reset! shown? false)))
|
||||
(fn []
|
||||
(.remove ^js @show-listener)
|
||||
(.remove ^js @hide-listener))))
|
||||
{:shown? shown?}))
|
||||
|
||||
(defn- f-messages-list
|
||||
[chat insets]
|
||||
(let [{keyboard-shown? :shown?} (use-keyboard-visibility)]
|
||||
[messages-list-content chat insets keyboard-shown?]))
|
||||
|
||||
(defn messages-list
|
||||
[chat insets]
|
||||
[:f> f-messages-list chat insets])
|
||||
@@ -4,16 +4,19 @@
|
||||
[react-native.background-timer :as background-timer]
|
||||
[react-native.core :as rn]
|
||||
[react-native.platform :as platform]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[reagent.core :as reagent]
|
||||
[status-im.ui.screens.chat.group :as chat.group]
|
||||
[status-im.ui.screens.chat.message.gap :as message.gap]
|
||||
[status-im2.common.not-implemented :as not-implemented]
|
||||
[status-im2.constants :as constants]
|
||||
[status-im2.contexts.chat.composer.utils :as utils]
|
||||
[status-im2.contexts.chat.messages.content.deleted.view :as content.deleted]
|
||||
[status-im2.contexts.chat.messages.content.view :as message]
|
||||
[status-im2.contexts.chat.messages.list.state :as state]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
[utils.re-frame :as rf]
|
||||
[status-im2.contexts.chat.composer.constants :as composer.constants]))
|
||||
|
||||
(defonce messages-list-ref (atom nil))
|
||||
|
||||
@@ -90,7 +93,7 @@
|
||||
|
||||
(defn render-fn
|
||||
[{:keys [type value deleted? deleted-for-me? content-type] :as message-data} _ _
|
||||
{:keys [keyboard-shown context]}]
|
||||
{:keys [context keyboard-shown]}]
|
||||
[rn/view {:style (when platform/android? {:scaleY -1})}
|
||||
(if (= type :datemark)
|
||||
[quo/divider-date value]
|
||||
@@ -102,47 +105,114 @@
|
||||
[content.deleted/deleted-message message-data context]
|
||||
[message/message-with-reactions message-data context keyboard-shown])]))])
|
||||
|
||||
(defn messages-list
|
||||
[{:keys [chat-id] :as chat}]
|
||||
(let [context (rf/sub [:chats/current-chat-message-list-view-context])
|
||||
messages (rf/sub [:chats/raw-chat-messages-stream chat-id])
|
||||
keyboard-shown (atom false)
|
||||
bottom-space 15]
|
||||
[rn/view
|
||||
{:style {:flex 1}}
|
||||
;; NOTE: DO NOT use anonymous functions for handlers
|
||||
[rn/flat-list
|
||||
{:key-fn list-key-fn
|
||||
:ref list-ref
|
||||
:header [list-header chat]
|
||||
:footer [list-footer chat]
|
||||
:data messages
|
||||
:render-data {:context context
|
||||
:keyboard-shown keyboard-shown}
|
||||
:render-fn render-fn
|
||||
:on-viewable-items-changed on-viewable-items-changed
|
||||
:on-end-reached list-on-end-reached
|
||||
:on-scroll-to-index-failed identity ; don't remove this
|
||||
:content-container-style {:padding-top (+ bottom-space 32)
|
||||
:padding-bottom 16}
|
||||
:scroll-indicator-insets {:top bottom-space} ; iOS only
|
||||
:keyboard-dismiss-mode :interactive
|
||||
:keyboard-should-persist-taps :handled
|
||||
:onMomentumScrollBegin state/start-scrolling
|
||||
:onMomentumScrollEnd state/stop-scrolling
|
||||
:scrollEventThrottle 16
|
||||
:on-scroll on-scroll
|
||||
;; TODO https://github.com/facebook/react-native/issues/30034
|
||||
:inverted (when platform/ios? true)
|
||||
:style (when platform/android? {:scaleY -1})
|
||||
:on-layout on-messages-view-layout}]
|
||||
(defn calc-shell-position
|
||||
[curr-pos input-content-height focused? reply edit images]
|
||||
(let [lines (utils/calc-lines input-content-height)
|
||||
base (if reply (- composer.constants/reply-container-height) 0)
|
||||
base (if edit (- composer.constants/edit-container-height) base)
|
||||
base (if (seq images) (- composer.constants/images-container-height) base)]
|
||||
(if (not focused?)
|
||||
(if (> lines 1) (+ -18 base) base)
|
||||
(if (> lines 12)
|
||||
curr-pos
|
||||
(if (> lines 1) (- (- input-content-height composer.constants/input-height base)) base)))))
|
||||
|
||||
(def memoized-calc-shell-position (memoize calc-shell-position))
|
||||
|
||||
(defn shell-button
|
||||
[insets]
|
||||
(let [y (reanimated/use-shared-value 0)
|
||||
{:keys [input-content-height focused?]} (rf/sub [:chats/current-chat-input])
|
||||
reply (rf/sub [:chats/reply-message])
|
||||
edit (rf/sub [:chats/edit-message])
|
||||
images (rf/sub [:chats/sending-image])
|
||||
curr-pos (reanimated/get-shared-value y)
|
||||
shell-position
|
||||
(memoized-calc-shell-position curr-pos input-content-height focused? reply edit images)]
|
||||
(rn/use-effect (fn []
|
||||
(reanimated/animate y shell-position))
|
||||
[shell-position])
|
||||
[reanimated/view
|
||||
{:style (reanimated/apply-animations-to-style
|
||||
{:transform [{:translate-y y}]}
|
||||
{:bottom (+ composer.constants/composer-default-height (:bottom insets) 6)
|
||||
:position :absolute
|
||||
:left 0
|
||||
:right 0})}
|
||||
[quo/floating-shell-button
|
||||
(merge {:jump-to
|
||||
{:on-press #(do
|
||||
(rf/dispatch [:chat/close true])
|
||||
(rf/dispatch [:shell/navigate-to-jump-to]))
|
||||
:label (i18n/label :t/jump-to)}}
|
||||
{:on-press (fn []
|
||||
(rf/dispatch [:chat/close true])
|
||||
(rf/dispatch [:shell/navigate-to-jump-to]))
|
||||
:label (i18n/label :t/jump-to)
|
||||
:style {:align-self :center}}}
|
||||
(when @show-floating-scroll-down-button
|
||||
{:scroll-to-bottom {:on-press scroll-to-bottom}}))
|
||||
{:position :absolute
|
||||
:bottom 6}]]))
|
||||
{}]]))
|
||||
|
||||
(defn messages-list-content
|
||||
[{:keys [chat-id] :as chat} insets keyboard-shown]
|
||||
(fn []
|
||||
(let [context (rf/sub [:chats/current-chat-message-list-view-context])
|
||||
messages (rf/sub [:chats/raw-chat-messages-stream chat-id])]
|
||||
[rn/view
|
||||
{:style {:flex 1}}
|
||||
;; NOTE: DO NOT use anonymous functions for handlers
|
||||
[rn/flat-list
|
||||
{:key-fn list-key-fn
|
||||
:ref list-ref
|
||||
:header [list-header chat]
|
||||
:footer [list-footer chat]
|
||||
:data messages
|
||||
:render-data {:context context
|
||||
:keyboard-shown keyboard-shown}
|
||||
:render-fn render-fn
|
||||
:on-viewable-items-changed on-viewable-items-changed
|
||||
:on-end-reached list-on-end-reached
|
||||
:on-scroll-to-index-failed identity ; don't remove this
|
||||
:content-container-style {:padding-top (+ composer.constants/composer-default-height
|
||||
(:bottom insets)
|
||||
32)
|
||||
:padding-bottom 16}
|
||||
:scroll-indicator-insets {:top (+ composer.constants/composer-default-height
|
||||
(:bottom insets))}
|
||||
:keyboard-dismiss-mode :interactive
|
||||
:keyboard-should-persist-taps :handled
|
||||
:on-momentum-scroll-begin state/start-scrolling
|
||||
:on-momentum-scroll-end state/stop-scrolling
|
||||
:scroll-event-throttle 16
|
||||
:on-scroll on-scroll
|
||||
;; TODO https://github.com/facebook/react-native/issues/30034
|
||||
:inverted (when platform/ios? true)
|
||||
:style (when platform/android? {:scaleY -1})
|
||||
:on-layout on-messages-view-layout}]
|
||||
[:f> shell-button insets]])))
|
||||
|
||||
;; This should be replaced with keyboard hook. It has to do with flat-list probably. The keyboard-shown
|
||||
;; value
|
||||
;; updates in the parent component, but does not get passed to the children.
|
||||
;; When using listeners and resetting the value on an atom it works.
|
||||
(defn use-keyboard-visibility
|
||||
[]
|
||||
(let [show-listener (atom nil)
|
||||
hide-listener (atom nil)
|
||||
shown? (atom nil)]
|
||||
(rn/use-effect
|
||||
(fn []
|
||||
(reset! show-listener
|
||||
(.addListener rn/keyboard "keyboardWillShow" #(reset! shown? true)))
|
||||
(reset! hide-listener
|
||||
(.addListener rn/keyboard "keyboardWillHide" #(reset! shown? false)))
|
||||
(fn []
|
||||
(.remove ^js @show-listener)
|
||||
(.remove ^js @hide-listener))))
|
||||
{:shown? shown?}))
|
||||
|
||||
(defn- f-messages-list
|
||||
[chat insets]
|
||||
(let [{keyboard-shown? :shown?} (use-keyboard-visibility)]
|
||||
[messages-list-content chat insets keyboard-shown?]))
|
||||
|
||||
(defn messages-list
|
||||
[chat insets]
|
||||
[:f> f-messages-list chat insets])
|
||||
|
||||
@@ -2,19 +2,28 @@
|
||||
(:require [quo2.core :as quo]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]
|
||||
[status-im2.contexts.chat.messages.resolver.message-resolver :as resolver]))
|
||||
[status-im2.contexts.chat.messages.resolver.message-resolver :as resolver]
|
||||
[status-im2.constants :as constants]))
|
||||
|
||||
(defn message-text
|
||||
[{:keys [content-type] :as message}]
|
||||
(cond (= content-type constants/content-type-audio)
|
||||
(i18n/label :audio-message)
|
||||
:else
|
||||
(get-in message [:content :parsed-text])))
|
||||
|
||||
(defn banner
|
||||
[chat-id]
|
||||
(let [pinned-message (rf/sub [:chats/last-pinned-message chat-id])
|
||||
latest-pin-text (get-in pinned-message [:content :parsed-text])
|
||||
latest-pin-text (message-text pinned-message)
|
||||
{:keys [deleted? deleted-for-me?]} pinned-message
|
||||
pins-count (rf/sub [:chats/pin-messages-count chat-id])
|
||||
|
||||
content-type-text? (= (:content-type pinned-message) constants/content-type-text)
|
||||
latest-pin-text
|
||||
(cond deleted? (i18n/label :t/message-deleted-for-everyone)
|
||||
deleted-for-me? (i18n/label :t/message-deleted-for-you)
|
||||
:else (resolver/resolve-message latest-pin-text))]
|
||||
(cond deleted? (i18n/label :t/message-deleted-for-everyone)
|
||||
deleted-for-me? (i18n/label :t/message-deleted-for-you)
|
||||
content-type-text? (resolver/resolve-message latest-pin-text)
|
||||
:else latest-pin-text)]
|
||||
[quo/banner
|
||||
{:latest-pin-text latest-pin-text
|
||||
:pins-count pins-count
|
||||
|
||||
@@ -4,14 +4,11 @@
|
||||
[react-native.core :as rn]
|
||||
[react-native.safe-area :as safe-area]
|
||||
[reagent.core :as reagent]
|
||||
[status-im2.config :as config]
|
||||
[status-im2.constants :as constants]
|
||||
[status-im2.contexts.chat.bottom-sheet-composer.view :as bottom-sheet-composer]
|
||||
[status-im2.contexts.chat.messages.composer.view :as composer]
|
||||
[status-im2.contexts.chat.composer.view :as composer]
|
||||
[status-im2.contexts.chat.messages.contact-requests.bottom-drawer :as
|
||||
contact-requests.bottom-drawer]
|
||||
[status-im2.contexts.chat.messages.list.view :as messages.list]
|
||||
[status-im2.contexts.chat.messages.list.new-temp-view :as messages.list.new]
|
||||
[status-im2.contexts.chat.messages.pin.banner.view :as pin.banner]
|
||||
[status-im2.navigation.state :as navigation.state]
|
||||
[utils.debounce :as debounce]
|
||||
@@ -78,14 +75,10 @@
|
||||
:keyboardVerticalOffset (- (:bottom insets))}
|
||||
[page-nav]
|
||||
[pin.banner/banner chat-id]
|
||||
(if config/new-composer-enabled?
|
||||
[messages.list.new/messages-list chat insets]
|
||||
[messages.list/messages-list chat insets])
|
||||
[messages.list/messages-list chat insets]
|
||||
(if-not able-to-send-message?
|
||||
[contact-requests.bottom-drawer/view chat-id contact-request-state group-chat]
|
||||
(if config/new-composer-enabled?
|
||||
[bottom-sheet-composer/bottom-sheet-composer insets]
|
||||
[:f> composer/f-composer chat-id insets]))]))
|
||||
[:f> composer/composer insets])]))
|
||||
|
||||
|
||||
(defn chat
|
||||
|
||||
@@ -3,7 +3,10 @@
|
||||
[react-native.blur :as blur]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]
|
||||
[oops.core :refer [oget]]
|
||||
[status-im2.common.resources :as resources]
|
||||
[status-im.async-storage.core :as async-storage]
|
||||
[status-im2.contexts.shell.animation :as shell.animation]
|
||||
[status-im2.contexts.onboarding.common.carousel.view :as carousel]
|
||||
[status-im2.contexts.onboarding.common.background.style :as style]
|
||||
[react-native.reanimated :as reanimated]
|
||||
@@ -29,6 +32,27 @@
|
||||
(defonce progress (atom nil))
|
||||
(defonce paused (atom nil))
|
||||
|
||||
(defn store-screen-height
|
||||
[evt]
|
||||
(let [window-height (rf/sub [:dimensions/window-height])
|
||||
height (or (oget evt "nativeEvent" "layout" "height") 0)
|
||||
width (or (oget evt "nativeEvent" "layout" "width") 0)]
|
||||
;; Layout height calculation
|
||||
;; 1. Make sure height is more than width, and on-layout is not fired while the
|
||||
;; screen is horizontal
|
||||
;; 2. Initialize values with 0 in case of nil
|
||||
;; 3. In the case of notch devices, the dimensions height will be smaller than
|
||||
;; on-layout,
|
||||
;; (without status bar height included)
|
||||
;; https://github.com/status-im/status-mobile/issues/14633
|
||||
;; 4. In the case of devices without a notch, both heights should be the same,
|
||||
;; but actual values differ in some pixels, so arbitrary 5 pixels is allowed
|
||||
(when (and (> height width)
|
||||
(>= (+ height 5) (or window-height 0))
|
||||
(not= height @shell.animation/screen-height))
|
||||
(reset! shell.animation/screen-height height)
|
||||
(async-storage/set-item! :screen-height height))))
|
||||
|
||||
(defn f-view
|
||||
[dark-overlay?]
|
||||
(let [view-id (rf/sub [:view-id])
|
||||
@@ -46,7 +70,8 @@
|
||||
[view-id])
|
||||
|
||||
[rn/view
|
||||
{:style style/background-container}
|
||||
{:style style/background-container
|
||||
:on-layout store-screen-height}
|
||||
[carousel/view
|
||||
{:animate? animate?
|
||||
:progress progress
|
||||
|
||||
@@ -46,7 +46,9 @@
|
||||
"Illustration here"]]
|
||||
[rn/view {:style (style/buttons insets)}
|
||||
[quo/button
|
||||
{:on-press #(rf/dispatch [:init-root :shell-stack])
|
||||
{:on-press (fn []
|
||||
(rf/dispatch [:init-root :shell-stack])
|
||||
(rf/dispatch [:universal-links/process-stored-event]))
|
||||
:type :primary
|
||||
:accessibility-label :welcome-button
|
||||
:override-background-color (colors/custom-color profile-color 60)}
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
(ns status-im2.contexts.quo-preview.buttons.predictive-keyboard
|
||||
(:require [quo2.core :as quo]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[react-native.blur :as blur]
|
||||
[react-native.core :as rn]
|
||||
[reagent.core :as reagent]
|
||||
[status-im2.contexts.quo-preview.preview :as preview]))
|
||||
|
||||
(def descriptor
|
||||
[{:label "Type"
|
||||
:key :type
|
||||
:type :select
|
||||
:options [{:key :error :value "Error"}
|
||||
{:key :empty :value "Empty"}
|
||||
{:key :info :value "Info"}
|
||||
{:key :words :value "Words"}]}
|
||||
{:label "Text"
|
||||
:key :text
|
||||
:type :text}
|
||||
{:label "Blur"
|
||||
:key :blur?
|
||||
:type :boolean}])
|
||||
|
||||
(defn cool-preview
|
||||
[]
|
||||
(let [state (reagent/atom {:type :info :text "Enter 12, 18 or 24 words separated by a space"})
|
||||
blur? (reagent/cursor state [:blur?])]
|
||||
(fn []
|
||||
[rn/touchable-without-feedback {:on-press rn/dismiss-keyboard!}
|
||||
[rn/view {:padding-bottom 150}
|
||||
[preview/customizer state descriptor]
|
||||
[rn/view
|
||||
(when @blur?
|
||||
[blur/view
|
||||
{:style {:position :absolute
|
||||
:left 0
|
||||
:right 0
|
||||
:top 0
|
||||
:bottom 0
|
||||
:background-color colors/neutral-80-opa-70}
|
||||
:overlay-color :transparent}])
|
||||
[rn/view {:padding-vertical 60 :align-items :center}
|
||||
[quo/predictive-keyboard
|
||||
(merge @state
|
||||
{:words ["label" "label" "labor" "ladder" "lady" "lake"]
|
||||
:on-press #(js/alert (str "Pressed: " %))})]]]]])))
|
||||
|
||||
(defn preview-predictive-keyboard
|
||||
[]
|
||||
[rn/view
|
||||
{:background-color (colors/theme-colors
|
||||
colors/white
|
||||
colors/neutral-95)
|
||||
:flex 1}
|
||||
[rn/flat-list
|
||||
{:flex 1
|
||||
:keyboard-should-persist-taps :always
|
||||
:header [cool-preview]
|
||||
:key-fn str}]])
|
||||
@@ -0,0 +1,132 @@
|
||||
(ns status-im2.contexts.quo-preview.drawers.documentation-drawers
|
||||
(:require [quo2.core :as quo]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[react-native.core :as rn]
|
||||
[reagent.core :as reagent]
|
||||
[utils.re-frame :as rf]
|
||||
[status-im2.contexts.quo-preview.preview :as preview]))
|
||||
|
||||
(def descriptor
|
||||
[{:label "Title"
|
||||
:key :title
|
||||
:type :text}
|
||||
{:label "Show button"
|
||||
:key :show-button?
|
||||
:type :boolean}
|
||||
{:label "Button label"
|
||||
:key :button-label
|
||||
:type :text}
|
||||
{:label "Shell"
|
||||
:key :shell?
|
||||
:type :boolean}])
|
||||
|
||||
(defn documentation-content
|
||||
[override-theme]
|
||||
[quo/text {:style {:color (colors/theme-colors colors/neutral-100 colors/white override-theme)}}
|
||||
"Group chats are conversations of more than two people. To invite someone to a group chat, you need to have them on your Status contact list."])
|
||||
|
||||
(defn documentation-content-full
|
||||
[override-theme]
|
||||
(let [text-color (colors/theme-colors colors/neutral-100 colors/white override-theme)
|
||||
text-style {:color text-color :margin-bottom 10}]
|
||||
[rn/view
|
||||
[quo/text {:style text-style}
|
||||
"Group chats are conversations of more than two people. To invite someone to a group chat, you need to have them on your Status contact list."]
|
||||
[quo/text {:style text-style}
|
||||
"Group chats are different to communities, as they're meant to unite smaller groups of people or be centred around specific topics. For more information about group chats, see Understand group chats."]
|
||||
[quo/text {:size :paragraph-1 :weight :semi-bold :style {:margin-top 16 :color text-color}}
|
||||
"What to expect"]
|
||||
[quo/text {:style text-style}
|
||||
"You can invite up to 20 members to your group chat. If you need more, consider creating a community."]
|
||||
[quo/text {:style text-style}
|
||||
"Once you create your group chat, you can customize it and add members, as well as remove them."]
|
||||
[quo/text {:style text-style}
|
||||
"Group chats are always end-to-end encrypted with secure cryptographic keys. Only the group chat members will have access to the messages in it. Status doesn't have the keys and can't access any messages by design."]
|
||||
[quo/text {:size :paragraph-1 :weight :semi-bold :style {:margin-top 16 :color text-color}}
|
||||
"What to expect"]
|
||||
[quo/text {:style text-style}
|
||||
"You can invite up to 20 members to your group chat. If you need more, consider creating a community."]
|
||||
[quo/text {:style text-style}
|
||||
"Once you create your group chat, you can customize it and add members, as well as remove them."]
|
||||
[quo/text {:style text-style}
|
||||
"Group chats are always end-to-end encrypted with secure cryptographic keys. Only the group chat members will have access to the messages in it. Status doesn't have the keys and can't access any messages by design."]
|
||||
[quo/text {:size :paragraph-1 :weight :semi-bold :style {:margin-top 16 :color text-color}}
|
||||
"What to expect"]
|
||||
[quo/text {:style text-style}
|
||||
"You can invite up to 20 members to your group chat. If you need more, consider creating a community."]
|
||||
[quo/text {:style text-style}
|
||||
"Once you create your group chat, you can customize it and add members, as well as remove them."]
|
||||
[quo/text {:style text-style}
|
||||
"Group chats are always end-to-end encrypted with secure cryptographic keys. Only the group chat members will have access to the messages in it. Status doesn't have the keys and can't access any messages by design."]
|
||||
[quo/text {:size :paragraph-1 :weight :semi-bold :style {:margin-top 16 :color text-color}}
|
||||
"What to expect"]
|
||||
[quo/text {:style text-style}
|
||||
"You can invite up to 20 members to your group chat. If you need more, consider creating a community."]
|
||||
[quo/text {:style text-style}
|
||||
"Once you create your group chat, you can customize it and add members, as well as remove them."]
|
||||
[quo/text {:style text-style}
|
||||
"Group chats are always end-to-end encrypted with secure cryptographic keys. Only the group chat members will have access to the messages in it. Status doesn't have the keys and can't access any messages by design."]
|
||||
[quo/text {:size :paragraph-1 :weight :semi-bold :style {:margin-top 16 :color text-color}}
|
||||
"What to expect"]
|
||||
[quo/text {:style text-style}
|
||||
"You can invite up to 20 members to your group chat. If you need more, consider creating a community."]
|
||||
[quo/text {:style text-style}
|
||||
"Once you create your group chat, you can customize it and add members, as well as remove them."]
|
||||
[quo/text {:style text-style}
|
||||
"Group chats are always end-to-end encrypted with secure cryptographic keys. Only the group chat members will have access to the messages in it. Status doesn't have the keys and can't access any messages by design."]]))
|
||||
|
||||
(defn render-documenation-drawer
|
||||
[title show-button? button-label expanded? shell?]
|
||||
[quo/documentation-drawers
|
||||
{:title title
|
||||
:show-button? (and show-button? (not @expanded?))
|
||||
:button-label button-label
|
||||
:button-icon :info
|
||||
:shell? shell?
|
||||
:on-press-button #(swap! expanded? not)}
|
||||
(if @expanded?
|
||||
[documentation-content-full (when shell? :dark)]
|
||||
[documentation-content (when shell? :dark)])])
|
||||
|
||||
(defn cool-preview
|
||||
[]
|
||||
(let
|
||||
[state
|
||||
(reagent/atom
|
||||
{:title "Create a group chat"
|
||||
:button-label "Read more"})
|
||||
title (reagent/cursor state [:title])
|
||||
show-button? (reagent/cursor state [:show-button?])
|
||||
button-label (reagent/cursor state [:button-label])
|
||||
shell? (reagent/cursor state [:shell?])
|
||||
expanded? (reagent/atom false)]
|
||||
(fn []
|
||||
[rn/touchable-without-feedback {:on-press rn/dismiss-keyboard!}
|
||||
[rn/view {:padding-bottom 150}
|
||||
[preview/customizer state descriptor]
|
||||
[rn/view {:padding-vertical 60}
|
||||
[quo/button
|
||||
{:style {:margin-horizontal 40}
|
||||
:on-press #(rf/dispatch [:show-bottom-sheet
|
||||
{:content (constantly [render-documenation-drawer @title
|
||||
@show-button?
|
||||
@button-label expanded? @shell?])
|
||||
:expandable? @show-button?
|
||||
:shell? @shell?
|
||||
:expanded? @expanded?}])}
|
||||
"Open drawer"]
|
||||
[render-documenation-drawer @title @show-button? @button-label expanded?]]]])))
|
||||
|
||||
(defn preview-documenation-drawers
|
||||
[]
|
||||
[rn/view
|
||||
{:background-color (colors/theme-colors
|
||||
colors/white
|
||||
colors/neutral-95)
|
||||
:flex 1}
|
||||
[rn/flat-list
|
||||
{:flex 1
|
||||
:keyboard-should-persist-taps :always
|
||||
:header [cool-preview]
|
||||
:key-fn str}]])
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
[status-im2.contexts.quo-preview.banners.banner :as banner]
|
||||
[status-im2.contexts.quo-preview.buttons.button :as button]
|
||||
[status-im2.contexts.quo-preview.buttons.dynamic-button :as dynamic-button]
|
||||
[status-im2.contexts.quo-preview.buttons.predictive-keyboard :as predictive-keyboard]
|
||||
[status-im2.contexts.quo-preview.code.snippet :as code-snippet]
|
||||
[status-im2.contexts.quo-preview.colors.color-picker :as color-picker]
|
||||
[status-im2.contexts.quo-preview.community.community-card-view :as community-card]
|
||||
@@ -32,6 +33,7 @@
|
||||
[status-im2.contexts.quo-preview.dividers.new-messages :as new-messages]
|
||||
[status-im2.contexts.quo-preview.dividers.strength-divider :as strength-divider]
|
||||
[status-im2.contexts.quo-preview.drawers.action-drawers :as action-drawers]
|
||||
[status-im2.contexts.quo-preview.drawers.documentation-drawers :as documenation-drawers]
|
||||
[status-im2.contexts.quo-preview.drawers.drawer-buttons :as drawer-buttons]
|
||||
[status-im2.contexts.quo-preview.drawers.permission-drawers :as permission-drawers]
|
||||
[status-im2.contexts.quo-preview.dropdowns.dropdown :as dropdown]
|
||||
@@ -123,7 +125,10 @@
|
||||
:component button/preview-button}
|
||||
{:name :dynamic-button
|
||||
:options {:topBar {:visible true}}
|
||||
:component dynamic-button/preview-dynamic-button}]
|
||||
:component dynamic-button/preview-dynamic-button}
|
||||
{:name :predictive-keyboard
|
||||
:options {:topBar {:visible true}}
|
||||
:component predictive-keyboard/preview-predictive-keyboard}]
|
||||
:code [{:name :snippet
|
||||
:options {:topBar {:visible true}}
|
||||
:component code-snippet/preview-code-snippet}]
|
||||
@@ -166,6 +171,9 @@
|
||||
:drawers [{:name :action-drawers
|
||||
:options {:topBar {:visible true}}
|
||||
:component action-drawers/preview-action-drawers}
|
||||
{:name :documentation-drawer
|
||||
:insets {:top false}
|
||||
:component documenation-drawers/preview-documenation-drawers}
|
||||
{:name :drawer-buttons
|
||||
:options {:topBar {:visible true}}
|
||||
:component drawer-buttons/preview-drawer-buttons}
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
(ns status-im2.contexts.shell.view
|
||||
(:require [utils.i18n :as i18n]
|
||||
[quo2.core :as quo]
|
||||
[oops.core :refer [oget]]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[react-native.core :as rn]
|
||||
[react-native.blur :as blur]
|
||||
[react-native.linear-gradient :as linear-gradient]
|
||||
[react-native.safe-area :as safe-area]
|
||||
[status-im2.common.home.view :as common.home]
|
||||
[status-im.async-storage.core :as async-storage]
|
||||
[status-im2.contexts.shell.animation :as animation]
|
||||
[status-im2.contexts.shell.bottom-tabs :as bottom-tabs]
|
||||
[status-im2.contexts.shell.cards.view :as switcher-cards]
|
||||
@@ -112,32 +110,11 @@
|
||||
:style {:margin-top top
|
||||
:z-index 2}}]]))
|
||||
|
||||
(defn on-layout
|
||||
[evt]
|
||||
(let [dimensions (rf/sub [:dimensions/window])
|
||||
height (or (oget evt "nativeEvent" "layout" "height") 0)
|
||||
width (or (oget evt "nativeEvent" "layout" "width") 0)]
|
||||
;; Layout height calculation
|
||||
;; 1. Make sure height is more than width, and on-layout is not fired while the
|
||||
;; screen is horizontal
|
||||
;; 2. Initialize values with 0 in case of nil
|
||||
;; 3. In the case of notch devices, the dimensions height will be smaller than
|
||||
;; on-layout,
|
||||
;; (without status bar height included)
|
||||
;; https://github.com/status-im/status-mobile/issues/14633
|
||||
;; 4. In the case of devices without a notch, both heights should be the same,
|
||||
;; but actual values differ in some pixels, so arbitrary 5 pixels is allowed
|
||||
(when (and (> height width)
|
||||
(>= (+ height 5) (or (:height dimensions) 0)))
|
||||
(reset! animation/screen-height height)
|
||||
(async-storage/set-item! :screen-height height))))
|
||||
|
||||
(defn f-shell-stack
|
||||
[]
|
||||
(let [shared-values (animation/calculate-shared-values)]
|
||||
[rn/view
|
||||
{:style {:flex 1}
|
||||
:on-layout on-layout}
|
||||
{:style {:flex 1}}
|
||||
[shell]
|
||||
[bottom-tabs/bottom-tabs]
|
||||
[:f> home-stack/f-home-stack]
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user