mirror of
https://github.com/ArcaneChat/android.git
synced 2026-07-03 14:05:24 +02:00
Compare commits
1162 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ad6f232d34 | |||
| efbe43ec70 | |||
| 5e38b25c43 | |||
| 6f3f356997 | |||
| d6f485511c | |||
| a527b2f404 | |||
| 7c77b946ed | |||
| ca77886012 | |||
| fa5e305dff | |||
| 9e70bfb5ae | |||
| f4c7a9439d | |||
| 5d05e99ad6 | |||
| 79bd1c7cb3 | |||
| 848a86c718 | |||
| e759efc389 | |||
| 63ea218b98 | |||
| 07f4a859f3 | |||
| 34eeec4a39 | |||
| 7f1734b57c | |||
| 83fa4c493d | |||
| cbc8d2b659 | |||
| 6ff1c7a689 | |||
| b10185b6b9 | |||
| 6ef35c6ce1 | |||
| e04e6dfe06 | |||
| 60b322d83e | |||
| 94e597d2d1 | |||
| c1168566f3 | |||
| 72fc6ca4dc | |||
| b2a3042d02 | |||
| ed4c5e7a72 | |||
| 29a0f3dadb | |||
| 1820af288e | |||
| be48179a25 | |||
| 2aa4245563 | |||
| 54b5dba6ea | |||
| 60fa0c98df | |||
| ea60418a70 | |||
| 2bd1493a42 | |||
| 04a22cc8c6 | |||
| d2780c4c03 | |||
| bc73e1a2ba | |||
| 0522aef0fd | |||
| d5a0be0c9c | |||
| d66acbb71e | |||
| 5c06156463 | |||
| c07b2b4aa1 | |||
| 389dddc9ea | |||
| 5dfdc94468 | |||
| 52d65c1bbb | |||
| f0f07055cf | |||
| c6c66f19f2 | |||
| fb3d95264a | |||
| 92e67bd80a | |||
| 1518bab671 | |||
| 632da643af | |||
| 7353873281 | |||
| f9ac0375b9 | |||
| 78820ec18a | |||
| 3c0e4fd853 | |||
| 31c9de1f03 | |||
| 4240c8b324 | |||
| f47fff292f | |||
| 9106f12b77 | |||
| be709fb6df | |||
| fca0c03087 | |||
| 2613be7216 | |||
| 43941f9075 | |||
| 765e2b490e | |||
| cfae361b88 | |||
| bdebd98627 | |||
| be159407ff | |||
| 9daa2d77cd | |||
| 05d2d0964f | |||
| 10c4a105bb | |||
| fe602004c7 | |||
| e2d7f2c3d3 | |||
| 6996836f80 | |||
| 7d689dc1d6 | |||
| 9960423b57 | |||
| 06183a9135 | |||
| 796acf1bb0 | |||
| 64e4816f5e | |||
| 1680d332f5 | |||
| 77ee5c6bc0 | |||
| f8c678b7ff | |||
| cde74ae2e1 | |||
| 5fd3352d81 | |||
| e41b7a4701 | |||
| dd85322333 | |||
| c7bffb85fd | |||
| 3518f3d213 | |||
| b31774c899 | |||
| eebb64ff04 | |||
| ee1a6ea5c6 | |||
| 063e80bbf7 | |||
| 9f30ebd62c | |||
| ae53415545 | |||
| 8a495411a3 | |||
| 2f432bfd3b | |||
| b2b006c512 | |||
| 7b63d383ee | |||
| 2b3a56bb26 | |||
| e3408af5be | |||
| b14b8eea9d | |||
| 5e6c5d7c5e | |||
| c1eff8362f | |||
| fbca401488 | |||
| 39fe0dd523 | |||
| 0491018c24 | |||
| f91ceb8463 | |||
| 9f1def20cd | |||
| 64a8c7755d | |||
| 12807763d6 | |||
| fbf8637c97 | |||
| 8aedbc60a4 | |||
| 38c3b5561b | |||
| 3e21f9be4d | |||
| ad1159c05c | |||
| 314ecf1639 | |||
| df6ac480c6 | |||
| 8974a62a0c | |||
| d2c8e2e63a | |||
| 11600184be | |||
| ee78397614 | |||
| b33311b9fb | |||
| b90f6e296a | |||
| 5789390451 | |||
| 1a84cd05a5 | |||
| 3578a9bef1 | |||
| 52280bf744 | |||
| 26645da56d | |||
| 828ff3d8ca | |||
| 7954e94d45 | |||
| c1e47f4a9c | |||
| d3193221f6 | |||
| e7b4accea0 | |||
| 67baedc0dc | |||
| 74c02932c3 | |||
| 2968d033f2 | |||
| 43d48fa510 | |||
| 337f353220 | |||
| 218295c4f3 | |||
| bf86d4f1b7 | |||
| d383bcc451 | |||
| 2e1a40b606 | |||
| 10c538ac8e | |||
| 35852604ea | |||
| 0c8ecaf8df | |||
| cbe70a93db | |||
| 7768ef3ff9 | |||
| d337230a4b | |||
| de76377f3b | |||
| f223b22ff8 | |||
| 9850e6fff7 | |||
| 6ab94814ca | |||
| e0db504b18 | |||
| fe44eec6c8 | |||
| 7bc595a889 | |||
| 5133461eb7 | |||
| b4b12862fd | |||
| 1340166a91 | |||
| 1663502d35 | |||
| 9a67f5b32a | |||
| 773913409f | |||
| e6988e3f61 | |||
| 0047259457 | |||
| 3e9c977b3f | |||
| 3a49e30d93 | |||
| 11addb6522 | |||
| 6353bb94f4 | |||
| 5df2ba4325 | |||
| 2f79310db6 | |||
| 129278443d | |||
| 0e27692c32 | |||
| 92be6947db | |||
| 884ba32ce9 | |||
| fe2ac243c7 | |||
| 4b978c0124 | |||
| 8bf799ec2a | |||
| f92225528c | |||
| 796b723be7 | |||
| 544ab41aa4 | |||
| cca9dfb04a | |||
| faa94acbcb | |||
| e7517c23ad | |||
| 370afbf2ce | |||
| bcee64317d | |||
| 6fe4d57b48 | |||
| 906db9155a | |||
| 9b7b35acb1 | |||
| 5d25ed7715 | |||
| 5691ab9e84 | |||
| 64aa0fb49c | |||
| d3fe672ec0 | |||
| 4e199c0080 | |||
| 8fd8927293 | |||
| 320f0ba27d | |||
| c7d903f64a | |||
| f394b22e45 | |||
| e7ced91670 | |||
| 35836ad18f | |||
| 2e99f6ee93 | |||
| 5c551cb2a8 | |||
| 6490a641da | |||
| 06164d240d | |||
| b729e93b8a | |||
| d7345f75e2 | |||
| 695e1e06dd | |||
| ccedf31b96 | |||
| 31f89cec02 | |||
| 42561266ba | |||
| 17a182625d | |||
| 625d0ed66c | |||
| f7f1f29531 | |||
| 134fbc7188 | |||
| 5d26387aa3 | |||
| 4a3070bb54 | |||
| 8377f23c58 | |||
| ec4c96dd92 | |||
| f0fb8e62f8 | |||
| 823e6b6e1f | |||
| 49a59fbebe | |||
| 3424d60ea4 | |||
| 1ead71c87a | |||
| 7a44182c3f | |||
| 75c111cb0b | |||
| 1c9b51f5dc | |||
| 5e88059283 | |||
| 76307706f1 | |||
| 4db770b1f8 | |||
| 96e635f0bd | |||
| 7dd3176a06 | |||
| 16037e7693 | |||
| 6f5756c331 | |||
| 8aa7dfabe6 | |||
| 13c45f37e7 | |||
| c45b5fe9e4 | |||
| 0a9d042747 | |||
| 6cbbb9608e | |||
| f8766820db | |||
| a2847ea45e | |||
| 841e5ee30a | |||
| 624f797888 | |||
| a640c81c73 | |||
| cd344daf5a | |||
| 247ddfcf1a | |||
| d09ad5748d | |||
| 4658adc2cd | |||
| 30ddf2b03e | |||
| edb2c963c6 | |||
| cf2f6bd2ec | |||
| 62ad0e942f | |||
| 8cc8ee404d | |||
| 180b278a95 | |||
| e91671b958 | |||
| 7e0fc59687 | |||
| 255a96d393 | |||
| dfed8aec00 | |||
| a498d58c2a | |||
| 4ec02a59de | |||
| 276c0785fa | |||
| 6a4efb3358 | |||
| bcad4a7302 | |||
| 120007d87a | |||
| 55eab9dd0b | |||
| ea99f0cd48 | |||
| 6f6cd80516 | |||
| 2bb63878b1 | |||
| c5d7ec0946 | |||
| da7a3fc50a | |||
| 9c36749619 | |||
| cb3fd74af9 | |||
| 7b11c5dd79 | |||
| e3c108c773 | |||
| 6621046d6d | |||
| ed23c93526 | |||
| 19cd640dc8 | |||
| f1fe3e0807 | |||
| fce62453d1 | |||
| 441f943190 | |||
| fb759e12f0 | |||
| d1737cb69f | |||
| c94f9371fe | |||
| c88a1b53b0 | |||
| 2e2aeed127 | |||
| 6e764a6f2f | |||
| 669d8f4cba | |||
| d8cdc21880 | |||
| c083195acf | |||
| 139dafab7a | |||
| ef8ac7ae04 | |||
| 7c6d47bfae | |||
| 185fd5d730 | |||
| ef4f79b4a3 | |||
| c09be6c35b | |||
| 2a385c6768 | |||
| 93a114cff4 | |||
| 49dab181aa | |||
| 3ad9ffd94f | |||
| 53f1c73e52 | |||
| 641c3da629 | |||
| 491bbfade0 | |||
| f8dc6bb3db | |||
| b0d842b3c4 | |||
| 9cc4422f9e | |||
| dce7d56fb2 | |||
| 9b9a546e69 | |||
| 1787d8665c | |||
| f29f8bf5f9 | |||
| 3b7fd24fcb | |||
| acdbba6351 | |||
| 2134f97956 | |||
| f45fd60ccd | |||
| dabe68fbf8 | |||
| 7193b4d64e | |||
| bf138aa2e7 | |||
| b5000e2fb9 | |||
| cbd4e2b520 | |||
| bf4087792d | |||
| 25164af440 | |||
| 9579bd5bc8 | |||
| 713623c11d | |||
| f2ee08a7f1 | |||
| 66339d77bf | |||
| 1da80e9264 | |||
| f501c41d16 | |||
| ec7e3fc91a | |||
| 5e91902a26 | |||
| 8b5b2d2f95 | |||
| 523b62cfeb | |||
| 19c158d1c4 | |||
| af1cbd09ce | |||
| 9b3dc7d434 | |||
| 4547f771f5 | |||
| be6f30da24 | |||
| bb0ae0772e | |||
| c38c5a5d36 | |||
| bd3ab20981 | |||
| 3dc216ca7f | |||
| 9d9630041e | |||
| 5095892847 | |||
| 25d0f4d017 | |||
| 3306c3e8d1 | |||
| fa0c59d01c | |||
| 94291bd0ab | |||
| ff0e004e20 | |||
| 415785b59d | |||
| a8f17d618b | |||
| c0e45abd3d | |||
| ca8767e0b0 | |||
| de96a4dc6e | |||
| 04d8437b89 | |||
| 38ed95003f | |||
| ca174e82a2 | |||
| f08d5a64b0 | |||
| d467285036 | |||
| 7b833b43d7 | |||
| f8cee59e28 | |||
| 2f85654567 | |||
| 205a7fd10e | |||
| b0ab464ef8 | |||
| c1a49332d0 | |||
| a69ff20ac4 | |||
| ddd4cacd1d | |||
| 836e11ca27 | |||
| 4fc53a4632 | |||
| 1391a902b0 | |||
| 876bdcacf1 | |||
| 37e6bbc53c | |||
| ab05222c32 | |||
| e87a3de296 | |||
| 9d96d7311c | |||
| 52b7f10c1b | |||
| 3ae4bf238e | |||
| a630fad9b0 | |||
| 6543ad0893 | |||
| 4ca4d81345 | |||
| 3b8a3e10ad | |||
| 814f892e98 | |||
| 8a2149b67d | |||
| ebfd9ca122 | |||
| ba34971d2b | |||
| 91f8e88db3 | |||
| a93b12909d | |||
| 8403abc5b9 | |||
| c49599f9c8 | |||
| deed7a569c | |||
| ec590613d0 | |||
| 24d1ca9015 | |||
| 0c914b3771 | |||
| 24e363e130 | |||
| 85b9444f86 | |||
| 19f6bd3b5c | |||
| 1999bab9a0 | |||
| e6325578ca | |||
| 44eb9b32fd | |||
| c5cf11d36a | |||
| fc36c6793e | |||
| 669a1a769d | |||
| 257e200c9c | |||
| 2c2bd2bf48 | |||
| 95fbe25b0a | |||
| ab7b2f4b1b | |||
| 97552bc751 | |||
| a81cdb79ad | |||
| 1b8de09c41 | |||
| db427a036e | |||
| ab2151b974 | |||
| 0fa59fa22d | |||
| ec7807e662 | |||
| d47196d899 | |||
| b692abc235 | |||
| 07b55b739e | |||
| e3809cf1f8 | |||
| 564c0fe27d | |||
| 705e283cf5 | |||
| 40b5e10999 | |||
| d1f77d9de5 | |||
| 0704f7f1e7 | |||
| 78b3c3883d | |||
| e28e6b9b73 | |||
| 4ed51b6b56 | |||
| 084707eb67 | |||
| 0eb02b59a3 | |||
| 00d411dd5a | |||
| 770861d6db | |||
| 17986e9d86 | |||
| 5ce1f415ce | |||
| e1c92712a0 | |||
| 1816a50dee | |||
| 6ec0f1bfce | |||
| db410d8b44 | |||
| 6c6c04ba53 | |||
| cd07f3de96 | |||
| 145432a57d | |||
| 12072a0342 | |||
| c6f3761bb9 | |||
| 673f0e78b1 | |||
| 20acd38ab4 | |||
| 65c8960ec8 | |||
| bf7095d0ee | |||
| 089ecc67d1 | |||
| 0f84af5b32 | |||
| 710ed6dd56 | |||
| a6b168f4eb | |||
| 335aabd4ff | |||
| 98c97a8aed | |||
| 23d18d2ac5 | |||
| a136b8b1e5 | |||
| 7f8b71cf28 | |||
| 9e5f2b18b9 | |||
| bdfeddecd5 | |||
| 883536a3a5 | |||
| 23cbe63cd4 | |||
| 3013af2a7a | |||
| f0f53455a5 | |||
| d8b49f57a9 | |||
| 7eaaf3bbb4 | |||
| d4f83cd38b | |||
| 9eca5f518e | |||
| 7b52bb6c85 | |||
| d17bed02e6 | |||
| b4b194a59b | |||
| 1439bc0a86 | |||
| c6f62a2b81 | |||
| e3a9f42a56 | |||
| 323bcef1fe | |||
| 095b92b498 | |||
| 18c2ccd66c | |||
| 9a5415eb66 | |||
| 28fdeac01c | |||
| a7e4267b9b | |||
| d6837aa121 | |||
| 5a2913b36f | |||
| 20180fa89c | |||
| 5da3748a6a | |||
| c6b89055d8 | |||
| 2308feea8c | |||
| bfda7ab2c3 | |||
| 953ce32bea | |||
| 961fa5ffe6 | |||
| b1b2959bcb | |||
| a3b0ee1ef9 | |||
| 70ef715dc6 | |||
| ffa58aae34 | |||
| 24f5209c03 | |||
| 7fd96732d6 | |||
| 4fa5f1f5c6 | |||
| 6e0759f719 | |||
| 63434e1e2f | |||
| f4701b92e2 | |||
| 9c17bc412a | |||
| d40144d50c | |||
| 131c0f5a37 | |||
| 7086314d8b | |||
| 6649165b56 | |||
| d75b2c2bb7 | |||
| c46d174869 | |||
| 17e03f2903 | |||
| 2c12a34051 | |||
| 2d3dde2101 | |||
| d539f5ecf2 | |||
| b17d6be4fc | |||
| 1c9b5977a8 | |||
| 3c737f2360 | |||
| 49471999b9 | |||
| 9ac5e714b8 | |||
| 94defa3091 | |||
| 052ada221e | |||
| 1d5e4cf2a9 | |||
| c46aef3ea0 | |||
| 86a8fbf463 | |||
| d30e141693 | |||
| 305940396e | |||
| 2ab567a9d3 | |||
| 238ec5b299 | |||
| a9c488ff03 | |||
| 8817b50c95 | |||
| 4c810c2b50 | |||
| 84c3710a35 | |||
| be7be9bba4 | |||
| f4d5547da7 | |||
| b50ae284fb | |||
| 97716d5c26 | |||
| 52850c25b0 | |||
| e77253c843 | |||
| 6aed8d003f | |||
| 0083e60c49 | |||
| 0fc79fd845 | |||
| 5117e103bb | |||
| a7c3bc7ac5 | |||
| 056f9bd4fb | |||
| 83b16e5f4b | |||
| ee17c6d75e | |||
| 877989b5c1 | |||
| c0525ac69c | |||
| e9d2a39098 | |||
| eef8609a66 | |||
| 4d6fd16767 | |||
| b43685bcdf | |||
| 794062b9ed | |||
| b398870823 | |||
| e68c50d614 | |||
| f6a27718a2 | |||
| 876721fae5 | |||
| f136fa3e3a | |||
| 0fdac57c68 | |||
| 8e55a3dbf3 | |||
| b3375f4f19 | |||
| 923227a0e8 | |||
| 14ecafe0e2 | |||
| b607ca21ff | |||
| b93f8323ab | |||
| 77f43cde9a | |||
| d6efa3c7e5 | |||
| e4d018393d | |||
| 9a816090de | |||
| 4b04aa65be | |||
| e461e2f7f1 | |||
| 489bb55788 | |||
| 684f8834fa | |||
| 9d244611bc | |||
| 3533916149 | |||
| 46bc3e7f72 | |||
| ed0f0107e3 | |||
| a855d7043a | |||
| 66fd795763 | |||
| b440a31820 | |||
| 05da43484f | |||
| a58de2278b | |||
| 6743df23e9 | |||
| 568a3f383f | |||
| 35ec0d05e2 | |||
| 6c212a5d3d | |||
| 6ead7207ec | |||
| 0d5223036d | |||
| 640fc433b8 | |||
| 35d814c3f6 | |||
| f8b9d2b0d9 | |||
| b6e43a6994 | |||
| 3390b865e0 | |||
| 883486da9c | |||
| d048203f45 | |||
| f9d70d1196 | |||
| d1f85e6dc4 | |||
| 4413b7b4fb | |||
| 7a4f263a62 | |||
| 1a360d5282 | |||
| 74ef8dc1c6 | |||
| dc785fc116 | |||
| 009593f7cc | |||
| 1da2d35af4 | |||
| 884be3a93e | |||
| 9a25328787 | |||
| 2d8ec490b1 | |||
| bb3f4a2e06 | |||
| 3b19ca99e1 | |||
| 8e4c5d6b63 | |||
| f751a48568 | |||
| 4549989a63 | |||
| 1b46edaddf | |||
| 19e2c4e051 | |||
| aa0c72356f | |||
| 6f5e90be53 | |||
| 34fa0620ab | |||
| fe37af1a3f | |||
| 3459802d67 | |||
| b8bf847941 | |||
| 5b6024584a | |||
| ee8fd429f4 | |||
| 4833a44542 | |||
| eb93e2bb7e | |||
| 291700dfc7 | |||
| 7a4913b394 | |||
| 0dae71f4b7 | |||
| bc022f5196 | |||
| 08e4229533 | |||
| 101a31628d | |||
| 2a2ce883b4 | |||
| 5a0e26bdb5 | |||
| d4dcdcf3bd | |||
| 0c9277dfd0 | |||
| 74b2369ca9 | |||
| 37886cf296 | |||
| df5ba2eced | |||
| 3c2ddb96b3 | |||
| 9eafdbd817 | |||
| e2a825dfb2 | |||
| 0a21d1d1b4 | |||
| 8d49c7e595 | |||
| b0cb6c73ba | |||
| 966d5dac24 | |||
| b6367416e5 | |||
| 0b582dd287 | |||
| 7f684f4d2e | |||
| d5cf919bcb | |||
| 1510f7f3a8 | |||
| 6916becf7f | |||
| ad5b496f5c | |||
| 490f1efe36 | |||
| e647401db4 | |||
| 3113f9c3ab | |||
| a1e47865c5 | |||
| 3a5f9b3fed | |||
| 5ffbc19d03 | |||
| c125d4fa24 | |||
| d9db4b818a | |||
| 693efdbd0f | |||
| 399b783437 | |||
| 4bc574dfbe | |||
| 294af0981d | |||
| e8c7014993 | |||
| 0edc8303c1 | |||
| 389098699a | |||
| 8c89c3e225 | |||
| df696e5fab | |||
| a93c8ab055 | |||
| c5cb79d116 | |||
| b3c50b9571 | |||
| e8801d1b64 | |||
| 41579de502 | |||
| e6f735b8bc | |||
| 70b6f2cdfa | |||
| c1e716d6a3 | |||
| 8bfc44c8ca | |||
| dde59b4673 | |||
| 36e963e717 | |||
| 9d77920adf | |||
| 6f50ee0cfb | |||
| 4c86d6d49e | |||
| 9e8fcf8ed7 | |||
| 6412d25420 | |||
| 963327dd64 | |||
| 5cba1ccd98 | |||
| de8e6b6852 | |||
| 811089f3b3 | |||
| e045a09d36 | |||
| a470366f03 | |||
| a3a6919b08 | |||
| cbee839a43 | |||
| 1434ce6f57 | |||
| efdd92b6a1 | |||
| 654ba5b460 | |||
| 75296e189a | |||
| e3835f70f7 | |||
| 708a68119e | |||
| 1d5ab98892 | |||
| bbb803f91c | |||
| 07753e211d | |||
| 8135d96300 | |||
| d151e825da | |||
| 6a4c73c821 | |||
| d5289cc3df | |||
| af40a8b57e | |||
| 853ce3c7a3 | |||
| 529139099e | |||
| d2ab4817b1 | |||
| b4aa18abae | |||
| 9ff1cafd5e | |||
| a7cee63d1c | |||
| eda735925a | |||
| 46650c8cc3 | |||
| fbab156d22 | |||
| bf6b678e2b | |||
| 539cb670f1 | |||
| 2a6aba110b | |||
| 0351a1e974 | |||
| d48ab128a0 | |||
| ef67585529 | |||
| 953e7c6da0 | |||
| ab5a9c9d60 | |||
| af91cf7413 | |||
| 6a618986d0 | |||
| 9eefcacbc1 | |||
| e245e29058 | |||
| 7d879f8d1f | |||
| f7963a56e9 | |||
| 0a73877c25 | |||
| 6c1f787a38 | |||
| 1b57880be3 | |||
| f54144e7e8 | |||
| b059741161 | |||
| b735759bd0 | |||
| a7199ecedf | |||
| 2cb529be32 | |||
| 235038027b | |||
| e8eb036594 | |||
| fdd5cc5d4b | |||
| d531eb8b47 | |||
| a88a619099 | |||
| 77465b5802 | |||
| 00bc429f20 | |||
| 3f25d002e4 | |||
| d17567029d | |||
| 74c6f20c3e | |||
| 4610a64732 | |||
| 8728a0a39b | |||
| dcf5cf7f54 | |||
| 7f89ecea5c | |||
| 30a63dd13b | |||
| a5d2642c37 | |||
| 79e5eedab0 | |||
| 27da217eb7 | |||
| a0c71a5387 | |||
| 4d19a59cb6 | |||
| 819a9f415a | |||
| dff1ef3778 | |||
| 0358e8ffcb | |||
| 7131f5774e | |||
| 406c263d82 | |||
| aa572508dc | |||
| 6ed070e437 | |||
| 1f880efb3f | |||
| 72ace5c156 | |||
| 1e4cfa124e | |||
| 2f34a6ffa4 | |||
| c42ba0f599 | |||
| afdfe7bbaa | |||
| 14f43f2a79 | |||
| 8798275170 | |||
| f3353cf6e9 | |||
| ac6495ff20 | |||
| 722f2cad1e | |||
| b135093628 | |||
| 8ae47e97cf | |||
| be44789b01 | |||
| 6a1ff0bace | |||
| 233197095b | |||
| 494cb728c3 | |||
| 047cd9a121 | |||
| 60e9a9101a | |||
| c23dac6f99 | |||
| 555547b6cc | |||
| 3965319ef4 | |||
| 5fe355fe90 | |||
| c4db7c515f | |||
| fbf88e102b | |||
| 6af3b0d985 | |||
| d5ea043893 | |||
| f70c79ba4a | |||
| 92d6147644 | |||
| 0b2a26e2f1 | |||
| b968ba67b3 | |||
| e234cc864b | |||
| b47e75eed6 | |||
| 6b684bf030 | |||
| ea89d37461 | |||
| 814af177d1 | |||
| 1ccbb7177f | |||
| 3118dbd32b | |||
| 72fb9992a1 | |||
| 1a5e062dac | |||
| 0bcaea6f01 | |||
| 8283a6c4ad | |||
| e8413019ff | |||
| cd159bac6c | |||
| 289118e671 | |||
| 21f917004f | |||
| 286a84b1d4 | |||
| 0abf2ff00c | |||
| 0ca92ec6b5 | |||
| e66fa53537 | |||
| 8c8c003f2b | |||
| a51013cc00 | |||
| a06e36993d | |||
| 171500a97d | |||
| ce054d93a8 | |||
| 9a4851961e | |||
| cabc159cd8 | |||
| e5ddbacb2e | |||
| 03c7d78e2b | |||
| c78cbbe145 | |||
| 00498b02b3 | |||
| ad6e2d1a9f | |||
| 5cfa71cd72 | |||
| 0551044ef9 | |||
| a297c71a90 | |||
| 5126b3eeb2 | |||
| 8d7078f96f | |||
| c446440537 | |||
| 333e4c9eca | |||
| fb1f5df234 | |||
| 247de63362 | |||
| cc419a9f62 | |||
| 2469b6efef | |||
| b7446c9a93 | |||
| 0c9b5bbaf4 | |||
| 3126544f00 | |||
| ccdad0469d | |||
| 20f7c7c616 | |||
| 9f3eeb3d0d | |||
| 92bc53b672 | |||
| 6364903a28 | |||
| 1355303360 | |||
| 7227f513a5 | |||
| 4933d66000 | |||
| 977b21618c | |||
| 5cecd5bec3 | |||
| d8db39f9c7 | |||
| 736fc44870 | |||
| 48bb77cfae | |||
| 537127ec4e | |||
| 53bfe52797 | |||
| a5167f3739 | |||
| d481541ad8 | |||
| 7ab19fb8af | |||
| 715a2c0653 | |||
| a8bc01e6c1 | |||
| 350cd0539c | |||
| 3fbccf3408 | |||
| 9f8fe08c75 | |||
| 86656f1155 | |||
| 5048239563 | |||
| 89473b8067 | |||
| 6e135e06a9 | |||
| 887f5881f0 | |||
| d52647b288 | |||
| aee757e71c | |||
| c0a729978c | |||
| 041c95c6d2 | |||
| 8de0fed18e | |||
| dd75a8e858 | |||
| 2e77db23d5 | |||
| 04a4a02235 | |||
| 2910730bc1 | |||
| 30d5eeeb45 | |||
| 23458a6c64 | |||
| d2c2f2cf07 | |||
| 9679b22072 | |||
| 3fae301ec2 | |||
| d08069f7b0 | |||
| f83d5a0dbb | |||
| 56a0607a5e | |||
| 9c08617f7d | |||
| 812dc8d738 | |||
| d8b278a1f5 | |||
| 4368a4f63e | |||
| 72ae90ae93 | |||
| c36ce7a8ab | |||
| 404097fe30 | |||
| 07d5c719d4 | |||
| 13a43473cc | |||
| 5a84198829 | |||
| 1f443cd87c | |||
| 4901b92ee2 | |||
| cd48e15071 | |||
| 2d4b570f48 | |||
| 3f0b36bd4b | |||
| b342fb9c30 | |||
| 0974655366 | |||
| 9675c419ac | |||
| de4e95d495 | |||
| 7a738abba8 | |||
| 512f8104e2 | |||
| 0cd445f4e7 | |||
| dbfbb9060b | |||
| f2f910fe23 | |||
| 7dde6ad61a | |||
| ca947aeef2 | |||
| 1680d14835 | |||
| b5a2280776 | |||
| ab61246240 | |||
| 957a5f75dc | |||
| dad490074b | |||
| 09640c88ac | |||
| 021a98c135 | |||
| deacf8efef | |||
| 6c482af28a | |||
| cfd9371739 | |||
| c58a77dc26 | |||
| e45d722ba1 | |||
| 83213d14ad | |||
| 931476a196 | |||
| 4ce3869744 | |||
| 5dee44605d | |||
| 249d57897e | |||
| 3c9cecbc39 | |||
| 5a2c28b91d | |||
| 7758f6d991 | |||
| 285f59e46a | |||
| 91f8ce7cda | |||
| 12ad3daa28 | |||
| eaa6981523 | |||
| cd8f799f14 | |||
| 69fb68a873 | |||
| 5954b13440 | |||
| a7647e18e2 | |||
| e025da4e91 | |||
| 8ba93f8b82 | |||
| 849c6798c0 | |||
| 7a85cf9db5 | |||
| aa45476028 | |||
| c12ed8060c | |||
| 90c8650aaf | |||
| 6f530215af | |||
| e8c4d0e606 | |||
| 7feb4bc93f | |||
| e4b1d52d1a | |||
| efc09f142a | |||
| e5b8e488a4 | |||
| d397ccaf7e | |||
| f7bd609f91 | |||
| a118c33f89 | |||
| 86a9da5062 | |||
| d3328df6f2 | |||
| 169a706e36 | |||
| bf2fd62154 | |||
| e74795851a | |||
| 139b7f84f4 | |||
| 3d55ea931c | |||
| 73ada05e99 | |||
| 7ecba725a0 | |||
| 6cad73a00b | |||
| c5e675a72e | |||
| 75f779e47b | |||
| 2b1bb6e434 | |||
| ca8dcfc599 | |||
| a26764355e | |||
| d92265cd63 | |||
| 1787dc4c8b | |||
| 1293d419f5 | |||
| 421db5b403 | |||
| 5f77f791d0 | |||
| aa78c607ce | |||
| 7bb855e32a | |||
| eaa24e89f8 | |||
| fc5a3e5c75 | |||
| 6fe5ed32cb | |||
| 304942e98b | |||
| 44df03ad52 | |||
| c485aa9f6a | |||
| cb416e6959 | |||
| ee6c464a5b | |||
| 8790b26123 | |||
| 04d2eb99aa | |||
| 5627f5f123 | |||
| 7a66085107 | |||
| aa45a9082e | |||
| 3955f4d505 | |||
| 74dd4c0d9a | |||
| 23eb418591 | |||
| edcfa80d92 | |||
| 5ff1f3d915 | |||
| b0ae2da439 | |||
| 8487c286e6 | |||
| ffa9177094 | |||
| 6f3d8a4414 | |||
| 9bbee2db10 | |||
| 30580366fd | |||
| ec4bffdabe | |||
| ca2d8f4b6e | |||
| a7f0f753fd | |||
| 4025fd5e0b | |||
| 577959a51a | |||
| 776dc05755 | |||
| 28141bf942 | |||
| 3431163c24 | |||
| 45cb3a953c | |||
| 3080313568 | |||
| f13251bc07 | |||
| 6a7c498481 | |||
| b72a1ec7d8 | |||
| 5fd06f2b9d | |||
| 899b075349 | |||
| 1c0dc91f03 | |||
| a76762f321 | |||
| 86ebb6e1a8 | |||
| ecf87c58e1 | |||
| 0bef0b3501 | |||
| bc6d676fcd | |||
| 8aa615157a | |||
| 9ffa76c0f4 | |||
| 9fc4bfb970 | |||
| 1bc40837fe | |||
| ba3ea172e5 | |||
| 3a4c02c8cd | |||
| 4b9d521c13 | |||
| df9e3007b2 | |||
| 117f144858 | |||
| e17d37ebb7 | |||
| 08200d8443 | |||
| 9809e3edd6 | |||
| 2255c267ef | |||
| 4a83f4005a | |||
| 8ea78b1930 | |||
| 9d4b5e8fed | |||
| ca74afb229 | |||
| 1757c417fa | |||
| 4e6119b85d | |||
| 91467e5c65 | |||
| 2870ad988f | |||
| a35da9ac7c | |||
| e4543be71c | |||
| b1e4d4dbe5 | |||
| e6f9eda787 | |||
| 12b5f0767c | |||
| 0bd2c2f825 | |||
| 5c9afb910d | |||
| e41e3374e8 | |||
| 0be6457cd1 | |||
| f3fa1d5e7c | |||
| 5f2b4590c0 | |||
| be4bc8259e | |||
| 529842ad60 | |||
| 78bd221fdf | |||
| 054902eb67 | |||
| ef578da78d | |||
| 884cce3e1a | |||
| fc6bdc2fea | |||
| e441a582dd | |||
| 3e3a01dd62 | |||
| 1cda594e02 | |||
| 357e6de031 | |||
| 30ac01a57e | |||
| de5d45d04d | |||
| c599fc8e79 | |||
| 295e1b50d2 | |||
| ef8838cbe3 | |||
| eed124a0f2 | |||
| 18974ff023 | |||
| e666bbf610 | |||
| 0330485123 | |||
| 56717d3f44 | |||
| 958bdddacf | |||
| 6375b85ef9 | |||
| e076691f2a | |||
| 4635cbbe4f | |||
| 71311d43e8 | |||
| 6efe540310 | |||
| 1843c29b7c | |||
| 653d940242 | |||
| 2f3a730be7 | |||
| 7a2401a3d5 | |||
| 6690add48f | |||
| ace1c99daa | |||
| 125ac5e7b3 | |||
| b3248c9f6d | |||
| 00d1803631 | |||
| 0482889dfa | |||
| 6113195977 | |||
| 4a02d6c73d | |||
| a252eec698 | |||
| b89e094f9f | |||
| bc511d6100 | |||
| 59435e8975 | |||
| 56b925f600 | |||
| 5a5ea83fa0 | |||
| c30ddf9c77 | |||
| e14b878aef | |||
| 9e3ebda12a | |||
| 4bb42b9995 | |||
| 59b158fe09 | |||
| 3033000e4e | |||
| 9f8da69b25 | |||
| aa52f8172d | |||
| 82ddcd0839 | |||
| 8d99b36347 | |||
| 589fa8e3dd | |||
| 434b40e51e | |||
| 755c346d82 | |||
| b13defdf9c | |||
| fbe533c701 | |||
| 13ebad4942 | |||
| f9539c160e | |||
| 0195f2f78f | |||
| 64553b5655 | |||
| ce38181502 | |||
| 4c58f31dc6 | |||
| e5a2bde5c4 | |||
| d984bf15a0 | |||
| ab2904e274 | |||
| c751d7015c | |||
| eef3be840b | |||
| fed96377f5 | |||
| 774bee1e28 | |||
| c0b3d87ff9 | |||
| e72eed807f | |||
| cd1821f6a7 | |||
| e79f4ef84e | |||
| 8071f64669 | |||
| fd2d3a5b5a | |||
| 2e500ce97b | |||
| 997d03829e | |||
| 67d6a2aed3 | |||
| 884481fa9e | |||
| 4c90890643 | |||
| 1209ec02f9 | |||
| 63e4b25cbf | |||
| acdde4c0a0 | |||
| a9fba59386 | |||
| 4ef7fc0401 | |||
| 148f07729c | |||
| 529f46f226 | |||
| 7ad8a48255 | |||
| 3d7d3157fc | |||
| 6b34438958 | |||
| 31bc04d190 | |||
| c1c2aa4930 | |||
| 78a9bd98b0 | |||
| c058eb2927 | |||
| 6180397f8f | |||
| b4bb2e2b5d | |||
| e717837e6c | |||
| b7ae41b249 | |||
| 270e31fc58 | |||
| 5900b340e4 | |||
| 066d794360 | |||
| c9d9d915a1 | |||
| d397f7f16e | |||
| d1d379b9b1 | |||
| a4abc0181b | |||
| 7c762bbb6c | |||
| 0d3e009500 | |||
| d16d58b77a | |||
| f4bbb61313 | |||
| a38a29167e | |||
| cf954d0970 | |||
| 7ded91d8af | |||
| 27d7e3b27d | |||
| 669e21b6f1 | |||
| b7e4dda6f5 |
@@ -0,0 +1,3 @@
|
||||
ko_fi: adbenitez
|
||||
liberapay: adbenitez
|
||||
custom: "https://arcanechat.me/#contribute"
|
||||
@@ -1 +1 @@
|
||||
blank_issues_enabled: true
|
||||
blank_issues_enabled: false
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
version: 2
|
||||
mergeable:
|
||||
- when: pull_request.*
|
||||
name: "Changelog check"
|
||||
validate:
|
||||
- do: or
|
||||
validate:
|
||||
- do: description
|
||||
must_include:
|
||||
regex: '#skip-changelog'
|
||||
- do: and
|
||||
validate:
|
||||
- do: dependent
|
||||
changed:
|
||||
file: '**/*.java'
|
||||
required: ['CHANGELOG.md']
|
||||
fail:
|
||||
- do: checks
|
||||
status: 'action_required'
|
||||
payload:
|
||||
title: CHANGELOG.md might need an update
|
||||
summary: "Please update CHANGELOG.md or add #skip-changelog to the description"
|
||||
@@ -35,7 +35,7 @@ jobs:
|
||||
- uses: nttld/setup-ndk@v1
|
||||
id: setup-ndk
|
||||
with:
|
||||
ndk-version: r23c
|
||||
ndk-version: r27
|
||||
|
||||
- name: Compile core
|
||||
env:
|
||||
@@ -51,7 +51,7 @@ jobs:
|
||||
run: ./gradlew --no-daemon -PABI_FILTER=armeabi-v7a assembleFossDebug
|
||||
|
||||
- name: Upload APK
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: app-preview.apk
|
||||
path: 'build/outputs/apk/foss/debug/*.apk'
|
||||
|
||||
@@ -37,7 +37,7 @@ jobs:
|
||||
- uses: nttld/setup-ndk@v1
|
||||
id: setup-ndk
|
||||
with:
|
||||
ndk-version: r23c
|
||||
ndk-version: r27
|
||||
|
||||
- name: Compile core
|
||||
env:
|
||||
@@ -49,11 +49,12 @@ jobs:
|
||||
- name: Build APK
|
||||
run: |
|
||||
mkdir -p ~/.gradle
|
||||
echo -n ${{ secrets.SIGNING_KEY }} | base64 -d >> ~/app.keystore
|
||||
echo "DC_RELEASE_STORE_FILE=$HOME/app.keystore" >> ~/.gradle/gradle.properties
|
||||
echo "DC_RELEASE_STORE_PASSWORD=${{ secrets.KEY_STORE_PASSWORD }}" >> ~/.gradle/gradle.properties
|
||||
echo "DC_RELEASE_KEY_ALIAS=${{ secrets.ALIAS }}" >> ~/.gradle/gradle.properties
|
||||
echo "DC_RELEASE_KEY_PASSWORD=${{ secrets.KEY_PASSWORD }}" >> ~/.gradle/gradle.properties
|
||||
echo -n ${{ secrets.KEYSTORE_FILE }} | base64 -d >> ~/keystore.jks
|
||||
echo "DC_RELEASE_STORE_FILE=$HOME/keystore.jks" >> ~/.gradle/gradle.properties
|
||||
echo "DC_RELEASE_STORE_PASSWORD=${{ secrets.KEYSTORE_PASSWORD }}" >> ~/.gradle/gradle.properties
|
||||
echo "DC_RELEASE_KEY_ALIAS_FDROID=${{ secrets.ALIAS_FDROID }}" >> ~/.gradle/gradle.properties
|
||||
echo "DC_RELEASE_KEY_ALIAS_GPLAY=${{ secrets.ALIAS_GPLAY }}" >> ~/.gradle/gradle.properties
|
||||
echo "DC_RELEASE_KEY_PASSWORD=${{ secrets.KEYSTORE_PASSWORD }}" >> ~/.gradle/gradle.properties
|
||||
./gradlew assembleFossRelease
|
||||
rm build/outputs/apk/foss/release/*universal*
|
||||
./gradlew assembleGplayRelease
|
||||
@@ -63,7 +64,7 @@ jobs:
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
token: "${{ secrets.GITHUB_TOKEN }}"
|
||||
body: "Auto-generated release"
|
||||
body: '[<img src="store/get-it-on-gplay.png" alt="Get it on Google Play" height="48">](https://play.google.com/store/apps/details?id=com.github.arcanechat) [<img src="store/get-it-on-fdroid.png" alt="Get it on F-Droid" height="48">](https://f-droid.org/packages/chat.delta.lite) [<img src="store/get-it-on-github.png" alt="Get it on GitHub" height="48">](https://github.com/ArcaneChat/android/releases/latest/download/ArcaneChat-gplay.apk)'
|
||||
prerelease: ${{ contains(github.event.ref, '-beta') }}
|
||||
fail_on_unmatched_files: true
|
||||
files: build/outputs/apk/foss/release/*.apk
|
||||
|
||||
@@ -1,5 +1,284 @@
|
||||
# Delta Chat Android Changelog
|
||||
|
||||
## Unreleased
|
||||
|
||||
* fix: webxdc.selfName uses the name otherwise displayed
|
||||
|
||||
## v1.58.2
|
||||
2025-04
|
||||
|
||||
* fix draft writing area disappearing for some chats
|
||||
* update to core 1.159.2
|
||||
|
||||
## v1.58.1
|
||||
2025-04
|
||||
|
||||
* tapping info messages with contacts open the contact's profile
|
||||
* hide superfluous "Show Classic E-mails" advanced setting for chatmail
|
||||
* show profile bio/status under name in main settings screen
|
||||
* remove mostly non-telling transport addresses when referring to a contact;
|
||||
the contact's profile gives a much better overview
|
||||
* Disable AEAP to enable us to overhaul some things - there are big changes underway in this area, which will come in a few months
|
||||
* don't display email address in contact list and member list for contacts with green-checkmark
|
||||
* avoid crash in Notifications preferences if ringtone title can't be read
|
||||
* don't display forwarded messages as "edited" if original message was edited
|
||||
* support importing contact from ProtonMail vCard attachments received in chats
|
||||
* send encrypted in the experimental broadcast lists feature
|
||||
* wait for QR scan (or invite link click) process to complete before allowing to send messages
|
||||
* show connectivity status dot when profile is connecting or not connected
|
||||
* never send Autocrypt-Gossip in broadcast lists.
|
||||
* update to core 1.159.1
|
||||
|
||||
## v1.56.1
|
||||
2025-03
|
||||
|
||||
* ignore click in info-messages from deleted in-chat apps
|
||||
* data saving: do not send messages to the server if user is the only member of the chat in single-device usage
|
||||
* protect metadata: encrypt message's sent date
|
||||
* do not fail to send messages in groups if some encryption keys are missing
|
||||
* synchronize contact name changes across devices
|
||||
* fix changing group names that was not working in some situations
|
||||
* fix: do not show outdated message text in "Message Info" of an edited message
|
||||
* some more small bug fixes and updated translations
|
||||
* update to core 1.158.0
|
||||
|
||||
## v1.56.0
|
||||
2025-03
|
||||
|
||||
* allow to edit messages
|
||||
* allow to delete messages for everyone
|
||||
* add mute option "8 hours"
|
||||
* add menu option to easily save/unsave selected message
|
||||
* improve deletion confirmation for "Device Messages"
|
||||
* remove dangerous encryption options
|
||||
* always paste as plain text in message draft area
|
||||
* some small bug fixes and updated translations
|
||||
* update to core 1.157.2
|
||||
|
||||
## v1.54.4
|
||||
2025-03
|
||||
|
||||
* allow better avatar (profile picture) quality
|
||||
* remove notifications from chat that was deleted from other device
|
||||
* when a chat is deleted, also delete its messages from server
|
||||
* avoid freezing when opening the app for the first time after install
|
||||
* avoid crash when adding chat shortcut to home screen
|
||||
* some small bug fixes and updated translations
|
||||
* update to core 1.156.3
|
||||
|
||||
## v1.54.3
|
||||
2025-03
|
||||
|
||||
* allow to add any chat to the home screen
|
||||
* update "forward message" icon and organize the messages actions bar
|
||||
* do not allow non-members to change ephemeral timer settings of groups
|
||||
* properly display padlock when the message is not sent over the network
|
||||
* sync message deletion to other devices
|
||||
* sync chat deletion across devices
|
||||
* Show sender in "Saved Messages"
|
||||
* allow scanning multiple QR-invitation codes without needing to wait for completion to scan the next one
|
||||
* when reactions are seen in one device, remove notification from your other devices
|
||||
* don't disturb with notification when someone leave a group
|
||||
* detect incompatible profiles from newer app version when importing them
|
||||
* prepare the app for receiving edited messages
|
||||
* prepare the app for receiving message deletion requests
|
||||
* do some small bug fixes
|
||||
* update translations
|
||||
* update to core 1.156.2
|
||||
|
||||
## v1.54.0
|
||||
2025-02
|
||||
|
||||
* enhanced "Saved Messages" feature, now when forwarding a message to "Saved Messages" chat, it retains the sender information and a button to jump to the original message
|
||||
* Saved messages are marked by a bookmark sign
|
||||
* improve explanation when blocking a contact
|
||||
* improve wording in empty "apps" and "files" tabs in chat media screen
|
||||
* remove deprecated/legacy built-in "half-camera"
|
||||
* UI improvement: keep avatars aligned to message bubble when message has reactions
|
||||
* fix problems when opening attachments in external apps
|
||||
* fix a bug with some big images appearing as blank/transparent
|
||||
* some other small bug fixes
|
||||
* update translations
|
||||
* update to core 1.155.4
|
||||
|
||||
## v1.52.1
|
||||
2025-01
|
||||
|
||||
* the app now requires less storage on your SD card by deduplicating newly received/sent files
|
||||
* some small bug fixes
|
||||
* update translations
|
||||
* update to core 1.155.1
|
||||
|
||||
## v1.52.0
|
||||
2025-01
|
||||
|
||||
* new group consistency algorithm
|
||||
* fix: don't show animated .webp stickers as static stickers
|
||||
* fix the chat shortcuts (created via long-press in launcher) to properly support multi-profile
|
||||
* fix some small bugs in certain android versions and special situations
|
||||
* avoid the app freezing in slow phones in some situations
|
||||
* improve menu in the help screen
|
||||
* update translations
|
||||
* update to core 1.155.0
|
||||
|
||||
## v1.50.5
|
||||
2025-01
|
||||
|
||||
* fix push-notifications handling for certain devices where it was not working correctly
|
||||
* update translations
|
||||
* using core 1.153.0
|
||||
|
||||
## v1.50.4
|
||||
2025-01
|
||||
|
||||
* properly send as animated stickers GIF files selected from keyboard
|
||||
* improve emoji picker in landscape mode and when changing from landscape to portrait
|
||||
* avoid crash when receiving push notifications if the user restricted the app from working in background
|
||||
* improve UI when attaching a file or image to easily recognize it is attached but not sent yet
|
||||
* avoid slow loading of in-chat apps in some devices when quickly re-opening an app after closing it
|
||||
* allow to select multiple images at once in the media picker via "Gallery" button
|
||||
* mark holiday notice messages as bot-generated
|
||||
* don't mark contacts as bot when receiving location-only and sync messages
|
||||
* prefer to encrypt even if peers have their preference to "no preference"
|
||||
* start ephemeral messages timers when the chat is archived or noticed
|
||||
* several bug fixes and updated translations
|
||||
* update to core 1.153.0
|
||||
|
||||
## v1.50.3
|
||||
2024-12
|
||||
|
||||
* Add in-chat apps picker to attachments options
|
||||
* Notify replies and reactions to your messages in muted chats (can be disabled in settings)
|
||||
* Cache HTTP GET requests (ex. when loading images from HTML messages)
|
||||
* update to core 1.152.0
|
||||
|
||||
## v1.50.2
|
||||
2024-12
|
||||
|
||||
* Encrypt notification tokens
|
||||
* update to core 1.151.5
|
||||
|
||||
## v1.50.0
|
||||
2024-12
|
||||
|
||||
* New emoji picker with support for more emojis
|
||||
* Webxdc apps can now trigger notifications
|
||||
* Webxdc apps can now deep-link to internal sections when you click their info-messages in chat
|
||||
* Add "Show in Chat" to the menu of opened Webxdc apps
|
||||
* Reverse order of messages in the notification group
|
||||
* Notify reactions to own messages
|
||||
* Improve the button to start Webxdc apps
|
||||
* Make account deletion confirmation dialog faster
|
||||
* Rename "Back up Chats to External Storage" to "Export Backup"
|
||||
* Improve compatibility with classic email clients in the outgoing messages
|
||||
* Removed internal font scaling setting in favor of the better system settings
|
||||
* Use privacy-preserving webxdc addresses
|
||||
* Use Rustls for connections with strict TLS
|
||||
* QR codes for adding contacts and joining groups provide help when opened in a normal browser
|
||||
* Mark Saved Messages chat as protected
|
||||
* Allow the user to replace maps integration
|
||||
* fix: Trim whitespace from scanned QR codes
|
||||
* fix quotes: Line-before-quote may be up to 120 character long instead of 80
|
||||
* fix: Prevent accidental wrong-password-notifications
|
||||
* fix: Remove footers from "Show Full Message..."
|
||||
* fix: Only add "member added/removed" messages if they actually do that
|
||||
* fix: Update state of message when fully downloading it
|
||||
* fix: send message: Do not fail if the message does not exist anymore
|
||||
* fix: Do not percent-encode dot when passing to autoconfig server (so, fix handling of some servers)
|
||||
* fix displaynames not being updated when intially scanned by a QR code
|
||||
* several bug fixes
|
||||
* update to core 1.151.3
|
||||
|
||||
## v1.48.3
|
||||
2024-10
|
||||
|
||||
* new Proxy settings screen available at "Advanced / Proxy"
|
||||
* manage a list of HTTP(S), SOCKS5 or Shadowsocks Proxies
|
||||
* Proxies icon shown on the chatlist if proxies are used
|
||||
* share Proxies by showing a QR code
|
||||
* scan Proxies' QR code and use them
|
||||
* make Proxy URLs inside Delta Chat tappable
|
||||
* open Delta Chat when tapping Proxy URLs in other apps
|
||||
* support for realtime webxdc apps moved out of experimental and enabled by default
|
||||
* realtime webxdc apps can be disabled at "Settings / Advanced"
|
||||
* "New Contact / Link" button to view, share or copy the invite line
|
||||
* "New Contact / Scan" button to easier access the scanner functionality
|
||||
* open "New Contact" scan/show activities directly, do not try to be too smart and open the last active tab
|
||||
* allow to attach multiple images in one step
|
||||
* to easier differ between multiple profiles, set a "Private Tag" (long tap profile switcher)
|
||||
* "Private Tag" is shown in notifications
|
||||
* improve profile deletion dialog: show name, size and avatar of the profile being deleted
|
||||
* show profile name in title bar when the user has multiple profiles
|
||||
* improve profile switcher layout
|
||||
* improve notification: allow to "Mark Read" from the notification
|
||||
* search for unread chats in the search's three-dot-menu
|
||||
* allow pasting QR codes from "Add As Second Device" screen
|
||||
* save traffic by supporting "IMAP COMPRESS"
|
||||
* automatic reconfiguration, e.g. switching to implicit TLS if STARTTLS port stops working
|
||||
* parallelize IMAP and SMTP connection attempts
|
||||
* improve DNS caching
|
||||
* always use preloaded DNS results
|
||||
* prioritize cached results if DNS resolver returns many results
|
||||
* always move auto-generated messages to DeltaChat folder
|
||||
* ignore invalid securejoin messages silently
|
||||
* delete messages from a chatmail server immediately by default
|
||||
* make resending pending messages possible
|
||||
* don't SMTP-send messages to self-chat if BccSelf is disabled
|
||||
* HTTP(S) tunneling
|
||||
* don't put displayname into From/To/Sender if it equals to address
|
||||
* hide sync messages from INBOX (use IMAP APPEND command to upload sync messages)
|
||||
* more verbose SMTP connection establishment errors
|
||||
* add "Learn More" button to "Manage keys"
|
||||
* visual feedback when tapping the action button of a message
|
||||
* log unexpected message state when resending fails
|
||||
* smoother backup and "Add Second Device" progress bars
|
||||
* assign messages to ad-hoc group with matching name and members
|
||||
* use stricter TLS checks for HTTPS downloads (images in HTML mails, Autoconfig)
|
||||
* improve logging for failed QR code scans, AEAP, Autocrypt, notification permissions and sending errors
|
||||
* improve logging of multi account setup (log account ID)
|
||||
* show more context for the "Cannot establish guaranteed..." info message
|
||||
* show file name in "Message Info"
|
||||
* show root SMTP connection failure in connectivity view
|
||||
* fix: Sort received outgoing message down if it's fresher than all non fresh messages
|
||||
* fix: avoid app being killed when processing a PUSH notification
|
||||
* fix crash when refreshing avatar
|
||||
* fix crash in gallery
|
||||
* fix: shorten message text in locally sent messages too
|
||||
* fix: Set http I/O timeout to 1 minute rather than whole request timeout
|
||||
* fix: don't sync QR code token before populating the group
|
||||
* fix: do not get stuck if the message to download does not exist anymore
|
||||
* fix: do not attempt to reference info messages
|
||||
* fix: do not get stuck if there is an error transferring backup
|
||||
* fix: make it possible to cancel ongoing backup transfer
|
||||
* fix: reset quota when entering a new address
|
||||
* fix: better detection of file extensions
|
||||
* fix: "database locked" errors
|
||||
* fix: never initialize realtime channels if realtime is disabled
|
||||
* fix reception of realtime channels
|
||||
* fix: normalize proxy URLs
|
||||
* fix connections getting stuck in "Updating..." sometimes
|
||||
* fix scanning "add second device" QR code from scanner above chatlist
|
||||
* fix warning about wrong password
|
||||
* fix app getting stale when receiving a PUSH notifications takes longer
|
||||
* fix app getting stale on network changes
|
||||
* fix: skip IDLE if we got unsolicited FETCH
|
||||
* update translations and local help
|
||||
* update to core 1.148.6
|
||||
|
||||
|
||||
## v1.46.14
|
||||
2024-09
|
||||
|
||||
* add monochrome/themed launcher icon support
|
||||
* allow to remove the selected profile in "Switch Profile" dialog
|
||||
* improve display of selected profile in "Switch Profile" dialog
|
||||
* improve the hit/tap area to open "Switch Profile" dialog in the main screen's toolbar
|
||||
* add support for system per-app language and remove in-app language selector
|
||||
* remove the experimental "encrypt database" checkbox in classic registration screen
|
||||
* fix various bugs
|
||||
* update to core 1.142.12
|
||||
|
||||
|
||||
## v1.46.13
|
||||
2024-08
|
||||
|
||||
@@ -689,7 +968,7 @@
|
||||
|
||||
* fix sending status updates of private apps
|
||||
* show full messages: do not load remote content for requests automatically
|
||||
* using to core107.1
|
||||
* using core107.1
|
||||
|
||||
|
||||
## v1.34.12
|
||||
+3
-3
@@ -34,10 +34,10 @@ ENV PATH ${PATH}:${ANDROID_SDK_ROOT}/cmdline-tools/bin
|
||||
# Install NDK manually. Other SDK parts are installed automatically by gradle.
|
||||
#
|
||||
# If you change the NDK version here, also change it in `flake.nix`.
|
||||
# NDK version r23c LTS aka 23.2.8568313
|
||||
RUN sdkmanager --sdk_root=${ANDROID_SDK_ROOT} 'ndk;23.2.8568313'
|
||||
# NDK version r27 LTS aka 27.0.11902837
|
||||
RUN sdkmanager --sdk_root=${ANDROID_SDK_ROOT} 'ndk;27.0.11902837'
|
||||
|
||||
ENV ANDROID_NDK_ROOT ${ANDROID_SDK_ROOT}/ndk/23.2.8568313
|
||||
ENV ANDROID_NDK_ROOT ${ANDROID_SDK_ROOT}/ndk/27.0.11902837
|
||||
ENV PATH ${PATH}:${ANDROID_NDK_ROOT}/toolchains/llvm/prebuilt/linux-x86_64/bin/
|
||||
|
||||
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain none
|
||||
|
||||
@@ -1,16 +1,10 @@
|
||||
## ArcaneChat Android Client
|
||||
|
||||
A [Delta Chat](https://delta.chat/) client for Android.
|
||||
A [Delta Chat](https://delta.chat/) client for Android. Learn more at: https://arcanechat.me
|
||||
|
||||
[<img src="store/get-it-on-IzzyOnDroid.png"
|
||||
alt="Get it on IzzyOnDroid"
|
||||
height="48">](https://apt.izzysoft.de/fdroid/index/apk/chat.delta.lite)
|
||||
[<img src="store/get-it-on-apklis.png"
|
||||
alt="Disponible en Apklis"
|
||||
height="48">](https://www.apklis.cu/application/chat.delta.lite)
|
||||
[<img src="store/get-it-on-github.png"
|
||||
alt="Get it on GitHub"
|
||||
height="48">](https://github.com/ArcaneChat/android/releases/latest)
|
||||
[<img src="store/get-it-on-gplay.png" alt="Get it on Google Play" height="48">](https://play.google.com/store/apps/details?id=com.github.arcanechat)
|
||||
[<img src="store/get-it-on-fdroid.png" alt="Get it on F-Droid" height="48">](https://f-droid.org/packages/chat.delta.lite)
|
||||
[<img src="store/get-it-on-github.png" alt="Get it on GitHub" height="48">](https://github.com/ArcaneChat/android/releases/latest/download/ArcaneChat-gplay.apk)
|
||||
|
||||
|
||||
<img alt="Screenshot" src="fastlane/metadata/android/en-US/images/phoneScreenshots/1.png" width="298" /> <img alt="Screenshot" src="fastlane/metadata/android/en-US/images/phoneScreenshots/2.png" width="298" />
|
||||
@@ -21,7 +15,6 @@ This app has some extended support for WebXDC apps:
|
||||
|
||||
- `window.webxdc.arcanechat` a string with the ArcaneChat version and can be used by app developers
|
||||
to detect when they can use the ArcaneChat-specific features.
|
||||
- `window.webxdc.isCommunity` true if the current account is a community account
|
||||
- `sendToChat()`: extra property `subject` can be set to a text string to set message/email's subject.
|
||||
- `sendToChat()`: extra property `html` can be set to a string of html markup to set the HTML part of the email/message.
|
||||
- `sendToChat()`: the file object parameter also accepts a `type` field that can be one of:
|
||||
|
||||
+27
-19
@@ -13,25 +13,28 @@ on the command-line, in a PR called "update-core-and-stuff-DATE":
|
||||
./scripts/ndk-make.sh
|
||||
```
|
||||
|
||||
a) Update `CHANGELOG.md`
|
||||
from <https://github.com/chatmail/core/blob/main/CHANGELOG.md>,
|
||||
do not just copy and avoid technical terms.
|
||||
The changelog is for the end user and shall show impacts form that angle.
|
||||
Add used core version to end of changelog entry
|
||||
as `update to core 1.2.3` or `using core 1.2.3`
|
||||
|
||||
|
||||
2. update translations and local help:
|
||||
```
|
||||
./scripts/tx-pull-translations.sh
|
||||
./scripts/create-local-help.sh # requires deltachat-pages checked out at ../deltachat-pages
|
||||
```
|
||||
|
||||
the "update-core-and-stuff-DATE" PR can be merged without review
|
||||
(as everything was already reviewed in their repos).
|
||||
|
||||
the following steps are done in a PR called `prep-VERSION` (no leading "v"):
|
||||
|
||||
3. update `CHANGELOG.md`
|
||||
from <https://github.com/deltachat/deltachat-core-rust/blob/main/CHANGELOG.md>
|
||||
and <https://github.com/deltachat/deltachat-android/pulls?q=is%3Apr+is%3Aclosed+sort%3Aupdated-desc>.
|
||||
avoid technical terms, library versions etc. the changelog is for the end user.
|
||||
do not forget to update/mention used core version and release month.
|
||||
3. Update `CHANGELOG.md`:
|
||||
Rename header with version number and add date as `YYYY-MM`
|
||||
|
||||
in case previous entries of the changelog refer to betas or to not officially released versions,
|
||||
the entries can be summarized.
|
||||
this makes it easier for the end user to follow changes by showing major changes atop
|
||||
this makes it easier for the end user to follow changes by showing major changes atop.
|
||||
|
||||
4. add a device message to `ConversationListActivity::onCreate()` or remove the old one.
|
||||
do not repeat the CHANGELOG here: write what really is the ux outcome
|
||||
@@ -44,7 +47,8 @@ the following steps are done in a PR called `prep-VERSION` (no leading "v"):
|
||||
6. build APKs:
|
||||
a) generate debug APK at "Build / Build Bundle(s)/APK / Build APK(s)"
|
||||
b) generate release APK at "Build / Generate Signed Bundle or APK",
|
||||
select "APK", add keys, flavor `gplayRelease`
|
||||
select "APK", add keys, flavor `gplayRelease`.
|
||||
this APK will go to the stores and is located at `gplay/release`
|
||||
|
||||
|
||||
## Push Test Releases
|
||||
@@ -75,16 +79,21 @@ only afterwards, push the APK to stores. **consider a blog post.**
|
||||
|
||||
on <https://play.google.com/apps/publish/>:
|
||||
|
||||
9. a) open "Delta Chat/Release/Production"
|
||||
then "Create new release" and upload APK from above
|
||||
9. a) open "Delta Chat / Test and release / Production"
|
||||
then "Create new release" and upload APK from above
|
||||
b) fill out "Release details/Release notes" (500 chars), add the line
|
||||
"These features will roll out over the coming days. Thanks for using Delta Chat!";
|
||||
release name should be default ("123 (1.2.3)")
|
||||
c) click "Next", set "Rollout Percentage" to 1% (later 2%, 5%, 10%, 20%, 50%, 100%),
|
||||
click "Save"
|
||||
c) click "Next", set "Rollout Percentage" to 50%, click "Save"
|
||||
d) Go to "Publishing Overview", "Managed publishing" is usually off;
|
||||
click "Send change for review", confirm
|
||||
|
||||
2 days later, change "Rollout Percentage" to 99%. Two more days later to 100%.
|
||||
Rollout is anyways slower in practise, however,
|
||||
only as long as we do not enter 100%, we can retract the version
|
||||
(Once we reach 100%, we have to submit a new version for approval.
|
||||
During these up to 4 days, sometimes longer, we cannot do anything on existing rollout)
|
||||
|
||||
|
||||
## Tag for F-Droid and create Github release
|
||||
|
||||
@@ -104,12 +113,11 @@ This may take some days.
|
||||
|
||||
on <https://developer.amazon.com/dashboard>:
|
||||
|
||||
12. a) for "Delta Chat", select "Add upcoming version" on the left
|
||||
12. a) click "App List", for "Delta Chat", select "Add upcoming version" on the left
|
||||
b) at "Step 1 / Existing file(s)" hit "Replace", upload the APK from above
|
||||
c) on the "Step 1" page, add "Release notes" from CHANGELOG.md, hit "Next"
|
||||
d) on "Step 2" page: "Does your app collect or transfer user data to third parties?" -> No, then "Next"
|
||||
e) on "Step 3" page: "Next"
|
||||
f) on "Step 4" page: "Submit app"
|
||||
d) on "Step 2" and "Step 3" pages, hit "Next"
|
||||
e) on "Step 4" page: "Submit app"
|
||||
|
||||
|
||||
## Release on Huawei AppGallery
|
||||
@@ -122,7 +130,7 @@ on <https://developer.huawei.com/consumer/en/appgallery>:
|
||||
d) Hit "Submit"; on the next page, confirm version and language
|
||||
|
||||
|
||||
## Releases on Apklis, Passkoocheh
|
||||
## Releases on other stores (ex. Passkoocheh)
|
||||
|
||||
These stores are not under our control.
|
||||
On important updates **ping store maintainers** and ask to update.
|
||||
|
||||
+48
-31
@@ -1,5 +1,5 @@
|
||||
plugins {
|
||||
id 'com.android.application' version '8.1.4'
|
||||
id 'com.android.application' version '8.5.2'
|
||||
id 'com.google.gms.google-services' version '4.4.1'
|
||||
}
|
||||
|
||||
@@ -29,12 +29,12 @@ android {
|
||||
// > Task :stripFatDebugDebugSymbols
|
||||
// Unable to strip the following libraries, packaging them as they are: libanimation-decoder-gif.so, libnative-utils.so.
|
||||
// See <https://issuetracker.google.com/issues/237187538> for details.
|
||||
ndkVersion "23.2.8568313"
|
||||
ndkVersion "27.0.12077973"
|
||||
useLibrary 'org.apache.http.legacy'
|
||||
|
||||
defaultConfig {
|
||||
versionCode 30000689
|
||||
versionName "1.46.17"
|
||||
versionCode 30000720
|
||||
versionName "1.58.2"
|
||||
|
||||
applicationId "chat.delta.lite"
|
||||
multiDexEnabled true
|
||||
@@ -87,15 +87,45 @@ android {
|
||||
storeFile file(DC_DEBUG_STORE_FILE )
|
||||
}
|
||||
}
|
||||
release {
|
||||
releaseFdroid {
|
||||
// can be defined at `~/.gradle/gradle.properties` or at "Build/Generate signed APK"
|
||||
if(project.hasProperty("DC_RELEASE_STORE_FILE")) {
|
||||
storeFile file(DC_RELEASE_STORE_FILE)
|
||||
storePassword DC_RELEASE_STORE_PASSWORD
|
||||
keyAlias DC_RELEASE_KEY_ALIAS
|
||||
keyAlias DC_RELEASE_KEY_ALIAS_FDROID
|
||||
keyPassword DC_RELEASE_KEY_PASSWORD
|
||||
}
|
||||
}
|
||||
releaseApk {
|
||||
// can be defined at `~/.gradle/gradle.properties` or at "Build/Generate signed APK"
|
||||
if(project.hasProperty("DC_RELEASE_STORE_FILE")) {
|
||||
storeFile file(DC_RELEASE_STORE_FILE)
|
||||
storePassword DC_RELEASE_STORE_PASSWORD
|
||||
keyAlias DC_RELEASE_KEY_ALIAS_GPLAY
|
||||
keyPassword DC_RELEASE_KEY_PASSWORD
|
||||
}
|
||||
}
|
||||
releaseBundle {
|
||||
if(project.hasProperty("DC_BUNDLE_STORE_FILE")) {
|
||||
storeFile file(DC_BUNDLE_STORE_FILE)
|
||||
storePassword DC_BUNDLE_STORE_PASSWORD
|
||||
keyAlias DC_BUNDLE_KEY_ALIAS
|
||||
keyPassword DC_BUNDLE_STORE_PASSWORD
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
productFlavors {
|
||||
foss {
|
||||
dimension "none"
|
||||
buildConfigField "boolean", "USE_PLAY_SERVICES", "false"
|
||||
}
|
||||
gplay {
|
||||
dimension "none"
|
||||
apply plugin: "com.google.gms.google-services"
|
||||
buildConfigField "boolean", "USE_PLAY_SERVICES", "true"
|
||||
applicationId "com.github.arcanechat"
|
||||
}
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
@@ -114,23 +144,12 @@ android {
|
||||
// nb: it is highly recommended to use the same settings in debug+release -
|
||||
// otherwise problems might be noticed delayed only
|
||||
minifyEnabled true
|
||||
signingConfig signingConfigs.release
|
||||
productFlavors.foss.signingConfig signingConfigs.releaseFdroid
|
||||
productFlavors.gplay.signingConfig signingConfigs.releaseApk
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
|
||||
productFlavors {
|
||||
foss {
|
||||
dimension "none"
|
||||
buildConfigField "boolean", "USE_PLAY_SERVICES", "false"
|
||||
}
|
||||
gplay {
|
||||
dimension "none"
|
||||
apply plugin: "com.google.gms.google-services"
|
||||
buildConfigField "boolean", "USE_PLAY_SERVICES", "true"
|
||||
}
|
||||
}
|
||||
|
||||
if(!project.hasProperty("ABI_FILTER")) {
|
||||
splits {
|
||||
abi {
|
||||
@@ -190,7 +209,7 @@ dependencies {
|
||||
implementation 'com.airbnb.android:lottie:4.2.2' // Lottie animations support.
|
||||
|
||||
implementation 'androidx.sharetarget:sharetarget:1.2.0'
|
||||
implementation 'androidx.webkit:webkit:1.11.0'
|
||||
implementation 'androidx.webkit:webkit:1.12.1'
|
||||
implementation 'androidx.multidex:multidex:2.0.1'
|
||||
implementation 'androidx.appcompat:appcompat:1.7.0'
|
||||
implementation 'com.google.android.material:material:1.12.0'
|
||||
@@ -206,26 +225,25 @@ dependencies {
|
||||
implementation 'androidx.lifecycle:lifecycle-viewmodel:2.6.2'
|
||||
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2'
|
||||
implementation 'androidx.work:work-runtime:2.9.1'
|
||||
implementation 'androidx.emoji2:emoji2-emojipicker:1.4.0'
|
||||
implementation 'androidx.emoji2:emoji2-emojipicker:1.5.0'
|
||||
implementation 'com.google.guava:guava:31.1-android'
|
||||
implementation 'com.google.android.exoplayer:exoplayer-core:2.19.1' // plays video and audio
|
||||
implementation 'com.google.android.exoplayer:exoplayer-ui:2.19.1'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.2.0'
|
||||
implementation 'com.google.zxing:core:3.3.0' // fixed version to support SDK<24
|
||||
implementation ('com.journeyapps:zxing-android-embedded:4.3.0') { transitive = false } // QR Code scanner
|
||||
implementation 'com.fasterxml.jackson.core:jackson-databind:2.11.1' // used as JSON library
|
||||
implementation 'com.google.code.gson:gson:2.9.1' // used as JSON library. Don't upgrade to 2.10.1: https://github.com/deltachat/deltachat-android/pull/2610
|
||||
implementation 'com.google.code.gson:gson:2.12.1' // used as JSON library.
|
||||
implementation "me.leolin:ShortcutBadger:1.1.16" // display messagecount on the home screen icon.
|
||||
implementation 'com.jpardogo.materialtabstrip:library:1.0.9' // used in the emoji selector for the tab selection.
|
||||
implementation 'com.github.chrisbanes:PhotoView:2.1.3' // does the zooming on photos / media
|
||||
implementation 'com.github.penfeizhou.android.animation:glide-plugin:2.25.0' // APNG & animated webp support.
|
||||
implementation 'com.github.Baseflow:PhotoView:2.3.0' // does the zooming on photos / media
|
||||
implementation 'com.github.penfeizhou.android.animation:awebp:3.0.2' // animated webp support.
|
||||
implementation 'com.caverock:androidsvg-aar:1.4' // SVG support.
|
||||
implementation 'com.github.bumptech.glide:glide:4.12.0'
|
||||
annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0'
|
||||
annotationProcessor 'androidx.annotation:annotation:1.8.2'
|
||||
annotationProcessor 'androidx.annotation:annotation:1.9.1'
|
||||
implementation 'com.makeramen:roundedimageview:2.1.0' // crops the avatars to circles
|
||||
implementation 'com.pnikosis:materialish-progress:1.5' // used only in the "Progress Wheel" in Share Activity.
|
||||
implementation 'com.soundcloud.android:android-crop:1.0.1@aar' // used for profile and group avatar selection in Android SDK<19
|
||||
implementation 'com.github.amulyakhare:TextDrawable:558677ea31' // number of unread messages,
|
||||
// the one-letter circle for the contacts (when there is not avatar) and a white background.
|
||||
implementation 'com.googlecode.mp4parser:isoparser:1.0.6' // MP4 recoding; upgrading eg. to 1.1.22 breaks recoding, however, i have not investigated further, just reset to 1.0.6
|
||||
@@ -234,13 +252,12 @@ dependencies {
|
||||
}
|
||||
implementation 'com.annimon:stream:1.1.8' // brings future java streams api to SDK Version < 24
|
||||
|
||||
implementation 'com.getkeepsafe.relinker:relinker:1.4.4' // needed to avoid safe-content-resolver-v14 trying to fetch older non-existing version
|
||||
// Replacement for ContentResolver
|
||||
// that protects against the Surreptitious Sharing attack.
|
||||
// <https://github.com/cketti/SafeContentResolver>
|
||||
implementation 'de.cketti.safecontentresolver:safe-content-resolver-v14:1.0.0'
|
||||
implementation 'de.cketti.safecontentresolver:safe-content-resolver-v21:1.0.0'
|
||||
|
||||
gplayImplementation('com.google.firebase:firebase-messaging:24.0.0') { // for PUSH notifications
|
||||
gplayImplementation('com.google.firebase:firebase-messaging:24.1.0') { // for PUSH notifications
|
||||
exclude group: 'com.google.firebase', module: 'firebase-core'
|
||||
exclude group: 'com.google.firebase', module: 'firebase-analytics'
|
||||
exclude group: 'com.google.firebase', module: 'firebase-measurement-connector'
|
||||
@@ -254,7 +271,7 @@ dependencies {
|
||||
testImplementation 'org.powermock:powermock-module-junit4-rule:1.6.1'
|
||||
testImplementation 'org.powermock:powermock-classloading-xstream:1.6.1'
|
||||
|
||||
androidTestImplementation 'androidx.test:runner:1.6.1'
|
||||
androidTestImplementation 'androidx.test:runner:1.6.2'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.6.1'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-contrib:3.6.1'
|
||||
androidTestImplementation 'androidx.test:rules:1.6.1'
|
||||
|
||||
@@ -1,40 +1,39 @@
|
||||
ArcaneChat is a decentralized and secure messenger app that is
|
||||
completely compatible with the existing e-mail infrastructure.
|
||||
ArcaneChat is a decentralized and secure instant messenger that is easy to use for friends and family.
|
||||
|
||||
Some features at a glance:
|
||||
• Anonymous. Instant onboarding without a phone number, e-mail or other private data.
|
||||
|
||||
💬 Reliable instant messaging with multi-profile and multi-device support.
|
||||
• Flexible. Supports multiple chat profiles and is easy to setup on multiple devices.
|
||||
|
||||
⚡️ Sign-up easily using secure fast chatmail servers. You don’t need a phone number or any private data.
|
||||
• Extensible. Use mini-apps in chats like shopping lists, calendars or games.
|
||||
|
||||
📧 Alternatively, use your existing classic e-mail address to read your inbox as chats.
|
||||
• Reliable. Works under bad and adverserial network conditions.
|
||||
|
||||
🎮 Interactive mini-apps in chats for gaming and collaboration.
|
||||
• Secure. Audited End-to-End encryption safe against network and server attacks.
|
||||
|
||||
🔒 Audited end-to-end encryption safe against network and server attacks.
|
||||
• Sovereign. Can be run with your own e-mail address or server.
|
||||
|
||||
ArcaneChat is a Delta Chat client and was created with a focus on usability,
|
||||
good user experience, and saving data plan. Also the app usually experiments with
|
||||
new features that eventually might get added to the official Delta Chat client.
|
||||
ArcaneChat is a Delta Chat client and was created with a focus on usability, good user experience, and saving data plan. Also the app usually experiments with new features that eventually might get added to the official Delta Chat client.
|
||||
|
||||
<b>Main differences with official Delta Chat client:</b>
|
||||
|
||||
<ul>
|
||||
<li>Basic markdown support (bold, italic, strike, etc.)</li>
|
||||
<li>Support for some markdown styles in text messages (bold, italic, strike, etc.)</li>
|
||||
<li>Support for displaying Telegram's animated stickers (.tgs files)</li>
|
||||
<li>Support for SVG images previews</li>
|
||||
<li>Multiple color themes/skins</li>
|
||||
<li>It is possible to enable/disable accounts</li>
|
||||
<li>It is possible to disable profiles to completely disconnect them saving data/bandwidth</li>
|
||||
<li>You can easily see the connection status of all your profiles in the profile switcher</li>
|
||||
<li>A videochat instance is set by default</li>
|
||||
<li>Replies to your messages in muted groups trigger notifications</li>
|
||||
<li>Location streaming feature enabled by default and have extra option to share location for 12 hours</li>
|
||||
<li>Extra option to share location for 12 hours</li>
|
||||
<li>Clicking on a message with a POI location, will open the POI on the map</li>
|
||||
<li>Last-seen status of contacts is shown in your contact list, like in WhatsApp, Telegram, etc.</li>
|
||||
<li>Videos are played in loop, useful for short GIF videos</li>
|
||||
<li>Verified icon is shown in the chat list for the "Device Messages" chat</li>
|
||||
<li>Voice messages have more aggressive compression in "worse quality" mode to save data plan</li>
|
||||
<li>Automatic download of messages limited to 640KB by default</li>
|
||||
<li>Account's display name is shown in the app's title bar instead of the name of the app</li>
|
||||
<li>Profile's display name is always shown in the app's title bar instead of the name of the app</li>
|
||||
<li>Your avatar is visible to other users in Mailing Lists</li>
|
||||
<li>Can be selected as app to open .xdc files</li>
|
||||
<li>For mini-apps developers: there are some differences in the WebXDC API, check https://github.com/ArcaneChat/android/#webxdc</li>
|
||||
<li>For mini-apps developers: there are some extra features in the WebXDC API, check https://github.com/ArcaneChat/android/#webxdc</li>
|
||||
<li>Better settings organization with additional "Privacy" section</li>
|
||||
</ul>
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 171 KiB After Width: | Height: | Size: 137 KiB |
Generated
+26
-94
@@ -3,15 +3,15 @@
|
||||
"android": {
|
||||
"inputs": {
|
||||
"devshell": "devshell",
|
||||
"flake-utils": "flake-utils_2",
|
||||
"flake-utils": "flake-utils",
|
||||
"nixpkgs": "nixpkgs"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1710633978,
|
||||
"narHash": "sha256-yemnwSvW7cdWtXGpivFA5jDO35rGPs6fqxlQ4l6ODXs=",
|
||||
"lastModified": 1733948466,
|
||||
"narHash": "sha256-o/uq/tU458Ykudi8Zk3sRga5iazkuSczt9wDOCUDOSU=",
|
||||
"owner": "tadfisher",
|
||||
"repo": "android-nixpkgs",
|
||||
"rev": "e91fb3d8517538e5ad9b422c9a4f604b56008a9e",
|
||||
"rev": "0bf99ffaea6a7c0948ae10cf2e40c2905e4e4d6b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -22,18 +22,17 @@
|
||||
},
|
||||
"devshell": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils",
|
||||
"nixpkgs": [
|
||||
"android",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1708939976,
|
||||
"narHash": "sha256-O5+nFozxz2Vubpdl1YZtPrilcIXPcRAjqNdNE8oCRoA=",
|
||||
"lastModified": 1728330715,
|
||||
"narHash": "sha256-xRJ2nPOXb//u1jaBnDP56M7v5ldavjbtR6lfGqSvcKg=",
|
||||
"owner": "numtide",
|
||||
"repo": "devshell",
|
||||
"rev": "5ddecd67edbd568ebe0a55905273e56cc82aabe3",
|
||||
"rev": "dd6b80932022cea34a019e2bb32f6fa9e494dfef",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -47,11 +46,11 @@
|
||||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1701680307,
|
||||
"narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=",
|
||||
"lastModified": 1731533236,
|
||||
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "4022d587cbbfd70fe950c1e2083a02621806a725",
|
||||
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -65,47 +64,11 @@
|
||||
"systems": "systems_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1709126324,
|
||||
"narHash": "sha256-q6EQdSeUZOG26WelxqkmR7kArjgWCdw5sfJVHPH/7j8=",
|
||||
"lastModified": 1731533236,
|
||||
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "d465f4819400de7c8d874d50b982301f28a84605",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils_3": {
|
||||
"inputs": {
|
||||
"systems": "systems_3"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1710146030,
|
||||
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils_4": {
|
||||
"inputs": {
|
||||
"systems": "systems_4"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1705309234,
|
||||
"narHash": "sha256-uNRRNRKmJyCRC/8y1RqBkqWBLM034y4qN7EprSdmgyA=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "1ef2e671c3b0c19053962c07dbda38332dcebf26",
|
||||
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -116,11 +79,11 @@
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1709237383,
|
||||
"narHash": "sha256-cy6ArO4k5qTx+l5o+0mL9f5fa86tYUX3ozE1S+Txlds=",
|
||||
"lastModified": 1733759999,
|
||||
"narHash": "sha256-463SNPWmz46iLzJKRzO3Q2b0Aurff3U1n0nYItxq7jU=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "1536926ef5621b09bba54035ae2bb6d806d72ac8",
|
||||
"rev": "a73246e2eef4c6ed172979932bc80e1404ba2d56",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -132,11 +95,11 @@
|
||||
},
|
||||
"nixpkgs_2": {
|
||||
"locked": {
|
||||
"lastModified": 1710889954,
|
||||
"narHash": "sha256-Pr6F5Pmd7JnNEMHHmspZ0qVqIBVxyZ13ik1pJtm2QXk=",
|
||||
"lastModified": 1733749988,
|
||||
"narHash": "sha256-+5qdtgXceqhK5ZR1YbP1fAUsweBIrhL38726oIEAtDs=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "7872526e9c5332274ea5932a0c3270d6e4724f3b",
|
||||
"rev": "bc27f0fde01ce4e1bfec1ab122d72b7380278e68",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -148,11 +111,11 @@
|
||||
},
|
||||
"nixpkgs_3": {
|
||||
"locked": {
|
||||
"lastModified": 1706487304,
|
||||
"narHash": "sha256-LE8lVX28MV2jWJsidW13D2qrHU/RUUONendL2Q/WlJg=",
|
||||
"lastModified": 1728538411,
|
||||
"narHash": "sha256-f0SBJz1eZ2yOuKUr5CA9BHULGXVSn6miBuUWdTyhUhU=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "90f456026d284c22b3e3497be980b2e47d0b28ac",
|
||||
"rev": "b69de56fac8c2b6f8fd27f2eca01dcda8e0a4221",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -165,22 +128,21 @@
|
||||
"root": {
|
||||
"inputs": {
|
||||
"android": "android",
|
||||
"flake-utils": "flake-utils_3",
|
||||
"flake-utils": "flake-utils_2",
|
||||
"nixpkgs": "nixpkgs_2",
|
||||
"rust-overlay": "rust-overlay"
|
||||
}
|
||||
},
|
||||
"rust-overlay": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils_4",
|
||||
"nixpkgs": "nixpkgs_3"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1711073443,
|
||||
"narHash": "sha256-PpNb4xq7U5Q/DdX40qe7CijUsqhVVM3VZrhN0+c6Lcw=",
|
||||
"lastModified": 1733970833,
|
||||
"narHash": "sha256-sPEKtSaZk2CtfF9cdhtbY93S6qGq+d2PKI1fcoDfDaI=",
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"rev": "eec55ba9fcde6be4c63942827247e42afef7fafe",
|
||||
"rev": "f7f4c59ccdf1bec3f1547d27398e9589aa94e3e8",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -218,36 +180,6 @@
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"systems_3": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"systems_4": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
|
||||
@@ -15,20 +15,22 @@
|
||||
pkgs = import nixpkgs { inherit system overlays; };
|
||||
android-sdk = android.sdk.${system} (sdkPkgs:
|
||||
with sdkPkgs; [
|
||||
build-tools-33-0-1
|
||||
build-tools-34-0-0
|
||||
cmdline-tools-latest
|
||||
ndk-bundle
|
||||
platform-tools
|
||||
platforms-android-34
|
||||
ndk-23-2-8568313
|
||||
ndk-27-2-12479018
|
||||
]);
|
||||
rust-version = pkgs.lib.removeSuffix "\n"
|
||||
(builtins.readFile ./scripts/rust-toolchain);
|
||||
in {
|
||||
in
|
||||
{
|
||||
formatter = pkgs.nixpkgs-fmt;
|
||||
|
||||
devShells.default = pkgs.mkShell {
|
||||
ANDROID_SDK_ROOT = "${android-sdk}/share/android-sdk";
|
||||
ANDROID_NDK_ROOT =
|
||||
"${android-sdk}/share/android-sdk/ndk/23.2.8568313";
|
||||
"${android-sdk}/share/android-sdk/ndk/27.2.12479018";
|
||||
buildInputs = [
|
||||
android-sdk
|
||||
pkgs.openjdk17
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
"client_info": {
|
||||
"mobilesdk_app_id": "1:922391085500:android:6f54e2c4e49405673e2bb9",
|
||||
"android_client_info": {
|
||||
"package_name": "chat.delta.lite.beta"
|
||||
"package_name": "com.github.arcanechat.beta"
|
||||
}
|
||||
},
|
||||
"oauth_client": [],
|
||||
@@ -47,7 +47,7 @@
|
||||
"client_info": {
|
||||
"mobilesdk_app_id": "1:922391085500:android:aff82fbc40c8172e3e2bb9",
|
||||
"android_client_info": {
|
||||
"package_name": "chat.delta.lite"
|
||||
"package_name": "com.github.arcanechat"
|
||||
}
|
||||
},
|
||||
"oauth_client": [],
|
||||
@@ -66,7 +66,7 @@
|
||||
"client_info": {
|
||||
"mobilesdk_app_id": "1:922391085500:android:92b4cf12669cc2083e2bb9",
|
||||
"android_client_info": {
|
||||
"package_name": "com.github.arcanechat"
|
||||
"package_name": "chat.delta.lite"
|
||||
}
|
||||
},
|
||||
"oauth_client": [],
|
||||
@@ -85,7 +85,7 @@
|
||||
"client_info": {
|
||||
"mobilesdk_app_id": "1:922391085500:android:228a205b8aa2bacc3e2bb9",
|
||||
"android_client_info": {
|
||||
"package_name": "com.github.arcanechat.beta"
|
||||
"package_name": "chat.delta.lite.beta"
|
||||
}
|
||||
},
|
||||
"oauth_client": [],
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
android.defaults.buildfeatures.buildconfig=true
|
||||
android.enableJetifier=true
|
||||
android.nonFinalResIds=false
|
||||
android.nonTransitiveRClass=false
|
||||
android.useAndroidX=true
|
||||
org.gradle.jvmargs=-Xmx4608m
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionSha256Sum=ff7bf6a86f09b9b2c40bb8f48b25fc19cf2b2664fd1d220cd7ab833ec758d0d7
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.2-bin.zip
|
||||
distributionSha256Sum=544c35d6bd849ae8a5ed0bcea39ba677dc40f49df7d1835561582da2009b961d
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
|
||||
networkTimeout=10000
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
||||
+88
-113
@@ -7,57 +7,6 @@
|
||||
#include "deltachat-core-rust/deltachat-ffi/deltachat.h"
|
||||
|
||||
|
||||
#if __ANDROID_API__ == 16
|
||||
unsigned long getauxval(unsigned long type) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int sendmmsg(int sockfd, struct mmsghdr *msgvec, unsigned int vlen,
|
||||
int flags)
|
||||
{
|
||||
if (flags != 0) {
|
||||
// Not supported by the fallback.
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (vlen == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t n = sendmsg(sockfd, &msgvec->msg_hdr, flags);
|
||||
if (n == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
(*msgvec).msg_len = n;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int recvmmsg(int sockfd, struct mmsghdr *msgvec, unsigned int vlen,
|
||||
int flags, struct timespec *timeout)
|
||||
{
|
||||
if (flags != 0) {
|
||||
// Not supported by the fallback.
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (vlen == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int n = recvmsg(sockfd, &msgvec->msg_hdr, flags);
|
||||
if (n == -1) {
|
||||
return -1;
|
||||
}
|
||||
(*msgvec).msg_len = n;
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static dc_msg_t* get_dc_msg(JNIEnv *env, jobject obj);
|
||||
|
||||
|
||||
@@ -276,9 +225,9 @@ JNIEXPORT void Java_com_b44t_messenger_DcAccounts_setPushDeviceToken(JNIEnv *env
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT jint Java_com_b44t_messenger_DcAccounts_addAccount(JNIEnv *env, jobject obj)
|
||||
JNIEXPORT jboolean Java_com_b44t_messenger_DcAccounts_backgroundFetch(JNIEnv *env, jobject obj, jint timeout_seconds)
|
||||
{
|
||||
return dc_accounts_add_account(get_dc_accounts(env, obj));
|
||||
return dc_accounts_background_fetch(get_dc_accounts(env, obj), timeout_seconds) != 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -704,6 +653,14 @@ JNIEXPORT jstring Java_com_b44t_messenger_DcContext_getMsgInfo(JNIEnv *env, jobj
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT void Java_com_b44t_messenger_DcContext_sendEditRequest(JNIEnv *env, jobject obj, jint msg_id, jstring text)
|
||||
{
|
||||
CHAR_REF(text);
|
||||
dc_send_edit_request(get_dc_context(env, obj), msg_id, textPtr);
|
||||
CHAR_UNREF(text);
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT jstring Java_com_b44t_messenger_DcContext_getMsgHtml(JNIEnv *env, jobject obj, jint msg_id)
|
||||
{
|
||||
char* temp = dc_get_msg_html(get_dc_context(env, obj), msg_id);
|
||||
@@ -728,6 +685,15 @@ JNIEXPORT void Java_com_b44t_messenger_DcContext_deleteMsgs(JNIEnv *env, jobject
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT void Java_com_b44t_messenger_DcContext_sendDeleteRequest(JNIEnv *env, jobject obj, jintArray msg_ids)
|
||||
{
|
||||
int msg_ids_cnt = 0;
|
||||
uint32_t* msg_ids_ptr = jintArray2uint32Pointer(env, msg_ids, &msg_ids_cnt);
|
||||
dc_send_delete_request(get_dc_context(env, obj), msg_ids_ptr, msg_ids_cnt);
|
||||
free(msg_ids_ptr);
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT void Java_com_b44t_messenger_DcContext_forwardMsgs(JNIEnv *env, jobject obj, jintArray msg_ids, jint chat_id)
|
||||
{
|
||||
int msg_ids_cnt = 0;
|
||||
@@ -736,6 +702,13 @@ JNIEXPORT void Java_com_b44t_messenger_DcContext_forwardMsgs(JNIEnv *env, jobjec
|
||||
free(msg_ids_ptr);
|
||||
}
|
||||
|
||||
JNIEXPORT void Java_com_b44t_messenger_DcContext_saveMsgs(JNIEnv *env, jobject obj, jintArray msg_ids)
|
||||
{
|
||||
int msg_ids_cnt = 0;
|
||||
uint32_t* msg_ids_ptr = jintArray2uint32Pointer(env, msg_ids, &msg_ids_cnt);
|
||||
dc_save_msgs(get_dc_context(env, obj), msg_ids_ptr, msg_ids_cnt);
|
||||
free(msg_ids_ptr);
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean Java_com_b44t_messenger_DcContext_resendMsgs(JNIEnv *env, jobject obj, jintArray msg_ids)
|
||||
{
|
||||
@@ -747,12 +720,6 @@ JNIEXPORT jboolean Java_com_b44t_messenger_DcContext_resendMsgs(JNIEnv *env, job
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT jint Java_com_b44t_messenger_DcContext_prepareMsg(JNIEnv *env, jobject obj, jint chat_id, jobject msg)
|
||||
{
|
||||
return dc_prepare_msg(get_dc_context(env, obj), chat_id, get_dc_msg(env, msg));
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT jint Java_com_b44t_messenger_DcContext_sendMsg(JNIEnv *env, jobject obj, jint chat_id, jobject msg)
|
||||
{
|
||||
return dc_send_msg(get_dc_context(env, obj), chat_id, get_dc_msg(env, msg));
|
||||
@@ -774,12 +741,10 @@ JNIEXPORT jint Java_com_b44t_messenger_DcContext_sendVideochatInvitation(JNIEnv
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT jboolean Java_com_b44t_messenger_DcContext_sendWebxdcStatusUpdate(JNIEnv *env, jobject obj, jint msg_id, jstring payload, jstring descr)
|
||||
JNIEXPORT jboolean Java_com_b44t_messenger_DcContext_sendWebxdcStatusUpdate(JNIEnv *env, jobject obj, jint msg_id, jstring payload)
|
||||
{
|
||||
CHAR_REF(payload);
|
||||
CHAR_REF(descr);
|
||||
jboolean ret = dc_send_webxdc_status_update(get_dc_context(env, obj), msg_id, payloadPtr, descrPtr) != 0;
|
||||
CHAR_UNREF(descr);
|
||||
jboolean ret = dc_send_webxdc_status_update(get_dc_context(env, obj), msg_id, payloadPtr, NULL) != 0;
|
||||
CHAR_UNREF(payload);
|
||||
return ret;
|
||||
}
|
||||
@@ -848,7 +813,7 @@ JNIEXPORT jstring Java_com_b44t_messenger_DcContext_getConfig(JNIEnv *env, jobje
|
||||
}
|
||||
dc_str_unref(temp);
|
||||
CHAR_UNREF(key);
|
||||
return ret; /* returns NULL only if key is unset and "def" is NULL */
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -878,6 +843,16 @@ JNIEXPORT jstring Java_com_b44t_messenger_DcContext_getSecurejoinQrSvg(JNIEnv *e
|
||||
return ret;
|
||||
}
|
||||
|
||||
JNIEXPORT jstring Java_com_b44t_messenger_DcContext_createQrSvg(JNIEnv *env, jobject obj, jstring payload)
|
||||
{
|
||||
CHAR_REF(payload);
|
||||
char* temp = dc_create_qr_svg(payloadPtr);
|
||||
jstring ret = JSTRING_NEW(temp);
|
||||
dc_str_unref(temp);
|
||||
CHAR_UNREF(payload);
|
||||
return ret;
|
||||
}
|
||||
|
||||
JNIEXPORT jint Java_com_b44t_messenger_DcContext_joinSecurejoin(JNIEnv *env, jobject obj, jstring qr)
|
||||
{
|
||||
CHAR_REF(qr);
|
||||
@@ -947,15 +922,6 @@ JNIEXPORT jstring Java_com_b44t_messenger_DcContext_initiateKeyTransfer(JNIEnv *
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT jboolean Java_com_b44t_messenger_DcContext_continueKeyTransfer(JNIEnv *env, jobject obj, jint msg_id, jstring setupCode)
|
||||
{
|
||||
CHAR_REF(setupCode);
|
||||
jboolean ret = dc_continue_key_transfer(get_dc_context(env, obj), msg_id, setupCodePtr);
|
||||
CHAR_UNREF(setupCode);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT void Java_com_b44t_messenger_DcContext_imex(JNIEnv *env, jobject obj, jint what, jstring dir)
|
||||
{
|
||||
CHAR_REF(dir);
|
||||
@@ -1325,12 +1291,6 @@ JNIEXPORT jintArray Java_com_b44t_messenger_DcContext_getChatMedia(JNIEnv *env,
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT jint Java_com_b44t_messenger_DcContext_getNextMedia(JNIEnv *env, jobject obj, jint msg_id, jint dir, jint type1, jint type2, jint type3)
|
||||
{
|
||||
return dc_get_next_media(get_dc_context(env, obj), msg_id, dir, type1, type2, type3);
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT jintArray Java_com_b44t_messenger_DcContext_getChatMsgs(JNIEnv *env, jobject obj, jint chat_id, jint flags, jint marker1before)
|
||||
{
|
||||
dc_array_t* ca = dc_get_chat_msgs(get_dc_context(env, obj), chat_id, flags, marker1before);
|
||||
@@ -1413,17 +1373,6 @@ JNIEXPORT jint Java_com_b44t_messenger_DcMsg_getId(JNIEnv *env, jobject obj)
|
||||
return dc_msg_get_id(get_dc_msg(env, obj));
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT jboolean Java_com_b44t_messenger_DcMsg_isOutgoing(JNIEnv *env, jobject obj)
|
||||
{
|
||||
return (jboolean)(dc_msg_is_outgoing(get_dc_msg(env, obj))!=0);
|
||||
}
|
||||
|
||||
JNIEXPORT jint Java_com_b44t_messenger_DcMsg_getSenderColor(JNIEnv *env, jobject obj)
|
||||
{
|
||||
return dc_msg_get_sender_color(get_dc_msg(env, obj));
|
||||
}
|
||||
|
||||
JNIEXPORT jstring Java_com_b44t_messenger_DcMsg_getText(JNIEnv *env, jobject obj)
|
||||
{
|
||||
char* temp = dc_msg_get_text(get_dc_msg(env, obj));
|
||||
@@ -1478,6 +1427,12 @@ JNIEXPORT jint Java_com_b44t_messenger_DcMsg_getInfoType(JNIEnv *env, jobject ob
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT jint Java_com_b44t_messenger_DcMsg_getInfoContactId(JNIEnv *env, jobject obj)
|
||||
{
|
||||
return dc_msg_get_info_contact_id(get_dc_msg(env, obj));
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT jint Java_com_b44t_messenger_DcMsg_getState(JNIEnv *env, jobject obj)
|
||||
{
|
||||
return dc_msg_get_state(get_dc_msg(env, obj));
|
||||
@@ -1616,30 +1571,27 @@ JNIEXPORT jstring Java_com_b44t_messenger_DcMsg_getWebxdcInfoJson(JNIEnv *env, j
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT jstring Java_com_b44t_messenger_DcMsg_getWebxdcHref(JNIEnv *env, jobject obj)
|
||||
{
|
||||
char* temp = dc_msg_get_webxdc_href(get_dc_msg(env, obj));
|
||||
jstring ret = JSTRING_NEW(temp);
|
||||
dc_str_unref(temp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT jboolean Java_com_b44t_messenger_DcMsg_isForwarded(JNIEnv *env, jobject obj)
|
||||
{
|
||||
return dc_msg_is_forwarded(get_dc_msg(env, obj))!=0;
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT jboolean Java_com_b44t_messenger_DcMsg_isIncreation(JNIEnv *env, jobject obj)
|
||||
{
|
||||
return dc_msg_is_increation(get_dc_msg(env, obj))!=0;
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT jboolean Java_com_b44t_messenger_DcMsg_isInfo(JNIEnv *env, jobject obj)
|
||||
{
|
||||
return dc_msg_is_info(get_dc_msg(env, obj))!=0;
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT jboolean Java_com_b44t_messenger_DcMsg_isSetupMessage(JNIEnv *env, jobject obj)
|
||||
{
|
||||
return dc_msg_is_setupmessage(get_dc_msg(env, obj));
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT jboolean Java_com_b44t_messenger_DcMsg_hasHtml(JNIEnv *env, jobject obj)
|
||||
{
|
||||
return dc_msg_has_html(get_dc_msg(env, obj))!=0;
|
||||
@@ -1694,12 +1646,35 @@ JNIEXPORT void Java_com_b44t_messenger_DcMsg_setHtml(JNIEnv *env, jobject obj, j
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT void Java_com_b44t_messenger_DcMsg_setFile(JNIEnv *env, jobject obj, jstring file, jstring filemime)
|
||||
JNIEXPORT void Java_com_b44t_messenger_DcMsg_forceSticker(JNIEnv *env, jobject obj)
|
||||
{
|
||||
dc_msg_force_sticker(get_dc_msg(env, obj));
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT jstring Java_com_b44t_messenger_DcMsg_getPOILocation(JNIEnv *env, jobject obj)
|
||||
{
|
||||
char* temp = dc_msg_get_poi_location(get_dc_msg(env, obj));
|
||||
jstring ret = JSTRING_NEW(temp);
|
||||
dc_str_unref(temp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT jboolean Java_com_b44t_messenger_DcMsg_isEdited(JNIEnv *env, jobject obj)
|
||||
{
|
||||
return dc_msg_is_edited(get_dc_msg(env, obj));
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT void Java_com_b44t_messenger_DcMsg_setFileAndDeduplicate(JNIEnv *env, jobject obj, jstring file, jstring name, jstring filemime)
|
||||
{
|
||||
CHAR_REF(file);
|
||||
CHAR_REF(name);
|
||||
CHAR_REF(filemime);
|
||||
dc_msg_set_file(get_dc_msg(env, obj), filePtr, filemimePtr);
|
||||
dc_msg_set_file_and_deduplicate(get_dc_msg(env, obj), filePtr, namePtr, filemimePtr);
|
||||
CHAR_UNREF(filemime);
|
||||
CHAR_UNREF(name);
|
||||
CHAR_UNREF(file);
|
||||
}
|
||||
|
||||
@@ -1748,6 +1723,15 @@ JNIEXPORT jlong Java_com_b44t_messenger_DcMsg_getParentCPtr(JNIEnv *env, jobject
|
||||
return (jlong)dc_msg_get_parent(get_dc_msg(env, obj));
|
||||
}
|
||||
|
||||
JNIEXPORT jint Java_com_b44t_messenger_DcMsg_getOriginalMsgId(JNIEnv *env, jobject obj)
|
||||
{
|
||||
return (jint)dc_msg_get_original_msg_id(get_dc_msg(env, obj));
|
||||
}
|
||||
|
||||
JNIEXPORT jint Java_com_b44t_messenger_DcMsg_getSavedMsgId(JNIEnv *env, jobject obj)
|
||||
{
|
||||
return (jint)dc_msg_get_saved_msg_id(get_dc_msg(env, obj));
|
||||
}
|
||||
|
||||
JNIEXPORT jstring Java_com_b44t_messenger_DcMsg_getError(JNIEnv *env, jobject obj)
|
||||
{
|
||||
@@ -1825,15 +1809,6 @@ JNIEXPORT jstring Java_com_b44t_messenger_DcContact_getAddr(JNIEnv *env, jobject
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT jstring Java_com_b44t_messenger_DcContact_getNameNAddr(JNIEnv *env, jobject obj)
|
||||
{
|
||||
char* temp = dc_contact_get_name_n_addr(get_dc_contact(env, obj));
|
||||
jstring ret = JSTRING_NEW(temp);
|
||||
dc_str_unref(temp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT jstring Java_com_b44t_messenger_DcContact_getProfileImage(JNIEnv *env, jobject obj)
|
||||
{
|
||||
char* temp = dc_contact_get_profile_image(get_dc_contact(env, obj));
|
||||
|
||||
+1
-1
Submodule jni/deltachat-core-rust updated: 7e6be4b3c7...771fd87e53
@@ -0,0 +1 @@
|
||||
Schreibe Nachrichten mit E-Mails. Retro, Offen. Privatsphäre im Design.
|
||||
@@ -0,0 +1,12 @@
|
||||
Delta Chat é um aplicativo de mensagens que é completamente compatível com a infraestrutura de email já existente.
|
||||
Assim, com o Delta Chat você tem a facilidade de muitos aplicativos de mensagens com o alcance de email. Além disso, você é independente de outras companhias e sercviços -- já que suas informações e dados não estão relacionadas com o Delta Chat, você não vai nem adicionar novas permissões aqui.
|
||||
Resumo de alguns recursos:
|
||||
* Seguro com criptografia de ponta a ponta, com suporte ao novo padrão <a href="https://autocrypt.org">Autocrypt</a>
|
||||
* Rápido usando Push-IMAP
|
||||
* Maior base de usuários -- destinatários que não estiverem usando Delta Chat podem ser alcançados também
|
||||
* Compatívle -- não apenas consigo mesmo
|
||||
* Interface de usuário elegante e simples
|
||||
* Sistema distribuído
|
||||
* Sem spam -- apenas mensages de usuários conhecidos são mostradas por padrão
|
||||
* Confiável -- pode até ser usado para mensagens comerciais
|
||||
* Completamente OpenSource e baseado em padrões
|
||||
@@ -1 +1 @@
|
||||
../deltachat-pages/tools/create-local-help.py ../deltachat-pages/_site src/main/assets/help
|
||||
../deltachat-pages/tools/create-local-help.py ../deltachat-pages/result src/main/assets/help
|
||||
|
||||
@@ -11,13 +11,13 @@ echo "==================== ANDROID USAGE ===================="
|
||||
grep --exclude={*.apk,*.a,*.o,*.so,strings.xml,*symbols.zip} --exclude-dir={.git,.gradle,obj,release,.idea,build,deltachat-core-rust} -ri $TEXT .
|
||||
|
||||
echo "==================== IOS USAGE ===================="
|
||||
grep --exclude=*.strings --exclude-dir={.git,libraries,Pods,deltachat-ios.xcodeproj,deltachat-ios.xcworkspace} -ri $TEXT ../deltachat-ios/
|
||||
grep --exclude=*.strings* --exclude-dir={.git,libraries,Pods,deltachat-ios.xcodeproj,deltachat-ios.xcworkspace} -ri $TEXT ../deltachat-ios/
|
||||
|
||||
echo "==================== DESKTOP USAGE ===================="
|
||||
grep --exclude-dir={.cache,.git,html-dist,node_modules,_locales} -ri $TEXT ../deltachat-desktop/
|
||||
|
||||
echo "==================== JSONRPC USAGE ===================="
|
||||
grep --exclude-dir={.git} -ri $TEXT ../deltachat-core-rust/deltachat-jsonrpc
|
||||
grep --exclude-dir={.git} -ri $TEXT ../chatmail/core/deltachat-jsonrpc
|
||||
|
||||
echo "==================== UBUNTU TOUCH USAGE ===================="
|
||||
grep --exclude-dir={.git} -ri $TEXT ../deltatouch/
|
||||
|
||||
+25
-19
@@ -53,7 +53,6 @@ fi
|
||||
# for reproducible build:
|
||||
export RUSTFLAGS="-C link-args=-Wl,--build-id=none --remap-path-prefix=$HOME/.cargo= --remap-path-prefix=$(realpath $(dirname $(dirname "$0")))="
|
||||
export SOURCE_DATE_EPOCH=1
|
||||
export CARGO_TARGET_DIR=/tmp/arcanechat-build
|
||||
# always use the same path to NDK:
|
||||
rm -f /tmp/android-ndk-root
|
||||
ln -s "$ANDROID_NDK_ROOT" /tmp/android-ndk-root
|
||||
@@ -74,10 +73,14 @@ if test -z "$NDK_HOST_TAG"; then
|
||||
NDK_HOST_TAG="$KERNEL-$ARCH"
|
||||
fi
|
||||
|
||||
if test -z "$CARGO_TARGET_DIR"; then
|
||||
export CARGO_TARGET_DIR=/tmp/arcanechat-build
|
||||
fi
|
||||
|
||||
TOOLCHAIN="$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/$NDK_HOST_TAG"
|
||||
export CARGO_TARGET_ARMV7_LINUX_ANDROIDEABI_LINKER="$TOOLCHAIN/bin/armv7a-linux-androideabi16-clang"
|
||||
export CARGO_TARGET_ARMV7_LINUX_ANDROIDEABI_LINKER="$TOOLCHAIN/bin/armv7a-linux-androideabi21-clang"
|
||||
export CARGO_TARGET_AARCH64_LINUX_ANDROID_LINKER="$TOOLCHAIN/bin/aarch64-linux-android21-clang"
|
||||
export CARGO_TARGET_I686_LINUX_ANDROID_LINKER="$TOOLCHAIN/bin/i686-linux-android16-clang"
|
||||
export CARGO_TARGET_I686_LINUX_ANDROID_LINKER="$TOOLCHAIN/bin/i686-linux-android21-clang"
|
||||
export CARGO_TARGET_X86_64_LINUX_ANDROID_LINKER="$TOOLCHAIN/bin/x86_64-linux-android21-clang"
|
||||
|
||||
export RUSTUP_TOOLCHAIN=$(cat "$(dirname "$0")/rust-toolchain")
|
||||
@@ -123,11 +126,11 @@ unset CPATH
|
||||
|
||||
if test -z $1 || test $1 = armeabi-v7a; then
|
||||
echo "-- cross compiling to armv7-linux-androideabi (arm) --"
|
||||
TARGET_CC="$TOOLCHAIN/bin/armv7a-linux-androideabi16-clang" \
|
||||
TARGET_CC="$TOOLCHAIN/bin/armv7a-linux-androideabi21-clang" \
|
||||
TARGET_AR="$TOOLCHAIN/bin/llvm-ar" \
|
||||
TARGET_RANLIB="$TOOLCHAIN/bin/llvm-ranlib" \
|
||||
cargo build $RELEASEFLAG --target armv7-linux-androideabi -p deltachat_ffi --features jsonrpc
|
||||
cp $CARGO_TARGET_DIR/armv7-linux-androideabi/$RELEASE/libdeltachat.a $jnidir/armeabi-v7a
|
||||
cargo build $RELEASEFLAG --target armv7-linux-androideabi -p deltachat_ffi
|
||||
cp "$CARGO_TARGET_DIR/armv7-linux-androideabi/$RELEASE/libdeltachat.a" "$jnidir/armeabi-v7a"
|
||||
fi
|
||||
|
||||
if test -z $1 || test $1 = arm64-v8a; then
|
||||
@@ -135,27 +138,27 @@ if test -z $1 || test $1 = arm64-v8a; then
|
||||
TARGET_CC="$TOOLCHAIN/bin/aarch64-linux-android21-clang" \
|
||||
TARGET_AR="$TOOLCHAIN/bin/llvm-ar" \
|
||||
TARGET_RANLIB="$TOOLCHAIN/bin/llvm-ranlib" \
|
||||
cargo build $RELEASEFLAG --target aarch64-linux-android -p deltachat_ffi --features jsonrpc
|
||||
cp $CARGO_TARGET_DIR/aarch64-linux-android/$RELEASE/libdeltachat.a $jnidir/arm64-v8a
|
||||
cargo build $RELEASEFLAG --target aarch64-linux-android -p deltachat_ffi
|
||||
cp "$CARGO_TARGET_DIR/aarch64-linux-android/$RELEASE/libdeltachat.a" "$jnidir/arm64-v8a"
|
||||
fi
|
||||
|
||||
if test -z $1 || test $1 = x86; then
|
||||
echo "-- cross compiling to i686-linux-android (x86) --"
|
||||
TARGET_CC="$TOOLCHAIN/bin/i686-linux-android16-clang" \
|
||||
TARGET_CC="$TOOLCHAIN/bin/i686-linux-android21-clang" \
|
||||
TARGET_AR="$TOOLCHAIN/bin/llvm-ar" \
|
||||
TARGET_RANLIB="$TOOLCHAIN/bin/llvm-ranlib" \
|
||||
cargo build $RELEASEFLAG --target i686-linux-android -p deltachat_ffi --features jsonrpc
|
||||
cp $CARGO_TARGET_DIR/i686-linux-android/$RELEASE/libdeltachat.a $jnidir/x86
|
||||
cargo build $RELEASEFLAG --target i686-linux-android -p deltachat_ffi
|
||||
cp "$CARGO_TARGET_DIR/i686-linux-android/$RELEASE/libdeltachat.a" "$jnidir/x86"
|
||||
fi
|
||||
|
||||
if test -z $1 || test $1 = x86_64; then
|
||||
echo "-- cross compiling to x86_64-linux-android (x86_64) --"
|
||||
TARGET_CC="$TOOLCHAIN/bin/x86_64-linux-android21-clang" \
|
||||
TARGET_AR="$TOOLCHAIN/bin/llvm-ar" \
|
||||
TARGET_RANLIB="$TOOLCHAIN/bin/llvm-ranlib" \
|
||||
cargo build $RELEASEFLAG --target x86_64-linux-android -p deltachat_ffi --features jsonrpc
|
||||
cp $CARGO_TARGET_DIR/x86_64-linux-android/$RELEASE/libdeltachat.a $jnidir/x86_64
|
||||
fi
|
||||
if test -z $1 || test $1 = x86_64; then
|
||||
echo "-- cross compiling to x86_64-linux-android (x86_64) --"
|
||||
TARGET_CC="$TOOLCHAIN/bin/x86_64-linux-android21-clang" \
|
||||
TARGET_AR="$TOOLCHAIN/bin/llvm-ar" \
|
||||
TARGET_RANLIB="$TOOLCHAIN/bin/llvm-ranlib" \
|
||||
cargo build $RELEASEFLAG --target x86_64-linux-android -p deltachat_ffi
|
||||
cp "$CARGO_TARGET_DIR/x86_64-linux-android/$RELEASE/libdeltachat.a" "$jnidir/x86_64"
|
||||
fi
|
||||
|
||||
echo -- ndk-build --
|
||||
|
||||
@@ -174,4 +177,7 @@ else
|
||||
rm -f ndkArch # Remove ndkArch, ignore if it doesn't exist
|
||||
fi
|
||||
|
||||
"$(dirname "$0")/rebrand.sh"
|
||||
|
||||
|
||||
echo "ending time: `date`"
|
||||
|
||||
Executable
+7
@@ -0,0 +1,7 @@
|
||||
#!/bin/sh
|
||||
|
||||
# replace Delta Chat with ArcaneChat
|
||||
find ./src/main/assets/help/ -type f -name '*.html' | xargs sed -i 's/get.delta.chat/github.com\/ArcaneChat/g'
|
||||
find ./src/main/assets/help/ -type f -name '*.html' | xargs sed -i 's/Delta Chat/ArcaneChat/g'
|
||||
find ./src/ -type f -name 'strings.xml' | xargs sed -i 's/get.delta.chat/github.com\/ArcaneChat/g'
|
||||
find ./src/ -type f -name 'strings.xml' | xargs sed -i 's/Delta Chat/ArcaneChat/g'
|
||||
@@ -1 +1 @@
|
||||
1.77.0
|
||||
1.83.0
|
||||
|
||||
Executable
+7
@@ -0,0 +1,7 @@
|
||||
#!/bin/sh
|
||||
|
||||
find ./src/main/assets/help/ -type f -name '*.html' | xargs sed -i 's/github.com\/ArcaneChat/get.delta.chat/g'
|
||||
find ./src/main/assets/help/ -type f -name '*.html' | xargs sed -i 's/ArcaneChat/Delta Chat/g'
|
||||
find ./src/ -type f -name 'strings.xml' | xargs sed -i 's/github.com\/ArcaneChat/get.delta.chat/g'
|
||||
find ./src/ -type f -name 'strings.xml' | xargs sed -i 's/ArcaneChat/Delta Chat/g'
|
||||
sed -i 's/>Delta Chat</>ArcaneChat</g' ./src/main/res/values/strings.xml
|
||||
@@ -1,3 +1,5 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e # stop on all errors
|
||||
|
||||
git submodule update --init --recursive
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
VERSION=$1
|
||||
|
||||
@@ -29,7 +30,6 @@ echo ""
|
||||
echo "and now: here is Delta Chat $VERSION - choose your flavour and mind your backups:"
|
||||
echo "- 🍋 https://download.delta.chat/android/beta/deltachat-gplay-release-$VERSION.apk (google play candidate, overwrites existing installs, should keep data)"
|
||||
echo "- 🍉 https://download.delta.chat/android/beta/deltachat-foss-debug-$VERSION.apk (f-droid candidate, can be installed beside google play)"
|
||||
echo "- 🍏 https://testflight.apple.com/join/uEMc1NxS (ios, update to $VERSION may take a day or so)"
|
||||
echo ""
|
||||
echo "what to test: PLEASE_FILL_OUT"
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
VERSION=$1
|
||||
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
package com.b44t.messenger;
|
||||
|
||||
import static androidx.test.espresso.Espresso.onView;
|
||||
import static androidx.test.espresso.action.ViewActions.typeText;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.isRoot;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withHint;
|
||||
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
@@ -23,12 +29,6 @@ import org.thoughtcrime.securesms.util.AccessibilityUtil;
|
||||
import org.thoughtcrime.securesms.util.Prefs;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
|
||||
import static androidx.test.espresso.Espresso.onView;
|
||||
import static androidx.test.espresso.action.ViewActions.typeText;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.isRoot;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withHint;
|
||||
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
|
||||
|
||||
public class TestUtils {
|
||||
private static int createdAccountId = 0;
|
||||
private static boolean resetEnterSends = false;
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
package com.b44t.messenger.uibenchmarks;
|
||||
|
||||
import static androidx.test.espresso.Espresso.onView;
|
||||
import static androidx.test.espresso.Espresso.pressBack;
|
||||
import static androidx.test.espresso.action.ViewActions.click;
|
||||
import static androidx.test.espresso.action.ViewActions.replaceText;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withContentDescription;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withHint;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withId;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withText;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.test.espresso.contrib.RecyclerViewActions;
|
||||
@@ -17,15 +26,6 @@ import org.junit.runner.RunWith;
|
||||
import org.thoughtcrime.securesms.ConversationListActivity;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
|
||||
import static androidx.test.espresso.Espresso.onView;
|
||||
import static androidx.test.espresso.Espresso.pressBack;
|
||||
import static androidx.test.espresso.action.ViewActions.click;
|
||||
import static androidx.test.espresso.action.ViewActions.replaceText;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withContentDescription;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withHint;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withId;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withText;
|
||||
|
||||
@Ignore("This is not a test, but a benchmark. Remove the @Ignore to run it.")
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@LargeTest
|
||||
|
||||
@@ -1,5 +1,16 @@
|
||||
package com.b44t.messenger.uitests.offline;
|
||||
|
||||
import static androidx.test.espresso.Espresso.onView;
|
||||
import static androidx.test.espresso.Espresso.pressBack;
|
||||
import static androidx.test.espresso.action.ViewActions.click;
|
||||
import static androidx.test.espresso.assertion.ViewAssertions.matches;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.hasDescendant;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.isClickable;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withHint;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withId;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withText;
|
||||
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
@@ -25,17 +36,6 @@ import org.thoughtcrime.securesms.connect.DcHelper;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import static androidx.test.espresso.Espresso.onView;
|
||||
import static androidx.test.espresso.Espresso.pressBack;
|
||||
import static androidx.test.espresso.action.ViewActions.click;
|
||||
import static androidx.test.espresso.assertion.ViewAssertions.matches;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.hasDescendant;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.isClickable;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withHint;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withId;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withText;
|
||||
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
|
||||
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@LargeTest
|
||||
@@ -93,7 +93,7 @@ public class SharingTest {
|
||||
}
|
||||
}
|
||||
Uri uri = Uri.parse("content://" + BuildConfig.APPLICATION_ID + ".attachments/" + Uri.encode(pngImage));
|
||||
DcHelper.sharedFiles.put("/" + pngImage, 1);
|
||||
DcHelper.sharedFiles.put(pngImage, "image/png");
|
||||
|
||||
Intent i = new Intent(Intent.ACTION_SEND);
|
||||
i.setType("image/png");
|
||||
|
||||
@@ -1,6 +1,15 @@
|
||||
package com.b44t.messenger.uitests.online;
|
||||
|
||||
|
||||
import static androidx.test.espresso.Espresso.onView;
|
||||
import static androidx.test.espresso.action.ViewActions.click;
|
||||
import static androidx.test.espresso.action.ViewActions.replaceText;
|
||||
import static androidx.test.espresso.assertion.ViewAssertions.matches;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.isClickable;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withContentDescription;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withHint;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withText;
|
||||
|
||||
import android.text.TextUtils;
|
||||
|
||||
import androidx.test.ext.junit.rules.ActivityScenarioRule;
|
||||
@@ -17,15 +26,6 @@ import org.thoughtcrime.securesms.BuildConfig;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.WelcomeActivity;
|
||||
|
||||
import static androidx.test.espresso.Espresso.onView;
|
||||
import static androidx.test.espresso.action.ViewActions.click;
|
||||
import static androidx.test.espresso.action.ViewActions.replaceText;
|
||||
import static androidx.test.espresso.assertion.ViewAssertions.matches;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.isClickable;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withContentDescription;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withHint;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withText;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@LargeTest
|
||||
public class OnboardingTest {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.thoughtcrime.securesms.notifications;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
/*
|
||||
|
||||
@@ -17,7 +17,7 @@ import com.google.firebase.messaging.RemoteMessage;
|
||||
|
||||
import org.thoughtcrime.securesms.ApplicationContext;
|
||||
import org.thoughtcrime.securesms.BuildConfig;
|
||||
import org.thoughtcrime.securesms.util.Prefs;
|
||||
import org.thoughtcrime.securesms.service.FetchForegroundService;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
|
||||
public class FcmReceiveService extends FirebaseMessagingService {
|
||||
@@ -28,11 +28,6 @@ public class FcmReceiveService extends FirebaseMessagingService {
|
||||
private static volatile String prefixedToken;
|
||||
|
||||
public static void register(Context context) {
|
||||
if (Build.VERSION.SDK_INT < 19) {
|
||||
Log.w(TAG, "FCM not available on SDK < 19");
|
||||
triedRegistering = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (FcmReceiveService.prefixedToken != null) {
|
||||
Log.i(TAG, "FCM already registered");
|
||||
@@ -92,18 +87,17 @@ public class FcmReceiveService extends FirebaseMessagingService {
|
||||
return prefixedToken;
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
@Override
|
||||
public void onMessageReceived(@NonNull RemoteMessage remoteMessage) {
|
||||
Log.i(TAG, "FCM push notification received");
|
||||
// the app is running (again) now and fetching and notifications should be processed as usual.
|
||||
// to support accounts that do not send PUSH notifications and for simplicity,
|
||||
// we just let the app run as long as possible.
|
||||
FetchForegroundService.start(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeletedMessages() {
|
||||
Log.i(TAG, "FCM push notifications dropped");
|
||||
// nothing special to do as we're running now and notifications should be processed as usual.
|
||||
FetchForegroundService.start(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="29" />
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>
|
||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
||||
@@ -66,6 +65,10 @@
|
||||
android:resource="@xml/automotive_app_desc" />
|
||||
-->
|
||||
|
||||
<!-- Opt out of metrics collection: https://developer.android.com/develop/ui/views/layout/webapps/managing-webview#metrics -->
|
||||
<meta-data android:name="android.webkit.WebView.MetricsOptOut"
|
||||
android:value="true" />
|
||||
|
||||
<activity android:name=".ShareActivity"
|
||||
android:theme="@android:style/Theme.Translucent.NoTitleBar"
|
||||
android:excludeFromRecents="true"
|
||||
@@ -262,6 +265,26 @@
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity android:name=".proxy.ProxySettingsActivity"
|
||||
android:label="@string/proxy_settings"
|
||||
android:windowSoftInputMode="stateHidden"
|
||||
android:exported="true"
|
||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize">
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW"/>
|
||||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
<category android:name="android.intent.category.BROWSABLE"/>
|
||||
<!-- Android's scheme matcher is case-sensitive, so include most likely variations -->
|
||||
<data android:scheme="ss" />
|
||||
<data android:scheme="socks5" />
|
||||
<data android:scheme="SOCKS5" tools:ignore="AppLinkUrlError" />
|
||||
<data android:scheme="SS" tools:ignore="AppLinkUrlError" />
|
||||
</intent-filter>
|
||||
|
||||
</activity>
|
||||
|
||||
|
||||
<activity android:name=".LogViewActivity"
|
||||
android:label="@string/pref_log_header"
|
||||
android:windowSoftInputMode="stateHidden"
|
||||
@@ -305,8 +328,6 @@
|
||||
android:theme="@style/TextSecure.ScribbleTheme"
|
||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
|
||||
|
||||
<activity android:name="com.soundcloud.android.crop.CropImageActivity" />
|
||||
|
||||
<activity android:name=".InstantOnboardingActivity"
|
||||
android:theme="@style/TextSecure.LightTheme"
|
||||
android:windowSoftInputMode="stateHidden|adjustResize"
|
||||
@@ -365,6 +386,11 @@
|
||||
android:exported="true">
|
||||
</activity>
|
||||
|
||||
<activity android:name=".WebxdcStoreActivity"
|
||||
android:theme="@style/TextSecure.LightTheme"
|
||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize|uiMode">
|
||||
</activity>
|
||||
|
||||
<activity android:name=".FullMsgActivity"
|
||||
android:theme="@style/TextSecure.LightTheme"
|
||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize">
|
||||
@@ -388,6 +414,10 @@
|
||||
android:name=".service.GenericForegroundService"
|
||||
android:foregroundServiceType="dataSync" />
|
||||
|
||||
<service
|
||||
android:name=".service.FetchForegroundService"
|
||||
android:foregroundServiceType="dataSync" />
|
||||
|
||||
<service
|
||||
android:name=".service.IPCAddAccountsService"
|
||||
android:foregroundServiceType="dataSync"
|
||||
|
||||
+403
-259
File diff suppressed because it is too large
Load Diff
+369
-228
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
After Width: | Height: | Size: 183 B |
+399
-256
File diff suppressed because it is too large
Load Diff
+403
-263
File diff suppressed because it is too large
Load Diff
+423
-281
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
After Width: | Height: | Size: 300 B |
Binary file not shown.
|
After Width: | Height: | Size: 324 B |
+397
-254
File diff suppressed because it is too large
Load Diff
+393
-250
File diff suppressed because it is too large
Load Diff
+406
-263
File diff suppressed because it is too large
Load Diff
+310
-198
File diff suppressed because it is too large
Load Diff
+398
-255
File diff suppressed because it is too large
Load Diff
+923
-758
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
After Width: | Height: | Size: 145 B |
+406
-267
File diff suppressed because it is too large
Load Diff
+396
-257
File diff suppressed because it is too large
Load Diff
+331
-215
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@@ -33,8 +33,8 @@ public class DcAccounts {
|
||||
public native void stopIo ();
|
||||
public native void maybeNetwork ();
|
||||
public native void setPushDeviceToken (String token);
|
||||
public native boolean backgroundFetch (int timeoutSeconds);
|
||||
|
||||
public native int addAccount ();
|
||||
public native int migrateAccount (String dbfile);
|
||||
public native boolean removeAccount (int accountId);
|
||||
public native int[] getAll ();
|
||||
|
||||
@@ -50,7 +50,6 @@ public class DcContact {
|
||||
public native String getAuthName ();
|
||||
public native String getDisplayName ();
|
||||
public native String getAddr ();
|
||||
public native String getNameNAddr ();
|
||||
public native String getProfileImage();
|
||||
public native int getColor ();
|
||||
public native String getStatus ();
|
||||
|
||||
@@ -2,16 +2,14 @@ package com.b44t.messenger;
|
||||
|
||||
public class DcContext {
|
||||
|
||||
public final static int DC_PREF_DEFAULT_MDNS_ENABLED = 1;
|
||||
public final static int DC_PREF_DEFAULT_TRIM_ENABLED = 0;
|
||||
public final static int DC_PREF_DEFAULT_TRIM_LENGTH = 500;
|
||||
|
||||
public final static int DC_EVENT_INFO = 100;
|
||||
public final static int DC_EVENT_WARNING = 300;
|
||||
public final static int DC_EVENT_ERROR = 400;
|
||||
public final static int DC_EVENT_ERROR_SELF_NOT_IN_GROUP = 410;
|
||||
public final static int DC_EVENT_MSGS_CHANGED = 2000;
|
||||
public final static int DC_EVENT_REACTIONS_CHANGED = 2001;
|
||||
public final static int DC_EVENT_INCOMING_REACTION = 2002;
|
||||
public final static int DC_EVENT_INCOMING_WEBXDC_NOTIFY = 2003;
|
||||
public final static int DC_EVENT_INCOMING_MSG = 2005;
|
||||
public final static int DC_EVENT_MSGS_NOTICED = 2008;
|
||||
public final static int DC_EVENT_MSG_DELIVERED = 2010;
|
||||
@@ -19,6 +17,7 @@ public class DcContext {
|
||||
public final static int DC_EVENT_MSG_READ = 2015;
|
||||
public final static int DC_EVENT_CHAT_MODIFIED = 2020;
|
||||
public final static int DC_EVENT_CHAT_EPHEMERAL_TIMER_MODIFIED = 2021;
|
||||
public final static int DC_EVENT_CHAT_DELETED = 2023;
|
||||
public final static int DC_EVENT_CONTACTS_CHANGED = 2030;
|
||||
public final static int DC_EVENT_LOCATION_CHANGED = 2035;
|
||||
public final static int DC_EVENT_CONFIGURE_PROGRESS = 2041;
|
||||
@@ -31,6 +30,7 @@ public class DcContext {
|
||||
public final static int DC_EVENT_WEBXDC_STATUS_UPDATE = 2120;
|
||||
public final static int DC_EVENT_WEBXDC_INSTANCE_DELETED = 2121;
|
||||
public final static int DC_EVENT_WEBXDC_REALTIME_DATA = 2150;
|
||||
public final static int DC_EVENT_ACCOUNTS_BACKGROUND_FETCH_DONE = 2200;
|
||||
|
||||
public final static int DC_IMEX_EXPORT_SELF_KEYS = 1;
|
||||
public final static int DC_IMEX_IMPORT_SELF_KEYS = 2;
|
||||
@@ -52,9 +52,10 @@ public class DcContext {
|
||||
public final static int DC_QR_FPR_MISMATCH = 220;
|
||||
public final static int DC_QR_FPR_WITHOUT_ADDR = 230;
|
||||
public final static int DC_QR_ACCOUNT = 250;
|
||||
public final static int DC_QR_BACKUP = 251;
|
||||
public final static int DC_QR_BACKUP2 = 252;
|
||||
public final static int DC_QR_BACKUP_TOO_NEW = 255;
|
||||
public final static int DC_QR_WEBRTC = 260;
|
||||
public final static int DC_QR_PROXY = 271;
|
||||
public final static int DC_QR_ADDR = 320;
|
||||
public final static int DC_QR_TEXT = 330;
|
||||
public final static int DC_QR_URL = 332;
|
||||
@@ -80,18 +81,15 @@ public class DcContext {
|
||||
public final static int DC_MEDIA_QUALITY_BALANCED = 0;
|
||||
public final static int DC_MEDIA_QUALITY_WORSE = 1;
|
||||
|
||||
public final static int DC_DECISION_START_CHAT = 0;
|
||||
public final static int DC_DECISION_BLOCK = 1;
|
||||
public final static int DC_DECISION_NOT_NOW = 2;
|
||||
|
||||
public final static int DC_CONNECTIVITY_NOT_CONNECTED = 1000;
|
||||
public final static int DC_CONNECTIVITY_CONNECTING = 2000;
|
||||
public final static int DC_CONNECTIVITY_WORKING = 3000;
|
||||
public final static int DC_CONNECTIVITY_CONNECTED = 4000;
|
||||
|
||||
private static final String CONFIG_ACCOUNT_ENABLED = "ui.enabled";
|
||||
private static final String CONFIG_MUTE_MENTIONS_IF_MUTED = "ui.mute_mentions_if_muted";
|
||||
|
||||
// when using DcAccounts, use DcAccounts.addAccount() instead
|
||||
// when using DcAccounts, use Rpc.addAccount() instead
|
||||
public DcContext(String osName, String dbfile) {
|
||||
contextCPtr = createContextCPtr(osName, dbfile);
|
||||
}
|
||||
@@ -121,7 +119,6 @@ public class DcContext {
|
||||
public native void setStockTranslation (int stockId, String translation);
|
||||
public native String getBlobdir ();
|
||||
public native String getLastError ();
|
||||
public native void configure ();
|
||||
public native void stopOngoingProcess ();
|
||||
public native int isConfigured ();
|
||||
public native boolean open (String passphrase);
|
||||
@@ -140,13 +137,13 @@ public class DcContext {
|
||||
public void setConfigInt (String key, int value) { setConfig(key, Integer.toString(value)); }
|
||||
public native boolean setConfigFromQr (String qr);
|
||||
public native String getConfig (String key);
|
||||
public int getConfigInt (String key) { try{return Integer.parseInt(getConfig(key));} catch(Exception e) {} return 0; }
|
||||
public int getConfigInt (String key) { return getConfigInt(key, 0); }
|
||||
public int getConfigInt (String key, int defValue) { try{return Integer.parseInt(getConfig(key));} catch(Exception e) {} return defValue; }
|
||||
public native String getInfo ();
|
||||
public native int getConnectivity ();
|
||||
public native String getConnectivityHtml ();
|
||||
public native String getOauth2Url (String addr, String redirectUrl);
|
||||
public native String initiateKeyTransfer ();
|
||||
public native boolean continueKeyTransfer (int msg_id, String setup_code);
|
||||
public native void imex (int what, String dir);
|
||||
public native String imexHasBackup (String dir);
|
||||
public DcBackupProvider newBackupProvider () { return new DcBackupProvider(newBackupProviderCPtr()); }
|
||||
@@ -182,7 +179,6 @@ public class DcContext {
|
||||
public native int[] searchMsgs (int chat_id, String query);
|
||||
public native int[] getFreshMsgs ();
|
||||
public native int[] getChatMedia (int chat_id, int type1, int type2, int type3);
|
||||
public native int getNextMedia (int msg_id, int dir, int type1, int type2, int type3);
|
||||
public native int[] getChatContacts (int chat_id);
|
||||
public native int getChatEphemeralTimer (int chat_id);
|
||||
public native boolean setChatEphemeralTimer (int chat_id, int timer);
|
||||
@@ -191,19 +187,21 @@ public class DcContext {
|
||||
public native void blockChat (int chat_id);
|
||||
public native void acceptChat (int chat_id);
|
||||
public DcMsg getMsg (int msg_id) { return new DcMsg(getMsgCPtr(msg_id)); }
|
||||
public native void sendEditRequest (int msg_id, String text);
|
||||
public native String getMsgInfo (int id);
|
||||
public native String getMsgHtml (int msg_id);
|
||||
public native void downloadFullMsg (int msg_id);
|
||||
public native int getFreshMsgCount (int chat_id);
|
||||
public native int estimateDeletionCount(boolean from_server, long seconds);
|
||||
public native void deleteMsgs (int msg_ids[]);
|
||||
public native void sendDeleteRequest (int msg_ids[]);
|
||||
public native void forwardMsgs (int msg_ids[], int chat_id);
|
||||
public native void saveMsgs (int msg_ids[]);
|
||||
public native boolean resendMsgs (int msg_ids[]);
|
||||
public native int prepareMsg (int chat_id, DcMsg msg);
|
||||
public native int sendMsg (int chat_id, DcMsg msg);
|
||||
public native int sendTextMsg (int chat_id, String text);
|
||||
public native int sendVideochatInvitation(int chat_id);
|
||||
public native boolean sendWebxdcStatusUpdate(int msg_id, String payload, String descr);
|
||||
public native boolean sendWebxdcStatusUpdate(int msg_id, String payload);
|
||||
public native String getWebxdcStatusUpdates(int msg_id, int last_known_serial);
|
||||
public native void setWebxdcIntegration (String file);
|
||||
public native int initWebxdcIntegration(int chat_id);
|
||||
@@ -212,6 +210,7 @@ public class DcContext {
|
||||
public DcLot checkQr (String qr) { return new DcLot(checkQrCPtr(qr)); }
|
||||
public native String getSecurejoinQr (int chat_id);
|
||||
public native String getSecurejoinQrSvg (int chat_id);
|
||||
public native String createQrSvg (String payload);
|
||||
public native int joinSecurejoin (String qr);
|
||||
public native void sendLocationsToChat (int chat_id, int seconds);
|
||||
public native boolean isSendingLocationsToChat(int chat_id);
|
||||
@@ -230,39 +229,20 @@ public class DcContext {
|
||||
}
|
||||
}
|
||||
|
||||
public String getNameNAddr() {
|
||||
public boolean isMentionsEnabled() {
|
||||
return getConfigInt(CONFIG_MUTE_MENTIONS_IF_MUTED) != 1;
|
||||
}
|
||||
|
||||
public void setMentionsEnabled(boolean enabled) {
|
||||
setConfigInt(CONFIG_MUTE_MENTIONS_IF_MUTED, enabled? 0 : 1);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
String displayname = getConfig("displayname");
|
||||
String addr = getConfig("addr");
|
||||
String ret = "";
|
||||
|
||||
if (!displayname.isEmpty() && !addr.isEmpty()) {
|
||||
ret = String.format("%s (%s)", displayname, addr);
|
||||
} else if (!addr.isEmpty()) {
|
||||
ret = addr;
|
||||
if (displayname.isEmpty()) {
|
||||
displayname = getContact(DcContact.DC_CONTACT_ID_SELF).getAddr();
|
||||
}
|
||||
|
||||
if (ret.isEmpty() || isConfigured() == 0) {
|
||||
ret += " (not configured)";
|
||||
}
|
||||
|
||||
return ret.trim();
|
||||
}
|
||||
|
||||
public boolean isCommunity() {
|
||||
return getConfigInt("is_community") == 1;
|
||||
}
|
||||
|
||||
public void setCommunityMode(boolean enable) {
|
||||
setConfig("is_community", enable? "1" : null);
|
||||
}
|
||||
|
||||
public String getCommunityUser() {
|
||||
String name = getConfig("ui.community.selfname");
|
||||
return name == null? "" : name;
|
||||
}
|
||||
|
||||
public void setCommunityUser(String name) {
|
||||
setConfig("ui.community.selfname", name);
|
||||
return displayname;
|
||||
}
|
||||
|
||||
public boolean isChatmail() {
|
||||
@@ -277,21 +257,6 @@ public class DcContext {
|
||||
setConfigInt("is_muted", muted? 1 : 0);
|
||||
}
|
||||
|
||||
// Called for new profiles on chatmail servers that are "single device" initially;
|
||||
// to save server disk space, we make use of that delete all messages immediately after download.
|
||||
public void assumeSingleDevice() {
|
||||
if (isChatmail()) {
|
||||
setConfigInt("delete_server_after", 1 /*at once*/);
|
||||
}
|
||||
}
|
||||
|
||||
// Called when we get a hint that another device may be set up.
|
||||
public void assumeMultiDevice() {
|
||||
if (isChatmail() && getConfigInt("delete_server_after") == 1 /*at once*/) {
|
||||
setConfigInt("delete_server_after", 0 /*never/automatic*/);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isGmailOauth2Addr(String addr) {
|
||||
final String oauth2url = getOauth2Url(addr, "chat.delta:/foo");
|
||||
return isGmailOauth2Url(oauth2url);
|
||||
@@ -301,6 +266,12 @@ public class DcContext {
|
||||
return oauth2url.startsWith("https://accounts.google.com/");
|
||||
}
|
||||
|
||||
public void restartIo() {
|
||||
if (!isEnabled()) return;
|
||||
stopIo();
|
||||
startIo();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if at least one chat has location streaming enabled
|
||||
*/
|
||||
|
||||
@@ -123,6 +123,7 @@ public class DcMsg {
|
||||
private native int getViewType ();
|
||||
public int getType () { return getDownloadState()==DC_DOWNLOAD_DONE? getViewType() : DC_MSG_TEXT; }
|
||||
public native int getInfoType ();
|
||||
public native int getInfoContactId ();
|
||||
public native int getState ();
|
||||
public native int getDownloadState ();
|
||||
public native int getChatId ();
|
||||
@@ -148,32 +149,32 @@ public class DcMsg {
|
||||
return new JSONObject();
|
||||
}
|
||||
}
|
||||
public native String getWebxdcHref ();
|
||||
public native boolean isForwarded ();
|
||||
public native boolean isInfo ();
|
||||
public native boolean isSetupMessage ();
|
||||
public native boolean hasHtml ();
|
||||
public native String getSetupCodeBegin ();
|
||||
public native String getVideochatUrl ();
|
||||
public native int getVideochatType ();
|
||||
public native boolean isIncreation ();
|
||||
public native void setText (String text);
|
||||
public native void setSubject (String text);
|
||||
public native void setHtml (String text);
|
||||
public native void setFile (String file, String filemime);
|
||||
public native void forceSticker ();
|
||||
public native void setFileAndDeduplicate(String file, String name, String filemime);
|
||||
public native void setDimension (int width, int height);
|
||||
public native void setDuration (int duration);
|
||||
public native void setLocation (float latitude, float longitude);
|
||||
public native String getPOILocation ();
|
||||
public void setQuote (DcMsg quote) { setQuoteCPtr(quote.msgCPtr); }
|
||||
public native String getQuotedText ();
|
||||
public native String getError ();
|
||||
public native String getOverrideSenderName();
|
||||
public native boolean isOutgoing();
|
||||
public native int getSenderColor();
|
||||
public native boolean isEdited ();
|
||||
|
||||
public String getSenderName(DcContact dcContact, boolean markOverride) {
|
||||
public String getSenderName(DcContact dcContact) {
|
||||
String overrideName = getOverrideSenderName();
|
||||
if (overrideName != null) {
|
||||
return (markOverride ? "~" : "") + overrideName;
|
||||
return "~" + overrideName;
|
||||
} else {
|
||||
return dcContact.getDisplayName();
|
||||
}
|
||||
@@ -189,6 +190,14 @@ public class DcMsg {
|
||||
return cPtr != 0 ? new DcMsg(cPtr) : null;
|
||||
}
|
||||
|
||||
public native int getOriginalMsgId ();
|
||||
public native int getSavedMsgId ();
|
||||
|
||||
public boolean canSave() {
|
||||
// saving info-messages out of context results in confusion, see https://github.com/deltachat/deltachat-ios/issues/2567
|
||||
return !isInfo() && getType() != DC_MSG_VIDEOCHAT_INVITATION;
|
||||
}
|
||||
|
||||
public File getFileAsFile() {
|
||||
if(getFile()==null)
|
||||
throw new AssertionError("expected a file to be present.");
|
||||
@@ -208,6 +217,10 @@ public class DcMsg {
|
||||
return ids;
|
||||
}
|
||||
|
||||
public boolean isOutgoing() {
|
||||
return getFromId() == DcContact.DC_CONTACT_ID_SELF;
|
||||
}
|
||||
|
||||
public String getDisplayBody() {
|
||||
return getText();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,171 @@
|
||||
package com.b44t.messenger.rpc;
|
||||
|
||||
public class EnteredLoginParam {
|
||||
// Email address.
|
||||
private final String addr;
|
||||
|
||||
// Password.
|
||||
private final String password;
|
||||
|
||||
// ============ IMAP settings ============
|
||||
|
||||
// Server hostname or IP address.
|
||||
private final String imapServer;
|
||||
|
||||
// Server port.
|
||||
private final int imapPort;
|
||||
|
||||
// Socket security.
|
||||
private final SocketSecurity imapSecurity;
|
||||
|
||||
// Username.
|
||||
private final String imapUser;
|
||||
|
||||
// ============ SMTP settings ============
|
||||
|
||||
// Server hostname or IP address.
|
||||
private final String smtpServer;
|
||||
|
||||
// Server port.
|
||||
private final int smtpPort;
|
||||
|
||||
// Socket security.
|
||||
private final SocketSecurity smtpSecurity;
|
||||
|
||||
// Username.
|
||||
private final String smtpUser;
|
||||
|
||||
// SMTP Password. Only needs to be specified if different than IMAP password.
|
||||
private final String smtpPassword;
|
||||
|
||||
// TLS options: whether to allow invalid certificates and/or
|
||||
// invalid hostnames
|
||||
private final EnteredCertificateChecks certificateChecks;
|
||||
|
||||
// If true, login via OAUTH2 (not recommended anymore)
|
||||
private final boolean oauth2;
|
||||
|
||||
public EnteredLoginParam(String addr,
|
||||
String password,
|
||||
String imapServer,
|
||||
int imapPort,
|
||||
SocketSecurity imapSecurity,
|
||||
String imapUser,
|
||||
String smtpServer,
|
||||
int smtpPort,
|
||||
SocketSecurity smtpSecurity,
|
||||
String smtpUser,
|
||||
String smtpPassword,
|
||||
EnteredCertificateChecks certificateChecks,
|
||||
boolean oauth2) {
|
||||
this.addr = addr;
|
||||
this.password = password;
|
||||
this.imapServer = imapServer;
|
||||
this.imapPort = imapPort;
|
||||
this.imapSecurity = imapSecurity;
|
||||
this.imapUser = imapUser;
|
||||
this.smtpServer = smtpServer;
|
||||
this.smtpPort = smtpPort;
|
||||
this.smtpSecurity = smtpSecurity;
|
||||
this.smtpUser = smtpUser;
|
||||
this.smtpPassword = smtpPassword;
|
||||
this.certificateChecks = certificateChecks;
|
||||
this.oauth2 = oauth2;
|
||||
}
|
||||
|
||||
public String getAddr() {
|
||||
return addr;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public String getImapServer() {
|
||||
return imapServer;
|
||||
}
|
||||
|
||||
public int getImapPort() {
|
||||
return imapPort;
|
||||
}
|
||||
|
||||
public SocketSecurity getImapSecurity() {
|
||||
return imapSecurity;
|
||||
}
|
||||
|
||||
public String getImapUser() {
|
||||
return imapUser;
|
||||
}
|
||||
|
||||
public String getSmtpServer() {
|
||||
return smtpServer;
|
||||
}
|
||||
|
||||
public int getSmtpPort() {
|
||||
return smtpPort;
|
||||
}
|
||||
|
||||
public SocketSecurity getSmtpSecurity() {
|
||||
return smtpSecurity;
|
||||
}
|
||||
|
||||
public String getSmtpUser() {
|
||||
return smtpUser;
|
||||
}
|
||||
|
||||
public String getSmtpPassword() {
|
||||
return smtpPassword;
|
||||
}
|
||||
|
||||
public EnteredCertificateChecks getCertificateChecks() {
|
||||
return certificateChecks;
|
||||
}
|
||||
|
||||
public boolean isOauth2() {
|
||||
return oauth2;
|
||||
}
|
||||
|
||||
public enum EnteredCertificateChecks {
|
||||
automatic, strict, acceptInvalidCertificates,
|
||||
}
|
||||
|
||||
public static EnteredCertificateChecks certificateChecksFromInt(int position) {
|
||||
switch (position) {
|
||||
case 0:
|
||||
return EnteredCertificateChecks.automatic;
|
||||
case 1:
|
||||
return EnteredCertificateChecks.strict;
|
||||
case 2:
|
||||
return EnteredCertificateChecks.acceptInvalidCertificates;
|
||||
}
|
||||
throw new IllegalArgumentException("Invalid certificate position: " + position);
|
||||
}
|
||||
|
||||
public enum SocketSecurity {
|
||||
// Unspecified socket security, select automatically.
|
||||
automatic,
|
||||
|
||||
// TLS connection.
|
||||
ssl,
|
||||
|
||||
// STARTTLS connection.
|
||||
starttls,
|
||||
|
||||
// No TLS, plaintext connection.
|
||||
plain,
|
||||
}
|
||||
|
||||
public static SocketSecurity socketSecurityFromInt(int position) {
|
||||
switch (position) {
|
||||
case 0:
|
||||
return SocketSecurity.automatic;
|
||||
case 1:
|
||||
return SocketSecurity.ssl;
|
||||
case 2:
|
||||
return SocketSecurity.starttls;
|
||||
case 3:
|
||||
return SocketSecurity.plain;
|
||||
}
|
||||
throw new IllegalArgumentException("Invalid socketSecurity position: " + position);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.b44t.messenger.rpc;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import com.b44t.messenger.DcJsonrpcInstance;
|
||||
import com.b44t.messenger.util.concurrent.SettableFuture;
|
||||
import com.google.gson.Gson;
|
||||
@@ -8,15 +10,20 @@ import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
|
||||
import org.thoughtcrime.securesms.qr.QrShowFragment;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
public class Rpc {
|
||||
private final static String TAG = Rpc.class.getSimpleName();
|
||||
|
||||
private final Map<Integer, SettableFuture<JsonElement>> requestFutures = new ConcurrentHashMap<>();
|
||||
private final DcJsonrpcInstance dcJsonrpcInstance;
|
||||
private int requestId = 0;
|
||||
private boolean started = false;
|
||||
private final Gson gson = new GsonBuilder().serializeNulls().create();
|
||||
|
||||
public Rpc(DcJsonrpcInstance dcJsonrpcInstance) {
|
||||
@@ -37,7 +44,14 @@ public class Rpc {
|
||||
}
|
||||
|
||||
if (response.error != null) {
|
||||
future.setException(new RpcException(response.error.toString()));
|
||||
String message;
|
||||
try {
|
||||
message = response.error.getAsJsonObject().get("message").getAsString();
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Can't get response error message: " + e);
|
||||
message = response.error.toString();
|
||||
}
|
||||
future.setException(new RpcException(message));
|
||||
} else if (response.result != null) {
|
||||
future.set(response.result);
|
||||
} else {
|
||||
@@ -46,6 +60,7 @@ public class Rpc {
|
||||
}
|
||||
|
||||
public void start() {
|
||||
started = true;
|
||||
new Thread(() -> {
|
||||
while (true) {
|
||||
try {
|
||||
@@ -57,7 +72,9 @@ public class Rpc {
|
||||
}, "jsonrpcThread").start();
|
||||
}
|
||||
|
||||
public SettableFuture<JsonElement> call(String method, Object... params) {
|
||||
public SettableFuture<JsonElement> call(String method, Object... params) throws RpcException {
|
||||
if (!started) throw new RpcException("RPC not started yet.");
|
||||
|
||||
int id;
|
||||
synchronized (this) {
|
||||
id = ++requestId;
|
||||
@@ -79,23 +96,6 @@ public class Rpc {
|
||||
}
|
||||
}
|
||||
|
||||
public int addAccount() throws RpcException {
|
||||
return gson.fromJson(getResult("add_account"), int.class);
|
||||
}
|
||||
|
||||
public void startIO() throws RpcException {
|
||||
getResult("start_io_for_all_accounts");
|
||||
}
|
||||
|
||||
public void stopIO() throws RpcException {
|
||||
getResult("stop_io_for_all_accounts");
|
||||
}
|
||||
|
||||
public Map<String, String> getSystemInfo() throws RpcException {
|
||||
TypeToken<Map<String, String>> mapType = new TypeToken<Map<String, String>>(){};
|
||||
return gson.fromJson(getResult("get_system_info"), mapType.getType());
|
||||
}
|
||||
|
||||
public List<VcardContact> parseVcard(String path) throws RpcException {
|
||||
TypeToken<List<VcardContact>> listType = new TypeToken<List<VcardContact>>(){};
|
||||
return gson.fromJson(getResult("parse_vcard", path), listType.getType());
|
||||
@@ -138,6 +138,26 @@ public class Rpc {
|
||||
getResult("leave_webxdc_realtime", accountId, instanceMessageId);
|
||||
}
|
||||
|
||||
public int getAccountFileSize(int accountId) throws RpcException {
|
||||
return getResult("get_account_file_size", accountId).getAsInt();
|
||||
}
|
||||
|
||||
public void changeContactName(int accountId, int contactId, String name) throws RpcException {
|
||||
getResult("change_contact_name", accountId, contactId, name);
|
||||
}
|
||||
|
||||
public int addAccount() throws RpcException {
|
||||
return getResult("add_account").getAsInt();
|
||||
}
|
||||
|
||||
public void addTransportFromQr(int accountId, String qrCode) throws RpcException {
|
||||
getResult("add_transport_from_qr", accountId, qrCode);
|
||||
}
|
||||
|
||||
public void addTransport(int accountId, EnteredLoginParam param) throws RpcException {
|
||||
getResult("add_transport", accountId, param);
|
||||
}
|
||||
|
||||
private static class Request {
|
||||
private final String jsonrpc = "2.0";
|
||||
public final String method;
|
||||
|
||||
@@ -26,8 +26,8 @@ import com.b44t.messenger.DcContext;
|
||||
import com.b44t.messenger.DcEvent;
|
||||
import com.b44t.messenger.DcEventEmitter;
|
||||
import com.b44t.messenger.rpc.Rpc;
|
||||
import com.b44t.messenger.rpc.RpcException;
|
||||
|
||||
import org.thoughtcrime.securesms.components.emoji.EmojiProvider;
|
||||
import org.thoughtcrime.securesms.connect.AccountManager;
|
||||
import org.thoughtcrime.securesms.connect.DcEventCenter;
|
||||
import org.thoughtcrime.securesms.connect.DcHelper;
|
||||
@@ -37,7 +37,6 @@ import org.thoughtcrime.securesms.connect.KeepAliveService;
|
||||
import org.thoughtcrime.securesms.connect.NetworkStateReceiver;
|
||||
import org.thoughtcrime.securesms.crypto.DatabaseSecret;
|
||||
import org.thoughtcrime.securesms.crypto.DatabaseSecretProvider;
|
||||
import org.thoughtcrime.securesms.crypto.PRNGFixes;
|
||||
import org.thoughtcrime.securesms.geolocation.DcLocationManager;
|
||||
import org.thoughtcrime.securesms.jobmanager.JobManager;
|
||||
import org.thoughtcrime.securesms.notifications.FcmReceiveService;
|
||||
@@ -107,15 +106,11 @@ public class ApplicationContext extends MultiDexApplication {
|
||||
|
||||
Log.i("DeltaChat", "++++++++++++++++++ ApplicationContext.onCreate() ++++++++++++++++++");
|
||||
|
||||
// The first call to `getInstance` takes about 100ms-300ms, so, do it on a background thread
|
||||
Thread t = new Thread(() -> EmojiProvider.getInstance(this), "InitEmojiProviderThread");
|
||||
t.setPriority(Thread.MIN_PRIORITY);
|
||||
t.start();
|
||||
|
||||
System.loadLibrary("native-utils");
|
||||
|
||||
dcAccounts = new DcAccounts(new File(getFilesDir(), "accounts").getAbsolutePath());
|
||||
rpc = new Rpc(dcAccounts.getJsonrpcInstance());
|
||||
rpc.start();
|
||||
AccountManager.getInstance().migrateToDcAccounts(this);
|
||||
int[] allAccounts = dcAccounts.getAll();
|
||||
for (int accountId : allAccounts) {
|
||||
@@ -131,12 +126,13 @@ public class ApplicationContext extends MultiDexApplication {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
if ("deltafans@nine.testrun.org".equals(ac.getConfig("configured_addr")) && !ac.isCommunity()) {
|
||||
ac.setCommunityMode(true);
|
||||
}
|
||||
}
|
||||
if (allAccounts.length == 0) {
|
||||
dcAccounts.addAccount();
|
||||
try {
|
||||
rpc.addAccount();
|
||||
} catch (RpcException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
dcContext = dcAccounts.getSelectedAccount();
|
||||
notificationCenter = new NotificationCenter(this);
|
||||
@@ -153,8 +149,6 @@ public class ApplicationContext extends MultiDexApplication {
|
||||
Log.i("DeltaChat", "shutting down event handler");
|
||||
}, "eventThread").start();
|
||||
|
||||
rpc.start();
|
||||
|
||||
// migrating global notifications pref. to per-account config, added 10/July/24
|
||||
final String NOTIFICATION_PREF = "pref_key_enable_notifications";
|
||||
boolean isMuted = !Prefs.getBooleanPreference(this, NOTIFICATION_PREF, true);
|
||||
@@ -209,7 +203,6 @@ public class ApplicationContext extends MultiDexApplication {
|
||||
|
||||
KeepAliveService.maybeStartSelf(this);
|
||||
|
||||
initializeRandomNumberFix();
|
||||
initializeLogging();
|
||||
initializeJobManager();
|
||||
InChatSounds.getInstance(this);
|
||||
@@ -240,11 +233,10 @@ public class ApplicationContext extends MultiDexApplication {
|
||||
TimeUnit.MILLISECONDS)
|
||||
.setConstraints(constraints)
|
||||
.build();
|
||||
try {
|
||||
// in Android 4 this throws exception due to R8/shrinking
|
||||
WorkManager.getInstance(this)
|
||||
.enqueueUniquePeriodicWork("FetchWorker", ExistingPeriodicWorkPolicy.KEEP, fetchWorkRequest);
|
||||
} catch (Throwable e) {}
|
||||
WorkManager.getInstance(this).enqueueUniquePeriodicWork(
|
||||
"FetchWorker",
|
||||
ExistingPeriodicWorkPolicy.KEEP,
|
||||
fetchWorkRequest);
|
||||
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
|
||||
|
||||
if (Prefs.isPushEnabled(this)) {
|
||||
@@ -258,10 +250,6 @@ public class ApplicationContext extends MultiDexApplication {
|
||||
return jobManager;
|
||||
}
|
||||
|
||||
private void initializeRandomNumberFix() {
|
||||
PRNGFixes.apply();
|
||||
}
|
||||
|
||||
private void initializeLogging() {
|
||||
SignalProtocolLoggerProvider.setProvider(new AndroidSignalProtocolLogger());
|
||||
}
|
||||
|
||||
@@ -17,22 +17,15 @@
|
||||
*/
|
||||
package org.thoughtcrime.securesms;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Build;
|
||||
import android.os.Build.VERSION;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.core.app.NotificationManagerCompat;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.core.graphics.drawable.DrawableCompat;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.fragment.app.FragmentTransaction;
|
||||
@@ -51,9 +44,10 @@ import org.thoughtcrime.securesms.preferences.PrivacyPreferenceFragment;
|
||||
import org.thoughtcrime.securesms.preferences.CorrectedPreferenceFragment;
|
||||
import org.thoughtcrime.securesms.preferences.NotificationsPreferenceFragment;
|
||||
import org.thoughtcrime.securesms.preferences.widgets.ProfilePreference;
|
||||
import org.thoughtcrime.securesms.util.DynamicTheme;
|
||||
import org.thoughtcrime.securesms.util.Prefs;
|
||||
import org.thoughtcrime.securesms.qr.BackupTransferActivity;
|
||||
import org.thoughtcrime.securesms.util.DynamicTheme;
|
||||
import org.thoughtcrime.securesms.util.IntentUtils;
|
||||
import org.thoughtcrime.securesms.util.Prefs;
|
||||
import org.thoughtcrime.securesms.util.ScreenLockUtil;
|
||||
|
||||
/**
|
||||
@@ -74,6 +68,7 @@ public class ApplicationPreferencesActivity extends PassphraseRequiredActionBarA
|
||||
private static final String PREFERENCE_CATEGORY_MULTIDEVICE = "preference_category_multidevice";
|
||||
private static final String PREFERENCE_CATEGORY_ADVANCED = "preference_category_advanced";
|
||||
private static final String PREFERENCE_CATEGORY_CONNECTIVITY = "preference_category_connectivity";
|
||||
private static final String PREFERENCE_CATEGORY_DONATE = "preference_category_donate";
|
||||
private static final String PREFERENCE_CATEGORY_HELP = "preference_category_help";
|
||||
|
||||
public static final int REQUEST_CODE_SET_BACKGROUND = 11;
|
||||
@@ -153,13 +148,12 @@ public class ApplicationPreferencesActivity extends PassphraseRequiredActionBarA
|
||||
this.findPreference(PREFERENCE_CATEGORY_ADVANCED)
|
||||
.setOnPreferenceClickListener(new CategoryClickListener(PREFERENCE_CATEGORY_ADVANCED));
|
||||
|
||||
this.findPreference(PREFERENCE_CATEGORY_DONATE)
|
||||
.setOnPreferenceClickListener(new CategoryClickListener(PREFERENCE_CATEGORY_DONATE));
|
||||
|
||||
this.findPreference(PREFERENCE_CATEGORY_HELP)
|
||||
.setOnPreferenceClickListener(new CategoryClickListener(PREFERENCE_CATEGORY_HELP));
|
||||
|
||||
if (VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
||||
tintIcons(getActivity());
|
||||
}
|
||||
|
||||
DcHelper.getEventCenter(getActivity()).addObserver(DcContext.DC_EVENT_CONNECTIVITY_CHANGED, this);
|
||||
}
|
||||
|
||||
@@ -186,7 +180,7 @@ public class ApplicationPreferencesActivity extends PassphraseRequiredActionBarA
|
||||
public void handleEvent(@NonNull DcEvent event) {
|
||||
if (event.getId() == DcContext.DC_EVENT_CONNECTIVITY_CHANGED) {
|
||||
this.findPreference(PREFERENCE_CATEGORY_CONNECTIVITY)
|
||||
.setSummary(DcHelper.getConnectivitySummary(getActivity(), R.string.connectivity_connected));
|
||||
.setSummary(DcHelper.getConnectivitySummary(getActivity(), getString(R.string.connectivity_connected)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -202,43 +196,11 @@ public class ApplicationPreferencesActivity extends PassphraseRequiredActionBarA
|
||||
this.findPreference(PREFERENCE_CATEGORY_PRIVACY)
|
||||
.setSummary(PrivacyPreferenceFragment.getSummary(getActivity()));
|
||||
this.findPreference(PREFERENCE_CATEGORY_CONNECTIVITY)
|
||||
.setSummary(DcHelper.getConnectivitySummary(getActivity(), R.string.connectivity_connected));
|
||||
.setSummary(DcHelper.getConnectivitySummary(getActivity(), getString(R.string.connectivity_connected)));
|
||||
this.findPreference(PREFERENCE_CATEGORY_HELP)
|
||||
.setSummary(AdvancedPreferenceFragment.getVersion(getActivity()));
|
||||
}
|
||||
|
||||
@TargetApi(11)
|
||||
private void tintIcons(Context context) {
|
||||
Drawable notifications = DrawableCompat.wrap(ContextCompat.getDrawable(context, R.drawable.ic_notifications_white_24dp));
|
||||
Drawable swap = DrawableCompat.wrap(ContextCompat.getDrawable(context, R.drawable.ic_swap_vert_white_24dp));
|
||||
Drawable appearance = DrawableCompat.wrap(ContextCompat.getDrawable(context, R.drawable.ic_brightness_6_white_24dp));
|
||||
Drawable chats = DrawableCompat.wrap(ContextCompat.getDrawable(context, R.drawable.ic_forum_white_24dp));
|
||||
Drawable privacy = DrawableCompat.wrap(ContextCompat.getDrawable(context, R.drawable.ic_lock_white_24dp));
|
||||
Drawable advanced = DrawableCompat.wrap(ContextCompat.getDrawable(context, R.drawable.ic_advanced_white_24dp));
|
||||
Drawable help = DrawableCompat.wrap(ContextCompat.getDrawable(context, R.drawable.ic_help_white_24dp));
|
||||
|
||||
int[] tintAttr = new int[]{R.attr.pref_icon_tint};
|
||||
TypedArray typedArray = context.obtainStyledAttributes(tintAttr);
|
||||
int color = typedArray.getColor(0, 0x0);
|
||||
typedArray.recycle();
|
||||
|
||||
DrawableCompat.setTint(notifications, color);
|
||||
DrawableCompat.setTint(swap, color);
|
||||
DrawableCompat.setTint(appearance, color);
|
||||
DrawableCompat.setTint(chats, color);
|
||||
DrawableCompat.setTint(privacy, color);
|
||||
DrawableCompat.setTint(advanced, color);
|
||||
DrawableCompat.setTint(help, color);
|
||||
|
||||
this.findPreference(PREFERENCE_CATEGORY_NOTIFICATIONS).setIcon(notifications);
|
||||
this.findPreference(PREFERENCE_CATEGORY_CONNECTIVITY).setIcon(swap);
|
||||
this.findPreference(PREFERENCE_CATEGORY_APPEARANCE).setIcon(appearance);
|
||||
this.findPreference(PREFERENCE_CATEGORY_CHATS).setIcon(chats);
|
||||
this.findPreference(PREFERENCE_CATEGORY_PRIVACY).setIcon(privacy);
|
||||
this.findPreference(PREFERENCE_CATEGORY_ADVANCED).setIcon(advanced);
|
||||
this.findPreference(PREFERENCE_CATEGORY_HELP).setIcon(help);
|
||||
}
|
||||
|
||||
private class CategoryClickListener implements Preference.OnPreferenceClickListener {
|
||||
private final String category;
|
||||
|
||||
@@ -293,6 +255,9 @@ public class ApplicationPreferencesActivity extends PassphraseRequiredActionBarA
|
||||
case PREFERENCE_CATEGORY_ADVANCED:
|
||||
fragment = new AdvancedPreferenceFragment();
|
||||
break;
|
||||
case PREFERENCE_CATEGORY_DONATE:
|
||||
IntentUtils.showInBrowser(requireActivity(), "https://arcanechat.me/#contribute");
|
||||
break;
|
||||
case PREFERENCE_CATEGORY_HELP:
|
||||
startActivity(new Intent(getActivity(), LocalHelpActivity.class));
|
||||
break;
|
||||
|
||||
@@ -9,9 +9,8 @@ public class AttachContactActivity extends ContactSelectionActivity {
|
||||
public static final String CONTACT_ID_EXTRA = "contact_id_extra";
|
||||
|
||||
@Override
|
||||
public void onContactSelected(int specialId, String addr) {
|
||||
public void onContactSelected(int contactId) {
|
||||
Intent intent = new Intent();
|
||||
int contactId = DcHelper.getContext(this).lookupContactIdByAddr(addr);
|
||||
intent.putExtra(CONTACT_ID_EXTRA, contactId);
|
||||
setResult(RESULT_OK, intent);
|
||||
finish();
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
package org.thoughtcrime.securesms;
|
||||
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.ViewConfiguration;
|
||||
@@ -33,9 +31,6 @@ public abstract class BaseActionBarActivity extends AppCompatActivity {
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
onPreCreate();
|
||||
if (BaseActivity.isMenuWorkaroundRequired()) {
|
||||
forceOverflowMenu();
|
||||
}
|
||||
super.onCreate(savedInstanceState);
|
||||
}
|
||||
|
||||
@@ -46,20 +41,6 @@ public abstract class BaseActionBarActivity extends AppCompatActivity {
|
||||
dynamicTheme.onResume(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
||||
return (keyCode == KeyEvent.KEYCODE_MENU && BaseActivity.isMenuWorkaroundRequired()) || super.onKeyDown(keyCode, event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyUp(int keyCode, @NonNull KeyEvent event) {
|
||||
if (keyCode == KeyEvent.KEYCODE_MENU && BaseActivity.isMenuWorkaroundRequired()) {
|
||||
openOptionsMenu();
|
||||
return true;
|
||||
}
|
||||
return super.onKeyUp(keyCode, event);
|
||||
}
|
||||
|
||||
private void initializeScreenshotSecurity() {
|
||||
if (Prefs.isScreenSecurityEnabled(this)) {
|
||||
getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE);
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
package org.thoughtcrime.securesms;
|
||||
|
||||
import android.os.Build;
|
||||
import android.os.Build.VERSION;
|
||||
import android.os.Build.VERSION_CODES;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import android.view.KeyEvent;
|
||||
|
||||
public abstract class BaseActivity extends FragmentActivity {
|
||||
@Override
|
||||
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
||||
return (keyCode == KeyEvent.KEYCODE_MENU && isMenuWorkaroundRequired()) || super.onKeyDown(keyCode, event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyUp(int keyCode, @NonNull KeyEvent event) {
|
||||
if (keyCode == KeyEvent.KEYCODE_MENU && isMenuWorkaroundRequired()) {
|
||||
openOptionsMenu();
|
||||
return true;
|
||||
}
|
||||
return super.onKeyUp(keyCode, event);
|
||||
}
|
||||
|
||||
public static boolean isMenuWorkaroundRequired() {
|
||||
return VERSION.SDK_INT < VERSION_CODES.KITKAT && ("LGE".equalsIgnoreCase(Build.MANUFACTURER) || "E6710".equalsIgnoreCase(Build.DEVICE));
|
||||
}
|
||||
}
|
||||
@@ -18,9 +18,8 @@ import com.b44t.messenger.rpc.Rpc;
|
||||
|
||||
import org.thoughtcrime.securesms.connect.DcHelper;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -11,19 +11,23 @@ import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Color;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Build;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.view.ActionMode;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.core.content.pm.ShortcutInfoCompat;
|
||||
import androidx.core.content.pm.ShortcutManagerCompat;
|
||||
import androidx.core.graphics.drawable.IconCompat;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.b44t.messenger.DcChat;
|
||||
@@ -33,6 +37,7 @@ import com.google.android.material.snackbar.Snackbar;
|
||||
import org.thoughtcrime.securesms.components.registration.PulsingFloatingActionButton;
|
||||
import org.thoughtcrime.securesms.connect.DcHelper;
|
||||
import org.thoughtcrime.securesms.connect.DirectShareUtil;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.util.RelayUtil;
|
||||
import org.thoughtcrime.securesms.util.SendRelayedMessageUtil;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
@@ -93,12 +98,16 @@ public abstract class BaseConversationListFragment extends Fragment implements A
|
||||
if (isForwarding(getActivity())) {
|
||||
message = String.format(Util.getLocale(), getString(R.string.ask_forward_multiple), selectedChats.size());
|
||||
} else if (!uris.isEmpty()) {
|
||||
message = String.format(Util.getLocale(), getString(R.string.share_multiple_attachments_multiple_chats), uris.size(), selectedChats.size());
|
||||
message = String.format(Util.getLocale(), getString(R.string.ask_send_files_to_selected_chats), uris.size(), selectedChats.size());
|
||||
} else {
|
||||
message = String.format(Util.getLocale(), getString(R.string.share_text_multiple_chats), selectedChats.size(), getSharedText(getActivity()));
|
||||
}
|
||||
|
||||
Context context = getContext();
|
||||
if (context != null) {
|
||||
if (SendRelayedMessageUtil.containsVideoType(context, uris)) {
|
||||
message += "\n\n" + getString(R.string.videos_sent_without_recoding);
|
||||
}
|
||||
new AlertDialog.Builder(context)
|
||||
.setMessage(message)
|
||||
.setCancelable(false)
|
||||
@@ -312,9 +321,41 @@ public abstract class BaseConversationListFragment extends Fragment implements A
|
||||
updateActionModeItems(actionMode.getMenu());
|
||||
}
|
||||
|
||||
private void handleAddToHomeScreen() {
|
||||
final Activity activity = requireActivity();
|
||||
final DcContext dcContext = DcHelper.getContext(activity);
|
||||
final Set<Long> selectedChats = getListAdapter().getBatchSelections();
|
||||
final DcChat chat = dcContext.getChat(selectedChats.iterator().next().intValue());
|
||||
|
||||
Intent intent = new Intent(activity, ShareActivity.class);
|
||||
intent.setAction(Intent.ACTION_SEND);
|
||||
intent.putExtra(ShareActivity.EXTRA_ACC_ID, dcContext.getAccountId());
|
||||
intent.putExtra(ShareActivity.EXTRA_CHAT_ID, chat.getId());
|
||||
|
||||
Recipient recipient = new Recipient(activity, chat);
|
||||
Util.runOnAnyBackgroundThread(() -> {
|
||||
Bitmap avatar = DirectShareUtil.getIconForShortcut(activity, recipient);
|
||||
ShortcutInfoCompat shortcutInfoCompat = new ShortcutInfoCompat.Builder(activity, "chat-" + dcContext.getAccountId() + "-" + chat.getId())
|
||||
.setShortLabel(chat.getName())
|
||||
.setIcon(IconCompat.createWithAdaptiveBitmap(avatar))
|
||||
.setIntent(intent)
|
||||
.build();
|
||||
Util.runOnMain(() -> {
|
||||
if (!ShortcutManagerCompat.requestPinShortcut(activity, shortcutInfoCompat, null)) {
|
||||
Toast.makeText(activity, "ErrAddToHomescreen: requestPinShortcut() failed", Toast.LENGTH_LONG).show();
|
||||
} else if (actionMode != null) {
|
||||
actionMode.finish();
|
||||
actionMode = null;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private void updateActionModeItems(Menu menu) {
|
||||
// We do not show action mode icons when relaying (= sharing or forwarding).
|
||||
if (!isRelayingMessageContent(requireActivity())) {
|
||||
final int selectedCount = getListAdapter().getBatchSelections().size();
|
||||
menu.findItem(R.id.menu_add_to_home_screen).setVisible(selectedCount == 1);
|
||||
MenuItem archiveItem = menu.findItem(R.id.menu_archive_selected);
|
||||
if (offerToArchive()) {
|
||||
archiveItem.setIcon(R.drawable.ic_archive_white_24dp);
|
||||
@@ -360,9 +401,7 @@ public abstract class BaseConversationListFragment extends Fragment implements A
|
||||
|
||||
mode.setTitle("1");
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
requireActivity().getWindow().setStatusBarColor(getResources().getColor(R.color.action_mode_status_bar));
|
||||
}
|
||||
requireActivity().getWindow().setStatusBarColor(getResources().getColor(R.color.action_mode_status_bar));
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -374,13 +413,28 @@ public abstract class BaseConversationListFragment extends Fragment implements A
|
||||
|
||||
@Override
|
||||
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.menu_select_all: handleSelectAllThreads(); return true;
|
||||
case R.id.menu_delete_selected: handleDeleteAllSelected(); return true;
|
||||
case R.id.menu_pin_selected: handlePinAllSelected(); return true;
|
||||
case R.id.menu_archive_selected: handleArchiveAllSelected(); return true;
|
||||
case R.id.menu_mute_selected: handleMuteAllSelected(); return true;
|
||||
case R.id.menu_marknoticed_selected: handleMarknoticedSelected(); return true;
|
||||
int itemId = item.getItemId();
|
||||
if (itemId == R.id.menu_select_all) {
|
||||
handleSelectAllThreads();
|
||||
return true;
|
||||
} else if (itemId == R.id.menu_delete_selected) {
|
||||
handleDeleteAllSelected();
|
||||
return true;
|
||||
} else if (itemId == R.id.menu_pin_selected) {
|
||||
handlePinAllSelected();
|
||||
return true;
|
||||
} else if (itemId == R.id.menu_archive_selected) {
|
||||
handleArchiveAllSelected();
|
||||
return true;
|
||||
} else if (itemId == R.id.menu_mute_selected) {
|
||||
handleMuteAllSelected();
|
||||
return true;
|
||||
} else if (itemId == R.id.menu_marknoticed_selected) {
|
||||
handleMarknoticedSelected();
|
||||
return true;
|
||||
} else if (itemId == R.id.menu_add_to_home_screen) {
|
||||
handleAddToHomeScreen();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -391,11 +445,9 @@ public abstract class BaseConversationListFragment extends Fragment implements A
|
||||
actionMode = null;
|
||||
getListAdapter().initializeBatchMode(false);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
TypedArray color = requireActivity().getTheme().obtainStyledAttributes(new int[] {android.R.attr.statusBarColor});
|
||||
requireActivity().getWindow().setStatusBarColor(color.getColor(0, Color.BLACK));
|
||||
color.recycle();
|
||||
}
|
||||
TypedArray color = requireActivity().getTheme().obtainStyledAttributes(new int[]{android.R.attr.statusBarColor});
|
||||
requireActivity().getWindow().setStatusBarColor(color.getColor(0, Color.BLACK));
|
||||
color.recycle();
|
||||
|
||||
Context context = getContext();
|
||||
if (context != null) {
|
||||
|
||||
@@ -25,6 +25,7 @@ public interface BindableConversationItem extends Unbindable {
|
||||
|
||||
interface EventListener {
|
||||
void onQuoteClicked(DcMsg messageRecord);
|
||||
void onJumpToOriginalClicked(DcMsg messageRecord);
|
||||
void onShowFullClicked(DcMsg messageRecord);
|
||||
void onDownloadClicked(DcMsg messageRecord);
|
||||
void onReactionClicked(DcMsg messageRecord);
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
package org.thoughtcrime.securesms;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.loader.app.LoaderManager;
|
||||
import androidx.loader.content.Loader;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.loader.app.LoaderManager;
|
||||
import androidx.loader.content.Loader;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.b44t.messenger.DcContext;
|
||||
import com.b44t.messenger.DcEvent;
|
||||
|
||||
|
||||
@@ -33,6 +33,8 @@ import java.util.List;
|
||||
*/
|
||||
public class ContactMultiSelectionActivity extends ContactSelectionActivity {
|
||||
|
||||
public static final String CONTACTS_EXTRA = "contacts_extra";
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle icicle, boolean ready) {
|
||||
getIntent().putExtra(ContactSelectionListFragment.MULTI_SELECT, true);
|
||||
@@ -57,11 +59,10 @@ public class ContactMultiSelectionActivity extends ContactSelectionActivity {
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
super.onOptionsItemSelected(item);
|
||||
switch (item.getItemId()) {
|
||||
case R.id.menu_add_members:
|
||||
saveSelection();
|
||||
finish();
|
||||
return true;
|
||||
if (item.getItemId() == R.id.menu_add_members) {
|
||||
saveSelection();
|
||||
finish();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -69,12 +70,8 @@ public class ContactMultiSelectionActivity extends ContactSelectionActivity {
|
||||
|
||||
private void saveSelection() {
|
||||
Intent resultIntent = getIntent();
|
||||
List<String> selectedContacts = contactsFragment.getSelectedContacts();
|
||||
|
||||
if (selectedContacts != null) {
|
||||
resultIntent.putStringArrayListExtra("contacts", new ArrayList<>(selectedContacts));
|
||||
}
|
||||
|
||||
List<Integer> selectedContacts = contactsFragment.getSelectedContacts();
|
||||
resultIntent.putIntegerArrayListExtra(CONTACTS_EXTRA, new ArrayList<>(selectedContacts));
|
||||
setResult(RESULT_OK, resultIntent);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,8 +89,8 @@ public abstract class ContactSelectionActivity extends PassphraseRequiredActionB
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onContactSelected(int specialId, String number) {}
|
||||
public void onContactSelected(int contactId) {}
|
||||
|
||||
@Override
|
||||
public void onContactDeselected(int specialId, String number) {}
|
||||
public void onContactDeselected(int contactId) {}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,6 @@ import android.content.Intent;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Color;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.util.SparseIntArray;
|
||||
@@ -90,7 +89,7 @@ public class ContactSelectionListFragment extends Fragment
|
||||
|
||||
private DcContext dcContext;
|
||||
|
||||
private Set<String> selectedContacts;
|
||||
private Set<Integer> selectedContacts;
|
||||
private OnContactSelectedListener onContactSelectedListener;
|
||||
private String cursorFilter;
|
||||
private RecyclerView recyclerView;
|
||||
@@ -136,9 +135,7 @@ public class ContactSelectionListFragment extends Fragment
|
||||
public boolean onCreateActionMode(ActionMode actionMode, Menu menu) {
|
||||
MenuInflater inflater = getActivity().getMenuInflater();
|
||||
inflater.inflate(R.menu.contact_list, menu);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
getActivity().getWindow().setStatusBarColor(getResources().getColor(R.color.action_mode_status_bar));
|
||||
}
|
||||
getActivity().getWindow().setStatusBarColor(getResources().getColor(R.color.action_mode_status_bar));
|
||||
setCorrectMenuVisibility(menu);
|
||||
actionMode.setTitle("1");
|
||||
return true;
|
||||
@@ -151,16 +148,16 @@ public class ContactSelectionListFragment extends Fragment
|
||||
|
||||
@Override
|
||||
public boolean onActionItemClicked(ActionMode actionMode, MenuItem menuItem) {
|
||||
switch (menuItem.getItemId()) {
|
||||
case R.id.menu_select_all:
|
||||
handleSelectAll();
|
||||
return true;
|
||||
case R.id.menu_view_profile:
|
||||
handleViewProfile();
|
||||
return true;
|
||||
case R.id.menu_delete_selected:
|
||||
handleDeleteSelected();
|
||||
return true;
|
||||
int itemId = menuItem.getItemId();
|
||||
if (itemId == R.id.menu_select_all) {
|
||||
handleSelectAll();
|
||||
return true;
|
||||
} else if (itemId == R.id.menu_view_profile) {
|
||||
handleViewProfile();
|
||||
return true;
|
||||
} else if (itemId == R.id.menu_delete_selected) {
|
||||
handleDeleteSelected();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -170,11 +167,9 @@ public class ContactSelectionListFragment extends Fragment
|
||||
ContactSelectionListFragment.this.actionMode = null;
|
||||
getContactSelectionListAdapter().resetActionModeSelection();
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
TypedArray color = getActivity().getTheme().obtainStyledAttributes(new int[] {android.R.attr.statusBarColor});
|
||||
getActivity().getWindow().setStatusBarColor(color.getColor(0, Color.BLACK));
|
||||
color.recycle();
|
||||
}
|
||||
TypedArray color = getActivity().getTheme().obtainStyledAttributes(new int[]{android.R.attr.statusBarColor});
|
||||
getActivity().getWindow().setStatusBarColor(color.getColor(0, Color.BLACK));
|
||||
color.recycle();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -217,16 +212,9 @@ public class ContactSelectionListFragment extends Fragment
|
||||
ContactSelectionListAdapter adapter = getContactSelectionListAdapter();
|
||||
final SparseIntArray actionModeSelection = adapter.getActionModeSelection().clone();
|
||||
new Thread(() -> {
|
||||
boolean failed = false;
|
||||
for (int index = 0; index < actionModeSelection.size(); index++) {
|
||||
int contactId = actionModeSelection.valueAt(index);
|
||||
boolean currentFailed = !dcContext.deleteContact(contactId);
|
||||
failed = currentFailed || failed;
|
||||
}
|
||||
if (failed) {
|
||||
Util.runOnMain(()-> {
|
||||
Toast.makeText(getActivity(), R.string.cannot_delete_contacts_in_use, Toast.LENGTH_LONG).show();
|
||||
});
|
||||
dcContext.deleteContact(contactId);
|
||||
}
|
||||
}).start();
|
||||
adapter.resetActionModeSelection();
|
||||
@@ -246,8 +234,8 @@ public class ContactSelectionListFragment extends Fragment
|
||||
Permissions.onRequestPermissionsResult(this, requestCode, permissions, grantResults);
|
||||
}
|
||||
|
||||
public @NonNull List<String> getSelectedContacts() {
|
||||
List<String> selected = new LinkedList<>();
|
||||
public @NonNull List<Integer> getSelectedContacts() {
|
||||
List<Integer> selected = new LinkedList<>();
|
||||
if (selectedContacts != null) {
|
||||
selected.addAll(selectedContacts);
|
||||
}
|
||||
@@ -270,7 +258,7 @@ public class ContactSelectionListFragment extends Fragment
|
||||
isMulti(),
|
||||
true);
|
||||
selectedContacts = adapter.getSelectedContacts();
|
||||
ArrayList<String> preselectedContacts = getActivity().getIntent().getStringArrayListExtra(PRESELECTED_CONTACTS);
|
||||
ArrayList<Integer> preselectedContacts = getActivity().getIntent().getIntegerArrayListExtra(PRESELECTED_CONTACTS);
|
||||
if(preselectedContacts!=null) {
|
||||
selectedContacts.addAll(preselectedContacts);
|
||||
}
|
||||
@@ -348,10 +336,9 @@ public class ContactSelectionListFragment extends Fragment
|
||||
}
|
||||
return;
|
||||
}
|
||||
int specialId = contact.getSpecialId();
|
||||
String addr = contact.getNumber();
|
||||
if (!isMulti() || !selectedContacts.contains(addr)) {
|
||||
if (specialId == DcContact.DC_CONTACT_ID_NEW_CLASSIC_CONTACT) {
|
||||
int contactId = contact.getSpecialId();
|
||||
if (!isMulti() || !selectedContacts.contains(contactId)) {
|
||||
if (contactId == DcContact.DC_CONTACT_ID_NEW_CLASSIC_CONTACT) {
|
||||
Intent intent = new Intent(getContext(), NewContactActivity.class);
|
||||
if (dcContext.mayBeValidAddr(cursorFilter)) {
|
||||
intent.putExtra(NewContactActivity.ADDR_EXTRA, cursorFilter);
|
||||
@@ -375,16 +362,16 @@ public class ContactSelectionListFragment extends Fragment
|
||||
return;
|
||||
}
|
||||
|
||||
selectedContacts.add(addr);
|
||||
selectedContacts.add(contactId);
|
||||
contact.setChecked(true);
|
||||
if (onContactSelectedListener != null) {
|
||||
onContactSelectedListener.onContactSelected(specialId, addr);
|
||||
onContactSelectedListener.onContactSelected(contactId);
|
||||
}
|
||||
} else {
|
||||
selectedContacts.remove(addr);
|
||||
selectedContacts.remove(contactId);
|
||||
contact.setChecked(false);
|
||||
if (onContactSelectedListener != null) {
|
||||
onContactSelectedListener.onContactDeselected(specialId, addr);
|
||||
onContactSelectedListener.onContactDeselected(contactId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -410,8 +397,8 @@ public class ContactSelectionListFragment extends Fragment
|
||||
}
|
||||
|
||||
public interface OnContactSelectedListener {
|
||||
void onContactSelected(int specialId, String number);
|
||||
void onContactDeselected(int specialId, String number);
|
||||
void onContactSelected(int contactId);
|
||||
void onContactDeselected(int contactId);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -425,7 +412,10 @@ public class ContactSelectionListFragment extends Fragment
|
||||
public void onActivityResult(int reqCode, int resultCode, final Intent data) {
|
||||
super.onActivityResult(reqCode, resultCode, data);
|
||||
if (resultCode == Activity.RESULT_OK && reqCode == CONTACT_ADDR_RESULT_CODE) {
|
||||
selectedContacts.add(data.getStringExtra(NewContactActivity.ADDR_EXTRA));
|
||||
int contactId = data.getIntExtra(NewContactActivity.CONTACT_ID_EXTRA, 0);
|
||||
if (contactId != 0) {
|
||||
selectedContacts.add(contactId);
|
||||
}
|
||||
getLoaderManager().restartLoader(0, null, ContactSelectionListFragment.this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ import static org.thoughtcrime.securesms.util.RelayUtil.isSharing;
|
||||
import android.Manifest;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.Context;
|
||||
import android.content.ClipData;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.res.Configuration;
|
||||
@@ -36,9 +36,7 @@ import android.graphics.Color;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.PowerManager;
|
||||
import android.os.Vibrator;
|
||||
import android.provider.Browser;
|
||||
import android.text.Editable;
|
||||
@@ -47,6 +45,7 @@ import android.text.TextWatcher;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
@@ -55,6 +54,7 @@ import android.view.View.OnFocusChangeListener;
|
||||
import android.view.View.OnKeyListener;
|
||||
import android.view.WindowManager;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
@@ -91,8 +91,6 @@ import org.thoughtcrime.securesms.components.InputPanel;
|
||||
import org.thoughtcrime.securesms.components.KeyboardAwareLinearLayout.OnKeyboardShownListener;
|
||||
import org.thoughtcrime.securesms.components.ScaleStableImageView;
|
||||
import org.thoughtcrime.securesms.components.SendButton;
|
||||
import org.thoughtcrime.securesms.components.emoji.EmojiKeyboardProvider;
|
||||
import org.thoughtcrime.securesms.components.emoji.EmojiProvider;
|
||||
import org.thoughtcrime.securesms.components.emoji.MediaKeyboard;
|
||||
import org.thoughtcrime.securesms.connect.AccountManager;
|
||||
import org.thoughtcrime.securesms.connect.DcEventCenter;
|
||||
@@ -121,7 +119,7 @@ import org.thoughtcrime.securesms.util.Util;
|
||||
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||
import org.thoughtcrime.securesms.util.concurrent.AssertedSuccessListener;
|
||||
import org.thoughtcrime.securesms.util.guava.Optional;
|
||||
import org.thoughtcrime.securesms.util.views.Stub;
|
||||
import org.thoughtcrime.securesms.util.views.ProgressDialog;
|
||||
import org.thoughtcrime.securesms.video.recode.VideoRecoder;
|
||||
import org.thoughtcrime.securesms.videochat.VideochatUtil;
|
||||
|
||||
@@ -164,8 +162,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
private static final int GROUP_EDIT = 6;
|
||||
private static final int TAKE_PHOTO = 7;
|
||||
private static final int RECORD_VIDEO = 8;
|
||||
private static final int PICK_LOCATION = 9; // TODO: i think, this can be deleted
|
||||
private static final int SMS_DEFAULT = 11; // TODO: i think, this can be deleted
|
||||
private static final int PICK_WEBXDC = 9;
|
||||
|
||||
private GlideRequests glideRequests;
|
||||
protected ComposeText composeText;
|
||||
@@ -178,11 +175,13 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
private View composePanel;
|
||||
private ScaleStableImageView backgroundView;
|
||||
private MessageRequestsBottomView messageRequestBottomView;
|
||||
private ProgressDialog progressDialog;
|
||||
|
||||
private AttachmentTypeSelector attachmentTypeSelector;
|
||||
private AttachmentManager attachmentManager;
|
||||
private AudioRecorder audioRecorder;
|
||||
private Stub<MediaKeyboard> emojiDrawerStub;
|
||||
private FrameLayout emojiPickerContainer;
|
||||
private MediaKeyboard emojiPicker;
|
||||
protected HidingLinearLayout quickAttachmentToggle;
|
||||
private InputPanel inputPanel;
|
||||
|
||||
@@ -196,6 +195,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
private boolean isDefaultSms = true;
|
||||
private boolean isSecurityInitialized = false;
|
||||
private boolean successfulForwardingAttempt = false;
|
||||
private boolean isEditing = false;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle state, boolean ready) {
|
||||
@@ -302,12 +302,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
DcHelper.getNotificationCenter(this).updateVisibleChat(dcContext.getAccountId(), chatId);
|
||||
|
||||
attachmentManager.onResume();
|
||||
|
||||
// action bar might be hidden by workaround in onStop()
|
||||
ActionBar supportActionBar = getSupportActionBar();
|
||||
if (supportActionBar != null && !supportActionBar.isShowing()) {
|
||||
supportActionBar.show();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -322,33 +316,17 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
AudioSlidePlayer.stopAll();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
super.onStop();
|
||||
|
||||
// hack/workaround to fix https://github.com/deltachat/deltachat-android/issues/2798
|
||||
// the real cause of the problem is still unknown but hiding the action bar here fixes it
|
||||
if ( Build.VERSION.SDK_INT >= 34) {
|
||||
ActionBar supportActionBar = getSupportActionBar();
|
||||
if (supportActionBar != null && container.isKeyboardOpen()) {
|
||||
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
|
||||
if (!pm.isInteractive()) {
|
||||
supportActionBar.hide();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(Configuration newConfig) {
|
||||
Log.i(TAG, "onConfigurationChanged(" + newConfig.orientation + ")");
|
||||
super.onConfigurationChanged(newConfig);
|
||||
composeText.setTransport(sendButton.getSelectedTransport());
|
||||
|
||||
if (emojiDrawerStub.resolved() && container.getCurrentInput() == emojiDrawerStub.get()) {
|
||||
if (emojiPicker != null && container.getCurrentInput() == emojiPicker) {
|
||||
container.hideAttachedInput(true);
|
||||
}
|
||||
|
||||
emojiPicker = null; // force reloading next time onEmojiToggle() is called
|
||||
initializeBackground();
|
||||
}
|
||||
|
||||
@@ -362,22 +340,38 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
public void onActivityResult(final int reqCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(reqCode, resultCode, data);
|
||||
|
||||
if ((data == null && reqCode != TAKE_PHOTO && reqCode != RECORD_VIDEO && reqCode != SMS_DEFAULT) ||
|
||||
(resultCode != RESULT_OK && reqCode != SMS_DEFAULT))
|
||||
if (resultCode != RESULT_OK || (data == null && reqCode != TAKE_PHOTO && reqCode != RECORD_VIDEO))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
switch (reqCode) {
|
||||
case PICK_GALLERY:
|
||||
MediaType mediaType;
|
||||
String mimeType = MediaUtil.getMimeType(this, data.getData());
|
||||
|
||||
if (MediaUtil.isGif(mimeType)) mediaType = MediaType.GIF;
|
||||
else if (MediaUtil.isVideo(mimeType)) mediaType = MediaType.VIDEO;
|
||||
else mediaType = MediaType.IMAGE;
|
||||
|
||||
setMedia(data.getData(), mediaType);
|
||||
final Uri singleUri = data.getData();
|
||||
if (singleUri != null) {
|
||||
MediaType mediaType;
|
||||
String mimeType = MediaUtil.getMimeType(this, singleUri);
|
||||
if (MediaUtil.isGif(mimeType)) mediaType = MediaType.GIF;
|
||||
else if (MediaUtil.isVideo(mimeType)) mediaType = MediaType.VIDEO;
|
||||
else mediaType = MediaType.IMAGE;
|
||||
setMedia(singleUri, mediaType);
|
||||
} else {
|
||||
final ClipData multipleUris = data.getClipData();
|
||||
if (multipleUris != null) {
|
||||
final int uriCount = multipleUris.getItemCount();
|
||||
if (uriCount > 0) {
|
||||
ArrayList<Uri> uriList = new ArrayList<>(uriCount);
|
||||
for (int i = 0; i < uriCount; i++) {
|
||||
uriList.add(multipleUris.getItemAt(i).getUri());
|
||||
}
|
||||
askSendingFiles(uriList, () -> {
|
||||
Util.runOnAnyBackgroundThread(() -> {
|
||||
SendRelayedMessageUtil.sendMultipleMsgs(this, chatId, uriList, null);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case PICK_DOCUMENT:
|
||||
@@ -386,6 +380,10 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
setMedia(data.getData(), docMediaType);
|
||||
break;
|
||||
|
||||
case PICK_WEBXDC:
|
||||
setMedia(data.getData(), MediaType.DOCUMENT);
|
||||
break;
|
||||
|
||||
case PICK_CONTACT:
|
||||
addAttachmentContactInfo(data.getIntExtra(AttachContactActivity.CONTACT_ID_EXTRA, 0));
|
||||
break;
|
||||
@@ -413,16 +411,9 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
}
|
||||
break;
|
||||
|
||||
case PICK_LOCATION:
|
||||
break;
|
||||
|
||||
case ScribbleActivity.SCRIBBLE_REQUEST_CODE:
|
||||
setMedia(data.getData(), MediaType.IMAGE);
|
||||
break;
|
||||
|
||||
case SMS_DEFAULT:
|
||||
initializeSecurity(isSecureText, isDefaultSms);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -505,6 +496,13 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
Log.e(TAG, "cannot set up in-chat-search: ", e);
|
||||
}
|
||||
|
||||
if (!dcChat.canSend() || isEditing) {
|
||||
MenuItem attachItem = menu.findItem(R.id.menu_add_attachment);
|
||||
if (attachItem!=null) {
|
||||
attachItem.setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
super.onPrepareOptionsMenu(menu);
|
||||
return true;
|
||||
}
|
||||
@@ -512,17 +510,40 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
super.onOptionsItemSelected(item);
|
||||
switch (item.getItemId()) {
|
||||
case R.id.menu_leave: handleLeaveGroup(); return true;
|
||||
case R.id.menu_archive_chat: handleArchiveChat(); return true;
|
||||
case R.id.menu_clear_chat: fragment.handleClearChat(); return true;
|
||||
case R.id.menu_delete_chat: handleDeleteChat(); return true;
|
||||
case R.id.menu_mute_notifications: handleMuteNotifications(); return true;
|
||||
case R.id.menu_show_map: WebxdcActivity.openMaps(this, chatId); return true;
|
||||
case R.id.menu_search_up: handleMenuSearchNext(false); return true;
|
||||
case R.id.menu_search_down: handleMenuSearchNext(true); return true;
|
||||
case android.R.id.home: handleReturnToConversationList(); return true;
|
||||
case R.id.menu_ephemeral_messages: handleEphemeralMessages(); return true;
|
||||
int itemId = item.getItemId();
|
||||
if (itemId == R.id.menu_add_attachment) {
|
||||
handleAddAttachment();
|
||||
return true;
|
||||
} else if (itemId == R.id.menu_leave) {
|
||||
handleLeaveGroup();
|
||||
return true;
|
||||
} else if (itemId == R.id.menu_archive_chat) {
|
||||
handleArchiveChat();
|
||||
return true;
|
||||
} else if (itemId == R.id.menu_clear_chat) {
|
||||
fragment.handleClearChat();
|
||||
return true;
|
||||
} else if (itemId == R.id.menu_delete_chat) {
|
||||
handleDeleteChat();
|
||||
return true;
|
||||
} else if (itemId == R.id.menu_mute_notifications) {
|
||||
handleMuteNotifications();
|
||||
return true;
|
||||
} else if (itemId == R.id.menu_show_map) {
|
||||
WebxdcActivity.openMaps(this, chatId);
|
||||
return true;
|
||||
} else if (itemId == R.id.menu_search_up) {
|
||||
handleMenuSearchNext(false);
|
||||
return true;
|
||||
} else if (itemId == R.id.menu_search_down) {
|
||||
handleMenuSearchNext(true);
|
||||
return true;
|
||||
} else if (itemId == android.R.id.home) {
|
||||
handleReturnToConversationList();
|
||||
return true;
|
||||
} else if (itemId == R.id.menu_ephemeral_messages) {
|
||||
handleEphemeralMessages();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -665,7 +686,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
if (!dcChat.isMultiUser()) {
|
||||
int[] contactIds = dcContext.getChatContacts(chatId);
|
||||
if (contactIds.length == 1 || contactIds.length == 2) {
|
||||
name = dcContext.getContact(contactIds[0]).getNameNAddr();
|
||||
name = dcContext.getContact(contactIds[0]).getDisplayName();
|
||||
}
|
||||
}
|
||||
new AlertDialog.Builder(this)
|
||||
@@ -680,17 +701,24 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
}
|
||||
}
|
||||
|
||||
private void askSendingFiles(ArrayList<Uri> uriList, Runnable onConfirm) {
|
||||
String message = String.format(getString(R.string.ask_send_files_to_chat), uriList.size(), dcChat.getName());
|
||||
if (SendRelayedMessageUtil.containsVideoType(context, uriList)) {
|
||||
message += "\n\n" + getString(R.string.videos_sent_without_recoding);
|
||||
}
|
||||
new AlertDialog.Builder(this)
|
||||
.setMessage(message)
|
||||
.setCancelable(false)
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.setPositiveButton(R.string.menu_send, (dialog, which) -> onConfirm.run())
|
||||
.show();
|
||||
}
|
||||
|
||||
private void handleSharing() {
|
||||
ArrayList<Uri> uriList = RelayUtil.getSharedUris(this);
|
||||
int sharedContactId = RelayUtil.getSharedContactId(this);
|
||||
if (uriList.size() > 1) {
|
||||
String message = String.format(getString(R.string.share_multiple_attachments), uriList.size());
|
||||
new AlertDialog.Builder(this)
|
||||
.setMessage(message)
|
||||
.setCancelable(false)
|
||||
.setNegativeButton(android.R.string.cancel, ((dialog, which) -> finish()))
|
||||
.setPositiveButton(R.string.menu_send, (dialog, which) -> SendRelayedMessageUtil.immediatelyRelay(this, chatId))
|
||||
.show();
|
||||
askSendingFiles(uriList, () -> SendRelayedMessageUtil.immediatelyRelay(this, chatId));
|
||||
} else {
|
||||
if (sharedContactId != 0) {
|
||||
addAttachmentContactInfo(sharedContactId);
|
||||
@@ -711,11 +739,12 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
* @return
|
||||
*/
|
||||
private ListenableFuture<Boolean> initializeDraft() {
|
||||
isEditing = false;
|
||||
final SettableFuture<Boolean> future = new SettableFuture<>();
|
||||
DcMsg draft = dcContext.getDraft(chatId);
|
||||
final String sharedText = RelayUtil.getSharedText(this);
|
||||
|
||||
if (draft == null) {
|
||||
if (!draft.isOk()) {
|
||||
if (TextUtils.isEmpty(sharedText)) {
|
||||
composeText.setText("");
|
||||
future.set(false);
|
||||
@@ -742,8 +771,8 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
handleReplyMessage(quote);
|
||||
}
|
||||
|
||||
String filename = draft.getFile();
|
||||
if (filename.isEmpty() || !new File(filename).exists()) {
|
||||
String file = draft.getFile();
|
||||
if (file.isEmpty() || !new File(file).exists()) {
|
||||
future.set(!text.isEmpty());
|
||||
updateToggleButtonState();
|
||||
return future;
|
||||
@@ -763,26 +792,21 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
}
|
||||
};
|
||||
|
||||
File file = new File(filename);
|
||||
Uri uri = Uri.fromFile(file);
|
||||
switch (draft.getType()) {
|
||||
case DcMsg.DC_MSG_IMAGE:
|
||||
setMedia(uri, MediaType.IMAGE).addListener(listener);
|
||||
setMedia(draft, MediaType.IMAGE).addListener(listener);
|
||||
break;
|
||||
case DcMsg.DC_MSG_GIF:
|
||||
setMedia(uri, MediaType.GIF).addListener(listener);
|
||||
setMedia(draft, MediaType.GIF).addListener(listener);
|
||||
break;
|
||||
case DcMsg.DC_MSG_AUDIO:
|
||||
setMedia(uri, MediaType.AUDIO).addListener(listener);
|
||||
setMedia(draft, MediaType.AUDIO).addListener(listener);
|
||||
break;
|
||||
case DcMsg.DC_MSG_VIDEO:
|
||||
setMedia(uri, MediaType.VIDEO).addListener(listener);
|
||||
break;
|
||||
case DcMsg.DC_MSG_WEBXDC:
|
||||
setMedia(draft, MediaType.DOCUMENT).addListener(listener);
|
||||
setMedia(draft, MediaType.VIDEO).addListener(listener);
|
||||
break;
|
||||
default:
|
||||
setMedia(uri, MediaType.DOCUMENT).addListener(listener);
|
||||
setMedia(draft, MediaType.DOCUMENT).addListener(listener);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -816,7 +840,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
sendButton = ViewUtil.findById(this, R.id.send_button);
|
||||
attachButton = ViewUtil.findById(this, R.id.attach_button);
|
||||
composeText = ViewUtil.findById(this, R.id.embedded_text_editor);
|
||||
emojiDrawerStub = ViewUtil.findStubById(this, R.id.emoji_drawer_stub);
|
||||
emojiPickerContainer = ViewUtil.findById(this, R.id.emoji_picker_container);
|
||||
composePanel = ViewUtil.findById(this, R.id.bottom_panel);
|
||||
container = ViewUtil.findById(this, R.id.layout_container);
|
||||
quickAttachmentToggle = ViewUtil.findById(this, R.id.quick_attachment_toggle);
|
||||
@@ -936,13 +960,10 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
case AttachmentTypeSelector.TAKE_PHOTO:
|
||||
attachmentManager.capturePhoto(this, TAKE_PHOTO); break;
|
||||
case AttachmentTypeSelector.RECORD_VIDEO:
|
||||
if(VideoRecoder.canRecode()) {
|
||||
attachmentManager.captureVideo(this, RECORD_VIDEO);
|
||||
}
|
||||
else {
|
||||
Toast.makeText(this, "This device does not support video-compression (requires Android 4.4 KitKat)", Toast.LENGTH_LONG).show();
|
||||
}
|
||||
attachmentManager.captureVideo(this, RECORD_VIDEO);
|
||||
break;
|
||||
case AttachmentTypeSelector.ADD_WEBXDC:
|
||||
AttachmentManager.selectWebxdc(this, PICK_WEBXDC); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -991,14 +1012,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
protected static final int ACTION_SEND_OUT = 1;
|
||||
protected static final int ACTION_SAVE_DRAFT = 2;
|
||||
|
||||
private String getSelfReaction(int msgId) {
|
||||
try {
|
||||
final String [] selfReactions = rpc.getMsgReactions(dcContext.getAccountId(), msgId).getReactionsByContact().get(DcContact.DC_CONTACT_ID_SELF);
|
||||
if (selfReactions != null && selfReactions.length > 0) return selfReactions[0];
|
||||
} catch(Exception e) { e.printStackTrace(); }
|
||||
return null;
|
||||
}
|
||||
|
||||
protected ListenableFuture<Integer> processComposeControls(int action) {
|
||||
return processComposeControls(action, composeText.getTextTrimmed(),
|
||||
attachmentManager.isAttachmentPresent() ?
|
||||
@@ -1009,9 +1022,8 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
|
||||
final SettableFuture<Integer> future = new SettableFuture<>();
|
||||
|
||||
DcMsg msg = null;
|
||||
Optional<QuoteModel> quote = inputPanel.getQuote();
|
||||
Integer recompress = 0;
|
||||
boolean editing = isEditing;
|
||||
|
||||
// for a quick ui feedback, we clear the related controls immediately on sending messages.
|
||||
// for drafts, however, we do not change the controls, the activity may be resumed.
|
||||
@@ -1020,106 +1032,114 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
inputPanel.clearQuote();
|
||||
}
|
||||
|
||||
if(slideDeck!=null) {
|
||||
Util.runOnAnyBackgroundThread(() -> {
|
||||
DcMsg msg = null;
|
||||
int recompress = 0;
|
||||
|
||||
if (action==ACTION_SEND_OUT) {
|
||||
attachmentManager.clear(glideRequests, false);
|
||||
if (editing) {
|
||||
int msgId = quote.get().getQuotedMsg().getId();
|
||||
if (action == ACTION_SEND_OUT) {
|
||||
dcContext.sendEditRequest(msgId, body);
|
||||
} else {
|
||||
dcContext.setDraft(chatId, null);
|
||||
}
|
||||
future.set(chatId);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
if (slideDeck.getWebxdctDraftId() != 0) {
|
||||
msg = dcContext.getDraft(chatId);
|
||||
} else {
|
||||
List<Attachment> attachments = slideDeck.asAttachments();
|
||||
for (Attachment attachment : attachments) {
|
||||
String contentType = attachment.getContentType();
|
||||
if (MediaUtil.isImageType(contentType) && slideDeck.getDocumentSlide() == null) {
|
||||
msg = new DcMsg(dcContext,
|
||||
MediaUtil.isGif(contentType) ? DcMsg.DC_MSG_GIF : DcMsg.DC_MSG_IMAGE);
|
||||
msg.setDimension(attachment.getWidth(), attachment.getHeight());
|
||||
} else if (MediaUtil.isAudioType(contentType)) {
|
||||
msg = new DcMsg(dcContext,
|
||||
attachment.isVoiceNote() ? DcMsg.DC_MSG_VOICE : DcMsg.DC_MSG_AUDIO);
|
||||
} else if (MediaUtil.isVideoType(contentType) && slideDeck.getDocumentSlide() == null) {
|
||||
msg = new DcMsg(dcContext, DcMsg.DC_MSG_VIDEO);
|
||||
recompress = DcMsg.DC_MSG_VIDEO;
|
||||
} else {
|
||||
msg = new DcMsg(dcContext, DcMsg.DC_MSG_FILE);
|
||||
if(slideDeck!=null) {
|
||||
if (action==ACTION_SEND_OUT) {
|
||||
Util.runOnMain(() -> attachmentManager.clear(glideRequests, false));
|
||||
}
|
||||
|
||||
try {
|
||||
if (slideDeck.getWebxdctDraftId() != 0) {
|
||||
msg = dcContext.getDraft(chatId);
|
||||
} else {
|
||||
List<Attachment> attachments = slideDeck.asAttachments();
|
||||
for (Attachment attachment : attachments) {
|
||||
String contentType = attachment.getContentType();
|
||||
if (MediaUtil.isImageType(contentType) && slideDeck.getDocumentSlide() == null) {
|
||||
msg = new DcMsg(dcContext,
|
||||
MediaUtil.isGif(contentType) ? DcMsg.DC_MSG_GIF : DcMsg.DC_MSG_IMAGE);
|
||||
msg.setDimension(attachment.getWidth(), attachment.getHeight());
|
||||
} else if (MediaUtil.isAudioType(contentType)) {
|
||||
msg = new DcMsg(dcContext,
|
||||
attachment.isVoiceNote() ? DcMsg.DC_MSG_VOICE : DcMsg.DC_MSG_AUDIO);
|
||||
} else if (MediaUtil.isVideoType(contentType) && slideDeck.getDocumentSlide() == null) {
|
||||
msg = new DcMsg(dcContext, DcMsg.DC_MSG_VIDEO);
|
||||
recompress = DcMsg.DC_MSG_VIDEO;
|
||||
} else {
|
||||
msg = new DcMsg(dcContext, DcMsg.DC_MSG_FILE);
|
||||
}
|
||||
String path = attachment.getRealPath(this);
|
||||
msg.setFileAndDeduplicate(path, attachment.getFileName(), null);
|
||||
}
|
||||
String path = attachment.getRealPath(this);
|
||||
msg.setFile(path, null);
|
||||
}
|
||||
if (msg != null) {
|
||||
msg.setText(body);
|
||||
}
|
||||
}
|
||||
msg.setText(body);
|
||||
catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
else if (action == ACTION_SEND_OUT && quote.isPresent() && EmojiProvider.getInstance(this).maybeEmoji(body)){
|
||||
int quotedMsg = quote.get().getQuotedMsg().getId();
|
||||
try {
|
||||
rpc.sendReaction(dcContext.getAccountId(), quotedMsg, body.equals(getSelfReaction(quotedMsg))? "" : body);
|
||||
future.set(chatId);
|
||||
return future;
|
||||
} catch (RpcException e) {
|
||||
e.printStackTrace();
|
||||
else if (!body.isEmpty()){
|
||||
msg = new DcMsg(dcContext, DcMsg.DC_MSG_TEXT);
|
||||
msg.setText(body);
|
||||
}
|
||||
}
|
||||
else if (!body.isEmpty()){
|
||||
msg = new DcMsg(dcContext, DcMsg.DC_MSG_TEXT);
|
||||
msg.setText(body);
|
||||
}
|
||||
|
||||
if (quote.isPresent()) {
|
||||
if (msg == null) msg = new DcMsg(dcContext, DcMsg.DC_MSG_TEXT);
|
||||
msg.setQuote(quote.get().getQuotedMsg());
|
||||
}
|
||||
if (quote.isPresent()) {
|
||||
if (msg == null) msg = new DcMsg(dcContext, DcMsg.DC_MSG_TEXT);
|
||||
msg.setQuote(quote.get().getQuotedMsg());
|
||||
}
|
||||
|
||||
// msg may still be null to clear drafts
|
||||
new AsyncTask<Object, Void, Void>() {
|
||||
@Override
|
||||
protected Void doInBackground(Object... param) {
|
||||
DcMsg msg = (DcMsg)param[0];
|
||||
Integer recompress = (Integer)param[1];
|
||||
if (action==ACTION_SEND_OUT) {
|
||||
if (action==ACTION_SEND_OUT) {
|
||||
|
||||
// for WEBXDC, drafts are just sent out as is.
|
||||
// for preparations and other cases, cleanup draft soon.
|
||||
if (msg == null || msg.getType() != DcMsg.DC_MSG_WEBXDC) {
|
||||
dcContext.setDraft(dcChat.getId(), null);
|
||||
}
|
||||
// for WEBXDC, drafts are just sent out as is.
|
||||
// for preparations and other cases, cleanup draft soon.
|
||||
if (msg == null || msg.getType() != DcMsg.DC_MSG_WEBXDC) {
|
||||
dcContext.setDraft(dcChat.getId(), null);
|
||||
}
|
||||
|
||||
if(msg!=null)
|
||||
{
|
||||
boolean doSend = true;
|
||||
if (recompress==DcMsg.DC_MSG_VIDEO) {
|
||||
doSend = VideoRecoder.prepareVideo(ConversationActivity.this, dcChat.getId(), msg);
|
||||
}
|
||||
|
||||
if (doSend) {
|
||||
if (dcContext.sendMsg(dcChat.getId(), msg) == 0) {
|
||||
Util.runOnMain(()-> Toast.makeText(ConversationActivity.this, dcContext.getLastError(), Toast.LENGTH_LONG).show());
|
||||
return null;
|
||||
if(msg!=null) {
|
||||
boolean doSend = true;
|
||||
if (recompress==DcMsg.DC_MSG_VIDEO) {
|
||||
Util.runOnMain(() -> {
|
||||
if (isFinishing()) return;
|
||||
progressDialog = ProgressDialog.show(
|
||||
ConversationActivity.this,
|
||||
"",
|
||||
getString(R.string.one_moment),
|
||||
true,
|
||||
false
|
||||
);
|
||||
});
|
||||
doSend = VideoRecoder.prepareVideo(ConversationActivity.this, dcChat.getId(), msg);
|
||||
Util.runOnMain(() -> {
|
||||
try {
|
||||
if (progressDialog != null) progressDialog.dismiss();
|
||||
} catch (final IllegalArgumentException e) {
|
||||
// The activity is finishing/destroyed, do nothing.
|
||||
}
|
||||
}
|
||||
|
||||
Util.runOnMain(()-> sendComplete(dcChat.getId()));
|
||||
});
|
||||
}
|
||||
}
|
||||
else {
|
||||
dcContext.setDraft(dcChat.getId(), msg);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Void result) {
|
||||
future.set(chatId);
|
||||
if (doSend) {
|
||||
if (dcContext.sendMsg(dcChat.getId(), msg) == 0) {
|
||||
Util.runOnMain(()-> Toast.makeText(ConversationActivity.this, dcContext.getLastError(), Toast.LENGTH_LONG).show());
|
||||
future.set(chatId);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Util.runOnMain(() -> sendComplete(dcChat.getId()));
|
||||
}
|
||||
} else {
|
||||
dcContext.setDraft(dcChat.getId(), msg);
|
||||
}
|
||||
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, msg, recompress);
|
||||
future.set(chatId);
|
||||
});
|
||||
|
||||
return future;
|
||||
}
|
||||
@@ -1154,7 +1174,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
return;
|
||||
}
|
||||
|
||||
if (composeText.getText().length() == 0 && !attachmentManager.isAttachmentPresent()) {
|
||||
if (!isEditing && composeText.getText().length() == 0 && !attachmentManager.isAttachmentPresent()) {
|
||||
buttonToggle.display(attachButton);
|
||||
quickAttachmentToggle.show();
|
||||
} else {
|
||||
@@ -1252,23 +1272,36 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
});
|
||||
}
|
||||
|
||||
private void reloadEmojiPicker() {
|
||||
emojiPickerContainer.removeAllViews();
|
||||
emojiPicker = (MediaKeyboard) LayoutInflater.from(this).inflate(R.layout.conversation_activity_emojidrawer_stub, emojiPickerContainer, false);
|
||||
emojiPickerContainer.addView(emojiPicker);
|
||||
inputPanel.setMediaKeyboard(emojiPicker);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEmojiToggle() {
|
||||
if (!emojiDrawerStub.resolved()) {
|
||||
initializeMediaKeyboardProviders(emojiDrawerStub.get(), false);
|
||||
inputPanel.setMediaKeyboard(emojiDrawerStub.get());
|
||||
if (emojiPicker == null) {
|
||||
reloadEmojiPicker();
|
||||
}
|
||||
|
||||
if (container.getCurrentInput() == emojiDrawerStub.get()) {
|
||||
if (container.getCurrentInput() == emojiPicker) {
|
||||
container.showSoftkey(composeText);
|
||||
} else {
|
||||
container.show(composeText, emojiDrawerStub.get());
|
||||
container.show(composeText, emojiPicker);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onQuoteDismissed() {
|
||||
if (isEditing) composeText.setText("");
|
||||
isEditing = false;
|
||||
}
|
||||
|
||||
// media selected by the system keyboard
|
||||
@Override
|
||||
public void onMediaSelected(@NonNull Uri uri, String contentType) {
|
||||
if (isEditing) return;
|
||||
if (MediaUtil.isImageType(contentType)) {
|
||||
sendSticker(uri, contentType);
|
||||
} else if (MediaUtil.isVideoType(contentType)) {
|
||||
@@ -1290,17 +1323,11 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
if (quote.isPresent()) {
|
||||
msg.setQuote(quote.get().getQuotedMsg());
|
||||
}
|
||||
msg.setFile(path, null);
|
||||
msg.setFileAndDeduplicate(path, null, null);
|
||||
msg.forceSticker();
|
||||
dcContext.sendMsg(chatId, msg);
|
||||
}
|
||||
|
||||
private void initializeMediaKeyboardProviders(@NonNull MediaKeyboard mediaKeyboard, boolean stickersAvailable) {
|
||||
boolean isSystemEmojiPreferred = Prefs.isSystemEmojiPreferred(this);
|
||||
if (!isSystemEmojiPreferred) {
|
||||
mediaKeyboard.setProviders(0, new EmojiKeyboardProvider(this, inputPanel));
|
||||
}
|
||||
}
|
||||
|
||||
// Listeners
|
||||
|
||||
private class AttachmentTypeListener implements AttachmentTypeSelector.AttachmentClickedListener {
|
||||
@@ -1332,8 +1359,12 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
else {
|
||||
processComposeControls(ACTION_SEND_OUT);
|
||||
DcHelper.getNotificationCenter(ConversationActivity.this).maybePlaySendSound(dcChat);
|
||||
processComposeControls(ACTION_SEND_OUT).addListener(new AssertedSuccessListener<Integer>() {
|
||||
@Override
|
||||
public void onSuccess(Integer chatId) {
|
||||
DcHelper.getNotificationCenter(ConversationActivity.this).maybePlaySendSound(dcChat);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1406,6 +1437,8 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
|
||||
@Override
|
||||
public void handleReplyMessage(DcMsg msg) {
|
||||
if (isEditing) composeText.setText("");
|
||||
isEditing = false;
|
||||
// If you modify these lines you may also want to modify ConversationItem.setQuote():
|
||||
Recipient author = new Recipient(this, dcContext.getContact(msg.getFromId()));
|
||||
|
||||
@@ -1421,11 +1454,32 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
msg.getTimestamp(),
|
||||
author,
|
||||
text,
|
||||
slideDeck);
|
||||
slideDeck,
|
||||
false);
|
||||
|
||||
inputPanel.clickOnComposeInput();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleEditMessage(DcMsg msg) {
|
||||
isEditing = true;
|
||||
Recipient author = new Recipient(this, dcContext.getContact(msg.getFromId()));
|
||||
|
||||
SlideDeck slideDeck = new SlideDeck();
|
||||
String text = msg.getSummarytext(500);
|
||||
|
||||
inputPanel.setQuote(GlideApp.with(this),
|
||||
msg,
|
||||
msg.getTimestamp(),
|
||||
author,
|
||||
text,
|
||||
slideDeck,
|
||||
true);
|
||||
|
||||
setDraftText(msg.getText());
|
||||
inputPanel.clickOnComposeInput();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttachmentChanged() {
|
||||
handleSecurityChange(isSecureText, isDefaultSms);
|
||||
|
||||
@@ -16,17 +16,19 @@
|
||||
*/
|
||||
package org.thoughtcrime.securesms;
|
||||
|
||||
import android.content.Context;
|
||||
import androidx.annotation.LayoutRes;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import static org.thoughtcrime.securesms.ConversationItem.PULSE_HIGHLIGHT_MILLIS;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.LayoutRes;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.b44t.messenger.DcChat;
|
||||
import com.b44t.messenger.DcContext;
|
||||
import com.b44t.messenger.DcMsg;
|
||||
@@ -49,8 +51,6 @@ import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.thoughtcrime.securesms.ConversationItem.PULSE_HIGHLIGHT_MILLIS;
|
||||
|
||||
/**
|
||||
* A DC adapter for a conversation thread. Ultimately
|
||||
* used by ConversationActivity to display a conversation
|
||||
@@ -294,7 +294,7 @@ public class ConversationAdapter <V extends View & BindableConversationItem>
|
||||
else if (type==DcMsg.DC_MSG_AUDIO || type==DcMsg.DC_MSG_VOICE) {
|
||||
return dcMsg.isOutgoing()? MESSAGE_TYPE_AUDIO_OUTGOING : MESSAGE_TYPE_AUDIO_INCOMING;
|
||||
}
|
||||
else if (type==DcMsg.DC_MSG_FILE && !dcMsg.isSetupMessage()) {
|
||||
else if (type==DcMsg.DC_MSG_FILE) {
|
||||
return dcMsg.isOutgoing()? MESSAGE_TYPE_DOCUMENT_OUTGOING : MESSAGE_TYPE_DOCUMENT_INCOMING;
|
||||
}
|
||||
else if (type==DcMsg.DC_MSG_IMAGE || type==DcMsg.DC_MSG_GIF || type==DcMsg.DC_MSG_VIDEO) {
|
||||
|
||||
@@ -24,10 +24,8 @@ import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
@@ -38,12 +36,10 @@ import android.view.ViewGroup;
|
||||
import android.view.Window;
|
||||
import android.view.animation.Animation;
|
||||
import android.view.animation.AnimationUtils;
|
||||
import android.widget.EditText;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.view.ActionMode;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
@@ -63,8 +59,8 @@ import org.thoughtcrime.securesms.connect.DcHelper;
|
||||
import org.thoughtcrime.securesms.database.Address;
|
||||
import org.thoughtcrime.securesms.mms.GlideApp;
|
||||
import org.thoughtcrime.securesms.reactions.AddReactionView;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.reactions.ReactionsDetailsFragment;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.util.AccessibilityUtil;
|
||||
import org.thoughtcrime.securesms.util.Debouncer;
|
||||
import org.thoughtcrime.securesms.util.StickyHeaderDecoration;
|
||||
@@ -211,7 +207,7 @@ public class ConversationFragment extends MessageSelectorFragment
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
|
||||
dcContext.marknoticedChat((int) chatId);
|
||||
Util.runOnBackground(() -> dcContext.marknoticedChat((int) chatId));
|
||||
if (list.getAdapter() != null) {
|
||||
list.getAdapter().notifyDataSetChanged();
|
||||
}
|
||||
@@ -321,12 +317,16 @@ public class ConversationFragment extends MessageSelectorFragment
|
||||
return;
|
||||
}
|
||||
|
||||
menu.findItem(R.id.menu_toggle_save).setVisible(false);
|
||||
|
||||
if (messageRecords.size() > 1) {
|
||||
menu.findItem(R.id.menu_context_details).setVisible(false);
|
||||
menu.findItem(R.id.menu_context_share).setVisible(false);
|
||||
menu.findItem(R.id.menu_context_reply).setVisible(false);
|
||||
menu.findItem(R.id.menu_context_edit).setVisible(false);
|
||||
menu.findItem(R.id.menu_context_reply_privately).setVisible(false);
|
||||
menu.findItem(R.id.menu_add_to_home_screen).setVisible(false);
|
||||
//menu.findItem(R.id.menu_toggle_save).setVisible(false);
|
||||
} else {
|
||||
DcMsg messageRecord = messageRecords.iterator().next();
|
||||
DcChat chat = getListAdapter().getChat();
|
||||
@@ -334,9 +334,19 @@ public class ConversationFragment extends MessageSelectorFragment
|
||||
menu.findItem(R.id.menu_context_share).setVisible(messageRecord.hasFile());
|
||||
boolean canReply = canReplyToMsg(messageRecord);
|
||||
menu.findItem(R.id.menu_context_reply).setVisible(chat.canSend() && canReply);
|
||||
boolean showReplyPrivately = !dcContext.isCommunity() && chat.isMultiUser() && !messageRecord.isOutgoing() && canReply;
|
||||
boolean canEdit = canEditMsg(messageRecord);
|
||||
menu.findItem(R.id.menu_context_edit).setVisible(chat.canSend() && canEdit);
|
||||
boolean showReplyPrivately = chat.isMultiUser() && !messageRecord.isOutgoing() && canReply;
|
||||
menu.findItem(R.id.menu_context_reply_privately).setVisible(showReplyPrivately);
|
||||
menu.findItem(R.id.menu_add_to_home_screen).setVisible(messageRecord.getType() == DcMsg.DC_MSG_WEBXDC);
|
||||
|
||||
/*
|
||||
boolean saved = messageRecord.getSavedMsgId() != 0;
|
||||
MenuItem toggleSave = menu.findItem(R.id.menu_toggle_save);
|
||||
toggleSave.setVisible(messageRecord.canSave() && !chat.isSelfTalk());
|
||||
toggleSave.setIcon(saved? R.drawable.baseline_bookmark_remove_24 : R.drawable.baseline_bookmark_border_24);
|
||||
toggleSave.setTitle(saved? R.string.unsave : R.string.save);
|
||||
*/
|
||||
}
|
||||
|
||||
// if one of the selected items cannot be saved, disable saving.
|
||||
@@ -377,6 +387,10 @@ public class ConversationFragment extends MessageSelectorFragment
|
||||
return canReply;
|
||||
}
|
||||
|
||||
static boolean canEditMsg(DcMsg dcMsg) {
|
||||
return dcMsg.isOutgoing() && !dcMsg.isInfo() && dcMsg.getType() != DcMsg.DC_MSG_VIDEOCHAT_INVITATION && !dcMsg.hasHtml() && !dcMsg.getText().isEmpty();
|
||||
}
|
||||
|
||||
public void handleClearChat() {
|
||||
handleDeleteMessages((int) chatId, getListAdapter().getMessageIds());
|
||||
}
|
||||
@@ -442,7 +456,7 @@ public class ConversationFragment extends MessageSelectorFragment
|
||||
|
||||
if (msg.getFromId() != prevMsg.getFromId() && !singleMsg) {
|
||||
DcContact contact = dcContext.getContact(msg.getFromId());
|
||||
result.append(msg.getSenderName(contact, false)).append(":\n");
|
||||
result.append(msg.getSenderName(contact)).append(":\n");
|
||||
}
|
||||
if (msg.getType() == DcMsg.DC_MSG_TEXT || (singleMsg && !msg.getText().isEmpty())) {
|
||||
result.append(msg.getText());
|
||||
@@ -477,6 +491,16 @@ public class ConversationFragment extends MessageSelectorFragment
|
||||
listener.handleReplyMessage(message);
|
||||
}
|
||||
|
||||
@SuppressLint("RestrictedApi")
|
||||
private void handleEditMessage(final DcMsg message) {
|
||||
if (getActivity() != null) {
|
||||
//noinspection ConstantConditions
|
||||
((AppCompatActivity) getActivity()).getSupportActionBar().collapseActionView();
|
||||
}
|
||||
|
||||
listener.handleEditMessage(message);
|
||||
}
|
||||
|
||||
private void handleReplyMessagePrivately(final DcMsg msg) {
|
||||
|
||||
if (getActivity() != null) {
|
||||
@@ -494,6 +518,15 @@ public class ConversationFragment extends MessageSelectorFragment
|
||||
}
|
||||
}
|
||||
|
||||
private void handleToggleSave(final Set<DcMsg> messageRecords) {
|
||||
DcMsg msg = getSelectedMessageRecord(messageRecords);
|
||||
if (msg.getSavedMsgId() != 0) {
|
||||
dcContext.deleteMsgs(new int[]{msg.getSavedMsgId()});
|
||||
} else {
|
||||
dcContext.saveMsgs(new int[]{msg.getId()});
|
||||
}
|
||||
}
|
||||
|
||||
private void reloadList() {
|
||||
reloadList(false);
|
||||
}
|
||||
@@ -607,6 +640,7 @@ public class ConversationFragment extends MessageSelectorFragment
|
||||
|
||||
public interface ConversationFragmentListener {
|
||||
void handleReplyMessage(DcMsg messageRecord);
|
||||
void handleEditMessage(DcMsg messageRecord);
|
||||
}
|
||||
|
||||
private class ConversationScrollListener extends OnScrollListener {
|
||||
@@ -704,81 +738,7 @@ public class ConversationFragment extends MessageSelectorFragment
|
||||
index++;
|
||||
}
|
||||
}
|
||||
dcContext.markseenMsgs(ids);
|
||||
}
|
||||
|
||||
|
||||
void querySetupCode(final DcMsg dcMsg, String[] preload)
|
||||
{
|
||||
if( !dcMsg.isSetupMessage()) {
|
||||
return;
|
||||
}
|
||||
|
||||
View gl = View.inflate(getActivity(), R.layout.setup_code_grid, null);
|
||||
final EditText[] editTexts = {
|
||||
gl.findViewById(R.id.setupCode0), gl.findViewById(R.id.setupCode1), gl.findViewById(R.id.setupCode2),
|
||||
gl.findViewById(R.id.setupCode3), gl.findViewById(R.id.setupCode4), gl.findViewById(R.id.setupCode5),
|
||||
gl.findViewById(R.id.setupCode6), gl.findViewById(R.id.setupCode7), gl.findViewById(R.id.setupCode8)
|
||||
};
|
||||
AlertDialog.Builder builder1 = new AlertDialog.Builder(getActivity());
|
||||
builder1.setView(gl);
|
||||
editTexts[0].setText(dcMsg.getSetupCodeBegin());
|
||||
editTexts[0].setSelection(editTexts[0].getText().length());
|
||||
|
||||
for( int i = 0; i < 9; i++ ) {
|
||||
if( preload != null && i < preload.length ) {
|
||||
editTexts[i].setText(preload[i]);
|
||||
editTexts[i].setSelection(editTexts[i].getText().length());
|
||||
}
|
||||
editTexts[i].addTextChangedListener(new TextWatcher() {
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
if( s.length()==4 ) {
|
||||
for ( int i = 0; i < 8; i++ ) {
|
||||
if( editTexts[i].hasFocus() && editTexts[i+1].getText().length()<4 ) {
|
||||
editTexts[i+1].requestFocus();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(Editable s) {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
builder1.setTitle(getActivity().getString(R.string.autocrypt_continue_transfer_title));
|
||||
builder1.setMessage(getActivity().getString(R.string.autocrypt_continue_transfer_please_enter_code));
|
||||
builder1.setNegativeButton(android.R.string.cancel, null);
|
||||
builder1.setCancelable(false); // prevent the dialog from being dismissed accidentally (when the dialog is closed, the setup code is gone forever and the user has to create a new setup message)
|
||||
builder1.setPositiveButton(android.R.string.ok, (dialog, which) -> {
|
||||
String setup_code = "";
|
||||
final String[] preload1 = new String[9];
|
||||
for ( int i = 0; i < 9; i++ ) {
|
||||
preload1[i] = editTexts[i].getText().toString();
|
||||
setup_code += preload1[i];
|
||||
}
|
||||
boolean success = dcContext.continueKeyTransfer(dcMsg.getId(), setup_code);
|
||||
|
||||
AlertDialog.Builder builder2 = new AlertDialog.Builder(getActivity());
|
||||
builder2.setTitle(getActivity().getString(R.string.autocrypt_continue_transfer_title));
|
||||
builder2.setMessage(getActivity().getString(success? R.string.autocrypt_continue_transfer_succeeded : R.string.autocrypt_bad_setup_code));
|
||||
if( success ) {
|
||||
builder2.setPositiveButton(android.R.string.ok, null);
|
||||
}
|
||||
else {
|
||||
builder2.setNegativeButton(android.R.string.cancel, null);
|
||||
builder2.setPositiveButton(R.string.autocrypt_continue_transfer_retry, (dialog1, which1) -> querySetupCode(dcMsg, preload1));
|
||||
}
|
||||
builder2.show();
|
||||
});
|
||||
builder1.show();
|
||||
Util.runOnAnyBackgroundThread(() -> dcContext.markseenMsgs(ids));
|
||||
}
|
||||
|
||||
private class ConversationFragmentItemClickListener implements ItemClickListener {
|
||||
@@ -800,9 +760,6 @@ public class ConversationFragment extends MessageSelectorFragment
|
||||
actionMode.setTitleOptionalHint(false); // the title represents important information, also indicating implicitly, more items can be selected
|
||||
}
|
||||
}
|
||||
else if(messageRecord.isSetupMessage()) {
|
||||
querySetupCode(messageRecord,null);
|
||||
}
|
||||
else if (messageRecord.getType()==DcMsg.DC_MSG_VIDEOCHAT_INVITATION) {
|
||||
new VideochatUtil().join(getActivity(), messageRecord.getId());
|
||||
}
|
||||
@@ -810,15 +767,29 @@ public class ConversationFragment extends MessageSelectorFragment
|
||||
DozeReminder.dozeReminderTapped(getContext());
|
||||
}
|
||||
else if(messageRecord.getInfoType() == DcMsg.DC_INFO_WEBXDC_INFO_MESSAGE) {
|
||||
scrollMaybeSmoothToMsgId(messageRecord.getParent().getId());
|
||||
if (messageRecord.getParent() != null) {
|
||||
// if the parent webxdc message still exists
|
||||
WebxdcActivity.openWebxdcActivity(getContext(), messageRecord.getParent(), messageRecord.getWebxdcHref());
|
||||
}
|
||||
}
|
||||
else if (!TextUtils.isEmpty(messageRecord.getPOILocation()) && messageRecord.getType() == DcMsg.DC_MSG_TEXT && !messageRecord.hasHtml()) {
|
||||
WebxdcActivity.openMaps(getContext(), getListAdapter().getChat().getId(), "index.html#"+messageRecord.getPOILocation());
|
||||
}
|
||||
else {
|
||||
String self_mail = dcContext.getConfig("configured_mail_user");
|
||||
if (self_mail != null && !self_mail.isEmpty()
|
||||
&& messageRecord.getText().contains(self_mail)
|
||||
&& getListAdapter().getChat().isDeviceTalk()) {
|
||||
// This is a device message informing the user that the password is wrong
|
||||
startActivity(new Intent(getActivity(), RegistrationActivity.class));
|
||||
int infoContactId = messageRecord.getInfoContactId();
|
||||
if (infoContactId != 0 && infoContactId != DC_CONTACT_ID_SELF) {
|
||||
Intent intent = new Intent(getContext(), ProfileActivity.class);
|
||||
intent.putExtra(ProfileActivity.CONTACT_ID_EXTRA, infoContactId);
|
||||
startActivity(intent);
|
||||
}
|
||||
else {
|
||||
String self_mail = dcContext.getConfig("configured_mail_user");
|
||||
if (self_mail != null && !self_mail.isEmpty()
|
||||
&& messageRecord.getText().contains(self_mail)
|
||||
&& getListAdapter().getChat().isDeviceTalk()) {
|
||||
// This is a device message informing the user that the password is wrong
|
||||
startActivity(new Intent(getActivity(), RegistrationActivity.class));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -830,9 +801,6 @@ public class ConversationFragment extends MessageSelectorFragment
|
||||
list.getAdapter().notifyDataSetChanged();
|
||||
|
||||
actionMode = ((AppCompatActivity)getActivity()).startSupportActionMode(actionModeCallback);
|
||||
|
||||
if (dcContext.isCommunity()) return;
|
||||
|
||||
addReactionView.show(messageRecord, view, () -> {
|
||||
if (actionMode != null) {
|
||||
actionMode.finish();
|
||||
@@ -841,20 +809,18 @@ public class ConversationFragment extends MessageSelectorFragment
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onQuoteClicked(DcMsg messageRecord) {
|
||||
DcMsg quoted = messageRecord.getQuotedMsg();
|
||||
if (quoted == null) {
|
||||
Log.i(TAG, "Clicked on a quote whose original message we never had.");
|
||||
private void jumpToOriginal(DcMsg original) {
|
||||
if (original == null) {
|
||||
Log.i(TAG, "Clicked on a quote or jump-to-original whose original message was deleted/non-existing.");
|
||||
Toast.makeText(getContext(), R.string.ConversationFragment_quoted_message_not_found, Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
|
||||
int foreignChatId = quoted.getChatId();
|
||||
int foreignChatId = original.getChatId();
|
||||
if (foreignChatId != 0 && foreignChatId != chatId) {
|
||||
Intent intent = new Intent(getActivity(), ConversationActivity.class);
|
||||
intent.putExtra(ConversationActivity.CHAT_ID_EXTRA, foreignChatId);
|
||||
int start = DcMsg.getMessagePosition(quoted, dcContext);
|
||||
int start = DcMsg.getMessagePosition(original, dcContext);
|
||||
intent.putExtra(ConversationActivity.STARTING_POSITION_EXTRA, start);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
((ConversationActivity) getActivity()).hideSoftKeyboard();
|
||||
@@ -864,10 +830,20 @@ public class ConversationFragment extends MessageSelectorFragment
|
||||
Log.e(TAG, "Activity was null");
|
||||
}
|
||||
} else {
|
||||
scrollMaybeSmoothToMsgId(quoted.getId());
|
||||
scrollMaybeSmoothToMsgId(original.getId());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onJumpToOriginalClicked(DcMsg messageRecord) {
|
||||
jumpToOriginal(dcContext.getMsg(messageRecord.getOriginalMsgId()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onQuoteClicked(DcMsg messageRecord) {
|
||||
jumpToOriginal(messageRecord.getQuotedMsg());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onShowFullClicked(DcMsg messageRecord) {
|
||||
Intent intent = new Intent(getActivity(), FullMsgActivity.class);
|
||||
@@ -911,12 +887,11 @@ public class ConversationFragment extends MessageSelectorFragment
|
||||
|
||||
mode.setTitle("1");
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
Window window = getActivity().getWindow();
|
||||
statusBarColor = window.getStatusBarColor();
|
||||
window.setStatusBarColor(getResources().getColor(R.color.action_mode_status_bar));
|
||||
}
|
||||
Window window = getActivity().getWindow();
|
||||
statusBarColor = window.getStatusBarColor();
|
||||
window.setStatusBarColor(getResources().getColor(R.color.action_mode_status_bar));
|
||||
|
||||
Util.redMenuItem(menu, R.id.menu_context_delete_message);
|
||||
setCorrectMenuVisibility(menu);
|
||||
ConversationAdaptiveActionsToolbar.adjustMenuActions(menu, 10, requireActivity().getWindow().getDecorView().getMeasuredWidth());
|
||||
return true;
|
||||
@@ -932,9 +907,7 @@ public class ConversationFragment extends MessageSelectorFragment
|
||||
((ConversationAdapter)list.getAdapter()).clearSelection();
|
||||
list.getAdapter().notifyDataSetChanged();
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
getActivity().getWindow().setStatusBarColor(statusBarColor);
|
||||
}
|
||||
getActivity().getWindow().setStatusBarColor(statusBarColor);
|
||||
|
||||
actionMode = null;
|
||||
hideAddReactionView();
|
||||
@@ -943,45 +916,52 @@ public class ConversationFragment extends MessageSelectorFragment
|
||||
@Override
|
||||
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
|
||||
hideAddReactionView();
|
||||
switch(item.getItemId()) {
|
||||
case R.id.menu_context_copy:
|
||||
handleCopyMessage(getListAdapter().getSelectedItems());
|
||||
actionMode.finish();
|
||||
return true;
|
||||
case R.id.menu_context_delete_message:
|
||||
handleDeleteMessages((int) chatId, getListAdapter().getSelectedItems());
|
||||
return true;
|
||||
case R.id.menu_context_share:
|
||||
DcHelper.openForViewOrShare(getContext(), getSelectedMessageRecord(getListAdapter().getSelectedItems()).getId(), Intent.ACTION_SEND);
|
||||
return true;
|
||||
case R.id.menu_context_details:
|
||||
handleDisplayDetails(getSelectedMessageRecord(getListAdapter().getSelectedItems()));
|
||||
actionMode.finish();
|
||||
return true;
|
||||
case R.id.menu_context_forward:
|
||||
handleForwardMessage(getListAdapter().getSelectedItems());
|
||||
actionMode.finish();
|
||||
return true;
|
||||
case R.id.menu_add_to_home_screen:
|
||||
WebxdcActivity.addToHomeScreen(getActivity(), getSelectedMessageRecord(getListAdapter().getSelectedItems()).getId());
|
||||
actionMode.finish();
|
||||
return true;
|
||||
case R.id.menu_context_save_attachment:
|
||||
handleSaveAttachment(getListAdapter().getSelectedItems());
|
||||
return true;
|
||||
case R.id.menu_context_reply:
|
||||
handleReplyMessage(getSelectedMessageRecord(getListAdapter().getSelectedItems()));
|
||||
actionMode.finish();
|
||||
return true;
|
||||
case R.id.menu_context_reply_privately:
|
||||
handleReplyMessagePrivately(getSelectedMessageRecord(getListAdapter().getSelectedItems()));
|
||||
return true;
|
||||
case R.id.menu_resend:
|
||||
handleResendMessage(getListAdapter().getSelectedItems());
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
int itemId = item.getItemId();
|
||||
if (itemId == R.id.menu_context_copy) {
|
||||
handleCopyMessage(getListAdapter().getSelectedItems());
|
||||
actionMode.finish();
|
||||
return true;
|
||||
} else if (itemId == R.id.menu_context_delete_message) {
|
||||
handleDeleteMessages((int) chatId, getListAdapter().getSelectedItems());
|
||||
return true;
|
||||
} else if (itemId == R.id.menu_context_share) {
|
||||
DcHelper.openForViewOrShare(getContext(), getSelectedMessageRecord(getListAdapter().getSelectedItems()).getId(), Intent.ACTION_SEND);
|
||||
return true;
|
||||
} else if (itemId == R.id.menu_context_details) {
|
||||
handleDisplayDetails(getSelectedMessageRecord(getListAdapter().getSelectedItems()));
|
||||
actionMode.finish();
|
||||
return true;
|
||||
} else if (itemId == R.id.menu_context_forward) {
|
||||
handleForwardMessage(getListAdapter().getSelectedItems());
|
||||
actionMode.finish();
|
||||
return true;
|
||||
} else if (itemId == R.id.menu_add_to_home_screen) {
|
||||
WebxdcActivity.addToHomeScreen(getActivity(), getSelectedMessageRecord(getListAdapter().getSelectedItems()).getId());
|
||||
actionMode.finish();
|
||||
return true;
|
||||
} else if (itemId == R.id.menu_context_save_attachment) {
|
||||
handleSaveAttachment(getListAdapter().getSelectedItems());
|
||||
return true;
|
||||
} else if (itemId == R.id.menu_context_reply) {
|
||||
handleReplyMessage(getSelectedMessageRecord(getListAdapter().getSelectedItems()));
|
||||
actionMode.finish();
|
||||
return true;
|
||||
} else if (itemId == R.id.menu_context_edit) {
|
||||
handleEditMessage(getSelectedMessageRecord(getListAdapter().getSelectedItems()));
|
||||
actionMode.finish();
|
||||
return true;
|
||||
} else if (itemId == R.id.menu_context_reply_privately) {
|
||||
handleReplyMessagePrivately(getSelectedMessageRecord(getListAdapter().getSelectedItems()));
|
||||
return true;
|
||||
} else if (itemId == R.id.menu_resend) {
|
||||
handleResendMessage(getListAdapter().getSelectedItems());
|
||||
return true;
|
||||
} else if (itemId == R.id.menu_toggle_save) {
|
||||
handleToggleSave(getListAdapter().getSelectedItems());
|
||||
actionMode.finish();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,12 +22,10 @@ import android.content.res.TypedArray;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Build;
|
||||
import android.text.Spannable;
|
||||
import android.text.TextUtils;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.util.TypedValue;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
@@ -56,7 +54,6 @@ import org.thoughtcrime.securesms.components.DocumentView;
|
||||
import org.thoughtcrime.securesms.components.QuoteView;
|
||||
import org.thoughtcrime.securesms.components.VcardView;
|
||||
import org.thoughtcrime.securesms.components.WebxdcView;
|
||||
import org.thoughtcrime.securesms.components.emoji.EmojiTextView;
|
||||
import org.thoughtcrime.securesms.connect.DcHelper;
|
||||
import org.thoughtcrime.securesms.mms.AudioSlide;
|
||||
import org.thoughtcrime.securesms.mms.DocumentSlide;
|
||||
@@ -69,10 +66,10 @@ import org.thoughtcrime.securesms.mms.StickerSlide;
|
||||
import org.thoughtcrime.securesms.mms.VcardSlide;
|
||||
import org.thoughtcrime.securesms.reactions.ReactionsConversationView;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.util.Linkifier;
|
||||
import org.thoughtcrime.securesms.util.LongClickMovementMethod;
|
||||
import org.thoughtcrime.securesms.util.MarkdownUtil;
|
||||
import org.thoughtcrime.securesms.util.MediaUtil;
|
||||
import org.thoughtcrime.securesms.util.Prefs;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||
import org.thoughtcrime.securesms.util.views.Stub;
|
||||
@@ -104,6 +101,7 @@ public class ConversationItem extends BaseConversationItem
|
||||
protected ViewGroup bodyBubble;
|
||||
protected ReactionsConversationView reactionsView;
|
||||
protected View replyView;
|
||||
protected View jumptoView;
|
||||
@Nullable private QuoteView quoteView;
|
||||
private ConversationItemFooter footer;
|
||||
private TextView groupSender;
|
||||
@@ -112,6 +110,7 @@ public class ConversationItem extends BaseConversationItem
|
||||
protected ViewGroup contactPhotoHolder;
|
||||
private ViewGroup container;
|
||||
private Button msgActionButton;
|
||||
private Button showFullButton;
|
||||
|
||||
private @NonNull Stub<ConversationItemThumbnail> mediaThumbnailStub;
|
||||
private @NonNull Stub<AudioView> audioViewStub;
|
||||
@@ -157,7 +156,9 @@ public class ConversationItem extends BaseConversationItem
|
||||
this.quoteView = findViewById(R.id.quote_view);
|
||||
this.container = findViewById(R.id.container);
|
||||
this.replyView = findViewById(R.id.reply_icon);
|
||||
this.jumptoView = findViewById(R.id.jumpto_icon);
|
||||
this.msgActionButton = findViewById(R.id.msg_action_button);
|
||||
this.showFullButton = findViewById(R.id.show_full_button);
|
||||
|
||||
setOnClickListener(new ClickListener(null));
|
||||
|
||||
@@ -177,12 +178,23 @@ public class ConversationItem extends BaseConversationItem
|
||||
{
|
||||
bind(messageRecord, dcChat, batchSelected, pulseHighlight, recipients);
|
||||
this.glideRequests = glideRequests;
|
||||
this.showSender = dcContext.isCommunity() || (dcChat.isMultiUser() && !messageRecord.isOutgoing()) || messageRecord.getOverrideSenderName() != null;
|
||||
this.showSender = ((dcChat.isMultiUser() || dcChat.isSelfTalk()) && !messageRecord.isOutgoing()) || messageRecord.getOverrideSenderName() != null;
|
||||
|
||||
if (showSender) {
|
||||
this.dcContact = dcContext.getContact(messageRecord.getFromId());
|
||||
}
|
||||
|
||||
if (dcChat.isSelfTalk() && messageRecord.getOriginalMsgId() != 0) {
|
||||
jumptoView.setVisibility(View.VISIBLE);
|
||||
jumptoView.setOnClickListener(view -> {
|
||||
if (eventListener != null) {
|
||||
eventListener.onJumpToOriginalClicked(messageRecord);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
jumptoView.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
setGutterSizes(messageRecord, showSender);
|
||||
setMessageShape(messageRecord);
|
||||
setMediaAttributes(messageRecord, showSender);
|
||||
@@ -258,11 +270,10 @@ public class ConversationItem extends BaseConversationItem
|
||||
R.attr.conversation_item_incoming_bubble_color,
|
||||
R.attr.conversation_item_outgoing_bubble_color,
|
||||
};
|
||||
final TypedArray attrs = context.obtainStyledAttributes(attributes);
|
||||
|
||||
incomingBubbleColor = attrs.getColor(0, Color.WHITE);
|
||||
outgoingBubbleColor = attrs.getColor(1, Color.WHITE);
|
||||
attrs.recycle();
|
||||
try (TypedArray attrs = context.obtainStyledAttributes(attributes)) {
|
||||
incomingBubbleColor = attrs.getColor(0, Color.WHITE);
|
||||
outgoingBubbleColor = attrs.getColor(1, Color.WHITE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -379,27 +390,22 @@ public class ConversationItem extends BaseConversationItem
|
||||
}
|
||||
|
||||
private boolean hasDocument(DcMsg dcMsg) {
|
||||
return dcMsg.getType()==DcMsg.DC_MSG_FILE && !dcMsg.isSetupMessage();
|
||||
return dcMsg.getType()==DcMsg.DC_MSG_FILE;
|
||||
}
|
||||
|
||||
private void setBodyText(DcMsg messageRecord) {
|
||||
bodyText.setClickable(false);
|
||||
bodyText.setFocusable(false);
|
||||
bodyText.setTextSize(TypedValue.COMPLEX_UNIT_SP, Prefs.getMessageBodyTextSize(context));
|
||||
|
||||
String text = messageRecord.getText();
|
||||
|
||||
if (messageRecord.isSetupMessage()) {
|
||||
bodyText.setText(context.getString(R.string.autocrypt_asm_click_body));
|
||||
bodyText.setVisibility(View.VISIBLE);
|
||||
}
|
||||
else if (text.isEmpty()) {
|
||||
if (text.isEmpty()) {
|
||||
bodyText.setVisibility(View.GONE);
|
||||
}
|
||||
else {
|
||||
Spannable spannable = (Spannable) MarkdownUtil.toMarkdown(context, text);
|
||||
if (batchSelected.isEmpty()) {
|
||||
spannable = EmojiTextView.linkify(spannable);
|
||||
spannable = Linkifier.linkify(spannable);
|
||||
}
|
||||
bodyText.setText(spannable);
|
||||
bodyText.setVisibility(View.VISIBLE);
|
||||
@@ -407,6 +413,7 @@ public class ConversationItem extends BaseConversationItem
|
||||
|
||||
int downloadState = messageRecord.getDownloadState();
|
||||
if (downloadState == DcMsg.DC_DOWNLOAD_AVAILABLE || downloadState == DcMsg.DC_DOWNLOAD_FAILURE || downloadState == DcMsg.DC_DOWNLOAD_IN_PROGRESS) {
|
||||
showFullButton.setVisibility(View.GONE);
|
||||
msgActionButton.setVisibility(View.VISIBLE);
|
||||
if (downloadState==DcMsg.DC_DOWNLOAD_IN_PROGRESS) {
|
||||
msgActionButton.setEnabled(false);
|
||||
@@ -427,22 +434,24 @@ public class ConversationItem extends BaseConversationItem
|
||||
}
|
||||
});
|
||||
} else if (messageRecord.getType() == DcMsg.DC_MSG_WEBXDC) {
|
||||
showFullButton.setVisibility(View.GONE);
|
||||
msgActionButton.setVisibility(View.VISIBLE);
|
||||
msgActionButton.setEnabled(true);
|
||||
msgActionButton.setText(webxdcViewStub.get().isCommunity()? R.string.join: R.string.start_app);
|
||||
msgActionButton.setText(R.string.start_app);
|
||||
msgActionButton.setOnClickListener(view -> {
|
||||
if (batchSelected.isEmpty()) {
|
||||
DcHelper.openWebxdc(getContext(), messageRecord);
|
||||
WebxdcActivity.openWebxdcActivity(getContext(), messageRecord);
|
||||
} else {
|
||||
passthroughClickListener.onClick(view);
|
||||
}
|
||||
});
|
||||
}
|
||||
else if (messageRecord.hasHtml()) {
|
||||
msgActionButton.setVisibility(View.VISIBLE);
|
||||
msgActionButton.setEnabled(true);
|
||||
msgActionButton.setText(R.string.show_full_message);
|
||||
msgActionButton.setOnClickListener(view -> {
|
||||
msgActionButton.setVisibility(View.GONE);
|
||||
showFullButton.setVisibility(View.VISIBLE);
|
||||
showFullButton.setEnabled(true);
|
||||
showFullButton.setText(R.string.show_full_message);
|
||||
showFullButton.setOnClickListener(view -> {
|
||||
if (eventListener != null && batchSelected.isEmpty()) {
|
||||
eventListener.onShowFullClicked(messageRecord);
|
||||
} else {
|
||||
@@ -451,6 +460,7 @@ public class ConversationItem extends BaseConversationItem
|
||||
});
|
||||
} else {
|
||||
msgActionButton.setVisibility(View.GONE);
|
||||
showFullButton.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -492,9 +502,7 @@ public class ConversationItem extends BaseConversationItem
|
||||
audioViewStub.get().setAudio(new AudioSlide(context, messageRecord), duration);
|
||||
audioViewStub.get().setOnClickListener(passthroughClickListener);
|
||||
audioViewStub.get().setOnLongClickListener(passthroughClickListener);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
audioViewStub.get().setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
|
||||
}
|
||||
audioViewStub.get().setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
|
||||
|
||||
ViewUtil.updateLayoutParams(bodyText, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
ViewUtil.updateLayoutParams(groupSenderHolder, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
@@ -512,9 +520,7 @@ public class ConversationItem extends BaseConversationItem
|
||||
documentViewStub.get().setDocument(new DocumentSlide(context, messageRecord));
|
||||
documentViewStub.get().setDocumentClickListener(new ThumbnailClickListener());
|
||||
documentViewStub.get().setOnLongClickListener(passthroughClickListener);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
documentViewStub.get().setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
|
||||
}
|
||||
documentViewStub.get().setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
|
||||
|
||||
ViewUtil.updateLayoutParams(bodyText, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
ViewUtil.updateLayoutParams(groupSenderHolder, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
@@ -531,9 +537,7 @@ public class ConversationItem extends BaseConversationItem
|
||||
webxdcViewStub.get().setWebxdc(messageRecord, context.getString(R.string.webxdc_app));
|
||||
webxdcViewStub.get().setWebxdcClickListener(new ThumbnailClickListener());
|
||||
webxdcViewStub.get().setOnLongClickListener(passthroughClickListener);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
webxdcViewStub.get().setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
|
||||
}
|
||||
webxdcViewStub.get().setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
|
||||
|
||||
ViewUtil.updateLayoutParams(bodyText, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
ViewUtil.updateLayoutParams(groupSenderHolder, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
@@ -551,9 +555,7 @@ public class ConversationItem extends BaseConversationItem
|
||||
vcardViewStub.get().setVcardClickListener(new ThumbnailClickListener());
|
||||
vcardViewStub.get().setOnLongClickListener(passthroughClickListener);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
vcardViewStub.get().setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
|
||||
}
|
||||
vcardViewStub.get().setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
|
||||
|
||||
ViewUtil.updateLayoutParams(bodyText, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
ViewUtil.updateLayoutParams(groupSenderHolder, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
@@ -589,9 +591,7 @@ public class ConversationItem extends BaseConversationItem
|
||||
mediaThumbnailStub.get().setOnLongClickListener(passthroughClickListener);
|
||||
mediaThumbnailStub.get().setOnClickListener(passthroughClickListener);
|
||||
mediaThumbnailStub.get().showShade(TextUtils.isEmpty(messageRecord.getText()));
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
mediaThumbnailStub.get().setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
|
||||
}
|
||||
mediaThumbnailStub.get().setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
|
||||
|
||||
setThumbnailOutlineCorners(messageRecord, showSender);
|
||||
|
||||
@@ -614,9 +614,7 @@ public class ConversationItem extends BaseConversationItem
|
||||
stickerStub.get().setThumbnailClickListener(new StickerClickListener());
|
||||
stickerStub.get().setOnLongClickListener(passthroughClickListener);
|
||||
stickerStub.get().setOnClickListener(passthroughClickListener);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
stickerStub.get().setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
|
||||
}
|
||||
stickerStub.get().setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
|
||||
|
||||
ViewUtil.updateLayoutParams(bodyText, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
ViewUtil.updateLayoutParams(groupSenderHolder, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
@@ -676,9 +674,7 @@ public class ConversationItem extends BaseConversationItem
|
||||
if (!showSender || dcContact ==null) {
|
||||
contactPhoto.setVisibility(View.GONE);
|
||||
} else {
|
||||
int color = messageRecord.getSenderColor();
|
||||
Recipient recipient = new Recipient(context, dcContact, messageRecord.getSenderName(dcContact, !dcContext.isCommunity()), color);
|
||||
contactPhoto.setAvatar(glideRequests, recipient, true);
|
||||
contactPhoto.setAvatar(glideRequests, new Recipient(context, dcContact), true);
|
||||
contactPhoto.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
@@ -703,7 +699,7 @@ public class ConversationItem extends BaseConversationItem
|
||||
Recipient author = null;
|
||||
SlideDeck slideDeck = new SlideDeck();
|
||||
if (msg != null) {
|
||||
author = new Recipient(context, dcContext.getContact(msg.getFromId()), msg.getSenderColor());
|
||||
author = new Recipient(context, dcContext.getContact(msg.getFromId()));
|
||||
if (msg.getType() != DcMsg.DC_MSG_TEXT) {
|
||||
Slide slide = MediaUtil.getSlideForMsg(context, msg);
|
||||
if (slide != null) {
|
||||
@@ -717,7 +713,8 @@ public class ConversationItem extends BaseConversationItem
|
||||
author,
|
||||
quoteTxt,
|
||||
slideDeck,
|
||||
current.getType() == DcMsg.DC_MSG_STICKER);
|
||||
current.getType() == DcMsg.DC_MSG_STICKER,
|
||||
false);
|
||||
|
||||
quoteView.setVisibility(View.VISIBLE);
|
||||
quoteView.getLayoutParams().width = ViewGroup.LayoutParams.WRAP_CONTENT;
|
||||
@@ -802,16 +799,15 @@ public class ConversationItem extends BaseConversationItem
|
||||
|
||||
if (messageRecord.isForwarded()) {
|
||||
if (showSender && dcContact !=null) {
|
||||
this.groupSender.setText(context.getString(R.string.forwarded_by, messageRecord.getSenderName(dcContact, false)));
|
||||
this.groupSender.setText(context.getString(R.string.forwarded_by, messageRecord.getSenderName(dcContact)));
|
||||
} else {
|
||||
this.groupSender.setText(context.getString(R.string.forwarded_message));
|
||||
}
|
||||
this.groupSender.setTextColor(context.getResources().getColor(R.color.unknown_sender));
|
||||
}
|
||||
else if (showSender && dcContact !=null) {
|
||||
this.groupSender.setText(messageRecord.getSenderName(dcContact, true));
|
||||
int color = messageRecord.getSenderColor();
|
||||
this.groupSender.setTextColor(Util.rgbToArgbColor(color!=0? color : dcContact.getColor()));
|
||||
this.groupSender.setText(messageRecord.getSenderName(dcContact));
|
||||
this.groupSender.setTextColor(Util.rgbToArgbColor(dcContact.getColor()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -894,7 +890,7 @@ public class ConversationItem extends BaseConversationItem
|
||||
if (shouldInterceptClicks(messageRecord) || !batchSelected.isEmpty()) {
|
||||
performClick();
|
||||
} else if (slide.isWebxdcDocument()) {
|
||||
msgActionButton.performClick();
|
||||
WebxdcActivity.openWebxdcActivity(context, messageRecord);
|
||||
} else if (slide.isVcard()) {
|
||||
try {
|
||||
String path = slide.asAttachment().getRealPath(context);
|
||||
@@ -904,7 +900,7 @@ public class ConversationItem extends BaseConversationItem
|
||||
.setPositiveButton(android.R.string.ok, (dialog, which) -> {
|
||||
try {
|
||||
List<Integer> contactIds = rpc.importVcard(dcContext.getAccountId(), path);
|
||||
if (contactIds.size() > 0) {
|
||||
if (!contactIds.isEmpty()) {
|
||||
int chatId = dcContext.createChatByContactId(contactIds.get(0));
|
||||
if (chatId != 0) {
|
||||
Intent intent = new Intent(context, ConversationActivity.class);
|
||||
|
||||
@@ -3,7 +3,6 @@ package org.thoughtcrime.securesms;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.os.Build;
|
||||
import android.os.Vibrator;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
@@ -174,9 +173,7 @@ class ConversationItemSwipeCallback extends ItemTouchHelper.SimpleCallback {
|
||||
vibrate(viewHolder.itemView.getContext());
|
||||
}
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
recyclerView.cancelPendingInputEvents();
|
||||
}
|
||||
recyclerView.cancelPendingInputEvents();
|
||||
}
|
||||
|
||||
private static void resetProgress(RecyclerView.ViewHolder viewHolder) {
|
||||
@@ -199,11 +196,7 @@ class ConversationItemSwipeCallback extends ItemTouchHelper.SimpleCallback {
|
||||
}
|
||||
|
||||
private static float getSignFromDirection(@NonNull View view) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
return view.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL ? -1f : 1f;
|
||||
} else {
|
||||
return 1f;
|
||||
}
|
||||
return view.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL ? -1f : 1f;
|
||||
}
|
||||
|
||||
private static boolean sameSign(float dX, float sign) {
|
||||
|
||||
@@ -19,6 +19,8 @@ package org.thoughtcrime.securesms;
|
||||
import static org.thoughtcrime.securesms.ConversationActivity.CHAT_ID_EXTRA;
|
||||
import static org.thoughtcrime.securesms.ConversationActivity.STARTING_POSITION_EXTRA;
|
||||
import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_ADDRESS;
|
||||
import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_PROXY_ENABLED;
|
||||
import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_PROXY_URL;
|
||||
import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_SERVER_FLAGS;
|
||||
import static org.thoughtcrime.securesms.util.RelayUtil.acquireRelayMessageContent;
|
||||
import static org.thoughtcrime.securesms.util.RelayUtil.getDirectSharingChatId;
|
||||
@@ -66,6 +68,7 @@ import org.thoughtcrime.securesms.connect.DcHelper;
|
||||
import org.thoughtcrime.securesms.connect.DirectShareUtil;
|
||||
import org.thoughtcrime.securesms.mms.GlideApp;
|
||||
import org.thoughtcrime.securesms.permissions.Permissions;
|
||||
import org.thoughtcrime.securesms.proxy.ProxySettingsActivity;
|
||||
import org.thoughtcrime.securesms.qr.QrActivity;
|
||||
import org.thoughtcrime.securesms.qr.QrCodeHandler;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
@@ -86,7 +89,6 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
|
||||
public static final String CLEAR_NOTIFICATIONS = "clear_notifications";
|
||||
public static final String ACCOUNT_ID_EXTRA = "account_id";
|
||||
public static final String FROM_WELCOME = "from_welcome";
|
||||
public static final String WARN_CANNOT_ENCRYPT = "warn_cannot_encrypt";
|
||||
|
||||
private ConversationListFragment conversationListFragment;
|
||||
public TextView title;
|
||||
@@ -110,7 +112,7 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
|
||||
// it is not needed to keep all past update messages, however, when deleted, also the strings should be deleted.
|
||||
try {
|
||||
DcContext dcContext = DcHelper.getContext(this);
|
||||
final String deviceMsgLabel = "update_1_46_0l_android";
|
||||
final String deviceMsgLabel = "update_1_58_0_android";
|
||||
if (!dcContext.wasDeviceMsgEverAdded(deviceMsgLabel)) {
|
||||
DcMsg msg = null;
|
||||
if (!getIntent().getBooleanExtra(FROM_WELCOME, false)) {
|
||||
@@ -121,7 +123,8 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
|
||||
// Util.copy(inputStream, new FileOutputStream(outputFile));
|
||||
// msg.setFile(outputFile, "image/jpeg");
|
||||
|
||||
msg.setText(getString(R.string.update_1_46_android, "https://get.delta.chat/#changelogs"));
|
||||
// full changelog link: "https://lemmy.ml/c/ArcaneChat"
|
||||
msg.setText(getString(R.string.update_1_58_android, "https://arcanechat.me/#contribute"));
|
||||
}
|
||||
dcContext.addDeviceMsg(deviceMsgLabel, msg);
|
||||
|
||||
@@ -186,7 +189,7 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
|
||||
|
||||
TooltipCompat.setTooltipText(selfAvatar, getText(R.string.switch_account));
|
||||
selfAvatar.setOnClickListener(v -> AccountManager.getInstance().showSwitchAccountMenu(this));
|
||||
title.setOnClickListener(v -> {
|
||||
findViewById(R.id.avatar_and_title).setOnClickListener(v -> {
|
||||
if (!isRelayingMessageContent(this)) {
|
||||
AccountManager.getInstance().showSwitchAccountMenu(this);
|
||||
}
|
||||
@@ -254,6 +257,10 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
|
||||
|
||||
@Override
|
||||
protected void onNewIntent(Intent intent) {
|
||||
if (isFinishing()) {
|
||||
Log.w(TAG, "Activity is finishing, aborting onNewIntent()");
|
||||
return;
|
||||
}
|
||||
super.onNewIntent(intent);
|
||||
setIntent(intent);
|
||||
refresh();
|
||||
@@ -265,17 +272,12 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
|
||||
DcContext dcContext = DcHelper.getContext(this);
|
||||
int accountId = getIntent().getIntExtra(ACCOUNT_ID_EXTRA, dcContext.getAccountId());
|
||||
if (getIntent().getBooleanExtra(CLEAR_NOTIFICATIONS, false)) {
|
||||
DcHelper.getNotificationCenter(this).removeAllNotifiations(accountId);
|
||||
DcHelper.getNotificationCenter(this).removeAllNotifications(accountId);
|
||||
}
|
||||
if (accountId != dcContext.getAccountId()) {
|
||||
AccountManager.getInstance().switchAccountAndStartActivity(this, accountId);
|
||||
}
|
||||
|
||||
String warnAddr = getIntent().getStringExtra(WARN_CANNOT_ENCRYPT);
|
||||
if (!TextUtils.isEmpty(warnAddr)) {
|
||||
DcHelper.showEncryptionRequiredDialog(this, warnAddr);
|
||||
}
|
||||
|
||||
refreshAvatar();
|
||||
refreshUnreadIndicator();
|
||||
refreshTitle();
|
||||
@@ -299,19 +301,16 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
|
||||
}
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
} else {
|
||||
DcContext dcContext = DcHelper.getContext(this);
|
||||
DcContact self = dcContext.getContact(DcContact.DC_CONTACT_ID_SELF);
|
||||
String name = dcContext.getConfig("displayname");
|
||||
if (TextUtils.isEmpty(name)) {
|
||||
name = self.getAddr();
|
||||
}
|
||||
title.setText(name);
|
||||
title.setText(DcHelper.getContext(this).getName());
|
||||
// refreshTitle is called by ConversationListFragment when connectivity changes so update connectivity dot here
|
||||
selfAvatar.setConnectivity(DcHelper.getContext(this).getConnectivity());
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
public void refreshAvatar() {
|
||||
if (selfAvatarContainer == null) return;
|
||||
|
||||
if (isRelayingMessageContent(this)) {
|
||||
selfAvatarContainer.setVisibility(View.GONE);
|
||||
} else {
|
||||
@@ -367,6 +366,7 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
refreshTitle();
|
||||
invalidateOptionsMenu();
|
||||
DirectShareUtil.triggerRefreshDirectShare(this);
|
||||
}
|
||||
|
||||
@@ -377,20 +377,16 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
|
||||
|
||||
if (!isRelayingMessageContent(this)) {
|
||||
inflater.inflate(R.menu.text_secure_normal, menu);
|
||||
MenuItem item = menu.findItem(R.id.menu_global_map);
|
||||
if (Prefs.isLocationStreamingEnabled(this)) {
|
||||
item.setVisible(true);
|
||||
}
|
||||
|
||||
if (!Prefs.isLocationStreamingEnabled(this)) {
|
||||
menu.findItem(R.id.menu_global_map).setVisible(false);
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
MenuCompat.setGroupDividerEnabled(menu, true);
|
||||
} else{
|
||||
menu.setGroupVisible(R.id.extra_services, false);
|
||||
menu.findItem(R.id.menu_global_map).setVisible(Prefs.isLocationStreamingEnabled(this));
|
||||
MenuItem proxyItem = menu.findItem(R.id.menu_proxy_settings);
|
||||
if (TextUtils.isEmpty(DcHelper.get(this, CONFIG_PROXY_URL))) {
|
||||
proxyItem.setVisible(false);
|
||||
} else {
|
||||
boolean proxyEnabled = DcHelper.getInt(this, CONFIG_PROXY_ENABLED) == 1;
|
||||
proxyItem.setIcon(proxyEnabled? R.drawable.ic_proxy_enabled_24 : R.drawable.ic_proxy_disabled_24);
|
||||
proxyItem.setVisible(true);
|
||||
}
|
||||
MenuCompat.setGroupDividerEnabled(menu, true);
|
||||
}
|
||||
|
||||
super.onPrepareOptionsMenu(menu);
|
||||
@@ -440,31 +436,31 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
super.onOptionsItemSelected(item);
|
||||
|
||||
switch (item.getItemId()) {
|
||||
case R.id.menu_invite_friends:
|
||||
shareInvite();
|
||||
return true;
|
||||
case R.id.menu_settings:
|
||||
startActivity(new Intent(this, ApplicationPreferencesActivity.class));
|
||||
return true;
|
||||
case R.id.menu_qr:
|
||||
new IntentIntegrator(this).setCaptureActivity(QrActivity.class).initiateScan();
|
||||
return true;
|
||||
case R.id.menu_global_map:
|
||||
WebxdcActivity.openMaps(this, 0);
|
||||
return true;
|
||||
case android.R.id.home:
|
||||
onBackPressed();
|
||||
return true;
|
||||
case R.id.menu_all_media:
|
||||
startActivity(new Intent(this, ProfileActivity.class));
|
||||
return true;
|
||||
case R.id.menu_webxdc_apps_store:
|
||||
handleShowBot("xstore@testrun.org", "OPENPGP4FPR:37DC2B704A2AE2F6A96235CE0C3A0EBCA4F5801D#a=xstore%40testrun.org&n=&i=-1IGtynaivZ&s=JqHsvvcDmnW");
|
||||
return true;
|
||||
case R.id.menu_public_bots:
|
||||
handleShowBot("publicbots@testrun.org", "OPENPGP4FPR:4DB8117591B27184A903FF7E9F469E00D40E13E7#a=publicbots%40testrun.org&n=Public%20Bots&i=zSuQpFtBa_Q&s=weLMu1-o1o1");
|
||||
return true;
|
||||
int itemId = item.getItemId();
|
||||
if (itemId == R.id.menu_invite_friends) {
|
||||
shareInvite();
|
||||
return true;
|
||||
} else if (itemId == R.id.menu_settings) {
|
||||
startActivity(new Intent(this, ApplicationPreferencesActivity.class));
|
||||
return true;
|
||||
} else if (itemId == R.id.menu_qr) {
|
||||
new IntentIntegrator(this).setCaptureActivity(QrActivity.class).initiateScan();
|
||||
return true;
|
||||
} else if (itemId == R.id.menu_global_map) {
|
||||
WebxdcActivity.openMaps(this, 0);
|
||||
return true;
|
||||
} else if (itemId == R.id.menu_proxy_settings) {
|
||||
startActivity(new Intent(this, ProxySettingsActivity.class));
|
||||
return true;
|
||||
} else if (itemId == android.R.id.home) {
|
||||
onBackPressed();
|
||||
return true;
|
||||
} else if (itemId == R.id.menu_all_media) {
|
||||
startActivity(new Intent(this, ProfileActivity.class));
|
||||
return true;
|
||||
} else if (itemId == R.id.menu_public_bots) {
|
||||
handleShowBot("botsindex@arcanechat.me", "https://i.delta.chat/#67889B0362BEDBFEE05ACD92C1D737FA632A9582&a=botsindex%40arcanechat.me&n=Public%20Bots&i=336MTEz38EH-RJxM9OKWygYK&s=TpVVGK6C4KrJmRG0bwHLalXt");
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -565,7 +561,7 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
|
||||
private void shareInvite() {
|
||||
Intent intent = new Intent(Intent.ACTION_SEND);
|
||||
intent.setType("text/plain");
|
||||
String inviteURL = Util.QrDataToInviteURL(DcHelper.getContext(this).getSecurejoinQr(0));
|
||||
String inviteURL = DcHelper.getContext(this).getSecurejoinQr(0);
|
||||
intent.putExtra(Intent.EXTRA_TEXT, getString(R.string.invite_friends_text, inviteURL));
|
||||
startActivity(Intent.createChooser(intent, getString(R.string.chat_share_with_title)));
|
||||
}
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
package org.thoughtcrime.securesms;
|
||||
|
||||
import static org.thoughtcrime.securesms.ConversationActivity.CHAT_ID_EXTRA;
|
||||
import static org.thoughtcrime.securesms.ConversationActivity.FROM_ARCHIVED_CHATS_EXTRA;
|
||||
import static org.thoughtcrime.securesms.util.RelayUtil.acquireRelayMessageContent;
|
||||
import static org.thoughtcrime.securesms.util.RelayUtil.isRelayingMessageContent;
|
||||
import static org.thoughtcrime.securesms.util.RelayUtil.isSharing;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.view.Menu;
|
||||
@@ -10,12 +16,6 @@ import com.b44t.messenger.DcChat;
|
||||
|
||||
import org.thoughtcrime.securesms.connect.DcHelper;
|
||||
|
||||
import static org.thoughtcrime.securesms.ConversationActivity.CHAT_ID_EXTRA;
|
||||
import static org.thoughtcrime.securesms.ConversationActivity.FROM_ARCHIVED_CHATS_EXTRA;
|
||||
import static org.thoughtcrime.securesms.util.RelayUtil.acquireRelayMessageContent;
|
||||
import static org.thoughtcrime.securesms.util.RelayUtil.isRelayingMessageContent;
|
||||
import static org.thoughtcrime.securesms.util.RelayUtil.isSharing;
|
||||
|
||||
public class ConversationListArchiveActivity extends PassphraseRequiredActionBarActivity
|
||||
implements ConversationListFragment.ConversationSelectedListener
|
||||
{
|
||||
@@ -60,14 +60,13 @@ public class ConversationListArchiveActivity extends PassphraseRequiredActionBar
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
super.onOptionsItemSelected(item);
|
||||
|
||||
switch (item.getItemId()) {
|
||||
case android.R.id.home:
|
||||
onBackPressed();
|
||||
return true;
|
||||
|
||||
case R.id.mark_as_read:
|
||||
DcHelper.getContext(this).marknoticedChat(DcChat.DC_CHAT_ID_ARCHIVED_LINK);
|
||||
return true;
|
||||
int itemId = item.getItemId();
|
||||
if (itemId == android.R.id.home) {
|
||||
onBackPressed();
|
||||
return true;
|
||||
} else if (itemId == R.id.mark_as_read) {
|
||||
DcHelper.getContext(this).marknoticedChat(DcChat.DC_CHAT_ID_ARCHIVED_LINK);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
@@ -42,7 +42,6 @@ import com.b44t.messenger.DcMsg;
|
||||
import org.thoughtcrime.securesms.ConversationListAdapter.ItemClickListener;
|
||||
import org.thoughtcrime.securesms.components.recyclerview.DeleteItemAnimator;
|
||||
import org.thoughtcrime.securesms.components.reminder.DozeReminder;
|
||||
import org.thoughtcrime.securesms.connect.AccountManager;
|
||||
import org.thoughtcrime.securesms.connect.DcEventCenter;
|
||||
import org.thoughtcrime.securesms.connect.DcHelper;
|
||||
import org.thoughtcrime.securesms.mms.GlideApp;
|
||||
@@ -81,6 +80,7 @@ public class ConversationListFragment extends BaseConversationListFragment
|
||||
DcEventCenter eventCenter = DcHelper.getEventCenter(requireActivity());
|
||||
eventCenter.addMultiAccountObserver(DcContext.DC_EVENT_INCOMING_MSG, this);
|
||||
eventCenter.addMultiAccountObserver(DcContext.DC_EVENT_MSGS_NOTICED, this);
|
||||
eventCenter.addMultiAccountObserver(DcContext.DC_EVENT_CHAT_DELETED, this);
|
||||
eventCenter.addObserver(DcContext.DC_EVENT_CHAT_MODIFIED, this);
|
||||
eventCenter.addObserver(DcContext.DC_EVENT_CONTACTS_CHANGED, this);
|
||||
eventCenter.addObserver(DcContext.DC_EVENT_MSGS_CHANGED, this);
|
||||
@@ -322,7 +322,10 @@ public class ConversationListFragment extends BaseConversationListFragment
|
||||
|
||||
@Override
|
||||
public void handleEvent(@NonNull DcEvent event) {
|
||||
if (event.getAccountId() != DcHelper.getContext(requireActivity()).getAccountId()) {
|
||||
final int accId = event.getAccountId();
|
||||
if (event.getId() == DcContext.DC_EVENT_CHAT_DELETED) {
|
||||
DcHelper.getNotificationCenter(requireActivity()).removeNotifications(accId, event.getData1Int());
|
||||
} else if (accId != DcHelper.getContext(requireActivity()).getAccountId()) {
|
||||
Activity activity = getActivity();
|
||||
if (activity instanceof ConversationListActivity) {
|
||||
((ConversationListActivity) activity).refreshUnreadIndicator();
|
||||
|
||||
@@ -64,11 +64,9 @@ public class ConversationListItem extends RelativeLayout
|
||||
private final static Typeface BOLD_TYPEFACE = Typeface.create("sans-serif-medium", Typeface.NORMAL);
|
||||
private final static Typeface LIGHT_TYPEFACE = Typeface.create("sans-serif", Typeface.NORMAL);
|
||||
|
||||
private DcLot dcSummary;
|
||||
private Set<Long> selectedThreads;
|
||||
private long chatId;
|
||||
private int msgId;
|
||||
private GlideRequests glideRequests;
|
||||
private TextView subjectView;
|
||||
private FromTextView fromView;
|
||||
private TextView dateView;
|
||||
@@ -122,12 +120,10 @@ public class ConversationListItem extends RelativeLayout
|
||||
boolean batchMode,
|
||||
@Nullable String highlightSubstring)
|
||||
{
|
||||
this.dcSummary = dcSummary;
|
||||
this.selectedThreads = selectedThreads;
|
||||
Recipient recipient = thread.getRecipient();
|
||||
this.chatId = thread.getThreadId();
|
||||
this.msgId = msgId;
|
||||
this.glideRequests = glideRequests;
|
||||
|
||||
int state = dcSummary.getState();
|
||||
int unreadCount = thread.getUnreadCount();
|
||||
@@ -163,7 +159,7 @@ public class ConversationListItem extends RelativeLayout
|
||||
this.avatar.setAvatar(glideRequests, recipient, false);
|
||||
|
||||
DcContact contact = recipient.getDcContact();
|
||||
avatar.setSeenRecently(contact!=null? contact.wasSeenRecently() : false);
|
||||
avatar.setSeenRecently(contact != null && contact.wasSeenRecently());
|
||||
|
||||
boolean isProtected = thread.isProtected() || DcHelper.getContext(getContext()).getChat((int)chatId).isDeviceTalk();
|
||||
|
||||
@@ -180,7 +176,6 @@ public class ConversationListItem extends RelativeLayout
|
||||
{
|
||||
this.selectedThreads = Collections.emptySet();
|
||||
Recipient recipient = new Recipient(getContext(), contact);
|
||||
this.glideRequests = glideRequests;
|
||||
|
||||
fromView.setText(getHighlightedSpan(contact.getDisplayName(), highlightSubstring));
|
||||
fromView.setCompoundDrawablesWithIntrinsicBounds(0, 0, contact.isVerified()? R.drawable.ic_verified : 0, 0);
|
||||
@@ -205,7 +200,6 @@ public class ConversationListItem extends RelativeLayout
|
||||
DcContact sender = dcContext.getContact(messageResult.getFromId());
|
||||
this.selectedThreads = Collections.emptySet();
|
||||
Recipient recipient = new Recipient(getContext(), sender);
|
||||
this.glideRequests = glideRequests;
|
||||
|
||||
fromView.setText(recipient, true);
|
||||
fromView.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
|
||||
@@ -312,9 +306,9 @@ public class ConversationListItem extends RelativeLayout
|
||||
if (thread!=null && thread.getVisibility()==DcChat.DC_CHAT_VISIBILITY_PINNED) {
|
||||
bg = R.attr.pinned_list_item_background;
|
||||
}
|
||||
TypedArray ta = getContext().obtainStyledAttributes(new int[] { bg });
|
||||
ViewUtil.setBackground(this, ta.getDrawable(0));
|
||||
ta.recycle();
|
||||
try (TypedArray ta = getContext().obtainStyledAttributes(new int[]{bg})) {
|
||||
ViewUtil.setBackground(this, ta.getDrawable(0));
|
||||
}
|
||||
}
|
||||
|
||||
private Spanned getHighlightedSpan(@Nullable String value,
|
||||
@@ -332,7 +326,10 @@ public class ConversationListItem extends RelativeLayout
|
||||
|
||||
String normalizedValue = value.toLowerCase(Util.getLocale());
|
||||
String normalizedTest = highlight.toLowerCase(Util.getLocale());
|
||||
List<String> testTokens = Stream.of(normalizedTest.split(" ")).filter(s -> s.trim().length() > 0).toList();
|
||||
List<String> testTokens;
|
||||
try (Stream<String> stream = Stream.of(normalizedTest.split(" "))) {
|
||||
testTokens = stream.filter(s -> !s.trim().isEmpty()).toList();
|
||||
}
|
||||
|
||||
Spannable spanned = new SpannableString(value);
|
||||
int searchStartIndex = 0;
|
||||
|
||||
@@ -2,13 +2,12 @@ package org.thoughtcrime.securesms;
|
||||
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.RequiresApi;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.b44t.messenger.DcLot;
|
||||
|
||||
import org.thoughtcrime.securesms.database.model.ThreadRecord;
|
||||
@@ -29,7 +28,6 @@ public class ConversationListItemInboxZero extends LinearLayout implements Binda
|
||||
super(context, attrs, defStyleAttr);
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
|
||||
public ConversationListItemInboxZero(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
}
|
||||
|
||||
@@ -99,10 +99,7 @@ public class ConversationTitleView extends RelativeLayout {
|
||||
}
|
||||
} else if( dcChat.isMultiUser() ) {
|
||||
if (!profileView) {
|
||||
if (dcContext.isCommunity() && chatContacts.length == 1)
|
||||
subtitleStr = context.getString(R.string.super_group);
|
||||
else
|
||||
subtitleStr = context.getResources().getQuantityString(R.plurals.n_members, chatContacts.length, chatContacts.length);
|
||||
subtitleStr = context.getResources().getQuantityString(R.plurals.n_members, chatContacts.length, chatContacts.length);
|
||||
}
|
||||
} else if( chatContacts.length>=1 ) {
|
||||
if( dcChat.isSelfTalk() ) {
|
||||
|
||||
@@ -4,11 +4,11 @@ import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.widget.AppCompatImageView;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
import com.b44t.messenger.DcChat;
|
||||
import com.b44t.messenger.DcMsg;
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
package org.thoughtcrime.securesms;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import android.text.TextUtils;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.b44t.messenger.DcChat;
|
||||
import com.b44t.messenger.DcContact;
|
||||
import com.b44t.messenger.DcContext;
|
||||
|
||||
@@ -5,14 +5,12 @@ import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.Bitmap;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
@@ -31,12 +29,9 @@ import com.bumptech.glide.load.engine.DiskCacheStrategy;
|
||||
import com.bumptech.glide.request.target.SimpleTarget;
|
||||
import com.bumptech.glide.request.transition.Transition;
|
||||
import com.google.android.material.textfield.TextInputLayout;
|
||||
import com.soundcloud.android.crop.Crop;
|
||||
|
||||
import org.thoughtcrime.securesms.components.AvatarSelector;
|
||||
import org.thoughtcrime.securesms.components.InputAwareLayout;
|
||||
import org.thoughtcrime.securesms.components.emoji.EmojiKeyboardProvider;
|
||||
import org.thoughtcrime.securesms.components.emoji.MediaKeyboard;
|
||||
import org.thoughtcrime.securesms.connect.DcHelper;
|
||||
import org.thoughtcrime.securesms.contacts.avatars.ResourceContactPhoto;
|
||||
import org.thoughtcrime.securesms.mms.AttachmentManager;
|
||||
@@ -54,7 +49,7 @@ import java.security.SecureRandom;
|
||||
|
||||
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
public class CreateProfileActivity extends BaseActionBarActivity implements EmojiKeyboardProvider.EmojiEventListener {
|
||||
public class CreateProfileActivity extends BaseActionBarActivity {
|
||||
|
||||
private static final String TAG = CreateProfileActivity.class.getSimpleName();
|
||||
|
||||
@@ -65,8 +60,6 @@ public class CreateProfileActivity extends BaseActionBarActivity implements Emoj
|
||||
private InputAwareLayout container;
|
||||
private ImageView avatar;
|
||||
private EditText name;
|
||||
private EditText overridenName;
|
||||
private MediaKeyboard emojiDrawer;
|
||||
private EditText statusView;
|
||||
|
||||
private boolean fromWelcome;
|
||||
@@ -91,7 +84,6 @@ public class CreateProfileActivity extends BaseActionBarActivity implements Emoj
|
||||
attachmentManager = new AttachmentManager(this, () -> {});
|
||||
avatarChanged = false;
|
||||
initializeResources();
|
||||
initializeEmojiInput();
|
||||
initializeProfileName();
|
||||
initializeProfileAvatar();
|
||||
initializeStatusText();
|
||||
@@ -107,13 +99,12 @@ public class CreateProfileActivity extends BaseActionBarActivity implements Emoj
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
super.onOptionsItemSelected(item);
|
||||
switch (item.getItemId()) {
|
||||
case android.R.id.home:
|
||||
onBackPressed();
|
||||
return true;
|
||||
case R.id.menu_create_profile:
|
||||
updateProfile();
|
||||
break;
|
||||
int itemId = item.getItemId();
|
||||
if (itemId == android.R.id.home) {
|
||||
onBackPressed();
|
||||
return true;
|
||||
} else if (itemId == R.id.menu_create_profile) {
|
||||
updateProfile();
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -130,15 +121,6 @@ public class CreateProfileActivity extends BaseActionBarActivity implements Emoj
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(Configuration newConfig) {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
|
||||
if (container.getCurrentInput() == emojiDrawer) {
|
||||
container.hideAttachedInput(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull int[] grantResults) {
|
||||
Permissions.onRequestPermissionsResult(this, requestCode, permissions, grantResults);
|
||||
@@ -161,10 +143,6 @@ public class CreateProfileActivity extends BaseActionBarActivity implements Emoj
|
||||
case ScribbleActivity.SCRIBBLE_REQUEST_CODE:
|
||||
setAvatarView(data.getData());
|
||||
break;
|
||||
|
||||
case Crop.REQUEST_CROP:
|
||||
setAvatarView(Crop.getOutput(data));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -205,28 +183,14 @@ public class CreateProfileActivity extends BaseActionBarActivity implements Emoj
|
||||
TextView loginSuccessText = ViewUtil.findById(this, R.id.login_success_text);
|
||||
this.avatar = ViewUtil.findById(this, R.id.avatar);
|
||||
this.name = ViewUtil.findById(this, R.id.name_text);
|
||||
this.overridenName = ViewUtil.findById(this, R.id.overriden_name);
|
||||
this.emojiDrawer = ViewUtil.findById(this, R.id.emoji_drawer);
|
||||
this.container = ViewUtil.findById(this, R.id.container);
|
||||
this.statusView = ViewUtil.findById(this, R.id.status_text);
|
||||
|
||||
if (fromWelcome) {
|
||||
if (DcHelper.getContext(this).isCommunity()) {
|
||||
ViewUtil.findById(this, R.id.community_user_container).setVisibility(View.VISIBLE);
|
||||
loginSuccessText.setText(R.string.community_set_name_explain);
|
||||
ViewUtil.findById(this, R.id.avatar_and_name).setVisibility(View.GONE);
|
||||
} else {
|
||||
loginSuccessText.setText(R.string.set_name_and_avatar_explain);
|
||||
}
|
||||
loginSuccessText.setText(R.string.set_name_and_avatar_explain);
|
||||
ViewUtil.findById(this, R.id.status_text_layout).setVisibility(View.GONE);
|
||||
ViewUtil.findById(this, R.id.information_label).setVisibility(View.GONE);
|
||||
} else {
|
||||
if (DcHelper.getContext(this).isCommunity()) {
|
||||
ViewUtil.findById(this, R.id.community_user_container).setVisibility(View.VISIBLE);
|
||||
ViewUtil.findById(this, R.id.information_label).setVisibility(View.GONE);
|
||||
((TextInputLayout)ViewUtil.findById(this, R.id.name)).setHint(R.string.community);
|
||||
((TextInputLayout)ViewUtil.findById(this, R.id.status_text_layout)).setHint(R.string.description);
|
||||
}
|
||||
loginSuccessText.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
@@ -237,10 +201,6 @@ public class CreateProfileActivity extends BaseActionBarActivity implements Emoj
|
||||
name.setText(profileName);
|
||||
name.setSelection(profileName.length(), profileName.length());
|
||||
}
|
||||
DcContext dcContext = DcHelper.getContext(this);
|
||||
if (dcContext.isCommunity()) {
|
||||
overridenName.setText(dcContext.getCommunityUser());
|
||||
}
|
||||
}
|
||||
|
||||
private void initializeProfileAvatar() {
|
||||
@@ -261,55 +221,22 @@ public class CreateProfileActivity extends BaseActionBarActivity implements Emoj
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onEmojiSelected(String emoji) {
|
||||
final int start = name.getSelectionStart();
|
||||
final int end = name.getSelectionEnd();
|
||||
|
||||
name.getText().replace(Math.min(start, end), Math.max(start, end), emoji);
|
||||
name.setSelection(start + emoji.length());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onKeyEvent(KeyEvent keyEvent) {
|
||||
name.dispatchKeyEvent(keyEvent);
|
||||
}
|
||||
|
||||
private void initializeMediaKeyboardProviders(@NonNull MediaKeyboard mediaKeyboard) {
|
||||
boolean isSystemEmojiPreferred = Prefs.isSystemEmojiPreferred(this);
|
||||
if (!isSystemEmojiPreferred) {
|
||||
mediaKeyboard.setProviders(0, new EmojiKeyboardProvider(this, this));
|
||||
}
|
||||
}
|
||||
|
||||
private void initializeEmojiInput() {
|
||||
initializeMediaKeyboardProviders(emojiDrawer);
|
||||
this.name.setOnClickListener(v -> container.showSoftkey(name));
|
||||
}
|
||||
|
||||
private void initializeStatusText() {
|
||||
String status = DcHelper.get(this, DcHelper.CONFIG_SELF_STATUS);
|
||||
statusView.setText(status);
|
||||
}
|
||||
|
||||
private void updateProfile() {
|
||||
boolean isCommunity = DcHelper.getContext(this).isCommunity();
|
||||
if (TextUtils.isEmpty(this.name.getText()) && !(isCommunity && fromWelcome)) {
|
||||
if (TextUtils.isEmpty(this.name.getText())) {
|
||||
Toast.makeText(this, R.string.please_enter_name, Toast.LENGTH_LONG).show();
|
||||
return;
|
||||
}
|
||||
|
||||
final String name = this.name.getText().toString();
|
||||
final String ovName = this.overridenName.getText().toString().trim();
|
||||
|
||||
new AsyncTask<Void, Void, Boolean>() {
|
||||
@Override
|
||||
protected Boolean doInBackground(Void... params) {
|
||||
Context context = CreateProfileActivity.this;
|
||||
if (isCommunity) {
|
||||
DcHelper.getContext(context).setCommunityUser(ovName);
|
||||
}
|
||||
DcHelper.set(context, DcHelper.CONFIG_DISPLAY_NAME, name);
|
||||
setStatusText();
|
||||
|
||||
|
||||
@@ -105,17 +105,16 @@ public class FullMsgActivity extends WebViewActivity
|
||||
|
||||
@Override
|
||||
public boolean onContextItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.action_export_image:
|
||||
// TODO: extract image from "data:" link or download URL
|
||||
return true;
|
||||
case R.id.action_copy_link:
|
||||
Util.writeTextToClipboard(this, imageUrl);
|
||||
Toast.makeText(this, getString(R.string.copied_to_clipboard), Toast.LENGTH_SHORT).show();
|
||||
return true;
|
||||
default:
|
||||
return super.onContextItemSelected(item);
|
||||
int itemId = item.getItemId();
|
||||
if (itemId == R.id.action_export_image) {
|
||||
// TODO: extract image from "data:" link or download URL
|
||||
return true;
|
||||
} else if (itemId == R.id.action_copy_link) {
|
||||
Util.writeTextToClipboard(this, imageUrl);
|
||||
Toast.makeText(this, getString(R.string.copied_to_clipboard), Toast.LENGTH_SHORT).show();
|
||||
return true;
|
||||
}
|
||||
return super.onContextItemSelected(item);
|
||||
}
|
||||
|
||||
private static void loadHtmlAsync(final WeakReference<FullMsgActivity> activityReference) {
|
||||
@@ -157,40 +156,39 @@ public class FullMsgActivity extends WebViewActivity
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
super.onOptionsItemSelected(item);
|
||||
switch (item.getItemId()) {
|
||||
case R.id.load_remote_content:
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this)
|
||||
.setTitle(R.string.load_remote_content)
|
||||
.setMessage(R.string.load_remote_content_ask);
|
||||
if (item.getItemId() == R.id.load_remote_content) {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this)
|
||||
.setTitle(R.string.load_remote_content)
|
||||
.setMessage(R.string.load_remote_content_ask);
|
||||
|
||||
// we are using the buttons "[Always] [Never][Once]" in that order.
|
||||
// 1. Checkmarks before [Always] and [Never] show the current state.
|
||||
// 2. [Once] is also shown in always-mode and disables always-mode if selected
|
||||
// (there was the idea to hide [Once] in always mode, but that looks more like a bug in the end)
|
||||
// (maybe a usual Always-Checkbox and "[Cancel][OK]" buttons are an alternative, however, a [Once]
|
||||
// would be required as well - probably as the leftmost button which is not that usable in
|
||||
// not-always-mode where the dialog is used more often. Or [Ok] would mean "Once" as well as "Change checkbox setting",
|
||||
// which is also a bit weird. Anyway, let's give the three buttons a try :)
|
||||
final String checkmark = DynamicTheme.getCheckmarkEmoji(this) + " ";
|
||||
String alwaysCheckmark = "";
|
||||
String onceCheckmark = "";
|
||||
String neverCheckmark = "";
|
||||
if (!blockLoadingRemote && Prefs.getAlwaysLoadRemoteContent(this)) {
|
||||
alwaysCheckmark = checkmark;
|
||||
} else if (loadRemoteContent) {
|
||||
onceCheckmark = checkmark;
|
||||
} else {
|
||||
neverCheckmark = checkmark;
|
||||
}
|
||||
// we are using the buttons "[Always] [Never][Once]" in that order.
|
||||
// 1. Checkmarks before [Always] and [Never] show the current state.
|
||||
// 2. [Once] is also shown in always-mode and disables always-mode if selected
|
||||
// (there was the idea to hide [Once] in always mode, but that looks more like a bug in the end)
|
||||
// (maybe a usual Always-Checkbox and "[Cancel][OK]" buttons are an alternative, however, a [Once]
|
||||
// would be required as well - probably as the leftmost button which is not that usable in
|
||||
// not-always-mode where the dialog is used more often. Or [Ok] would mean "Once" as well as "Change checkbox setting",
|
||||
// which is also a bit weird. Anyway, let's give the three buttons a try :)
|
||||
final String checkmark = DynamicTheme.getCheckmarkEmoji(this) + " ";
|
||||
String alwaysCheckmark = "";
|
||||
String onceCheckmark = "";
|
||||
String neverCheckmark = "";
|
||||
if (!blockLoadingRemote && Prefs.getAlwaysLoadRemoteContent(this)) {
|
||||
alwaysCheckmark = checkmark;
|
||||
} else if (loadRemoteContent) {
|
||||
onceCheckmark = checkmark;
|
||||
} else {
|
||||
neverCheckmark = checkmark;
|
||||
}
|
||||
|
||||
if (!blockLoadingRemote) {
|
||||
builder.setNeutralButton(alwaysCheckmark + getString(R.string.always), (dialog, which) -> onChangeLoadRemoteContent(LoadRemoteContent.ALWAYS));
|
||||
}
|
||||
builder.setNegativeButton(neverCheckmark + getString(blockLoadingRemote ? R.string.no : R.string.never), (dialog, which) -> onChangeLoadRemoteContent(LoadRemoteContent.NEVER));
|
||||
builder.setPositiveButton(onceCheckmark + getString(R.string.once), (dialog, which) -> onChangeLoadRemoteContent(LoadRemoteContent.ONCE));
|
||||
if (!blockLoadingRemote) {
|
||||
builder.setNeutralButton(alwaysCheckmark + getString(R.string.always), (dialog, which) -> onChangeLoadRemoteContent(LoadRemoteContent.ALWAYS));
|
||||
}
|
||||
builder.setNegativeButton(neverCheckmark + getString(blockLoadingRemote ? R.string.no : R.string.never), (dialog, which) -> onChangeLoadRemoteContent(LoadRemoteContent.NEVER));
|
||||
builder.setPositiveButton(onceCheckmark + getString(R.string.once), (dialog, which) -> onChangeLoadRemoteContent(LoadRemoteContent.ONCE));
|
||||
|
||||
builder.show();
|
||||
return true;
|
||||
builder.show();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package org.thoughtcrime.securesms;
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.view.Menu;
|
||||
@@ -17,16 +18,14 @@ import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.loader.app.LoaderManager;
|
||||
|
||||
import com.b44t.messenger.DcChat;
|
||||
import com.b44t.messenger.DcContact;
|
||||
import com.b44t.messenger.DcContext;
|
||||
import com.bumptech.glide.load.engine.DiskCacheStrategy;
|
||||
import com.bumptech.glide.request.target.SimpleTarget;
|
||||
import com.bumptech.glide.request.target.CustomTarget;
|
||||
import com.bumptech.glide.request.transition.Transition;
|
||||
import com.soundcloud.android.crop.Crop;
|
||||
|
||||
import org.thoughtcrime.securesms.components.AvatarSelector;
|
||||
import org.thoughtcrime.securesms.connect.DcHelper;
|
||||
@@ -76,7 +75,7 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
|
||||
setContentView(R.layout.group_create_activity);
|
||||
verified = false;
|
||||
broadcast = getIntent().getBooleanExtra(CREATE_BROADCAST, false);
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
Objects.requireNonNull(getSupportActionBar()).setDisplayHomeAsUpEnabled(true);
|
||||
getSupportActionBar().setHomeAsUpIndicator(R.drawable.ic_close_white_24dp);
|
||||
|
||||
groupChatId = getIntent().getIntExtra(EDIT_GROUP_CHAT_ID, 0);
|
||||
@@ -209,37 +208,22 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
|
||||
super.onOptionsItemSelected(item);
|
||||
switch (item.getItemId()) {
|
||||
case android.R.id.home:
|
||||
finish();
|
||||
return true;
|
||||
case R.id.menu_create_group:
|
||||
String groupName = getGroupName();
|
||||
if (showGroupNameEmptyToast(groupName)) return true;
|
||||
int itemId = item.getItemId();
|
||||
if (itemId == android.R.id.home) {
|
||||
finish();
|
||||
return true;
|
||||
} else if (itemId == R.id.menu_create_group) {
|
||||
String groupName = getGroupName();
|
||||
if (showGroupNameEmptyToast(groupName)) return true;
|
||||
|
||||
if (groupChatId!=0) {
|
||||
updateGroup(groupName);
|
||||
} else {
|
||||
verified = !broadcast && allMembersVerified();
|
||||
if (verified && getAdapter().getContacts().size() == 1) {
|
||||
new AlertDialog.Builder(this)
|
||||
.setMessage(R.string.create_verified_group_ask)
|
||||
.setNeutralButton(R.string.learn_more, (d, w) -> DcHelper.openHelp(this, "#e2eeguarantee"))
|
||||
.setPositiveButton(R.string.yes, (d, w) -> {
|
||||
createGroup(groupName);
|
||||
})
|
||||
.setNegativeButton(R.string.no, (d, w) -> {
|
||||
verified = false;
|
||||
createGroup(groupName);
|
||||
})
|
||||
.setCancelable(true)
|
||||
.show();
|
||||
} else {
|
||||
createGroup(groupName);
|
||||
}
|
||||
}
|
||||
if (groupChatId != 0) {
|
||||
updateGroup(groupName);
|
||||
} else {
|
||||
verified = !broadcast && allMembersVerified();
|
||||
createGroup(groupName);
|
||||
}
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -260,10 +244,7 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
|
||||
if (contactId == DcContact.DC_CONTACT_ID_ADD_MEMBER) {
|
||||
Intent intent = new Intent(this, ContactMultiSelectionActivity.class);
|
||||
intent.putExtra(ContactSelectionListFragment.SELECT_VERIFIED_EXTRA, verified);
|
||||
ArrayList<String> preselectedContacts = new ArrayList<>();
|
||||
for (int id : getAdapter().getContacts()) {
|
||||
preselectedContacts.add(dcContext.getContact(id).getAddr());
|
||||
}
|
||||
ArrayList<Integer> preselectedContacts = new ArrayList<>(getAdapter().getContacts());
|
||||
intent.putExtra(ContactSelectionListFragment.PRESELECTED_CONTACTS, preselectedContacts);
|
||||
startActivityForResult(intent, PICK_CONTACT);
|
||||
}
|
||||
@@ -349,9 +330,9 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
|
||||
|
||||
case PICK_CONTACT:
|
||||
ArrayList<Integer> contactIds = new ArrayList<>();
|
||||
for (String addr : Objects.requireNonNull(data.getStringArrayListExtra("contacts"))) {
|
||||
if(addr != null) {
|
||||
contactIds.add(dcContext.createContact(null, addr));
|
||||
for (Integer contactId : Objects.requireNonNull(data.getIntegerArrayListExtra(ContactMultiSelectionActivity.CONTACTS_EXTRA))) {
|
||||
if(contactId != null) {
|
||||
contactIds.add(contactId);
|
||||
}
|
||||
}
|
||||
getAdapter().changeData(contactIds);
|
||||
@@ -360,10 +341,6 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
|
||||
case ScribbleActivity.SCRIBBLE_REQUEST_CODE:
|
||||
setAvatarView(data.getData());
|
||||
break;
|
||||
|
||||
case Crop.REQUEST_CROP:
|
||||
setAvatarView(Crop.getOutput(data));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -375,11 +352,14 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
|
||||
.diskCacheStrategy(DiskCacheStrategy.NONE)
|
||||
.centerCrop()
|
||||
.override(AVATAR_SIZE, AVATAR_SIZE)
|
||||
.into(new SimpleTarget<Bitmap>() {
|
||||
.into(new CustomTarget<Bitmap>() {
|
||||
@Override
|
||||
public void onResourceReady(@NonNull Bitmap resource, Transition<? super Bitmap> transition) {
|
||||
setAvatar(output, resource);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadCleared(@Nullable Drawable placeholder) {}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,18 +1,22 @@
|
||||
package org.thoughtcrime.securesms;
|
||||
|
||||
import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_PROXY_ENABLED;
|
||||
import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_PROXY_URL;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.text.util.Linkify;
|
||||
import android.util.Log;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
@@ -30,12 +34,13 @@ import androidx.loader.app.LoaderManager;
|
||||
import com.b44t.messenger.DcContext;
|
||||
import com.b44t.messenger.DcEvent;
|
||||
import com.b44t.messenger.DcLot;
|
||||
import com.b44t.messenger.rpc.Rpc;
|
||||
import com.b44t.messenger.rpc.RpcException;
|
||||
import com.bumptech.glide.load.engine.DiskCacheStrategy;
|
||||
import com.bumptech.glide.request.target.CustomTarget;
|
||||
import com.bumptech.glide.request.transition.Transition;
|
||||
import com.google.zxing.integration.android.IntentIntegrator;
|
||||
import com.google.zxing.integration.android.IntentResult;
|
||||
import com.soundcloud.android.crop.Crop;
|
||||
|
||||
import org.thoughtcrime.securesms.components.AvatarSelector;
|
||||
import org.thoughtcrime.securesms.connect.AccountManager;
|
||||
@@ -47,8 +52,10 @@ import org.thoughtcrime.securesms.mms.GlideApp;
|
||||
import org.thoughtcrime.securesms.permissions.Permissions;
|
||||
import org.thoughtcrime.securesms.profiles.AvatarHelper;
|
||||
import org.thoughtcrime.securesms.profiles.ProfileMediaConstraints;
|
||||
import org.thoughtcrime.securesms.proxy.ProxySettingsActivity;
|
||||
import org.thoughtcrime.securesms.qr.RegistrationQrActivity;
|
||||
import org.thoughtcrime.securesms.scribbles.ScribbleActivity;
|
||||
import org.thoughtcrime.securesms.util.IntentUtils;
|
||||
import org.thoughtcrime.securesms.util.Prefs;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.thoughtcrime.securesms.util.views.ProgressDialog;
|
||||
@@ -64,7 +71,7 @@ public class InstantOnboardingActivity extends BaseActionBarActivity implements
|
||||
private static final String DCACCOUNT = "dcaccount";
|
||||
private static final String DCLOGIN = "dclogin";
|
||||
private static final String INSTANCES_URL = "https://delta.chat/chatmail";
|
||||
private static final String DEFAULT_CHATMAIL_HOST = "nine.testrun.org";
|
||||
private static final String DEFAULT_CHATMAIL_HOST = "arcanechat.me";
|
||||
|
||||
public static final String QR_ACCOUNT_EXTRA = "qr_account_extra";
|
||||
public static final String FROM_WELCOME = "from_welcome";
|
||||
@@ -83,7 +90,7 @@ public class InstantOnboardingActivity extends BaseActionBarActivity implements
|
||||
|
||||
private AttachmentManager attachmentManager;
|
||||
private Bitmap avatarBmp;
|
||||
private ProgressDialog progressDialog;
|
||||
private @Nullable ProgressDialog progressDialog;
|
||||
private DcContext dcContext;
|
||||
|
||||
@Override
|
||||
@@ -132,13 +139,37 @@ public class InstantOnboardingActivity extends BaseActionBarActivity implements
|
||||
handleIntent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPrepareOptionsMenu(Menu menu) {
|
||||
menu.clear();
|
||||
getMenuInflater().inflate(R.menu.instant_onboarding_menu, menu);
|
||||
MenuItem proxyItem = menu.findItem(R.id.menu_proxy_settings);
|
||||
if (TextUtils.isEmpty(DcHelper.get(this, CONFIG_PROXY_URL))) {
|
||||
proxyItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
|
||||
} else {
|
||||
boolean proxyEnabled = DcHelper.getInt(this, CONFIG_PROXY_ENABLED) == 1;
|
||||
proxyItem.setIcon(proxyEnabled? R.drawable.ic_proxy_enabled_24 : R.drawable.ic_proxy_disabled_24);
|
||||
proxyItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
|
||||
}
|
||||
return super.onPrepareOptionsMenu(menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
|
||||
super.onOptionsItemSelected(item);
|
||||
if (item.getItemId() == android.R.id.home) {
|
||||
|
||||
int itemId = item.getItemId();
|
||||
if (itemId == android.R.id.home) {
|
||||
getOnBackPressedDispatcher().onBackPressed();
|
||||
return true;
|
||||
} else if (itemId == R.id.menu_proxy_settings) {
|
||||
startActivity(new Intent(this, ProxySettingsActivity.class));
|
||||
return true;
|
||||
} else if (itemId == R.id.menu_view_log) {
|
||||
startActivity(new Intent(this, LogViewActivity.class));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -160,14 +191,16 @@ public class InstantOnboardingActivity extends BaseActionBarActivity implements
|
||||
setAvatarView(data.getData());
|
||||
break;
|
||||
|
||||
case Crop.REQUEST_CROP:
|
||||
setAvatarView(Crop.getOutput(data));
|
||||
break;
|
||||
|
||||
case IntentIntegrator.REQUEST_CODE:
|
||||
IntentResult scanResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, data);
|
||||
if (scanResult != null && scanResult.getFormatName() != null) {
|
||||
setProviderFromQr(scanResult.getContents());
|
||||
String qrRaw = data.getStringExtra(RegistrationQrActivity.QRDATA_EXTRA);
|
||||
if (qrRaw == null) {
|
||||
IntentResult scanResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, data);
|
||||
if (scanResult != null && scanResult.getFormatName() != null) {
|
||||
qrRaw = scanResult.getContents();
|
||||
}
|
||||
}
|
||||
if (qrRaw != null) {
|
||||
setProviderFromQr(qrRaw);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -209,20 +242,32 @@ public class InstantOnboardingActivity extends BaseActionBarActivity implements
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
|
||||
final String displayName = name.getText().toString();
|
||||
DcHelper.set(this, DcHelper.CONFIG_DISPLAY_NAME, TextUtils.isEmpty(displayName)? null : displayName);
|
||||
// Save display name and avatar in the unconfigured profile.
|
||||
// If the currently selected profile is configured, then this means that rollbackAccountCreation()
|
||||
// was called (see handleOnBackPressed() above), i.e. the newly created profile was removed already
|
||||
// and we can't save the display name & avatar.
|
||||
if (DcHelper.getContext(this).isConfigured() == 0) {
|
||||
final String displayName = name.getText().toString();
|
||||
DcHelper.set(this, DcHelper.CONFIG_DISPLAY_NAME, TextUtils.isEmpty(displayName) ? null : displayName);
|
||||
|
||||
if (avatarChanged) {
|
||||
try {
|
||||
AvatarHelper.setSelfAvatar(InstantOnboardingActivity.this, avatarBmp);
|
||||
Prefs.setProfileAvatarId(InstantOnboardingActivity.this, new SecureRandom().nextInt());
|
||||
avatarChanged = false;
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Failed to save avatar", e);
|
||||
if (avatarChanged) {
|
||||
try {
|
||||
AvatarHelper.setSelfAvatar(InstantOnboardingActivity.this, avatarBmp);
|
||||
Prefs.setProfileAvatarId(InstantOnboardingActivity.this, new SecureRandom().nextInt());
|
||||
avatarChanged = false;
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Failed to save avatar", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
invalidateOptionsMenu();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
@@ -284,38 +329,21 @@ public class InstantOnboardingActivity extends BaseActionBarActivity implements
|
||||
|
||||
privacyPolicyBtn.setOnClickListener(view -> {
|
||||
if (!isDcLogin) {
|
||||
WebViewActivity.openUrlInBrowser(this, "https://" + providerHost + "/privacy.html");
|
||||
IntentUtils.showInBrowser(this, "https://" + providerHost + "/privacy.html");
|
||||
}
|
||||
});
|
||||
|
||||
signUpBtn.setOnClickListener(view -> createProfile());
|
||||
|
||||
Button otherOptionsBtn = findViewById(R.id.other_options_button);
|
||||
otherOptionsBtn.setOnClickListener(view -> showOtherOptionsDialog());
|
||||
}
|
||||
|
||||
private void showOtherOptionsDialog() {
|
||||
View view = View.inflate(this, R.layout.signup_options_view, null);
|
||||
AlertDialog signUpDialog = new AlertDialog.Builder(this)
|
||||
.setView(view)
|
||||
.setTitle(R.string.instant_onboarding_show_more_instances)
|
||||
.setNegativeButton(R.string.cancel, null)
|
||||
.create();
|
||||
|
||||
view.findViewById(R.id.use_other_server).setOnClickListener((v) -> {
|
||||
WebViewActivity.openUrlInBrowser(this, INSTANCES_URL);
|
||||
signUpDialog.dismiss();
|
||||
findViewById(R.id.use_other_server).setOnClickListener((v) -> {
|
||||
IntentUtils.showInBrowser(this, INSTANCES_URL);
|
||||
});
|
||||
view.findViewById(R.id.login_button).setOnClickListener((v) -> {
|
||||
findViewById(R.id.login_button).setOnClickListener((v) -> {
|
||||
startRegistrationActivity();
|
||||
signUpDialog.dismiss();
|
||||
});
|
||||
view.findViewById(R.id.scan_qr_button).setOnClickListener((v) -> {
|
||||
findViewById(R.id.scan_qr_button).setOnClickListener((v) -> {
|
||||
new IntentIntegrator(this).setCaptureActivity(RegistrationQrActivity.class).initiateScan();
|
||||
signUpDialog.dismiss();
|
||||
});
|
||||
|
||||
signUpDialog.show();
|
||||
}
|
||||
|
||||
private void startRegistrationActivity() {
|
||||
@@ -330,7 +358,11 @@ public class InstantOnboardingActivity extends BaseActionBarActivity implements
|
||||
privacyPolicyBtn.setText(getString(R.string.qrlogin_ask_login, providerHost));
|
||||
} else {
|
||||
signUpBtn.setText(R.string.instant_onboarding_create);
|
||||
privacyPolicyBtn.setTextColor(getResources().getColor(R.color.def_accent));
|
||||
|
||||
try (TypedArray typedArray = obtainStyledAttributes(new int[]{R.attr.colorAccent})) {
|
||||
privacyPolicyBtn.setTextColor(typedArray.getColor(0, Color.BLACK));
|
||||
}
|
||||
|
||||
if (DEFAULT_CHATMAIL_HOST.equals(providerHost)) {
|
||||
privacyPolicyBtn.setText(getString(R.string.instant_onboarding_agree_default2, providerHost));
|
||||
} else {
|
||||
@@ -367,31 +399,34 @@ public class InstantOnboardingActivity extends BaseActionBarActivity implements
|
||||
|
||||
if (eventId == DcContext.DC_EVENT_CONFIGURE_PROGRESS) {
|
||||
long progress = event.getData1Int();
|
||||
if (progress==0/*error/aborted*/) {
|
||||
progressError(event.getData2Str());
|
||||
} else if (progress<1000/*progress in permille*/) {
|
||||
progressUpdate((int)progress);
|
||||
} else if (progress==1000/*done*/) {
|
||||
DcHelper.getAccounts(this).startIo();
|
||||
dcContext.assumeSingleDevice();
|
||||
progressSuccess();
|
||||
}
|
||||
progressUpdate((int)progress);
|
||||
}
|
||||
}
|
||||
|
||||
private void progressUpdate(int progress) {
|
||||
int percent = progress / 10;
|
||||
progressDialog.setMessage(getResources().getString(R.string.one_moment)+String.format(" %d%%", percent));
|
||||
if (progressDialog != null) {
|
||||
progressDialog.setMessage(getResources().getString(R.string.one_moment)+String.format(" %d%%", percent));
|
||||
}
|
||||
}
|
||||
|
||||
private void progressError(String data2) {
|
||||
progressDialog.dismiss();
|
||||
maybeShowConfigurationError(this, data2);
|
||||
if (progressDialog != null) {
|
||||
try {
|
||||
progressDialog.dismiss();
|
||||
} catch (IllegalArgumentException e) {
|
||||
// see https://stackoverflow.com/a/5102572/4557005
|
||||
Log.w(TAG, e);
|
||||
}
|
||||
}
|
||||
WelcomeActivity.maybeShowConfigurationError(this, data2);
|
||||
}
|
||||
|
||||
private void progressSuccess() {
|
||||
DcHelper.getEventCenter(this).endCaptureNextError();
|
||||
progressDialog.dismiss();
|
||||
if (progressDialog != null) {
|
||||
progressDialog.dismiss();
|
||||
}
|
||||
|
||||
Intent intent = new Intent(getApplicationContext(), ConversationListActivity.class);
|
||||
intent.putExtra(ConversationListActivity.FROM_WELCOME, true);
|
||||
@@ -399,22 +434,6 @@ public class InstantOnboardingActivity extends BaseActionBarActivity implements
|
||||
finishAffinity();
|
||||
}
|
||||
|
||||
public static void maybeShowConfigurationError(Activity activity, String data2) {
|
||||
if (data2 != null && !data2.isEmpty()) {
|
||||
AlertDialog d = new AlertDialog.Builder(activity)
|
||||
.setMessage(data2)
|
||||
.setPositiveButton(android.R.string.ok, null)
|
||||
.create();
|
||||
d.show();
|
||||
try {
|
||||
//noinspection ConstantConditions
|
||||
Linkify.addLinks((TextView) d.findViewById(android.R.id.message), Linkify.WEB_URLS | Linkify.EMAIL_ADDRESSES);
|
||||
} catch(NullPointerException e) {
|
||||
Log.e(TAG, "Linkify failed", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
private void createProfile() {
|
||||
if (TextUtils.isEmpty(this.name.getText())) {
|
||||
@@ -475,14 +494,13 @@ public class InstantOnboardingActivity extends BaseActionBarActivity implements
|
||||
DcHelper.getEventCenter(this).captureNextError();
|
||||
|
||||
new Thread(() -> {
|
||||
if (!dcContext.setConfigFromQr(qrCode)) {
|
||||
Util.runOnMain(() -> {
|
||||
progressError(dcContext.getLastError());
|
||||
});
|
||||
return;
|
||||
}
|
||||
DcHelper.getAccounts(this).stopIo();
|
||||
dcContext.configure();
|
||||
Rpc rpc = DcHelper.getRpc(this);
|
||||
try {
|
||||
rpc.addTransportFromQr(dcContext.getAccountId(), qrCode);
|
||||
progressSuccess();
|
||||
} catch (RpcException e) {
|
||||
Util.runOnMain(() -> progressError(e.getMessage()));
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
|
||||
@@ -57,22 +57,22 @@ public class LocalHelpActivity extends WebViewActivity
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
super.onOptionsItemSelected(item);
|
||||
switch (item.getItemId()) {
|
||||
case R.id.log_scroll_up:
|
||||
webView.scrollTo(0, 0);
|
||||
return true;
|
||||
case R.id.learn_more:
|
||||
openOnlineUrl("https://delta.chat");
|
||||
return true;
|
||||
case R.id.privacy_policy:
|
||||
openOnlineUrl("https://delta.chat/gdpr");
|
||||
return true;
|
||||
case R.id.contribute:
|
||||
openOnlineUrl("https://github.com/deltachat/deltachat-android");
|
||||
return true;
|
||||
case R.id.report_issue:
|
||||
openOnlineUrl("https://github.com/deltachat/deltachat-android/issues");
|
||||
return true;
|
||||
int itemId = item.getItemId();
|
||||
if (itemId == R.id.log_scroll_up) {
|
||||
webView.scrollTo(0, 0);
|
||||
return true;
|
||||
} else if (itemId == R.id.learn_more) {
|
||||
openOnlineUrl("https://arcanechat.me");
|
||||
return true;
|
||||
} else if (itemId == R.id.privacy_policy) {
|
||||
openOnlineUrl("https://arcanechat.me/privacy.html");
|
||||
return true;
|
||||
} else if (itemId == R.id.contribute) {
|
||||
openOnlineUrl("https://arcanechat.me/#contribute");
|
||||
return true;
|
||||
} else if (itemId == R.id.report_issue) {
|
||||
openOnlineUrl("https://github.com/ArcaneChat/android/issues");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -54,42 +54,42 @@ public class LogViewActivity extends BaseActionBarActivity {
|
||||
super.onOptionsItemSelected(item);
|
||||
Float newSize;
|
||||
|
||||
switch (item.getItemId()) {
|
||||
case android.R.id.home:
|
||||
finish();
|
||||
return true;
|
||||
case R.id.save_log:
|
||||
Permissions.with(this)
|
||||
.request(Manifest.permission.WRITE_EXTERNAL_STORAGE)
|
||||
.alwaysGrantOnSdk30()
|
||||
.ifNecessary()
|
||||
.onAllGranted(() -> {
|
||||
File outputDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
|
||||
boolean success = logViewFragment.saveLogFile(outputDir) != null;
|
||||
new AlertDialog.Builder(this)
|
||||
.setMessage(success? R.string.pref_saved_log : R.string.pref_save_log_failed)
|
||||
.setPositiveButton(android.R.string.ok, null)
|
||||
.show();
|
||||
})
|
||||
.execute();
|
||||
return true;
|
||||
case R.id.share_log:
|
||||
shareLog();
|
||||
return true;
|
||||
case R.id.log_zoom_in:
|
||||
newSize = logViewFragment.getLogTextSize() + 2.0f;
|
||||
logViewFragment.setLogTextSize(newSize);
|
||||
return false;
|
||||
case R.id.log_zoom_out:
|
||||
newSize = logViewFragment.getLogTextSize() - 2.0f;
|
||||
logViewFragment.setLogTextSize(newSize);
|
||||
return false;
|
||||
case R.id.log_scroll_down:
|
||||
logViewFragment.scrollDownLog();
|
||||
return false;
|
||||
case R.id.log_scroll_up:
|
||||
logViewFragment.scrollUpLog();
|
||||
return false;
|
||||
int itemId = item.getItemId();
|
||||
if (itemId == android.R.id.home) {
|
||||
finish();
|
||||
return true;
|
||||
} else if (itemId == R.id.save_log) {
|
||||
Permissions.with(this)
|
||||
.request(Manifest.permission.WRITE_EXTERNAL_STORAGE)
|
||||
.alwaysGrantOnSdk30()
|
||||
.ifNecessary()
|
||||
.onAllGranted(() -> {
|
||||
File outputDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
|
||||
boolean success = logViewFragment.saveLogFile(outputDir) != null;
|
||||
new AlertDialog.Builder(this)
|
||||
.setMessage(success ? R.string.pref_saved_log : R.string.pref_save_log_failed)
|
||||
.setPositiveButton(android.R.string.ok, null)
|
||||
.show();
|
||||
})
|
||||
.execute();
|
||||
return true;
|
||||
} else if (itemId == R.id.share_log) {
|
||||
shareLog();
|
||||
return true;
|
||||
} else if (itemId == R.id.log_zoom_in) {
|
||||
newSize = logViewFragment.getLogTextSize() + 2.0f;
|
||||
logViewFragment.setLogTextSize(newSize);
|
||||
return false;
|
||||
} else if (itemId == R.id.log_zoom_out) {
|
||||
newSize = logViewFragment.getLogTextSize() - 2.0f;
|
||||
logViewFragment.setLogTextSize(newSize);
|
||||
return false;
|
||||
} else if (itemId == R.id.log_scroll_down) {
|
||||
logViewFragment.scrollDownLog();
|
||||
return false;
|
||||
} else if (itemId == R.id.log_scroll_up) {
|
||||
logViewFragment.scrollUpLog();
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
@@ -17,14 +17,13 @@
|
||||
|
||||
package org.thoughtcrime.securesms;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.Manifest;
|
||||
import android.app.ActivityManager;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Build;
|
||||
import android.os.Build.VERSION;
|
||||
import android.os.Build.VERSION_CODES;
|
||||
import android.os.Bundle;
|
||||
import android.os.PowerManager;
|
||||
import android.text.TextUtils;
|
||||
@@ -35,6 +34,7 @@ import android.view.ViewGroup;
|
||||
import android.widget.EditText;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.content.PermissionChecker;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.b44t.messenger.DcContext;
|
||||
@@ -195,12 +195,11 @@ public class LogViewFragment extends Fragment {
|
||||
asMegs(info.maxMemory()));
|
||||
}
|
||||
|
||||
@TargetApi(VERSION_CODES.KITKAT)
|
||||
public static String getMemoryClass(Context context) {
|
||||
ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
|
||||
String lowMem = "";
|
||||
|
||||
if (VERSION.SDK_INT >= VERSION_CODES.KITKAT && activityManager.isLowRamDevice()) {
|
||||
if (activityManager.isLowRamDevice()) {
|
||||
lowMem = ", low-mem device";
|
||||
}
|
||||
return activityManager.getMemoryClass() + lowMem;
|
||||
@@ -250,9 +249,14 @@ public class LogViewFragment extends Fragment {
|
||||
|
||||
Locale locale = Util.getLocale();
|
||||
builder.append("lang=").append(locale.toString()).append("\n");
|
||||
if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
boolean isRtl = Util.getLayoutDirection(context) == View.LAYOUT_DIRECTION_RTL;
|
||||
builder.append("rtl=").append(isRtl).append("\n");
|
||||
boolean isRtl = Util.getLayoutDirection(context) == View.LAYOUT_DIRECTION_RTL;
|
||||
builder.append("rtl=").append(isRtl).append("\n");
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
boolean notifPermGranted = PermissionChecker.checkSelfPermission(context, Manifest.permission.POST_NOTIFICATIONS) == PermissionChecker.PERMISSION_GRANTED;
|
||||
builder.append("post-notifications-granted=").append(notifPermGranted).append("\n");
|
||||
} else {
|
||||
builder.append("post-notifications-granted=<not needed>").append("\n");
|
||||
}
|
||||
|
||||
final String token = FcmReceiveService.getToken();
|
||||
|
||||
@@ -16,9 +16,9 @@
|
||||
*/
|
||||
package org.thoughtcrime.securesms;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.Manifest;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
@@ -207,7 +207,7 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity
|
||||
messageRecord = null;
|
||||
long date = getIntent().getLongExtra(DATE_EXTRA, 0);
|
||||
long size = getIntent().getLongExtra(SIZE_EXTRA, 0);
|
||||
initialMedia = new MediaItem(null, getIntent().getData(), getIntent().getType(),
|
||||
initialMedia = new MediaItem(null, getIntent().getData(), null, getIntent().getType(),
|
||||
DcMsg.DC_MSG_NO_ID, date, size, false);
|
||||
|
||||
if (address != null) {
|
||||
@@ -218,7 +218,7 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity
|
||||
} else {
|
||||
messageRecord = dcContext.getMsg(msgId);
|
||||
initialMedia = new MediaItem(Recipient.fromChat(context, msgId), Uri.fromFile(messageRecord.getFileAsFile()),
|
||||
messageRecord.getFilemime(), messageRecord.getId(), messageRecord.getDateReceived(),
|
||||
messageRecord.getFilename(), messageRecord.getFilemime(), messageRecord.getId(), messageRecord.getDateReceived(),
|
||||
messageRecord.getFilebytes(), messageRecord.isOutgoing());
|
||||
conversationRecipient = Recipient.fromChat(context, msgId);
|
||||
}
|
||||
@@ -232,12 +232,11 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity
|
||||
// if you search for the place where the media are loaded, go to 'onCreateLoader'.
|
||||
|
||||
Log.w(TAG, "Loading Part URI: " + initialMedia);
|
||||
|
||||
if (messageRecord != null) {
|
||||
getSupportLoaderManager().restartLoader(0, null, this);
|
||||
} else {
|
||||
mediaPager.setAdapter(new SingleItemPagerAdapter(this, GlideApp.with(this),
|
||||
getWindow(), initialMedia.uri, initialMedia.type, initialMedia.size));
|
||||
getWindow(), initialMedia.uri, initialMedia.name, initialMedia.type, initialMedia.size));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -313,7 +312,7 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity
|
||||
private void performSavetoDisk(@NonNull MediaItem mediaItem) {
|
||||
SaveAttachmentTask saveTask = new SaveAttachmentTask(MediaPreviewActivity.this);
|
||||
long saveDate = (mediaItem.date > 0) ? mediaItem.date : System.currentTimeMillis();
|
||||
saveTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, new Attachment(mediaItem.uri, mediaItem.type, saveDate, null));
|
||||
saveTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, new Attachment(mediaItem.uri, mediaItem.type, saveDate, mediaItem.name));
|
||||
}
|
||||
|
||||
private void showInChat() {
|
||||
@@ -346,27 +345,32 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity
|
||||
DcChat dcChat = dcContext.getChat(dcMsg.getChatId());
|
||||
|
||||
String text = getResources().getQuantityString(
|
||||
dcChat.isDeviceTalk()? R.plurals.ask_delete_messages_simple : R.plurals.ask_delete_messages,
|
||||
dcChat.isDeviceTalk() ? R.plurals.ask_delete_messages_simple : R.plurals.ask_delete_messages,
|
||||
1, 1);
|
||||
int positiveBtnLabel = dcChat.isSelfTalk() ? R.string.delete : R.string.delete_for_me;
|
||||
final int[] messageIds = new int[]{mediaItem.msgId};
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||
builder.setMessage(text);
|
||||
builder.setCancelable(true);
|
||||
|
||||
builder.setPositiveButton(R.string.delete, (dialogInterface, which) -> {
|
||||
new AsyncTask<Void, Void, Void>() {
|
||||
@Override
|
||||
protected Void doInBackground(Void... voids) {
|
||||
dcContext.deleteMsgs(new int[]{mediaItem.msgId});
|
||||
return null;
|
||||
}
|
||||
}.execute();
|
||||
|
||||
builder.setNeutralButton(android.R.string.cancel, null);
|
||||
builder.setPositiveButton(positiveBtnLabel, (dialogInterface, which) -> {
|
||||
Util.runOnAnyBackgroundThread(() -> dcContext.deleteMsgs(messageIds));
|
||||
finish();
|
||||
});
|
||||
builder.setNegativeButton(android.R.string.cancel, null);
|
||||
AlertDialog dialog = builder.show();
|
||||
Util.redPositiveButton(dialog);
|
||||
|
||||
if(dcChat.canSend() && !dcChat.isSelfTalk() && dcMsg.isOutgoing()) {
|
||||
builder.setNegativeButton(R.string.delete_for_everyone, (d, which) -> {
|
||||
Util.runOnAnyBackgroundThread(() -> dcContext.sendDeleteRequest(messageIds));
|
||||
finish();
|
||||
});
|
||||
AlertDialog dialog = builder.show();
|
||||
Util.redButton(dialog, AlertDialog.BUTTON_NEGATIVE);
|
||||
Util.redPositiveButton(dialog);
|
||||
} else {
|
||||
AlertDialog dialog = builder.show();
|
||||
Util.redPositiveButton(dialog);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -396,14 +400,28 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
super.onOptionsItemSelected(item);
|
||||
|
||||
switch (item.getItemId()) {
|
||||
case R.id.media_preview__edit: editAvatar(); return true;
|
||||
case R.id.media_preview__overview: showOverview(); return true;
|
||||
case R.id.media_preview__share: share(); return true;
|
||||
case R.id.save: saveToDisk(); return true;
|
||||
case R.id.delete: deleteMedia(); return true;
|
||||
case R.id.show_in_chat: showInChat(); return true;
|
||||
case android.R.id.home: finish(); return true;
|
||||
int itemId = item.getItemId();
|
||||
if (itemId == R.id.media_preview__edit) {
|
||||
editAvatar();
|
||||
return true;
|
||||
} else if (itemId == R.id.media_preview__overview) {
|
||||
showOverview();
|
||||
return true;
|
||||
} else if (itemId == R.id.media_preview__share) {
|
||||
share();
|
||||
return true;
|
||||
} else if (itemId == R.id.save) {
|
||||
saveToDisk();
|
||||
return true;
|
||||
} else if (itemId == R.id.delete) {
|
||||
deleteMedia();
|
||||
return true;
|
||||
} else if (itemId == R.id.show_in_chat) {
|
||||
showInChat();
|
||||
return true;
|
||||
} else if (itemId == android.R.id.home) {
|
||||
finish();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -473,9 +491,12 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity
|
||||
MediaItemAdapter adapter = (MediaItemAdapter)mediaPager.getAdapter();
|
||||
|
||||
if (adapter != null) {
|
||||
MediaItem item = adapter.getMediaItemFor(position);
|
||||
if (item.recipient != null) item.recipient.removeListener(MediaPreviewActivity.this);
|
||||
|
||||
try {
|
||||
MediaItem item = adapter.getMediaItemFor(position);
|
||||
if (item.recipient != null) item.recipient.removeListener(MediaPreviewActivity.this);
|
||||
} catch (IllegalArgumentException e) {
|
||||
Log.w(TAG, "Ignoring invalid position index");
|
||||
}
|
||||
adapter.pause(position);
|
||||
}
|
||||
}
|
||||
@@ -486,18 +507,20 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity
|
||||
private final GlideRequests glideRequests;
|
||||
private final Window window;
|
||||
private final Uri uri;
|
||||
private final String name;
|
||||
private final String mediaType;
|
||||
private final long size;
|
||||
|
||||
private final LayoutInflater inflater;
|
||||
|
||||
SingleItemPagerAdapter(@NonNull Context context, @NonNull GlideRequests glideRequests,
|
||||
@NonNull Window window, @NonNull Uri uri, @NonNull String mediaType,
|
||||
@NonNull Window window, @NonNull Uri uri, @Nullable String name, @NonNull String mediaType,
|
||||
long size)
|
||||
{
|
||||
this.glideRequests = glideRequests;
|
||||
this.window = window;
|
||||
this.uri = uri;
|
||||
this.name = name;
|
||||
this.mediaType = mediaType;
|
||||
this.size = size;
|
||||
this.inflater = LayoutInflater.from(context);
|
||||
@@ -519,7 +542,7 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity
|
||||
MediaView mediaView = itemView.findViewById(R.id.media_view);
|
||||
|
||||
try {
|
||||
mediaView.set(glideRequests, window, uri, mediaType, size, true);
|
||||
mediaView.set(glideRequests, window, uri, name, mediaType, size, true);
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, e);
|
||||
}
|
||||
@@ -539,7 +562,7 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity
|
||||
|
||||
@Override
|
||||
public MediaItem getMediaItemFor(int position) {
|
||||
return new MediaItem(null, uri, mediaType, DcMsg.DC_MSG_NO_ID, -1, -1, true);
|
||||
return new MediaItem(null, uri, name, mediaType, DcMsg.DC_MSG_NO_ID, -1, -1, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -604,7 +627,7 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity
|
||||
|
||||
try {
|
||||
//noinspection ConstantConditions
|
||||
mediaView.set(glideRequests, window, Uri.fromFile(msg.getFileAsFile()),
|
||||
mediaView.set(glideRequests, window, Uri.fromFile(msg.getFileAsFile()), msg.getFilename(),
|
||||
msg.getFilemime(), msg.getFilebytes(), autoplay);
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, e);
|
||||
@@ -633,6 +656,7 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity
|
||||
|
||||
return new MediaItem(Recipient.fromChat(context, msg.getId()),
|
||||
Uri.fromFile(msg.getFileAsFile()),
|
||||
msg.getFilename(),
|
||||
msg.getFilemime(),
|
||||
msg.getId(),
|
||||
msg.getDateReceived(),
|
||||
@@ -655,6 +679,7 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity
|
||||
private static class MediaItem {
|
||||
private final @Nullable Recipient recipient;
|
||||
private final @NonNull Uri uri;
|
||||
private final @Nullable String name;
|
||||
private final @NonNull String type;
|
||||
private final int msgId;
|
||||
private final long date;
|
||||
@@ -663,6 +688,7 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity
|
||||
|
||||
private MediaItem(@Nullable Recipient recipient,
|
||||
@NonNull Uri uri,
|
||||
@Nullable String name,
|
||||
@NonNull String type,
|
||||
int msgId,
|
||||
long date,
|
||||
@@ -671,6 +697,7 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity
|
||||
{
|
||||
this.recipient = recipient;
|
||||
this.uri = uri;
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
this.msgId = msgId;
|
||||
this.date = date;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.thoughtcrime.securesms;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
@@ -61,22 +62,46 @@ public abstract class MessageSelectorFragment
|
||||
}
|
||||
|
||||
protected void handleDeleteMessages(int chatId, final int[] messageIds) {
|
||||
DcChat dcChat = DcHelper.getContext(getActivity()).getChat(chatId);
|
||||
DcChat dcChat = dcContext.getChat(chatId);
|
||||
boolean canDeleteForAll = true;
|
||||
if (dcChat.canSend() && !dcChat.isSelfTalk()) {
|
||||
for(int msgId : messageIds) {
|
||||
DcMsg msg = dcContext.getMsg(msgId);
|
||||
if (!msg.isOutgoing() || msg.isInfo()) {
|
||||
canDeleteForAll = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
canDeleteForAll = false;
|
||||
}
|
||||
|
||||
String text = getActivity().getResources().getQuantityString(
|
||||
dcChat.isDeviceTalk()? R.plurals.ask_delete_messages_simple : R.plurals.ask_delete_messages,
|
||||
dcChat.isDeviceTalk() ? R.plurals.ask_delete_messages_simple : R.plurals.ask_delete_messages,
|
||||
messageIds.length, messageIds.length);
|
||||
int positiveBtnLabel = dcChat.isSelfTalk() ? R.string.delete : R.string.delete_for_me;
|
||||
|
||||
AlertDialog dialog = new AlertDialog.Builder(getActivity())
|
||||
.setMessage(text)
|
||||
.setCancelable(true)
|
||||
.setPositiveButton(R.string.delete, (d, which) -> {
|
||||
dcContext.deleteMsgs(messageIds);
|
||||
if (actionMode != null) actionMode.finish();
|
||||
})
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.show();
|
||||
Util.redPositiveButton(dialog);
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(requireActivity())
|
||||
.setMessage(text)
|
||||
.setCancelable(true)
|
||||
.setNeutralButton(android.R.string.cancel, null)
|
||||
.setPositiveButton(positiveBtnLabel, (d, which) -> {
|
||||
dcContext.deleteMsgs(messageIds);
|
||||
if (actionMode != null) actionMode.finish();
|
||||
});
|
||||
|
||||
if(canDeleteForAll) {
|
||||
builder.setNegativeButton(R.string.delete_for_everyone, (d, which) -> {
|
||||
Util.runOnAnyBackgroundThread(() -> dcContext.sendDeleteRequest(messageIds));
|
||||
if (actionMode != null) actionMode.finish();
|
||||
});
|
||||
AlertDialog dialog = builder.show();
|
||||
Util.redButton(dialog, AlertDialog.BUTTON_NEGATIVE);
|
||||
Util.redPositiveButton(dialog);
|
||||
} else {
|
||||
AlertDialog dialog = builder.show();
|
||||
Util.redPositiveButton(dialog);
|
||||
}
|
||||
}
|
||||
|
||||
protected void handleSaveAttachment(final Set<DcMsg> messageRecords) {
|
||||
@@ -121,15 +146,22 @@ public abstract class MessageSelectorFragment
|
||||
|
||||
protected void handleResendMessage(final Set<DcMsg> dcMsgsSet) {
|
||||
int[] ids = DcMsg.msgSetToIds(dcMsgsSet);
|
||||
if (dcContext.resendMsgs(ids)) {
|
||||
actionMode.finish();
|
||||
Toast.makeText(getContext(), R.string.sending, Toast.LENGTH_SHORT).show();
|
||||
} else {
|
||||
new AlertDialog.Builder(getContext())
|
||||
.setMessage(dcContext.getLastError())
|
||||
.setCancelable(false)
|
||||
.setPositiveButton(android.R.string.ok, null)
|
||||
.show();
|
||||
}
|
||||
Util.runOnAnyBackgroundThread(() -> {
|
||||
boolean success = dcContext.resendMsgs(ids);
|
||||
Util.runOnMain(() -> {
|
||||
Activity activity = getActivity();
|
||||
if (activity == null || activity.isFinishing()) return;
|
||||
if (success) {
|
||||
actionMode.finish();
|
||||
Toast.makeText(getContext(), R.string.sending, Toast.LENGTH_SHORT).show();
|
||||
} else {
|
||||
new AlertDialog.Builder(activity)
|
||||
.setMessage(dcContext.getLastError())
|
||||
.setCancelable(false)
|
||||
.setPositiveButton(android.R.string.ok, null)
|
||||
.show();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.thoughtcrime.securesms;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
|
||||
@@ -18,7 +19,7 @@ public class MuteDialog {
|
||||
// See https://c.delta.chat/classdc__context__t.html#a6460395925d49d2053bc95224bf5ce37.
|
||||
switch (which) {
|
||||
case 0: muteUntil = TimeUnit.HOURS.toSeconds(1); break;
|
||||
case 1: muteUntil = TimeUnit.HOURS.toSeconds(2); break;
|
||||
case 1: muteUntil = TimeUnit.HOURS.toSeconds(8); break;
|
||||
case 2: muteUntil = TimeUnit.DAYS.toSeconds(1); break;
|
||||
case 3: muteUntil = TimeUnit.DAYS.toSeconds(7); break;
|
||||
case 4: muteUntil = -1; break; // mute forever
|
||||
|
||||
@@ -16,12 +16,15 @@
|
||||
*/
|
||||
package org.thoughtcrime.securesms;
|
||||
|
||||
import static org.thoughtcrime.securesms.ConversationActivity.CHAT_ID_EXTRA;
|
||||
import static org.thoughtcrime.securesms.ConversationActivity.TEXT_EXTRA;
|
||||
import static org.thoughtcrime.securesms.util.RelayUtil.acquireRelayMessageContent;
|
||||
import static org.thoughtcrime.securesms.util.RelayUtil.isRelayingMessageContent;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.Menu;
|
||||
import android.view.View;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
@@ -36,11 +39,6 @@ import org.thoughtcrime.securesms.qr.QrActivity;
|
||||
import org.thoughtcrime.securesms.qr.QrCodeHandler;
|
||||
import org.thoughtcrime.securesms.util.MailtoUtil;
|
||||
|
||||
import static org.thoughtcrime.securesms.ConversationActivity.CHAT_ID_EXTRA;
|
||||
import static org.thoughtcrime.securesms.ConversationActivity.TEXT_EXTRA;
|
||||
import static org.thoughtcrime.securesms.util.RelayUtil.acquireRelayMessageContent;
|
||||
import static org.thoughtcrime.securesms.util.RelayUtil.isRelayingMessageContent;
|
||||
|
||||
/**
|
||||
* Activity container for starting a new conversation.
|
||||
*
|
||||
@@ -74,7 +72,17 @@ public class NewConversationActivity extends ContactSelectionActivity {
|
||||
if (!textToShare.isEmpty()) {
|
||||
getIntent().putExtra(TEXT_EXTRA, textToShare);
|
||||
}
|
||||
onContactSelected(DcContact.DC_CONTACT_ID_NEW_CLASSIC_CONTACT, recipientsArray[0]);
|
||||
final String addr = recipientsArray[0];
|
||||
final DcContext dcContext = DcHelper.getContext(this);
|
||||
int contactId = dcContext.lookupContactIdByAddr(addr);
|
||||
if (contactId == 0 && dcContext.mayBeValidAddr(addr)) {
|
||||
contactId = dcContext.createContact(null, recipientsArray[0]);
|
||||
}
|
||||
if (contactId == 0) {
|
||||
Toast.makeText(this, R.string.bad_email_address, Toast.LENGTH_LONG).show();
|
||||
} else {
|
||||
onContactSelected(contactId);
|
||||
}
|
||||
} else {
|
||||
Intent shareIntent = new Intent(this, ShareActivity.class);
|
||||
shareIntent.putExtra(Intent.EXTRA_TEXT, textToShare);
|
||||
@@ -96,39 +104,28 @@ public class NewConversationActivity extends ContactSelectionActivity {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onContactSelected(int specialId, String addr) {
|
||||
final DcContext dcContext = DcHelper.getContext(this);
|
||||
if(specialId == DcContact.DC_CONTACT_ID_NEW_GROUP) {
|
||||
public void onContactSelected(int contactId) {
|
||||
if(contactId == DcContact.DC_CONTACT_ID_NEW_GROUP) {
|
||||
startActivity(new Intent(this, GroupCreateActivity.class));
|
||||
} else if(specialId == DcContact.DC_CONTACT_ID_NEW_BROADCAST_LIST) {
|
||||
} else if(contactId == DcContact.DC_CONTACT_ID_NEW_BROADCAST_LIST) {
|
||||
Intent intent = new Intent(this, GroupCreateActivity.class);
|
||||
intent.putExtra(GroupCreateActivity.CREATE_BROADCAST, true);
|
||||
startActivity(intent);
|
||||
} else if (specialId == DcContact.DC_CONTACT_ID_QR_INVITE) {
|
||||
} else if (contactId == DcContact.DC_CONTACT_ID_QR_INVITE) {
|
||||
new IntentIntegrator(this).setCaptureActivity(QrActivity.class).initiateScan();
|
||||
}
|
||||
else {
|
||||
int contactId = dcContext.lookupContactIdByAddr(addr);
|
||||
if (contactId!=0 && dcContext.getChatIdByContactId(contactId)!=0) {
|
||||
final DcContext dcContext = DcHelper.getContext(this);
|
||||
if (dcContext.getChatIdByContactId(contactId)!=0) {
|
||||
openConversation(dcContext.getChatIdByContactId(contactId));
|
||||
} else if (contactId == 0 && dcContext.isChatmail()) {
|
||||
DcHelper.showEncryptionRequiredDialog(this, addr);
|
||||
} else {
|
||||
String nameNAddr = contactId == 0 ? addr : dcContext.getContact(contactId).getNameNAddr();
|
||||
String name = dcContext.getContact(contactId).getDisplayName();
|
||||
new AlertDialog.Builder(this)
|
||||
.setMessage(getString(R.string.ask_start_chat_with, nameNAddr))
|
||||
.setMessage(getString(R.string.ask_start_chat_with, name))
|
||||
.setCancelable(true)
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.setPositiveButton(android.R.string.ok, (dialog, which) -> {
|
||||
int contactId1 = dcContext.lookupContactIdByAddr(addr);
|
||||
if (contactId1 == 0) {
|
||||
contactId1 = dcContext.createContact(null, addr);
|
||||
if (contactId1 == 0) {
|
||||
Toast.makeText(NewConversationActivity.this, R.string.bad_email_address, Toast.LENGTH_LONG).show();
|
||||
return;
|
||||
}
|
||||
}
|
||||
openConversation(dcContext.createChatByContactId(contactId1));
|
||||
openConversation(dcContext.createChatByContactId(contactId));
|
||||
}).show();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,8 @@ import com.b44t.messenger.DcChat;
|
||||
import com.b44t.messenger.DcContact;
|
||||
import com.b44t.messenger.DcContext;
|
||||
import com.b44t.messenger.DcEvent;
|
||||
import com.b44t.messenger.rpc.Rpc;
|
||||
import com.b44t.messenger.rpc.RpcException;
|
||||
import com.google.android.material.tabs.TabLayout;
|
||||
|
||||
import org.thoughtcrime.securesms.connect.DcEventCenter;
|
||||
@@ -63,6 +65,7 @@ public class ProfileActivity extends PassphraseRequiredActionBarActivity
|
||||
private static final int REQUEST_CODE_PICK_RINGTONE = 1;
|
||||
|
||||
private DcContext dcContext;
|
||||
private Rpc rpc;
|
||||
private int chatId;
|
||||
private boolean chatIsMultiUser;
|
||||
private boolean chatIsDeviceTalk;
|
||||
@@ -82,6 +85,7 @@ public class ProfileActivity extends PassphraseRequiredActionBarActivity
|
||||
dynamicTheme = new DynamicNoActionBarTheme();
|
||||
super.onPreCreate();
|
||||
dcContext = DcHelper.getContext(this);
|
||||
rpc = DcHelper.getRpc(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -92,23 +96,25 @@ public class ProfileActivity extends PassphraseRequiredActionBarActivity
|
||||
|
||||
setSupportActionBar(this.toolbar);
|
||||
ActionBar supportActionBar = getSupportActionBar();
|
||||
if (isGlobalProfile()) {
|
||||
supportActionBar.setDisplayHomeAsUpEnabled(true);
|
||||
supportActionBar.setHomeActionContentDescription(getString(R.string.back));
|
||||
} else {
|
||||
supportActionBar.setDisplayHomeAsUpEnabled(false);
|
||||
supportActionBar.setCustomView(R.layout.conversation_title_view);
|
||||
supportActionBar.setDisplayShowCustomEnabled(true);
|
||||
supportActionBar.setDisplayShowTitleEnabled(false);
|
||||
Toolbar parent = (Toolbar) supportActionBar.getCustomView().getParent();
|
||||
parent.setPadding(0,0,0,0);
|
||||
parent.setContentInsetsAbsolute(0,0);
|
||||
if (supportActionBar != null) {
|
||||
if (isGlobalProfile()) {
|
||||
supportActionBar.setDisplayHomeAsUpEnabled(true);
|
||||
supportActionBar.setHomeActionContentDescription(getString(R.string.back));
|
||||
} else {
|
||||
supportActionBar.setDisplayHomeAsUpEnabled(false);
|
||||
supportActionBar.setCustomView(R.layout.conversation_title_view);
|
||||
supportActionBar.setDisplayShowCustomEnabled(true);
|
||||
supportActionBar.setDisplayShowTitleEnabled(false);
|
||||
Toolbar parent = (Toolbar) supportActionBar.getCustomView().getParent();
|
||||
parent.setPadding(0,0,0,0);
|
||||
parent.setContentInsetsAbsolute(0,0);
|
||||
|
||||
titleView = (ConversationTitleView) supportActionBar.getCustomView();
|
||||
titleView.setOnBackClickedListener(view -> onBackPressed());
|
||||
titleView.setOnClickListener(view -> onEnlargeAvatar());
|
||||
if (isContactProfile() && !isSelfProfile() && !chatIsDeviceTalk) {
|
||||
titleView.registerForContextMenu(this);
|
||||
titleView = (ConversationTitleView) supportActionBar.getCustomView();
|
||||
titleView.setOnBackClickedListener(view -> onBackPressed());
|
||||
titleView.setOnClickListener(view -> onEnlargeAvatar());
|
||||
if (isContactProfile() && !isSelfProfile() && !chatIsDeviceTalk) {
|
||||
titleView.registerForContextMenu(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,6 +159,7 @@ public class ProfileActivity extends PassphraseRequiredActionBarActivity
|
||||
menu.findItem(R.id.share).setVisible(false);
|
||||
}
|
||||
} else {
|
||||
menu.findItem(R.id.menu_clone).setVisible(false);
|
||||
canReceive = false;
|
||||
}
|
||||
|
||||
@@ -299,7 +306,7 @@ public class ProfileActivity extends PassphraseRequiredActionBarActivity
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPrimaryItem(ViewGroup container, int position, Object object) {
|
||||
public void setPrimaryItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
|
||||
super.setPrimaryItem(container, position, object);
|
||||
if (currentFragment != null && currentFragment != object) {
|
||||
ActionMode action = null;
|
||||
@@ -315,6 +322,7 @@ public class ProfileActivity extends PassphraseRequiredActionBarActivity
|
||||
currentFragment = object;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Fragment getItem(int position) {
|
||||
int tabId = tabs.get(position);
|
||||
@@ -412,50 +420,40 @@ public class ProfileActivity extends PassphraseRequiredActionBarActivity
|
||||
// =========================================================================
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
|
||||
super.onOptionsItemSelected(item);
|
||||
|
||||
switch (item.getItemId()) {
|
||||
case android.R.id.home:
|
||||
backPressed = true;
|
||||
finish();
|
||||
return true;
|
||||
case R.id.menu_mute_notifications:
|
||||
onNotifyOnOff();
|
||||
break;
|
||||
case R.id.menu_sound:
|
||||
onSoundSettings();
|
||||
break;
|
||||
case R.id.menu_vibrate:
|
||||
onVibrateSettings();
|
||||
break;
|
||||
case R.id.edit_name:
|
||||
onEditName();
|
||||
break;
|
||||
case R.id.share:
|
||||
onShare();
|
||||
break;
|
||||
case R.id.show_encr_info:
|
||||
onEncrInfo();
|
||||
break;
|
||||
case R.id.block_contact:
|
||||
onBlockContact();
|
||||
break;
|
||||
case R.id.menu_clone:
|
||||
onClone();
|
||||
break;
|
||||
int itemId = item.getItemId();
|
||||
if (itemId == android.R.id.home) {
|
||||
backPressed = true;
|
||||
finish();
|
||||
return true;
|
||||
} else if (itemId == R.id.menu_mute_notifications) {
|
||||
onNotifyOnOff();
|
||||
} else if (itemId == R.id.menu_sound) {
|
||||
onSoundSettings();
|
||||
} else if (itemId == R.id.menu_vibrate) {
|
||||
onVibrateSettings();
|
||||
} else if (itemId == R.id.edit_name) {
|
||||
onEditName();
|
||||
} else if (itemId == R.id.share) {
|
||||
onShare();
|
||||
} else if (itemId == R.id.show_encr_info) {
|
||||
onEncrInfo();
|
||||
} else if (itemId == R.id.block_contact) {
|
||||
onBlockContact();
|
||||
} else if (itemId == R.id.menu_clone) {
|
||||
onClone();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onContextItemSelected(MenuItem item) {
|
||||
public boolean onContextItemSelected(@NonNull MenuItem item) {
|
||||
super.onContextItemSelected(item);
|
||||
switch (item.getItemId()) {
|
||||
case R.id.copy_addr_to_clipboard:
|
||||
onCopyAddrToClipboard();
|
||||
break;
|
||||
if (item.getItemId() == R.id.copy_addr_to_clipboard) {
|
||||
onCopyAddrToClipboard();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -465,7 +463,7 @@ public class ProfileActivity extends PassphraseRequiredActionBarActivity
|
||||
setMuted(0);
|
||||
}
|
||||
else {
|
||||
MuteDialog.show(this, duration -> setMuted(duration));
|
||||
MuteDialog.show(this, this::setMuted);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -545,6 +543,7 @@ public class ProfileActivity extends PassphraseRequiredActionBarActivity
|
||||
}
|
||||
}
|
||||
else {
|
||||
int accountId = dcContext.getAccountId();
|
||||
DcContact dcContact = dcContext.getContact(contactId);
|
||||
|
||||
String authName = dcContact.getAuthName();
|
||||
@@ -564,7 +563,11 @@ public class ProfileActivity extends PassphraseRequiredActionBarActivity
|
||||
.setView(gl)
|
||||
.setPositiveButton(android.R.string.ok, (dialog, whichButton) -> {
|
||||
String newName = inputField.getText().toString();
|
||||
dcContext.createContact(newName, dcContact.getAddr());
|
||||
try {
|
||||
rpc.changeContactName(accountId, contactId, newName);
|
||||
} catch (RpcException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
})
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.setCancelable(false)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user