mirror of
https://github.com/ArcaneChat/android.git
synced 2026-07-03 14:05:24 +02:00
Compare commits
454 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 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 | |||
| 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 | |||
| 883536a3a5 | |||
| 23cbe63cd4 | |||
| 3013af2a7a | |||
| f0f53455a5 | |||
| d8b49f57a9 | |||
| 7eaaf3bbb4 | |||
| 7b52bb6c85 | |||
| 1439bc0a86 | |||
| 9a5415eb66 | |||
| 5da3748a6a | |||
| 2308feea8c | |||
| a3b0ee1ef9 | |||
| 4fa5f1f5c6 | |||
| f4701b92e2 | |||
| 6649165b56 | |||
| 1c9b5977a8 | |||
| 49471999b9 | |||
| 86a8fbf463 | |||
| 238ec5b299 | |||
| 4c810c2b50 | |||
| f4d5547da7 | |||
| 52850c25b0 | |||
| 5117e103bb | |||
| 056f9bd4fb | |||
| 877989b5c1 | |||
| eef8609a66 | |||
| b43685bcdf | |||
| 794062b9ed | |||
| 876721fae5 | |||
| 0fdac57c68 | |||
| b3375f4f19 | |||
| b607ca21ff | |||
| d6efa3c7e5 | |||
| e461e2f7f1 | |||
| 684f8834fa | |||
| b440a31820 | |||
| 568a3f383f | |||
| 6c212a5d3d | |||
| b6e43a6994 | |||
| d1f85e6dc4 | |||
| 74ef8dc1c6 | |||
| 1da2d35af4 | |||
| bb3f4a2e06 | |||
| 8e4c5d6b63 | |||
| 1b46edaddf | |||
| aa0c72356f | |||
| ee8fd429f4 | |||
| bc022f5196 | |||
| d4dcdcf3bd | |||
| 74b2369ca9 | |||
| 9eafdbd817 | |||
| 0a21d1d1b4 | |||
| b0cb6c73ba | |||
| b6367416e5 | |||
| 0b582dd287 | |||
| d5cf919bcb | |||
| 490f1efe36 | |||
| c125d4fa24 | |||
| 389098699a | |||
| df696e5fab | |||
| e8801d1b64 | |||
| 8bfc44c8ca | |||
| 36e963e717 | |||
| 9e8fcf8ed7 | |||
| 6412d25420 | |||
| a470366f03 | |||
| 1434ce6f57 | |||
| 654ba5b460 | |||
| e3835f70f7 | |||
| bbb803f91c | |||
| 6a4c73c821 | |||
| 853ce3c7a3 | |||
| d2ab4817b1 | |||
| 9ff1cafd5e | |||
| bf6b678e2b | |||
| 6c1f787a38 | |||
| b059741161 | |||
| fdd5cc5d4b | |||
| 77465b5802 | |||
| d17567029d | |||
| 4610a64732 | |||
| 0358e8ffcb | |||
| 406c263d82 | |||
| 6ed070e437 | |||
| 1e4cfa124e | |||
| c42ba0f599 | |||
| 8798275170 | |||
| ac6495ff20 | |||
| 8ae47e97cf | |||
| 6a1ff0bace | |||
| 047cd9a121 | |||
| 555547b6cc | |||
| 5fe355fe90 | |||
| 6af3b0d985 | |||
| 92d6147644 | |||
| 72fb9992a1 | |||
| e8413019ff | |||
| 289118e671 | |||
| 286a84b1d4 | |||
| 8c8c003f2b | |||
| a06e36993d | |||
| ce054d93a8 | |||
| cabc159cd8 | |||
| c78cbbe145 | |||
| a297c71a90 | |||
| 247de63362 | |||
| 20f7c7c616 | |||
| 6364903a28 | |||
| 48bb77cfae | |||
| 53bfe52797 | |||
| a8bc01e6c1 | |||
| 3fbccf3408 | |||
| 86656f1155 | |||
| 89473b8067 | |||
| 887f5881f0 | |||
| aee757e71c | |||
| 30d5eeeb45 | |||
| d2c2f2cf07 | |||
| f83d5a0dbb | |||
| c30ddf9c77 | |||
| e14b878aef | |||
| 9e3ebda12a | |||
| 4bb42b9995 | |||
| 59b158fe09 |
+1
-1
@@ -1,3 +1,3 @@
|
||||
ko_fi: adbenitez
|
||||
liberapay: adbenitez
|
||||
custom: "https://arcanechat.myspreadshop.net"
|
||||
custom: "https://arcanechat.me/#contribute"
|
||||
|
||||
@@ -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"
|
||||
@@ -64,7 +64,7 @@ jobs:
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
token: "${{ secrets.GITHUB_TOKEN }}"
|
||||
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-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/download/ArcaneChat-gplay.apk)'
|
||||
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,6 +1,65 @@
|
||||
# ArcaneChat Android Changelog
|
||||
# Delta Chat Android Changelog
|
||||
|
||||
## v1.52.1 Testrun
|
||||
## 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
|
||||
@@ -4,8 +4,6 @@ A [Delta Chat](https://delta.chat/) client for Android. Learn more at: https://a
|
||||
|
||||
[<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-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/download/ArcaneChat-gplay.apk)
|
||||
|
||||
|
||||
|
||||
+2
-2
@@ -25,7 +25,7 @@ the "update-core-and-stuff-DATE" PR can be merged without review
|
||||
the following steps are done in a PR called `prep-VERSION` (no leading "v"):
|
||||
|
||||
3. a) update `CHANGELOG.md`
|
||||
from <https://github.com/deltachat/deltachat-core-rust/blob/main/CHANGELOG.md>
|
||||
from <https://github.com/chatmail/core/blob/main/CHANGELOG.md>
|
||||
and <https://github.com/deltachat/deltachat-android/pulls?q=is%3Apr+is%3Aclosed+sort%3Aupdated-desc>.
|
||||
do not just copy and avoid technical terms.
|
||||
the changelog is for the end user and shall show impacts form that angle.
|
||||
@@ -114,7 +114,7 @@ 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" and "Step 3" pages, hit "Next"
|
||||
|
||||
+5
-6
@@ -33,8 +33,8 @@ android {
|
||||
useLibrary 'org.apache.http.legacy'
|
||||
|
||||
defaultConfig {
|
||||
versionCode 30000707
|
||||
versionName "1.52.1"
|
||||
versionCode 30000716
|
||||
versionName "1.56.0"
|
||||
|
||||
applicationId "chat.delta.lite"
|
||||
multiDexEnabled true
|
||||
@@ -233,11 +233,11 @@ dependencies {
|
||||
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:3.0.2' // APNG & animated webp support.
|
||||
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'
|
||||
@@ -252,11 +252,10 @@ 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.1.0') { // for PUSH notifications
|
||||
exclude group: 'com.google.firebase', module: 'firebase-core'
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
ArcaneChat is a decentralized and secure messenger app that is 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.
|
||||
|
||||
@@ -24,7 +24,7 @@ ArcaneChat is a Delta Chat client and was created with a focus on usability, goo
|
||||
<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>Location streaming feature enabled by default and 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>
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 171 KiB After Width: | Height: | Size: 137 KiB |
@@ -19,15 +19,18 @@
|
||||
cmdline-tools-latest
|
||||
platform-tools
|
||||
platforms-android-34
|
||||
ndk-27-0-11902837
|
||||
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/27.0.11902837";
|
||||
"${android-sdk}/share/android-sdk/ndk/27.2.12479018";
|
||||
buildInputs = [
|
||||
android-sdk
|
||||
pkgs.openjdk17
|
||||
|
||||
@@ -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
|
||||
|
||||
+39
-16
@@ -231,12 +231,6 @@ JNIEXPORT jboolean Java_com_b44t_messenger_DcAccounts_backgroundFetch(JNIEnv *en
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT jint Java_com_b44t_messenger_DcAccounts_addAccount(JNIEnv *env, jobject obj)
|
||||
{
|
||||
return dc_accounts_add_account(get_dc_accounts(env, obj));
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT jint Java_com_b44t_messenger_DcAccounts_migrateAccount(JNIEnv *env, jobject obj, jstring dbfile)
|
||||
{
|
||||
CHAR_REF(dbfile);
|
||||
@@ -659,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);
|
||||
@@ -683,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;
|
||||
@@ -691,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)
|
||||
{
|
||||
@@ -1642,16 +1660,6 @@ 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)
|
||||
{
|
||||
CHAR_REF(file);
|
||||
CHAR_REF(filemime);
|
||||
dc_msg_set_file(get_dc_msg(env, obj), filePtr, filemimePtr);
|
||||
CHAR_UNREF(filemime);
|
||||
CHAR_UNREF(file);
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT void Java_com_b44t_messenger_DcMsg_forceSticker(JNIEnv *env, jobject obj)
|
||||
{
|
||||
dc_msg_force_sticker(get_dc_msg(env, obj));
|
||||
@@ -1667,6 +1675,12 @@ JNIEXPORT jstring Java_com_b44t_messenger_DcMsg_getPOILocation(JNIEnv *env, jobj
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
@@ -1723,6 +1737,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)
|
||||
{
|
||||
|
||||
+1
-1
Submodule jni/deltachat-core-rust updated: e98f6a2c9b...ae0439885b
@@ -0,0 +1 @@
|
||||
Schreibe Nachrichten mit E-Mails. Retro, Offen. Privatsphäre im Design.
|
||||
@@ -1,7 +0,0 @@
|
||||
- nuovo inserimento: puoi creare un nuovo profilo con un tocco su "Crea Nuovo Profilo" - oppure utilizzare un accesso esistente o la configurazione del secondo dispositivo come al solito
|
||||
i contatti possono essere allegati come "Schede" in "Allega/Contatto"; quando il destinatario tocca le carte, è possibile stabilire la crittografia end-to-end garantita
|
||||
- aggiungi contatti manualmente in "Nuova Chat / Nuovo Contatto / Aggiungi Contatto Manualmente"
|
||||
- invia qualsiasi emoji come reazione
|
||||
- mostrare le reazioni nei riepiloghi
|
||||
- blocca/archivia/ecc. le chat direttamente dai risultati di ricerca
|
||||
- Risolti bug e altro ancora
|
||||
@@ -1,4 +0,0 @@
|
||||
- aggiungi un'opzione per contrassegnare tutte le chat selezionate come "Lette" (tocca a lungo una chat per avviare la modalità di selezione)
|
||||
- i nuovi profili chatmail per dispositivo singolo hanno come impostazione predefinita "Elimina Messaggi Dopo il Download"
|
||||
- quando si utilizza un profilo chatmail su più dispositivi, la cancellazione viene modificata in "Automatica" (la strategia di cancellazione dipende quindi dal server)
|
||||
- Risolti bug e altro ancora
|
||||
@@ -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,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;
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<html><head><meta charset="UTF-8" /><meta name="viewport" content="initial-scale=1.0" /><link rel="stylesheet" href="../help.css" /></head><body><ul id="top">
|
||||
<html lang="cs"><head><meta charset="UTF-8" /><meta name="viewport" content="initial-scale=1.0" /><link rel="stylesheet" href="../help.css" /></head><body><ul id="top">
|
||||
<li><a href="#co-je-delta-chat">Co je Delta Chat?</a>
|
||||
<ul>
|
||||
<li><a href="#jak-najít-lidi-k-hovoru">Jak najít lidi k hovoru?</a></li>
|
||||
@@ -890,7 +890,7 @@ and GnuPG (GPG), a command line tool implementing OpenPGP.
|
||||
Many public critiques of OpenPGP actually discuss GnuPG which Delta Chat has never used.
|
||||
Delta Chat rather uses the OpenPGP Rust implementation <a href="https://github.com/rpgp/rpgp">rPGP</a>,
|
||||
available as <a href="https://crates.io/crates/pgp">an independent “pgp” package</a>,
|
||||
and <a href="https://delta.chat/assets/blog/2019-first-security-review.pdf">security-audited in 2019</a>.</p>
|
||||
and <a href="#security-audits">security-audited in 2019 and 2024</a>.</p>
|
||||
|
||||
<p>We aim, along with other OpenPGP implementors,
|
||||
to further improve security characteristics by implementing the
|
||||
@@ -1198,10 +1198,25 @@ Pro ostatní programy by mělo jít nalézt řešení na Interentu.</p>
|
||||
|
||||
</h3>
|
||||
|
||||
<p>The Delta Chat project underwent four independent security audits and one
|
||||
independent security analysis, from most recent to older:</p>
|
||||
<p>Yes, multiple times.
|
||||
The Delta Chat project continuously undergoes independent security audits and analysis,
|
||||
from most recent to older:</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>2024 December, an <a href="https://github.com/rpgp/docs/blob/main/audits/NGI%20Core%20rPGP%20penetration%20test%20report%202024%201.0.pdf">NLNET-commissioned Evaluation of
|
||||
rPGP</a> by <a href="https://www.radicallyopensecurity.com/">Radically Open Security</a> took place.
|
||||
rPGP serves as the end-to-end encyption <a href="https://openpgp.org">OpenPGP</a> engine of Delta Chat.
|
||||
Two advisories were released related to the findings of this audit:</p>
|
||||
|
||||
<ul>
|
||||
<li><a href="https://github.com/rpgp/rpgp/security/advisories/GHSA-9rmp-2568-59rv">“Panics on Malformed Untrusted Input”</a> CVE-2024-53856</li>
|
||||
<li><a href="https://github.com/rpgp/rpgp/security/advisories/GHSA-4grw-m28r-q285">“Potential Resource Exhaustion when handling Untrusted Messages”</a> CVE-2024-53857</li>
|
||||
</ul>
|
||||
|
||||
<p>The issues outlined in these advisories have been fixed and are part of Delta Chat
|
||||
releases on all appstores since December 2024.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>2024 March, we received a deep security analysis from the Applied Cryptography
|
||||
research group at ETH Zuerich and addressed all raised issues.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<html><head><meta charset="UTF-8" /><meta name="viewport" content="initial-scale=1.0" /><link rel="stylesheet" href="../help.css" /></head><body><ul id="top">
|
||||
<html lang="de"><head><meta charset="UTF-8" /><meta name="viewport" content="initial-scale=1.0" /><link rel="stylesheet" href="../help.css" /></head><body><ul id="top">
|
||||
<li><a href="#was-ist-delta-chat">Was ist Delta Chat?</a>
|
||||
<ul>
|
||||
<li><a href="#wie-finde-ich-leute-mit-denen-ich-chatten-kann">Wie finde ich Leute, mit denen ich chatten kann?</a></li>
|
||||
@@ -836,7 +836,7 @@ und <em>GnuPG (GPG)</em>, einem Kommandozeilenprogramm, das OpenPGP implementier
|
||||
In vielen öffentlichen Kritiken zu OpenPGP wird GnuPG diskutiert, das Delta Chat nie verwendet hat.
|
||||
Delta Chat verwendet stattdessen die OpenPGP-Rust-Implementierung <a href="https://github.com/rpgp/rpgp">rPGP</a>,
|
||||
die als <a href="https://crates.io/crates/pgp">ein unabhängiges “pgp”-Paket</a>,
|
||||
verfügbar und <a href="https://delta.chat/assets/blog/2019-first-security-review.pdf">2019 sicherheitsgeprüft</a> wurde.</p>
|
||||
verfügbar ist und <a href="#security-audits">2019 und 2024 sicherheitsgeprüft</a> wurde.</p>
|
||||
|
||||
<p>Unser Ziel ist, zusammen mit anderen OpenPGP-Implementierungen,
|
||||
die Sicherheitseigenschaften durch das im Sommer 2023 angenommene
|
||||
@@ -1080,7 +1080,7 @@ aber irgendwie nicht Ihre Nachrichten - gleichzeitig aber eine vollständige Auf
|
||||
vergangenen verschlüsselten Nachrichten hat.</p>
|
||||
|
||||
<p>In jedem Fall verwendet die Ende-zu-Ende-Verschlüsselung von Delta Chat eine <a href="#openpgp-secure">sichere Untermenge von OpenPGP</a>
|
||||
das [unabhängig sicherheitsgeprüft] wurde (../assets/blog/2019-first-security-review.pdf).</p>
|
||||
das <a href="https://delta.chat/assets/blog/2019-first-security-review.pdf">unabhängig sicherheitsgeprüft</a> wurde.</p>
|
||||
|
||||
<h3 id="importkey">
|
||||
|
||||
@@ -1138,9 +1138,22 @@ Für andere Programme können Sie online eine Lösung finden.</p>
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Das Delta-Chat-Projekt wurde in den letzten Jahren fünf unabhängigen Sicherheitsprüfungen und -analysen unterzogen:</p>
|
||||
<p>Ja, mehrfach.
|
||||
Das Delta-Chat-Projekt wird kontinuierlich unabhängigen Sicherheitsaudits und -analysen unterzogen:</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>Im Dezember 2024 fand eine <a href="https://github.com/rpgp/docs/blob/main/audits/NGI%20Core%20rPGP%20penetration%20test%20report%202024%201.0.pdf">von NLNET in Auftrag gegebene Bewertung von rPGP</a> durch <a href="https://www.radicallyopensecurity.com/">Radically Open Security</a> statt.
|
||||
rPGP wird für die <a href="https://openpgp.org">OpenPGP</a>-Ende-zu-Ende-Verschlüsselung verwendet.
|
||||
Im Zusammenhang mit den Ergebnissen dieser Prüfung wurden zwei Hinweise veröffentlicht:</p>
|
||||
|
||||
<ul>
|
||||
<li><a href="https://github.com/rpgp/rpgp/security/advisories/GHSA-9rmp-2568-59rv">“Panics on Malformed Untrusted Input”</a> CVE-2024-53856</li>
|
||||
<li><a href="https://github.com/rpgp/rpgp/security/advisories/GHSA-4grw-m28r-q285">“Potential Resource Exhaustion when handling Untrusted Messages”</a> CVE-2024-53857</li>
|
||||
</ul>
|
||||
|
||||
<p>Die in diesen Hinweisen beschriebenen Probleme wurden behoben und sind Bestandteil der Delta Chat Veröffentlichungen in allen Appstores seit Dezember 2024.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Im März 2024 erhielten wir von der Forschungsgruppe “Applied Cryptography” der ETH Zürich eine umfassende Sicherheitsanalyse und haben alle aufgeworfenen Fragen adressiert.
|
||||
Weitere Informationen finden Sie in unserem Blogbeitrag über <a href="https://delta.chat/en/2024-03-25-crypto-analysis-securejoin">Hardening Guaranteed End-to-End encryption</a> und in der hinterher publizierten <a href="https://eprint.iacr.org/2024/918.pdf">Kryptografischen Analyse von Delta Chat</a></p>
|
||||
@@ -1157,7 +1170,7 @@ Es wurden keine kritischen oder hochgradig gefährlichen Probleme gefunden. Der
|
||||
</li>
|
||||
<li>
|
||||
<p>Im Jahr 2019 analysierte <a href="https://includesecurity.com">Include Security</a> die von Delta Chat verwendeten <a href="https://github.com/rpgp/rpgp">PGP-</a> und <a href="https://github.com/RustCrypto/RSA">RSA-</a> Bibliotheken.
|
||||
Es wurden keine kritischen Probleme gefunden, aber zwei Probleme mit hohem Schweregrad, die wir anschließend behoben haben. Außerdem wurden ein mittelschweres und einige weniger schwerwiegende Probleme gefunden, aber es gab keine Möglichkeit, diese Schwachstellen in der Delta-Chat-Implementierung auszunutzen. Einige dieser Schwachstellen haben wir dennoch nach Abschluss des Audits behoben. Sie können den [vollständigen Bericht hier] lesen (../assets/blog/2019-first-security-review.pdf).</p>
|
||||
Es wurden keine kritischen Probleme gefunden, aber zwei Probleme mit hohem Schweregrad, die wir anschließend behoben haben. Außerdem wurden ein mittelschweres und einige weniger schwerwiegende Probleme gefunden, aber es gab keine Möglichkeit, diese Schwachstellen in der Delta-Chat-Implementierung auszunutzen. Einige dieser Schwachstellen haben wir dennoch nach Abschluss des Audits behoben. Sie können den <a href="https://delta.chat/assets/blog/2019-first-security-review.pdf">vollständigen Bericht hier</a> lesen.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<html><head><meta charset="UTF-8" /><meta name="viewport" content="initial-scale=1.0" /><link rel="stylesheet" href="../help.css" /></head><body><ul id="top">
|
||||
<html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="initial-scale=1.0" /><link rel="stylesheet" href="../help.css" /></head><body><ul id="top">
|
||||
<li><a href="#what-is-delta-chat">What is Delta Chat?</a>
|
||||
<ul>
|
||||
<li><a href="#how-can-i-find-people-to-chat-with">How can I find people to chat with?</a></li>
|
||||
@@ -894,7 +894,7 @@ and GnuPG (GPG), a command line tool implementing OpenPGP.
|
||||
Many public critiques of OpenPGP actually discuss GnuPG which Delta Chat has never used.
|
||||
Delta Chat rather uses the OpenPGP Rust implementation <a href="https://github.com/rpgp/rpgp">rPGP</a>,
|
||||
available as <a href="https://crates.io/crates/pgp">an independent “pgp” package</a>,
|
||||
and <a href="https://delta.chat/assets/blog/2019-first-security-review.pdf">security-audited in 2019</a>.</p>
|
||||
and <a href="#security-audits">security-audited in 2019 and 2024</a>.</p>
|
||||
|
||||
<p>We aim, along with other OpenPGP implementors,
|
||||
to further improve security characteristics by implementing the
|
||||
@@ -1204,10 +1204,25 @@ For other programs, you should be able to find a solution online.</p>
|
||||
|
||||
</h3>
|
||||
|
||||
<p>The Delta Chat project underwent four independent security audits and one
|
||||
independent security analysis, from most recent to older:</p>
|
||||
<p>Yes, multiple times.
|
||||
The Delta Chat project continuously undergoes independent security audits and analysis,
|
||||
from most recent to older:</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>2024 December, an <a href="https://github.com/rpgp/docs/blob/main/audits/NGI%20Core%20rPGP%20penetration%20test%20report%202024%201.0.pdf">NLNET-commissioned Evaluation of
|
||||
rPGP</a> by <a href="https://www.radicallyopensecurity.com/">Radically Open Security</a> took place.
|
||||
rPGP serves as the end-to-end encyption <a href="https://openpgp.org">OpenPGP</a> engine of Delta Chat.
|
||||
Two advisories were released related to the findings of this audit:</p>
|
||||
|
||||
<ul>
|
||||
<li><a href="https://github.com/rpgp/rpgp/security/advisories/GHSA-9rmp-2568-59rv">“Panics on Malformed Untrusted Input”</a> CVE-2024-53856</li>
|
||||
<li><a href="https://github.com/rpgp/rpgp/security/advisories/GHSA-4grw-m28r-q285">“Potential Resource Exhaustion when handling Untrusted Messages”</a> CVE-2024-53857</li>
|
||||
</ul>
|
||||
|
||||
<p>The issues outlined in these advisories have been fixed and are part of Delta Chat
|
||||
releases on all appstores since December 2024.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>2024 March, we received a deep security analysis from the Applied Cryptography
|
||||
research group at ETH Zuerich and addressed all raised issues.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<html><head><meta charset="UTF-8" /><meta name="viewport" content="initial-scale=1.0" /><link rel="stylesheet" href="../help.css" /></head><body><ul id="top">
|
||||
<html lang="es"><head><meta charset="UTF-8" /><meta name="viewport" content="initial-scale=1.0" /><link rel="stylesheet" href="../help.css" /></head><body><ul id="top">
|
||||
<li><a href="#qué-es-delta-chat">¿Qué es Delta Chat?</a>
|
||||
<ul>
|
||||
<li><a href="#cómo-puedo-encontrar-personas-con-las-que-chatear">¿Cómo puedo encontrar personas con las que chatear?</a></li>
|
||||
@@ -872,7 +872,7 @@ and GnuPG (GPG), a command line tool implementing OpenPGP.
|
||||
Many public critiques of OpenPGP actually discuss GnuPG which Delta Chat has never used.
|
||||
Delta Chat rather uses the OpenPGP Rust implementation <a href="https://github.com/rpgp/rpgp">rPGP</a>,
|
||||
available as <a href="https://crates.io/crates/pgp">an independent “pgp” package</a>,
|
||||
and <a href="https://delta.chat/assets/blog/2019-first-security-review.pdf">security-audited in 2019</a>.</p>
|
||||
and <a href="#security-audits">security-audited in 2019 and 2024</a>.</p>
|
||||
|
||||
<p>We aim, along with other OpenPGP implementors,
|
||||
to further improve security characteristics by implementing the
|
||||
@@ -1167,10 +1167,25 @@ For other programs, you should be able to find a solution online.</p>
|
||||
|
||||
</h3>
|
||||
|
||||
<p>The Delta Chat project underwent four independent security audits and one
|
||||
independent security analysis, from most recent to older:</p>
|
||||
<p>Yes, multiple times.
|
||||
The Delta Chat project continuously undergoes independent security audits and analysis,
|
||||
from most recent to older:</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>2024 December, an <a href="https://github.com/rpgp/docs/blob/main/audits/NGI%20Core%20rPGP%20penetration%20test%20report%202024%201.0.pdf">NLNET-commissioned Evaluation of
|
||||
rPGP</a> by <a href="https://www.radicallyopensecurity.com/">Radically Open Security</a> took place.
|
||||
rPGP serves as the end-to-end encyption <a href="https://openpgp.org">OpenPGP</a> engine of Delta Chat.
|
||||
Two advisories were released related to the findings of this audit:</p>
|
||||
|
||||
<ul>
|
||||
<li><a href="https://github.com/rpgp/rpgp/security/advisories/GHSA-9rmp-2568-59rv">“Panics on Malformed Untrusted Input”</a> CVE-2024-53856</li>
|
||||
<li><a href="https://github.com/rpgp/rpgp/security/advisories/GHSA-4grw-m28r-q285">“Potential Resource Exhaustion when handling Untrusted Messages”</a> CVE-2024-53857</li>
|
||||
</ul>
|
||||
|
||||
<p>The issues outlined in these advisories have been fixed and are part of Delta Chat
|
||||
releases on all appstores since December 2024.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>2024 March, we received a deep security analysis from the Applied Cryptography
|
||||
research group at ETH Zuerich and addressed all raised issues.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<html><head><meta charset="UTF-8" /><meta name="viewport" content="initial-scale=1.0" /><link rel="stylesheet" href="../help.css" /></head><body><ul id="top">
|
||||
<html lang="fr"><head><meta charset="UTF-8" /><meta name="viewport" content="initial-scale=1.0" /><link rel="stylesheet" href="../help.css" /></head><body><ul id="top">
|
||||
<li><a href="#quest-ce-que-delta-chat-">Qu’est-ce que Delta Chat ?</a>
|
||||
<ul>
|
||||
<li><a href="#comment-puis-je-trouver-des-gens-avec-qui-discuter-">Comment puis-je trouver des gens avec qui discuter ?</a></li>
|
||||
@@ -869,7 +869,7 @@ and GnuPG (GPG), a command line tool implementing OpenPGP.
|
||||
Many public critiques of OpenPGP actually discuss GnuPG which Delta Chat has never used.
|
||||
Delta Chat rather uses the OpenPGP Rust implementation <a href="https://github.com/rpgp/rpgp">rPGP</a>,
|
||||
available as <a href="https://crates.io/crates/pgp">an independent “pgp” package</a>,
|
||||
and <a href="https://delta.chat/assets/blog/2019-first-security-review.pdf">security-audited in 2019</a>.</p>
|
||||
and <a href="#security-audits">security-audited in 2019 and 2024</a>.</p>
|
||||
|
||||
<p>We aim, along with other OpenPGP implementors,
|
||||
to further improve security characteristics by implementing the
|
||||
@@ -1171,10 +1171,25 @@ Pour les autres programmes, vous devriez pouvoir trouver la solution en ligne.</
|
||||
|
||||
</h3>
|
||||
|
||||
<p>The Delta Chat project underwent four independent security audits and one
|
||||
independent security analysis, from most recent to older:</p>
|
||||
<p>Yes, multiple times.
|
||||
The Delta Chat project continuously undergoes independent security audits and analysis,
|
||||
from most recent to older:</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>2024 December, an <a href="https://github.com/rpgp/docs/blob/main/audits/NGI%20Core%20rPGP%20penetration%20test%20report%202024%201.0.pdf">NLNET-commissioned Evaluation of
|
||||
rPGP</a> by <a href="https://www.radicallyopensecurity.com/">Radically Open Security</a> took place.
|
||||
rPGP serves as the end-to-end encyption <a href="https://openpgp.org">OpenPGP</a> engine of Delta Chat.
|
||||
Two advisories were released related to the findings of this audit:</p>
|
||||
|
||||
<ul>
|
||||
<li><a href="https://github.com/rpgp/rpgp/security/advisories/GHSA-9rmp-2568-59rv">“Panics on Malformed Untrusted Input”</a> CVE-2024-53856</li>
|
||||
<li><a href="https://github.com/rpgp/rpgp/security/advisories/GHSA-4grw-m28r-q285">“Potential Resource Exhaustion when handling Untrusted Messages”</a> CVE-2024-53857</li>
|
||||
</ul>
|
||||
|
||||
<p>The issues outlined in these advisories have been fixed and are part of Delta Chat
|
||||
releases on all appstores since December 2024.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>2024 March, we received a deep security analysis from the Applied Cryptography
|
||||
research group at ETH Zuerich and addressed all raised issues.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<html><head><meta charset="UTF-8" /><meta name="viewport" content="initial-scale=1.0" /><link rel="stylesheet" href="../help.css" /></head><body><ul id="top">
|
||||
<html lang="id"><head><meta charset="UTF-8" /><meta name="viewport" content="initial-scale=1.0" /><link rel="stylesheet" href="../help.css" /></head><body><ul id="top">
|
||||
<li><a href="#apa-itu-delta-chat">Apa itu Delta Chat?</a>
|
||||
<ul>
|
||||
<li><a href="#bagaimana-saya-bisa-menemukan-orang-untuk-diajak-ngobrol">Bagaimana Saya bisa menemukan orang untuk diajak ngobrol?</a></li>
|
||||
@@ -894,7 +894,7 @@ and GnuPG (GPG), a command line tool implementing OpenPGP.
|
||||
Many public critiques of OpenPGP actually discuss GnuPG which Delta Chat has never used.
|
||||
Delta Chat rather uses the OpenPGP Rust implementation <a href="https://github.com/rpgp/rpgp">rPGP</a>,
|
||||
available as <a href="https://crates.io/crates/pgp">an independent “pgp” package</a>,
|
||||
and <a href="https://delta.chat/assets/blog/2019-first-security-review.pdf">security-audited in 2019</a>.</p>
|
||||
and <a href="#security-audits">security-audited in 2019 and 2024</a>.</p>
|
||||
|
||||
<p>We aim, along with other OpenPGP implementors,
|
||||
to further improve security characteristics by implementing the
|
||||
@@ -1204,10 +1204,25 @@ For other programs, you should be able to find a solution online.</p>
|
||||
|
||||
</h3>
|
||||
|
||||
<p>The Delta Chat project underwent four independent security audits and one
|
||||
independent security analysis, from most recent to older:</p>
|
||||
<p>Yes, multiple times.
|
||||
The Delta Chat project continuously undergoes independent security audits and analysis,
|
||||
from most recent to older:</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>2024 December, an <a href="https://github.com/rpgp/docs/blob/main/audits/NGI%20Core%20rPGP%20penetration%20test%20report%202024%201.0.pdf">NLNET-commissioned Evaluation of
|
||||
rPGP</a> by <a href="https://www.radicallyopensecurity.com/">Radically Open Security</a> took place.
|
||||
rPGP serves as the end-to-end encyption <a href="https://openpgp.org">OpenPGP</a> engine of Delta Chat.
|
||||
Two advisories were released related to the findings of this audit:</p>
|
||||
|
||||
<ul>
|
||||
<li><a href="https://github.com/rpgp/rpgp/security/advisories/GHSA-9rmp-2568-59rv">“Panics on Malformed Untrusted Input”</a> CVE-2024-53856</li>
|
||||
<li><a href="https://github.com/rpgp/rpgp/security/advisories/GHSA-4grw-m28r-q285">“Potential Resource Exhaustion when handling Untrusted Messages”</a> CVE-2024-53857</li>
|
||||
</ul>
|
||||
|
||||
<p>The issues outlined in these advisories have been fixed and are part of Delta Chat
|
||||
releases on all appstores since December 2024.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>2024 March, we received a deep security analysis from the Applied Cryptography
|
||||
research group at ETH Zuerich and addressed all raised issues.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<html><head><meta charset="UTF-8" /><meta name="viewport" content="initial-scale=1.0" /><link rel="stylesheet" href="../help.css" /></head><body><ul id="top">
|
||||
<html lang="it"><head><meta charset="UTF-8" /><meta name="viewport" content="initial-scale=1.0" /><link rel="stylesheet" href="../help.css" /></head><body><ul id="top">
|
||||
<li><a href="#cosè-delta-chat">Cos’è Delta Chat?</a>
|
||||
<ul>
|
||||
<li><a href="#come-posso-trovare-persone-con-cui-messaggiare">Come posso trovare persone con cui messaggiare?</a></li>
|
||||
@@ -597,17 +597,15 @@ a qualsiasi sistema coinvolto nella consegna di Notifiche Push.</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>A Delta Chat app obtains a “device token” locally, encrypts it and stores it
|
||||
on the <a href="https://delta.chat/chatmail">chatmail</a> server.</p>
|
||||
<p>Un’app Delta Chat ottiene un “token del dispositivo” localmente, lo crittografa e lo memorizza sul server <a href="https://delta.chat/chatmail">chatmail</a>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>When a <a href="https://delta.chat/chatmail">chatmail</a> server receives an e-mail for a Delta Chat user
|
||||
it forwards the encrypted device token to the central Delta Chat notification proxy.</p>
|
||||
<p>Quando un server <a href="https://delta.chat/chatmail">chatmail</a> riceve un’e-mail per un utente Delta Chat, inoltra il token del dispositivo crittografato al proxy di notifica centrale Delta Chat.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>The central Delta Chat notification proxy decrypts the device token
|
||||
and forwards it to the respective Push service (Apple, Google, etc.),
|
||||
without ever knowing the IP or e-mail address of Delta Chat users.</p>
|
||||
<p>Il proxy di notifica centrale di Delta Chat decifra il token del dispositivo
|
||||
e lo inoltra al rispettivo servizio Push (Apple, Google, ecc.),
|
||||
senza mai conoscere l’IP o l’indirizzo e-mail degli utenti di Delta Chat.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Il Servizio Push centrale (Apple, Google, ecc.)
|
||||
@@ -623,10 +621,10 @@ e inoltre non vedono mai il contenuto del messaggio (anche non in forma crittogr
|
||||
e si dimentica dei gettoni del dispositivo non appena Apple/Google/ecc li elabora,
|
||||
di solito nel giro di pochi millisecondi.</p>
|
||||
|
||||
<p>Note that the device token is encrypted between apps and notification proxy
|
||||
but it is not signed.
|
||||
The notification proxy thus never sees e-mail addresses, IP-addresses or
|
||||
any cryptographic identity information associated with a user’s device (token).</p>
|
||||
<p>Si noti che il token del dispositivo è crittografato tra le app e il proxy di notifica
|
||||
ma non è firmato.
|
||||
Il proxy di notifica quindi non vede mai indirizzi e-mail, indirizzi IP o
|
||||
alcune informazioni di identità crittografica associate al dispositivo di un utente (token).</p>
|
||||
|
||||
<p>Come risultato di questo disegno complessivo sulla riservatezza, anche il sequestro di un server chatmail,
|
||||
o il sequestro totale del proxy di notifica centrale di Delta Chat
|
||||
@@ -876,14 +874,13 @@ se l’intero messaggio è crittografato e firmato correttamente.
|
||||
Ad esempio, le “Firme distaccate” non sono considerate sicure.</p>
|
||||
|
||||
<p>OpenPGP non è insicuro di per sé.
|
||||
I problemi di sicurezza di OpenPGP più discussi pubblicamente
|
||||
in realtà derivano da una cattiva usabilità o da cattive implementazioni di strumenti o app (o entrambi).
|
||||
La maggior parte dei problemi di sicurezza di OpenPGP discussi pubblicamentederivano in realtà da una cattiva usabilità o da cattive implementazioni di strumenti o app (o entrambi).
|
||||
È particolarmente importante distinguere tra OpenPGP, lo standard di crittografia IETF,
|
||||
e GnuPG (GPG), uno strumento da riga di comando che implementa OpenPGP.
|
||||
Molte critiche pubbliche di OpenPGP in realtà discutono di GnuPG che Delta Chat non ha mai utilizzato.
|
||||
Delta Chat utilizza piuttosto l’implementazione OpenPGP Rust <a href="https://github.com/rpgp/rpgp">rPGP</a>,
|
||||
Delta Chat utilizza piuttosto l’implementazione Rust di OpenPGP <a href="https://github.com/rpgp/rpgp">rPGP</a>,
|
||||
disponibile come <a href="https://crates.io/crates/pgp">un pacchetto “pgp” indipendente</a>,
|
||||
e <a href="https://delta.chat/assets/blog/2019-first-security-review.pdf">controllato sulla sicurezza nel 2019</a>.</p>
|
||||
e <a href="#security-audits">verificato per la sicurezza nel 2019 e nel 2024</a>.</p>
|
||||
|
||||
<p>Puntiamo, insieme ad altri implementatori di OpenPGP,
|
||||
per migliorare ulteriormente le caratteristiche di sicurezza implementando il
|
||||
@@ -948,7 +945,7 @@ compresi eventuali allegati,
|
||||
se non sono crittografati end-to-end.</p>
|
||||
|
||||
<p>Delta Chat per impostazione predefinita utilizza
|
||||
[Crittografia TLS] rigorosa (https://en.wikipedia.org/wiki/Transport_Layer_Security)
|
||||
<a href="https://en.wikipedia.org/wiki/Transport_Layer_Security">Crittografia TLS</a> rigorosa
|
||||
che protegge le connessioni tra il tuo dispositivo e il tuo provider e-mail.
|
||||
Tutta la gestione TLS di Delta Chat è stata sottoposta a <a href="#security-audits">controlli di sicurezza</a> in modo indipendente.
|
||||
Inoltre, la connessione tra il tuo provider e-mail e quello del destinatario
|
||||
@@ -1192,10 +1189,26 @@ Per altri programmi, dovresti essere in grado di trovare una soluzione online.</
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Il progetto Delta Chat è stato sottoposto a quattro controlli di sicurezza indipendenti e
|
||||
un’analisi di sicurezza indipendente, dal più recente al più vecchio:</p>
|
||||
<p>Sì, più volte.
|
||||
Il progetto Delta Chat è sottoposto costantemente a verifiche e analisi di sicurezza indipendenti,
|
||||
dal più recente al più vecchio:</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>Dicembre 2024, un <a href="https://github.com/rpgp/docs/blob/main/audits/NGI%20Core%20rPGP%20penetration%20test%20report%202024%201.0.pdf">Valutazione commissionata da NLNET di
|
||||
rPGP</a> di <a href="https://www.radicallyopensecurity.com/">Radically Open Security</a> ha preso parte.
|
||||
rPGP serves as the end-to-end encyption <a href="https://openpgp.org">OpenPGP</a> engine of Delta Chat.
|
||||
Sono stati rilasciati due avvisi relativi ai risultati di questa verifica:</p>
|
||||
|
||||
<ul>
|
||||
<li><a href="https://github.com/rpgp/rpgp/security/advisories/GHSA-9rmp-2568-59rv">“Panico per Input non Attendibili e Malformati”</a> CVE-2024-53856</li>
|
||||
<li><a href="https://github.com/rpgp/rpgp/security/advisories/GHSA-4grw-m28r-q285">“Potenziale Esaurimento delle Risorse durante la gestione di Messaggi non Attendibili”</a> CVE-2024-53857</li>
|
||||
</ul>
|
||||
|
||||
<p>I problemi descritti in questi avvisi sono stati risolti e fanno
|
||||
parte delle versioni di Delta Chat
|
||||
su tutti gli appstore da Dicembre 2024.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Marzo 2024, abbiamo ricevuto un’analisi approfondita della sicurezza dalla Crittografia Applicata
|
||||
gruppo di ricerca dell’ETH di Zurigo e ha affrontato tutte le questioni sollevate.
|
||||
@@ -1912,7 +1925,7 @@ tramite <a href="https://autocrypt.org">Autocrypt</a>.</p>
|
||||
prima sovvenzione 2018/2019 (~$200K) durante la quale abbiamo notevolmente migliorato l’app Android
|
||||
e ha rilasciato una prima versione beta dell’app desktop, e che inoltre
|
||||
ancorato i nostri sviluppi delle funzionalità nella ricerca sulla UX nei contesti dei diritti umani,
|
||||
vedete il nostro [Rapporto Needfinding e UX] conclusivo (https://delta.chat/en/2019-07-19-uxreport).
|
||||
vedete il nostro <a href="https://delta.chat/en/2019-07-19-uxreport">Rapporto Needfinding e UX</a> conclusivo.
|
||||
La seconda sovvenzione 2019/2020 (~$300K) ci ha aiutato a farlo
|
||||
rilasciare nelle versioni Delta/iOS, per convertire la nostra libreria principale in Rust, e
|
||||
per fornire nuove funzionalità per tutte le piattaforme.</p>
|
||||
@@ -1936,7 +1949,7 @@ e fornendo “inserimento immediato” in tutte le app rilasciate da aprile 2024
|
||||
</li>
|
||||
<li>
|
||||
<p>Nel 2023 e nel 2024 siamo stati accettati nel programma Next Generation Internet (NGI)
|
||||
per il nostro lavoro in [webxdc PUSH].(https://nlnet.nl/project/WebXDC-Push/),
|
||||
per il nostro lavoro in <a href="https://nlnet.nl/project/WebXDC-Push/">webxdc PUSH</a>,
|
||||
insieme ai partner di collaborazione che lavorano su
|
||||
<a href="https://nlnet.nl/project/Webxdc-Evolve/">webxdc evolve</a>,
|
||||
<a href="https://nlnet.nl/project/WebXDC-XMPP/">webxdc XMPP</a>,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<html><head><meta charset="UTF-8" /><meta name="viewport" content="initial-scale=1.0" /><link rel="stylesheet" href="../help.css" /></head><body><ul id="top">
|
||||
<html lang="nl"><head><meta charset="UTF-8" /><meta name="viewport" content="initial-scale=1.0" /><link rel="stylesheet" href="../help.css" /></head><body><ul id="top">
|
||||
<li><a href="#wat-is-delta-chat">Wat is Delta Chat?</a>
|
||||
<ul>
|
||||
<li><a href="#hoe-kan-ik-gesprekspartners-vinden">Hoe kan ik gesprekspartners vinden?</a></li>
|
||||
@@ -888,7 +888,7 @@ and GnuPG (GPG), a command line tool implementing OpenPGP.
|
||||
Many public critiques of OpenPGP actually discuss GnuPG which Delta Chat has never used.
|
||||
Delta Chat rather uses the OpenPGP Rust implementation <a href="https://github.com/rpgp/rpgp">rPGP</a>,
|
||||
available as <a href="https://crates.io/crates/pgp">an independent “pgp” package</a>,
|
||||
and <a href="https://delta.chat/assets/blog/2019-first-security-review.pdf">security-audited in 2019</a>.</p>
|
||||
and <a href="#security-audits">security-audited in 2019 and 2024</a>.</p>
|
||||
|
||||
<p>We aim, along with other OpenPGP implementors,
|
||||
to further improve security characteristics by implementing the
|
||||
@@ -1197,10 +1197,25 @@ Voor andere programma’s kun je zélf een oplossing zoeken op internet.</p>
|
||||
|
||||
</h3>
|
||||
|
||||
<p>The Delta Chat project underwent four independent security audits and one
|
||||
independent security analysis, from most recent to older:</p>
|
||||
<p>Yes, multiple times.
|
||||
The Delta Chat project continuously undergoes independent security audits and analysis,
|
||||
from most recent to older:</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>2024 December, an <a href="https://github.com/rpgp/docs/blob/main/audits/NGI%20Core%20rPGP%20penetration%20test%20report%202024%201.0.pdf">NLNET-commissioned Evaluation of
|
||||
rPGP</a> by <a href="https://www.radicallyopensecurity.com/">Radically Open Security</a> took place.
|
||||
rPGP serves as the end-to-end encyption <a href="https://openpgp.org">OpenPGP</a> engine of Delta Chat.
|
||||
Two advisories were released related to the findings of this audit:</p>
|
||||
|
||||
<ul>
|
||||
<li><a href="https://github.com/rpgp/rpgp/security/advisories/GHSA-9rmp-2568-59rv">“Panics on Malformed Untrusted Input”</a> CVE-2024-53856</li>
|
||||
<li><a href="https://github.com/rpgp/rpgp/security/advisories/GHSA-4grw-m28r-q285">“Potential Resource Exhaustion when handling Untrusted Messages”</a> CVE-2024-53857</li>
|
||||
</ul>
|
||||
|
||||
<p>The issues outlined in these advisories have been fixed and are part of Delta Chat
|
||||
releases on all appstores since December 2024.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>2024 March, we received a deep security analysis from the Applied Cryptography
|
||||
research group at ETH Zuerich and addressed all raised issues.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<html><head><meta charset="UTF-8" /><meta name="viewport" content="initial-scale=1.0" /><link rel="stylesheet" href="../help.css" /></head><body><ul id="top">
|
||||
<html lang="pl"><head><meta charset="UTF-8" /><meta name="viewport" content="initial-scale=1.0" /><link rel="stylesheet" href="../help.css" /></head><body><ul id="top">
|
||||
<li><a href="#czym-jest-delta-chat">Czym jest Delta Chat?</a>
|
||||
<ul>
|
||||
<li><a href="#jak-mogę-znaleźć-ludzi-z-którymi-mogę-czatować">Jak mogę znaleźć ludzi, z którymi mogę czatować?</a></li>
|
||||
@@ -669,7 +669,7 @@ nadal będziesz mógł pisać, ale nie będziesz już powiadamiany o żadnych no
|
||||
|
||||
<p>Tak, Delta Chat korzysta z bezpiecznego podzbioru OpenPGP i wyświetla wskaźnik bezpieczeństwa kłódki na wiadomości tylko wtedy, gdy cała wiadomość jest prawidłowo zaszyfrowana i podpisana. Na przykład „Odłączone podpisy” nie są traktowane jako bezpieczne.</p>
|
||||
|
||||
<p>OpenPGP samo w sobie nie jest niebezpieczne. Większość publicznie omawianych problemów związanych z bezpieczeństwem OpenPGP tak naprawdę wynika ze złej użyteczności lub złej implementacji narzędzi, lub aplikacji (lub obu). Szczególnie ważne jest rozróżnienie pomiędzy OpenPGP, standardem szyfrowania IETF, a GnuPG (GPG), narzędziem wiersza poleceń implementującym OpenPGP. Wiele publicznych komentarzy krytycznych na temat OpenPGP tak naprawdę omawia GnuPG, którego Delta Chat nigdy nie używał. Delta Chat korzysta raczej z implementacji OpenPGP Rust <a href="https://github.com/rpgp/rpgp">rPGP</a>, dostępnej jako <a href="https://crates.io/crates/pgp">niezależny pakiet „pgp”</a> i poddanej <a href="https://delta.chat/assets/blog/2019-first-security-review.pdf">audytowi bezpieczeństwa w 2019 roku</a>.</p>
|
||||
<p>OpenPGP samo w sobie nie jest niebezpieczne. Większość publicznie omawianych problemów związanych z bezpieczeństwem OpenPGP tak naprawdę wynika ze złej użyteczności lub złej implementacji narzędzi, lub aplikacji (lub obu). Szczególnie ważne jest rozróżnienie pomiędzy OpenPGP, standardem szyfrowania IETF, a GnuPG (GPG), narzędziem wiersza poleceń implementującym OpenPGP. Wiele publicznych komentarzy krytycznych na temat OpenPGP tak naprawdę omawia GnuPG, którego Delta Chat nigdy nie używał. Delta Chat korzysta raczej z implementacji OpenPGP Rust <a href="https://github.com/rpgp/rpgp">rPGP</a>, dostępnej jako <a href="https://crates.io/crates/pgp">niezależny pakiet „pgp”</a> i poddanej <a href="#security-audits">audytowi bezpieczeństwa w 2019 i 2024 roku</a>.</p>
|
||||
|
||||
<p>Naszym celem, wraz z innymi wdrażającymi OpenPGP, jest dalsza poprawa parametrów bezpieczeństwa poprzez wdrożenie <a href="https://datatracker.ietf.org/doc/draft-ietf-openpgp-crypto-refresh/">nowego IETF OpenPGP Crypto-Refresh</a>, który na szczęście został przyjęty latem 2023 roku.</p>
|
||||
|
||||
@@ -868,7 +868,18 @@ W przypadku innych programów można znaleźć rozwiązanie online.</p>
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Projekt Delta Chat przeszedł cztery niezależne audyty bezpieczeństwa i jedną niezależną analizę bezpieczeństwa, od najnowszego do najstarszego:</p>
|
||||
<p>Tak, wielokrotnie.
|
||||
Projekt Delta Chat stale przechodzi niezależne audyty bezpieczeństwa i analizy,
|
||||
od najnowszych do najstarszych:</p>
|
||||
|
||||
<p>W grudniu 2024 r. <a href="https://github.com/rpgp/docs/blob/main/audits/NGI%20Core%20rPGP%20penetration%20test%20report%202024%201.0.pdf">NLNET</a> wykonała ocenę rPGP zleconą przez <a href="https://www.radicallyopensecurity.com/">Radically Open Security</a>. rPGP służy jako kompleksowy silnik szyfrowania <a href="https://openpgp.org">OpenPGP</a> w Delta Chat. Wydano dwa ostrzeżenia związane z wynikami tego audytu:</p>
|
||||
|
||||
<ul>
|
||||
<li><a href="https://github.com/rpgp/rpgp/security/advisories/GHSA-9rmp-2568-59rv">„Paniki przy nieprawidłowym wprowadzaniu niezaufanych danych wejściowych”</a> CVE-2024-53856</li>
|
||||
<li><a href="https://github.com/rpgp/rpgp/security/advisories/GHSA-4grw-m28r-q285">„Potencjalne wyczerpanie zasobów podczas obsługi niezaufanych wiadomości”</a> CVE-2024-53857</li>
|
||||
</ul>
|
||||
|
||||
<p>Problemy opisane w tych ostrzeżeniach zostały naprawione i są częścią wydań Delta Chat we wszystkich sklepach z aplikacjami od grudnia 2024 r.</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<html><head><meta charset="UTF-8" /><meta name="viewport" content="initial-scale=1.0" /><link rel="stylesheet" href="../help.css" /></head><body><ul id="top">
|
||||
<html lang="pt"><head><meta charset="UTF-8" /><meta name="viewport" content="initial-scale=1.0" /><link rel="stylesheet" href="../help.css" /></head><body><ul id="top">
|
||||
<li><a href="#o-que-é-o-delta-chat">O que é o Delta Chat</a>
|
||||
<ul>
|
||||
<li><a href="#como-encontro-as-pessoas-para-conversar">Como encontro as pessoas para conversar?</a></li>
|
||||
@@ -888,7 +888,7 @@ and GnuPG (GPG), a command line tool implementing OpenPGP.
|
||||
Many public critiques of OpenPGP actually discuss GnuPG which Delta Chat has never used.
|
||||
Delta Chat rather uses the OpenPGP Rust implementation <a href="https://github.com/rpgp/rpgp">rPGP</a>,
|
||||
available as <a href="https://crates.io/crates/pgp">an independent “pgp” package</a>,
|
||||
and <a href="https://delta.chat/assets/blog/2019-first-security-review.pdf">security-audited in 2019</a>.</p>
|
||||
and <a href="#security-audits">security-audited in 2019 and 2024</a>.</p>
|
||||
|
||||
<p>We aim, along with other OpenPGP implementors,
|
||||
to further improve security characteristics by implementing the
|
||||
@@ -1198,10 +1198,25 @@ Para outros programas, você deveria achar uma solução online.</p>
|
||||
|
||||
</h3>
|
||||
|
||||
<p>The Delta Chat project underwent four independent security audits and one
|
||||
independent security analysis, from most recent to older:</p>
|
||||
<p>Yes, multiple times.
|
||||
The Delta Chat project continuously undergoes independent security audits and analysis,
|
||||
from most recent to older:</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>2024 December, an <a href="https://github.com/rpgp/docs/blob/main/audits/NGI%20Core%20rPGP%20penetration%20test%20report%202024%201.0.pdf">NLNET-commissioned Evaluation of
|
||||
rPGP</a> by <a href="https://www.radicallyopensecurity.com/">Radically Open Security</a> took place.
|
||||
rPGP serves as the end-to-end encyption <a href="https://openpgp.org">OpenPGP</a> engine of Delta Chat.
|
||||
Two advisories were released related to the findings of this audit:</p>
|
||||
|
||||
<ul>
|
||||
<li><a href="https://github.com/rpgp/rpgp/security/advisories/GHSA-9rmp-2568-59rv">“Panics on Malformed Untrusted Input”</a> CVE-2024-53856</li>
|
||||
<li><a href="https://github.com/rpgp/rpgp/security/advisories/GHSA-4grw-m28r-q285">“Potential Resource Exhaustion when handling Untrusted Messages”</a> CVE-2024-53857</li>
|
||||
</ul>
|
||||
|
||||
<p>The issues outlined in these advisories have been fixed and are part of Delta Chat
|
||||
releases on all appstores since December 2024.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>2024 March, we received a deep security analysis from the Applied Cryptography
|
||||
research group at ETH Zuerich and addressed all raised issues.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<html><head><meta charset="UTF-8" /><meta name="viewport" content="initial-scale=1.0" /><link rel="stylesheet" href="../help.css" /></head><body><ul id="top">
|
||||
<html lang="ru"><head><meta charset="UTF-8" /><meta name="viewport" content="initial-scale=1.0" /><link rel="stylesheet" href="../help.css" /></head><body><ul id="top">
|
||||
<li><a href="#что-такое-delta-chat">Что такое Delta Chat?</a>
|
||||
<ul>
|
||||
<li><a href="#как-мне-найти-людей-для-общения">Как мне найти людей для общения?</a></li>
|
||||
@@ -118,7 +118,7 @@
|
||||
<p>Delta Chat — надежное, децентрализованное и безопасное приложение для обмена сообщениями,
|
||||
доступное для мобильных и настольных платформ.</p>
|
||||
|
||||
<p>Delta Chat напоминает Whatsapp или Telegram, но его можно использовать и приложение электронной почты.
|
||||
<p>Delta Chat напоминает Whatsapp или Telegram, но его можно использовать и как приложение электронной почты.
|
||||
Вы можете анонимно зарегистрироваться на различных <a href="https://delta.chat/chatmail">совместимых с chatmail серверах</a>,
|
||||
которые представляют собой минимальные почтовые серверы, оптимизированные для быстрой и безопасной работы.
|
||||
Или вы можете использовать обычные почтовые серверы и существующий почтовый аккаунт,
|
||||
@@ -134,7 +134,7 @@
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Чтобы безопасно настроить связь с другими <a href="#howtoe2ee">отсканируйте QR-код приглашения
|
||||
<p>Чтобы безопасно настроить связь с другими, <a href="#howtoe2ee">отсканируйте QR-код приглашения
|
||||
или поделитесь ссылкой-приглашением</a>.
|
||||
Это необходимо при использовании профиля чата на основе почты chatmail (по умолчанию),
|
||||
потому что серверы chatmail отклоняют незашифрованные исходящие сообщения.</p>
|
||||
@@ -891,7 +891,7 @@ Autocrypt использует ограниченное и <a href="#openpgp-sec
|
||||
Многие публичные критические замечания по OpenPGP фактически касаются GnuPG, который Delta Chat никогда не использовал.
|
||||
Delta Chat вместо этого использует реализацию OpenPGP на Rust <a href="https://github.com/rpgp/rpgp">rPGP</a>,
|
||||
доступную как <a href="https://crates.io/crates/pgp">независимый пакет “pgp”</a>,
|
||||
и <a href="https://delta.chat/assets/blog/2019-first-security-review.pdf">проверенную на безопасность в 2019 году</a>.</p>
|
||||
и <a href="#security-audits">проверенную на безопасность в 2019 и 2024 годах</a>.</p>
|
||||
|
||||
<p>Вместе с другими разработчиками OpenPGP мы стремимся,
|
||||
повысить характеристики безопасности путём реализации
|
||||
@@ -1201,10 +1201,25 @@ Delta Chat не будут иметь никакого ключа, прежде
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Проект Delta Chat прошёл четыре независимых аудита безопасности и один
|
||||
независимый анализ безопасности, от самого последнего к более старому:</p>
|
||||
<p>Да, множество раз.
|
||||
Проект Delta Chat находится в постоянном режиме аудита безопасности и анализа,
|
||||
от последних до более ранних:</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>Декабрь 2024 года, <a href="https://github.com/rpgp/docs/blob/main/audits/NGI%20Core%20rPGP%20penetration%20test%20report%202024%201.0.pdf">экспертиза rPGP, организованная
|
||||
NLNET</a> выполненная <a href="https://www.radicallyopensecurity.com/">Radically Open Security</a>.
|
||||
rPGP является движком сквозного шифрования OpenPGP <a href="https://openpgp.org">OpenPGP</a> в Delta Chat.
|
||||
В результате этого аудита были подготовлены два отчета по безопасности:</p>
|
||||
|
||||
<ul>
|
||||
<li><a href="https://github.com/rpgp/rpgp/security/advisories/GHSA-9rmp-2568-59rv">“Паника при обработке некорректных, недоверенных входных данных”</a> CVE-2024-53856</li>
|
||||
<li><a href="https://github.com/rpgp/rpgp/security/advisories/GHSA-4grw-m28r-q285">“Возможная нехватка ресурсов при обработке непроверенных сообщений”</a> CVE-2024-53857</li>
|
||||
</ul>
|
||||
|
||||
<p>Проблемы, описанные в этих рекомендациях, были исправлены и включены в релизы Delta Chat,
|
||||
во всех магазинах приложений с декабря 2024 года.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>В марте 2024 года мы получили подробный анализ безопасности от исследовательской группы
|
||||
Applied Cryptography в ETH Цюрихе и устранили все выявленные проблемы.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<html><head><meta charset="UTF-8" /><meta name="viewport" content="initial-scale=1.0" /><link rel="stylesheet" href="../help.css" /></head><body><ul id="top">
|
||||
<html lang="sk"><head><meta charset="UTF-8" /><meta name="viewport" content="initial-scale=1.0" /><link rel="stylesheet" href="../help.css" /></head><body><ul id="top">
|
||||
<li><a href="#čo-je-to-delta-chat">Čo je to Delta Chat?</a>
|
||||
<ul>
|
||||
<li><a href="#ako-nájdem-ľudí-s-ktorými-môžem-chatovať">Ako nájdem ľudí s ktorými môžem chatovať?</a></li>
|
||||
@@ -894,7 +894,7 @@ and GnuPG (GPG), a command line tool implementing OpenPGP.
|
||||
Many public critiques of OpenPGP actually discuss GnuPG which Delta Chat has never used.
|
||||
Delta Chat rather uses the OpenPGP Rust implementation <a href="https://github.com/rpgp/rpgp">rPGP</a>,
|
||||
available as <a href="https://crates.io/crates/pgp">an independent “pgp” package</a>,
|
||||
and <a href="https://delta.chat/assets/blog/2019-first-security-review.pdf">security-audited in 2019</a>.</p>
|
||||
and <a href="#security-audits">security-audited in 2019 and 2024</a>.</p>
|
||||
|
||||
<p>We aim, along with other OpenPGP implementors,
|
||||
to further improve security characteristics by implementing the
|
||||
@@ -1204,10 +1204,25 @@ Pre iné programy by ste mali vedieť nájsť riešenie online.</p>
|
||||
|
||||
</h3>
|
||||
|
||||
<p>The Delta Chat project underwent four independent security audits and one
|
||||
independent security analysis, from most recent to older:</p>
|
||||
<p>Yes, multiple times.
|
||||
The Delta Chat project continuously undergoes independent security audits and analysis,
|
||||
from most recent to older:</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>2024 December, an <a href="https://github.com/rpgp/docs/blob/main/audits/NGI%20Core%20rPGP%20penetration%20test%20report%202024%201.0.pdf">NLNET-commissioned Evaluation of
|
||||
rPGP</a> by <a href="https://www.radicallyopensecurity.com/">Radically Open Security</a> took place.
|
||||
rPGP serves as the end-to-end encyption <a href="https://openpgp.org">OpenPGP</a> engine of Delta Chat.
|
||||
Two advisories were released related to the findings of this audit:</p>
|
||||
|
||||
<ul>
|
||||
<li><a href="https://github.com/rpgp/rpgp/security/advisories/GHSA-9rmp-2568-59rv">“Panics on Malformed Untrusted Input”</a> CVE-2024-53856</li>
|
||||
<li><a href="https://github.com/rpgp/rpgp/security/advisories/GHSA-4grw-m28r-q285">“Potential Resource Exhaustion when handling Untrusted Messages”</a> CVE-2024-53857</li>
|
||||
</ul>
|
||||
|
||||
<p>The issues outlined in these advisories have been fixed and are part of Delta Chat
|
||||
releases on all appstores since December 2024.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>2024 March, we received a deep security analysis from the Applied Cryptography
|
||||
research group at ETH Zuerich and addressed all raised issues.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<html><head><meta charset="UTF-8" /><meta name="viewport" content="initial-scale=1.0" /><link rel="stylesheet" href="../help.css" /></head><body><ul id="top">
|
||||
<html lang="sq"><head><meta charset="UTF-8" /><meta name="viewport" content="initial-scale=1.0" /><link rel="stylesheet" href="../help.css" /></head><body><ul id="top">
|
||||
<li><a href="#çështë-delta-chat-i">Ç’është Delta Chat-i?</a>
|
||||
<ul>
|
||||
<li><a href="#si-mund-të-gjej-persona-për-të-biseduar-me-ta">Si mund të gjej persona për të biseduar me ta?</a></li>
|
||||
@@ -896,7 +896,7 @@ and GnuPG (GPG), a command line tool implementing OpenPGP.
|
||||
Many public critiques of OpenPGP actually discuss GnuPG which Delta Chat has never used.
|
||||
Delta Chat rather uses the OpenPGP Rust implementation <a href="https://github.com/rpgp/rpgp">rPGP</a>,
|
||||
available as <a href="https://crates.io/crates/pgp">an independent “pgp” package</a>,
|
||||
and <a href="https://delta.chat/assets/blog/2019-first-security-review.pdf">security-audited in 2019</a>.</p>
|
||||
and <a href="#security-audits">security-audited in 2019 and 2024</a>.</p>
|
||||
|
||||
<p>We aim, along with other OpenPGP implementors,
|
||||
to further improve security characteristics by implementing the
|
||||
@@ -1206,10 +1206,25 @@ Për programe të tjera, mund të gjeni një zgjidhje në internet.</p>
|
||||
|
||||
</h3>
|
||||
|
||||
<p>The Delta Chat project underwent four independent security audits and one
|
||||
independent security analysis, from most recent to older:</p>
|
||||
<p>Yes, multiple times.
|
||||
The Delta Chat project continuously undergoes independent security audits and analysis,
|
||||
from most recent to older:</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>2024 December, an <a href="https://github.com/rpgp/docs/blob/main/audits/NGI%20Core%20rPGP%20penetration%20test%20report%202024%201.0.pdf">NLNET-commissioned Evaluation of
|
||||
rPGP</a> by <a href="https://www.radicallyopensecurity.com/">Radically Open Security</a> took place.
|
||||
rPGP serves as the end-to-end encyption <a href="https://openpgp.org">OpenPGP</a> engine of Delta Chat.
|
||||
Two advisories were released related to the findings of this audit:</p>
|
||||
|
||||
<ul>
|
||||
<li><a href="https://github.com/rpgp/rpgp/security/advisories/GHSA-9rmp-2568-59rv">“Panics on Malformed Untrusted Input”</a> CVE-2024-53856</li>
|
||||
<li><a href="https://github.com/rpgp/rpgp/security/advisories/GHSA-4grw-m28r-q285">“Potential Resource Exhaustion when handling Untrusted Messages”</a> CVE-2024-53857</li>
|
||||
</ul>
|
||||
|
||||
<p>The issues outlined in these advisories have been fixed and are part of Delta Chat
|
||||
releases on all appstores since December 2024.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>2024 March, we received a deep security analysis from the Applied Cryptography
|
||||
research group at ETH Zuerich and addressed all raised issues.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<html><head><meta charset="UTF-8" /><meta name="viewport" content="initial-scale=1.0" /><link rel="stylesheet" href="../help.css" /></head><body><ul id="top">
|
||||
<html lang="uk"><head><meta charset="UTF-8" /><meta name="viewport" content="initial-scale=1.0" /><link rel="stylesheet" href="../help.css" /></head><body><ul id="top">
|
||||
<li><a href="#що-таке-delta-chat">Що таке Delta Chat?</a>
|
||||
<ul>
|
||||
<li><a href="#як-мені-знайти-людей-для-спілкування">Як мені знайти людей для спілкування?</a></li>
|
||||
@@ -676,7 +676,10 @@ Autocrypt використовує обмежену і <a href="#openpgp-secure"
|
||||
|
||||
<p>Так, Delta Chat використовує безпечну підмножину OpenPGP і відображає індикатор безпеки у вигляді замка в повідомленні лише тоді, коли все повідомлення належним чином зашифровано і підписано. Наприклад, “Відокремлені підписи” не вважаються безпечними.</p>
|
||||
|
||||
<p>OpenPGP не є небезпечним сам по собі. Більшість публічно обговорюваних проблем безпеки OpenPGP насправді виникають через погане використання або погану реалізацію інструментів або програм (або і те, і інше). Особливо важливо розрізняти OpenPGP, стандарт шифрування IETF, і GnuPG (GPG), інструментом командного рядка, що реалізує OpenPGP. Багато публічних критиків OpenPGP насправді обговорюють GnuPG, який Delta Chat ніколи не використовував. Натомість Delta Chat використовує реалізацію OpenPGP на Rust <a href="https://github.com/rpgp/rpgp">rPGP</a>, доступну як <a href="https://crates.io/crates/pgp">незалежний пакет “pgp”</a>, і <a href="https://delta.chat/assets/blog/2019-first-security-review.pdf">пройшов аудит безпеки у 2019 році</a>.</p>
|
||||
<p>OpenPGP сам по собі не є небезпечним. Більшість публічно обговорюваних проблем безпеки OpenPGP насправді виникають через недостатню зручність використання або погану реалізацію інструментів чи програм (або обох).
|
||||
Особливо важливо розрізняти OpenPGP, стандарт шифрування IETF, і GnuPG (GPG), інструмент командного рядка, що реалізує OpenPGP.
|
||||
Багато публічних критиків OpenPGP насправді обговорюють GnuPG, який Delta Chat ніколи не використовував.
|
||||
Delta Chat скоріше використовує реалізацію OpenPGP Rust <a href="https://github.com/rpgp/rpgp">rPGP</a>, доступну як <a href="https://crates.io/crates/pgp">незалежний пакет «pgp»</a> і <a href="#security-audits">перевірку безпеки в 2019 і 2024 роках</a>.</p>
|
||||
|
||||
<p>Ми прагнемо, разом з іншими розробниками OpenPGP, подальше покращення характеристик безпеки шляхом впровадження <a href="https://datatracker.ietf.org/doc/draft-ietf-openpgp-crypto-refresh/">нового IETF OpenPGP Crypto-Refresh</a> який, на щастя, був прийнятий влітку 2023 року.</p>
|
||||
|
||||
@@ -872,7 +875,17 @@ Look for something like <strong>Start Autocrypt Setup Transfer</strong> in the s
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Проект Delta Chat пройшов чотири незалежні аудити безпеки та один незалежний аналіз безпеки, від найновіших до найстаріших:</p>
|
||||
<p>Так, багаторазово. Проект Delta Chat постійно проходить незалежні перевірки та аналіз безпеки, а саме, від останніх і закінчуючи старішими:</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>2024 грудня відбулася <a href="https://github.com/rpgp/docs/blob/main/audits/NGI%20Core%20rPGP%20penetration%20test%20report%202024%201.0.pdf">оцінка rPGP на замовлення NLNET</a> від <a href="https://www.radicallyopensecurity.com/">Radically Open Security</a>. rPGP слугує рушієм наскрізного шифрування <a href="https://openpgp.org">OpenPGP</a> для Delta Chat. За результатами цього аудиту було випущено дві рекомендації:</p>
|
||||
</li>
|
||||
<li><a href="https://github.com/rpgp/rpgp/security/advisories/GHSA-9rmp-2568-59rv">“Паніка через неправильне ненадійне введення”</a> CVE-2024-53856</li>
|
||||
<li><a href="https://github.com/rpgp/rpgp/security/advisories/GHSA-4grw-m28r-q285">“Потенційне виснаження ресурсів під час обробки ненадійних повідомлень”</a> CVE-2024-53857</li>
|
||||
</ul>
|
||||
|
||||
<p>Проблеми, описані в цих рекомендаціях, виправлено, і вони є частиною випусків Delta Chat у всіх магазинах додатків з грудня 2024 року.</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<html><head><meta charset="UTF-8" /><meta name="viewport" content="initial-scale=1.0" /><link rel="stylesheet" href="../help.css" /></head><body><ul id="top">
|
||||
<html lang="zh_CN"><head><meta charset="UTF-8" /><meta name="viewport" content="initial-scale=1.0" /><link rel="stylesheet" href="../help.css" /></head><body><ul id="top">
|
||||
<li><a href="#什么是-delta-chat">什么是 Delta Chat?</a>
|
||||
<ul>
|
||||
<li><a href="#如何找到可以聊天的人">如何找到可以聊天的人?</a></li>
|
||||
@@ -835,15 +835,15 @@ Autocrypt 使用 OpenPGP 标准的有限且<a href="#openpgp-secure">安全子
|
||||
,前提是整个消息都已正确加密和签名。
|
||||
例如,“分离签名”不被视为安全。</p>
|
||||
|
||||
<p>OpenPGP 本身并不不安全。
|
||||
大多数公开讨论的 OpenPGP 安全问题
|
||||
实际上都源于工具或应用的糟糕可用性或糟糕实现(或两者兼而有之)。
|
||||
区分 OpenPGP(IETF 加密标准)
|
||||
和 GnuPG (GPG)(实现 OpenPGP 的命令行工具)尤为重要。
|
||||
许多对 OpenPGP 的公开批评实际上是在讨论 GnuPG,而 Delta Chat 从未使用过 GnuPG。
|
||||
Delta Chat 而是使用 OpenPGP Rust 实现 <a href="https://github.com/rpgp/rpgp">rPGP</a>,
|
||||
作为 <a href="https://crates.io/crates/pgp">独立的“pgp”软件包</a> 提供,
|
||||
并且 <a href="https://delta.chat/assets/blog/2019-first-security-review.pdf">在 2019 年进行了安全审计</a>。</p>
|
||||
<p>OpenPGP is not insecure by itself.
|
||||
Most publically discussed OpenPGP security problems
|
||||
actually stem from bad usability or bad implementations of tools or apps (or both).
|
||||
It is particularly important to distinguish between OpenPGP, the IETF encryption standard,
|
||||
and GnuPG (GPG), a command line tool implementing OpenPGP.
|
||||
Many public critiques of OpenPGP actually discuss GnuPG which Delta Chat has never used.
|
||||
Delta Chat rather uses the OpenPGP Rust implementation <a href="https://github.com/rpgp/rpgp">rPGP</a>,
|
||||
available as <a href="https://crates.io/crates/pgp">an independent “pgp” package</a>,
|
||||
and <a href="#security-audits">security-audited in 2019 and 2024</a>.</p>
|
||||
|
||||
<p>我们的目标是与其他 OpenPGP 实现者一起,
|
||||
通过实施 <a href="https://datatracker.ietf.org/doc/draft-ietf-openpgp-crypto-refresh/">新的 IETF OpenPGP Crypto-Refresh</a>
|
||||
@@ -1137,10 +1137,25 @@ Look for something like <strong>Start Autocrypt Setup Transfer</strong> in the s
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Delta Chat 项目经历了四次独立的安全性审计和一次
|
||||
独立的安全性分析,从最近到最旧:</p>
|
||||
<p>Yes, multiple times.
|
||||
The Delta Chat project continuously undergoes independent security audits and analysis,
|
||||
from most recent to older:</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>2024 December, an <a href="https://github.com/rpgp/docs/blob/main/audits/NGI%20Core%20rPGP%20penetration%20test%20report%202024%201.0.pdf">NLNET-commissioned Evaluation of
|
||||
rPGP</a> by <a href="https://www.radicallyopensecurity.com/">Radically Open Security</a> took place.
|
||||
rPGP serves as the end-to-end encyption <a href="https://openpgp.org">OpenPGP</a> engine of Delta Chat.
|
||||
Two advisories were released related to the findings of this audit:</p>
|
||||
|
||||
<ul>
|
||||
<li><a href="https://github.com/rpgp/rpgp/security/advisories/GHSA-9rmp-2568-59rv">“Panics on Malformed Untrusted Input”</a> CVE-2024-53856</li>
|
||||
<li><a href="https://github.com/rpgp/rpgp/security/advisories/GHSA-4grw-m28r-q285">“Potential Resource Exhaustion when handling Untrusted Messages”</a> CVE-2024-53857</li>
|
||||
</ul>
|
||||
|
||||
<p>The issues outlined in these advisories have been fixed and are part of Delta Chat
|
||||
releases on all appstores since December 2024.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>2024 年 3 月,我们收到了苏黎世联邦理工学院应用密码学
|
||||
研究小组的深入安全性分析,并解决了所有提出的问题。
|
||||
|
||||
@@ -35,7 +35,6 @@ public class DcAccounts {
|
||||
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 ();
|
||||
|
||||
@@ -17,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;
|
||||
@@ -51,8 +52,8 @@ 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;
|
||||
@@ -88,7 +89,7 @@ public class DcContext {
|
||||
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);
|
||||
}
|
||||
@@ -137,7 +138,8 @@ 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 ();
|
||||
@@ -187,13 +189,16 @@ 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 sendMsg (int chat_id, DcMsg msg);
|
||||
public native int sendTextMsg (int chat_id, String text);
|
||||
|
||||
@@ -151,7 +151,6 @@ public class DcMsg {
|
||||
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 ();
|
||||
@@ -159,7 +158,6 @@ public class DcMsg {
|
||||
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);
|
||||
@@ -171,6 +169,7 @@ public class DcMsg {
|
||||
public native String getError ();
|
||||
public native String getOverrideSenderName();
|
||||
public native int getSenderColor();
|
||||
public native boolean isEdited ();
|
||||
|
||||
public String getSenderName(DcContact dcContact) {
|
||||
String overrideName = getOverrideSenderName();
|
||||
@@ -191,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.");
|
||||
|
||||
@@ -17,6 +17,7 @@ public class Rpc {
|
||||
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) {
|
||||
@@ -46,6 +47,7 @@ public class Rpc {
|
||||
}
|
||||
|
||||
public void start() {
|
||||
started = true;
|
||||
new Thread(() -> {
|
||||
while (true) {
|
||||
try {
|
||||
@@ -57,7 +59,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;
|
||||
@@ -125,6 +129,10 @@ public class Rpc {
|
||||
return getResult("get_account_file_size", accountId).getAsInt();
|
||||
}
|
||||
|
||||
public int addAccount() throws RpcException {
|
||||
return getResult("add_account").getAsInt();
|
||||
}
|
||||
|
||||
private static class Request {
|
||||
private final String jsonrpc = "2.0";
|
||||
public final String method;
|
||||
|
||||
@@ -26,6 +26,7 @@ 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.connect.AccountManager;
|
||||
import org.thoughtcrime.securesms.connect.DcEventCenter;
|
||||
@@ -109,6 +110,7 @@ public class ApplicationContext extends MultiDexApplication {
|
||||
|
||||
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) {
|
||||
@@ -126,7 +128,11 @@ public class ApplicationContext extends MultiDexApplication {
|
||||
}
|
||||
}
|
||||
if (allAccounts.length == 0) {
|
||||
dcAccounts.addAccount();
|
||||
try {
|
||||
rpc.addAccount();
|
||||
} catch (RpcException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
dcContext = dcAccounts.getSelectedAccount();
|
||||
notificationCenter = new NotificationCenter(this);
|
||||
@@ -143,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);
|
||||
|
||||
@@ -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,6 +148,9 @@ 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));
|
||||
|
||||
@@ -203,38 +201,6 @@ public class ApplicationPreferencesActivity extends PassphraseRequiredActionBarA
|
||||
.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;
|
||||
|
||||
@@ -289,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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
@@ -316,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);
|
||||
@@ -376,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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -57,11 +57,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;
|
||||
|
||||
@@ -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;
|
||||
@@ -149,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;
|
||||
}
|
||||
@@ -213,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();
|
||||
|
||||
@@ -195,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) {
|
||||
@@ -495,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;
|
||||
}
|
||||
@@ -502,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;
|
||||
@@ -708,6 +739,7 @@ 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);
|
||||
@@ -990,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.
|
||||
@@ -1001,110 +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.setFileAndDeduplicate(path, attachment.getFileName(), null);
|
||||
}
|
||||
if (msg != null) {
|
||||
msg.setText(body);
|
||||
}
|
||||
}
|
||||
catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
else if (!body.isEmpty()){
|
||||
msg = new DcMsg(dcContext, DcMsg.DC_MSG_TEXT);
|
||||
msg.setText(body);
|
||||
}
|
||||
catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
|
||||
if (quote.isPresent()) {
|
||||
if (msg == null) msg = new DcMsg(dcContext, DcMsg.DC_MSG_TEXT);
|
||||
msg.setQuote(quote.get().getQuotedMsg());
|
||||
}
|
||||
}
|
||||
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 (action==ACTION_SEND_OUT) {
|
||||
|
||||
// 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) {
|
||||
// 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) {
|
||||
Util.runOnMain(() -> {
|
||||
progressDialog = ProgressDialog.show(
|
||||
ConversationActivity.this,
|
||||
"",
|
||||
getString(R.string.one_moment),
|
||||
true,
|
||||
false
|
||||
);
|
||||
});
|
||||
doSend = VideoRecoder.prepareVideo(ConversationActivity.this, dcChat.getId(), msg);
|
||||
Util.runOnMain(() -> {
|
||||
try {
|
||||
progressDialog.dismiss();
|
||||
} catch (final IllegalArgumentException e) {
|
||||
// The activity is finishing/destroyed, do nothing.
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -1139,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 {
|
||||
@@ -1257,9 +1292,16 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
}
|
||||
}
|
||||
|
||||
@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)) {
|
||||
@@ -1317,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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1391,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()));
|
||||
|
||||
@@ -1406,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) {
|
||||
|
||||
@@ -25,9 +25,7 @@ import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Bundle;
|
||||
import android.text.Editable;
|
||||
import android.text.TextUtils;
|
||||
import android.text.TextWatcher;
|
||||
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;
|
||||
@@ -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 canEdit = canEditMsg(messageRecord);
|
||||
menu.findItem(R.id.menu_context_edit).setVisible(chat.canSend() && canEdit);
|
||||
boolean showReplyPrivately = !dcContext.isCommunity() && 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());
|
||||
}
|
||||
@@ -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 {
|
||||
@@ -707,80 +741,6 @@ public class ConversationFragment extends MessageSelectorFragment
|
||||
Util.runOnAnyBackgroundThread(() -> 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();
|
||||
}
|
||||
|
||||
private class ConversationFragmentItemClickListener implements ItemClickListener {
|
||||
|
||||
@Override
|
||||
@@ -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());
|
||||
}
|
||||
@@ -844,20 +801,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();
|
||||
@@ -867,10 +822,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);
|
||||
@@ -918,6 +883,7 @@ public class ConversationFragment extends MessageSelectorFragment
|
||||
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;
|
||||
@@ -942,45 +908,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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -101,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;
|
||||
@@ -155,6 +156,7 @@ 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);
|
||||
|
||||
@@ -176,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 = dcContext.isCommunity() || ((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);
|
||||
@@ -378,7 +391,7 @@ 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) {
|
||||
@@ -387,11 +400,7 @@ public class ConversationItem extends BaseConversationItem
|
||||
|
||||
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 {
|
||||
@@ -707,7 +716,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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -20,8 +20,8 @@ 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_SERVER_FLAGS;
|
||||
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;
|
||||
import static org.thoughtcrime.securesms.util.RelayUtil.getSharedTitle;
|
||||
@@ -112,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_50_0_android";
|
||||
final String deviceMsgLabel = "update_1_56_0_android";
|
||||
if (!dcContext.wasDeviceMsgEverAdded(deviceMsgLabel)) {
|
||||
DcMsg msg = null;
|
||||
if (!getIntent().getBooleanExtra(FROM_WELCOME, false)) {
|
||||
@@ -123,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_50_android, "https://raw.githubusercontent.com/ArcaneChat/android/refs/heads/main/CHANGELOG.md"));
|
||||
// full changelog link: "https://lemmy.ml/c/ArcaneChat"
|
||||
msg.setText(getString(R.string.update_1_56_android, "https://arcanechat.me/#contribute"));
|
||||
}
|
||||
dcContext.addDeviceMsg(deviceMsgLabel, msg);
|
||||
|
||||
@@ -434,31 +435,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 R.id.menu_proxy_settings:
|
||||
startActivity(new Intent(this, ProxySettingsActivity.class));
|
||||
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_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;
|
||||
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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -11,7 +11,6 @@ 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;
|
||||
@@ -101,13 +100,12 @@ public class CreateProfileActivity extends BaseActionBarActivity {
|
||||
@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;
|
||||
|
||||
@@ -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;
|
||||
@@ -23,7 +24,7 @@ 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 org.thoughtcrime.securesms.components.AvatarSelector;
|
||||
@@ -74,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);
|
||||
@@ -207,22 +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();
|
||||
createGroup(groupName);
|
||||
}
|
||||
if (groupChatId != 0) {
|
||||
updateGroup(groupName);
|
||||
} else {
|
||||
verified = !broadcast && allMembersVerified();
|
||||
createGroup(groupName);
|
||||
}
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -354,11 +355,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) {}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ 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;
|
||||
@@ -16,7 +15,6 @@ 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;
|
||||
@@ -158,14 +156,14 @@ public class InstantOnboardingActivity extends BaseActionBarActivity implements
|
||||
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
|
||||
super.onOptionsItemSelected(item);
|
||||
|
||||
switch (item.getItemId()) {
|
||||
case android.R.id.home:
|
||||
int itemId = item.getItemId();
|
||||
if (itemId == android.R.id.home) {
|
||||
getOnBackPressedDispatcher().onBackPressed();
|
||||
return true;
|
||||
case R.id.menu_proxy_settings:
|
||||
} else if (itemId == R.id.menu_proxy_settings) {
|
||||
startActivity(new Intent(this, ProxySettingsActivity.class));
|
||||
return true;
|
||||
case R.id.menu_view_log:
|
||||
} else if (itemId == R.id.menu_view_log) {
|
||||
startActivity(new Intent(this, LogViewActivity.class));
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -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://arcanechat.me");
|
||||
return true;
|
||||
case R.id.privacy_policy:
|
||||
openOnlineUrl("https://arcanechat.me/privacy.html");
|
||||
return true;
|
||||
case R.id.contribute:
|
||||
openOnlineUrl("https://arcanechat.me/#contribute");
|
||||
return true;
|
||||
case R.id.report_issue:
|
||||
openOnlineUrl("https://github.com/ArcaneChat/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;
|
||||
|
||||
@@ -18,14 +18,12 @@
|
||||
package org.thoughtcrime.securesms;
|
||||
|
||||
import android.Manifest;
|
||||
import android.annotation.TargetApi;
|
||||
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;
|
||||
|
||||
@@ -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;
|
||||
@@ -345,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
|
||||
@@ -395,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;
|
||||
|
||||
@@ -61,22 +61,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) -> {
|
||||
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) {
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -153,6 +153,7 @@ public class ProfileActivity extends PassphraseRequiredActionBarActivity
|
||||
menu.findItem(R.id.share).setVisible(false);
|
||||
}
|
||||
} else {
|
||||
menu.findItem(R.id.menu_clone).setVisible(false);
|
||||
canReceive = false;
|
||||
}
|
||||
|
||||
@@ -415,35 +416,27 @@ public class ProfileActivity extends PassphraseRequiredActionBarActivity
|
||||
public boolean onOptionsItemSelected(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;
|
||||
@@ -452,10 +445,8 @@ public class ProfileActivity extends PassphraseRequiredActionBarActivity
|
||||
@Override
|
||||
public boolean onContextItemSelected(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;
|
||||
}
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
package org.thoughtcrime.securesms;
|
||||
|
||||
import android.content.Context;
|
||||
import androidx.annotation.NonNull;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.b44t.messenger.DcMsg;
|
||||
import com.codewaves.stickyheadergrid.StickyHeaderGridAdapter;
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ import static com.b44t.messenger.DcChat.DC_CHAT_NO_CHAT;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
@@ -122,7 +121,13 @@ public class ProfileDocumentsFragment
|
||||
|
||||
noMedia.setVisibility(recyclerView.getAdapter().getItemCount() > 0 ? View.GONE : View.VISIBLE);
|
||||
if (chatId == DC_CHAT_NO_CHAT) {
|
||||
noMedia.setText(R.string.tab_all_media_empty_hint);
|
||||
if (showWebxdc) {
|
||||
noMedia.setText(R.string.all_apps_empty_hint);
|
||||
} else if (!showAudio){
|
||||
noMedia.setText(R.string.all_files_empty_hint);
|
||||
} else {
|
||||
noMedia.setText(R.string.tab_all_media_empty_hint);
|
||||
}
|
||||
} else if (showAudio) {
|
||||
noMedia.setText(R.string.tab_audio_empty_hint);
|
||||
} else if (showWebxdc) {
|
||||
@@ -243,35 +248,35 @@ public class ProfileDocumentsFragment
|
||||
|
||||
@Override
|
||||
public boolean onActionItemClicked(ActionMode mode, MenuItem menuItem) {
|
||||
switch (menuItem.getItemId()) {
|
||||
case R.id.details:
|
||||
handleDisplayDetails(getSelectedMessageRecord(getListAdapter().getSelectedMedia()));
|
||||
mode.finish();
|
||||
return true;
|
||||
case R.id.delete:
|
||||
handleDeleteMessages(chatId, getListAdapter().getSelectedMedia());
|
||||
mode.finish();
|
||||
return true;
|
||||
case R.id.share:
|
||||
handleShare(getSelectedMessageRecord(getListAdapter().getSelectedMedia()));
|
||||
return true;
|
||||
case R.id.menu_add_to_home_screen:
|
||||
WebxdcActivity.addToHomeScreen(getActivity(), getSelectedMessageRecord(getListAdapter().getSelectedMedia()).getId());
|
||||
mode.finish();
|
||||
return true;
|
||||
case R.id.show_in_chat:
|
||||
handleShowInChat(getSelectedMessageRecord(getListAdapter().getSelectedMedia()));
|
||||
return true;
|
||||
case R.id.save:
|
||||
handleSaveAttachment(getListAdapter().getSelectedMedia());
|
||||
return true;
|
||||
case R.id.menu_resend:
|
||||
handleResendMessage(getListAdapter().getSelectedMedia());
|
||||
return true;
|
||||
case R.id.menu_select_all:
|
||||
getListAdapter().selectAll();
|
||||
updateActionModeBar();
|
||||
return true;
|
||||
int itemId = menuItem.getItemId();
|
||||
if (itemId == R.id.details) {
|
||||
handleDisplayDetails(getSelectedMessageRecord(getListAdapter().getSelectedMedia()));
|
||||
mode.finish();
|
||||
return true;
|
||||
} else if (itemId == R.id.delete) {
|
||||
handleDeleteMessages(chatId, getListAdapter().getSelectedMedia());
|
||||
mode.finish();
|
||||
return true;
|
||||
} else if (itemId == R.id.share) {
|
||||
handleShare(getSelectedMessageRecord(getListAdapter().getSelectedMedia()));
|
||||
return true;
|
||||
} else if (itemId == R.id.menu_add_to_home_screen) {
|
||||
WebxdcActivity.addToHomeScreen(getActivity(), getSelectedMessageRecord(getListAdapter().getSelectedMedia()).getId());
|
||||
mode.finish();
|
||||
return true;
|
||||
} else if (itemId == R.id.show_in_chat) {
|
||||
handleShowInChat(getSelectedMessageRecord(getListAdapter().getSelectedMedia()));
|
||||
return true;
|
||||
} else if (itemId == R.id.save) {
|
||||
handleSaveAttachment(getListAdapter().getSelectedMedia());
|
||||
return true;
|
||||
} else if (itemId == R.id.menu_resend) {
|
||||
handleResendMessage(getListAdapter().getSelectedMedia());
|
||||
return true;
|
||||
} else if (itemId == R.id.menu_select_all) {
|
||||
getListAdapter().selectAll();
|
||||
updateActionModeBar();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
package org.thoughtcrime.securesms;
|
||||
|
||||
import android.content.Context;
|
||||
import androidx.annotation.NonNull;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.b44t.messenger.DcMsg;
|
||||
import com.codewaves.stickyheadergrid.StickyHeaderGridAdapter;
|
||||
|
||||
|
||||
@@ -5,14 +5,7 @@ import static com.b44t.messenger.DcChat.DC_CHAT_NO_CHAT;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.loader.app.LoaderManager;
|
||||
import androidx.loader.content.Loader;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.view.ActionMode;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
@@ -21,6 +14,13 @@ import android.view.ViewGroup;
|
||||
import android.view.Window;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.view.ActionMode;
|
||||
import androidx.loader.app.LoaderManager;
|
||||
import androidx.loader.content.Loader;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.b44t.messenger.DcContext;
|
||||
import com.b44t.messenger.DcEvent;
|
||||
import com.b44t.messenger.DcMsg;
|
||||
@@ -233,31 +233,31 @@ public class ProfileGalleryFragment
|
||||
|
||||
@Override
|
||||
public boolean onActionItemClicked(ActionMode mode, MenuItem menuItem) {
|
||||
switch (menuItem.getItemId()) {
|
||||
case R.id.details:
|
||||
handleDisplayDetails(getSelectedMessageRecord(getListAdapter().getSelectedMedia()));
|
||||
mode.finish();
|
||||
return true;
|
||||
case R.id.delete:
|
||||
handleDeleteMessages(chatId, getListAdapter().getSelectedMedia());
|
||||
mode.finish();
|
||||
return true;
|
||||
case R.id.share:
|
||||
handleShare(getSelectedMessageRecord(getListAdapter().getSelectedMedia()));
|
||||
return true;
|
||||
case R.id.show_in_chat:
|
||||
handleShowInChat(getSelectedMessageRecord(getListAdapter().getSelectedMedia()));
|
||||
return true;
|
||||
case R.id.save:
|
||||
handleSaveAttachment(getListAdapter().getSelectedMedia());
|
||||
return true;
|
||||
case R.id.menu_resend:
|
||||
handleResendMessage(getListAdapter().getSelectedMedia());
|
||||
return true;
|
||||
case R.id.menu_select_all:
|
||||
getListAdapter().selectAll();
|
||||
updateActionModeBar();
|
||||
return true;
|
||||
int itemId = menuItem.getItemId();
|
||||
if (itemId == R.id.details) {
|
||||
handleDisplayDetails(getSelectedMessageRecord(getListAdapter().getSelectedMedia()));
|
||||
mode.finish();
|
||||
return true;
|
||||
} else if (itemId == R.id.delete) {
|
||||
handleDeleteMessages(chatId, getListAdapter().getSelectedMedia());
|
||||
mode.finish();
|
||||
return true;
|
||||
} else if (itemId == R.id.share) {
|
||||
handleShare(getSelectedMessageRecord(getListAdapter().getSelectedMedia()));
|
||||
return true;
|
||||
} else if (itemId == R.id.show_in_chat) {
|
||||
handleShowInChat(getSelectedMessageRecord(getListAdapter().getSelectedMedia()));
|
||||
return true;
|
||||
} else if (itemId == R.id.save) {
|
||||
handleSaveAttachment(getListAdapter().getSelectedMedia());
|
||||
return true;
|
||||
} else if (itemId == R.id.menu_resend) {
|
||||
handleResendMessage(getListAdapter().getSelectedMedia());
|
||||
return true;
|
||||
} else if (itemId == R.id.menu_select_all) {
|
||||
getListAdapter().selectAll();
|
||||
updateActionModeBar();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import org.thoughtcrime.securesms.connect.DcHelper;
|
||||
import org.thoughtcrime.securesms.contacts.ContactSelectionListItem;
|
||||
import org.thoughtcrime.securesms.mms.GlideRequests;
|
||||
import org.thoughtcrime.securesms.util.DateUtils;
|
||||
import org.thoughtcrime.securesms.util.ResUtil;
|
||||
import org.thoughtcrime.securesms.util.StickyHeaderDecoration.StickyHeaderAdapter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -330,7 +331,8 @@ public class ProfileSettingsAdapter extends RecyclerView.Adapter
|
||||
itemData.add(new ItemData(ItemData.CATEGORY_INFO, INFO_LAST_SEEN, lastSeenTxt, 0, 0));
|
||||
|
||||
|
||||
itemData.add(new ItemData(ItemData.CATEGORY_INFO, INFO_SEND_MESSAGE_BUTTON, context.getString(R.string.send_message), R.color.def_accent, 0));
|
||||
int color = ResUtil.getColor(context, R.attr.colorAccent);
|
||||
itemData.add(new ItemData(ItemData.CATEGORY_INFO, INFO_SEND_MESSAGE_BUTTON, context.getString(R.string.send_message), color, 0));
|
||||
}
|
||||
|
||||
itemDataStatusText = dcContact.getStatus();
|
||||
|
||||
@@ -4,7 +4,6 @@ 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.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
@@ -281,29 +280,28 @@ public class ProfileSettingsFragment extends Fragment
|
||||
|
||||
@Override
|
||||
public boolean onActionItemClicked(ActionMode mode, MenuItem menuItem) {
|
||||
switch (menuItem.getItemId()) {
|
||||
case R.id.delete:
|
||||
final Collection<Integer> toDelIds = adapter.getSelectedMembers();
|
||||
StringBuilder readableToDelList = new StringBuilder();
|
||||
for (Integer toDelId : toDelIds) {
|
||||
if(readableToDelList.length()>0) {
|
||||
readableToDelList.append(", ");
|
||||
}
|
||||
readableToDelList.append(dcContext.getContact(toDelId).getDisplayName());
|
||||
if (menuItem.getItemId() == R.id.delete) {
|
||||
final Collection<Integer> toDelIds = adapter.getSelectedMembers();
|
||||
StringBuilder readableToDelList = new StringBuilder();
|
||||
for (Integer toDelId : toDelIds) {
|
||||
if (readableToDelList.length() > 0) {
|
||||
readableToDelList.append(", ");
|
||||
}
|
||||
DcChat dcChat = dcContext.getChat(chatId);
|
||||
AlertDialog dialog = new AlertDialog.Builder(getContext())
|
||||
.setPositiveButton(R.string.remove_desktop, (d, which) -> {
|
||||
for (Integer toDelId : toDelIds) {
|
||||
dcContext.removeContactFromChat(chatId, toDelId);
|
||||
}
|
||||
mode.finish();
|
||||
})
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.setMessage(getString(dcChat.isBroadcast()? R.string.ask_remove_from_broadcast : R.string.ask_remove_members, readableToDelList))
|
||||
.show();
|
||||
Util.redPositiveButton(dialog);
|
||||
return true;
|
||||
readableToDelList.append(dcContext.getContact(toDelId).getDisplayName());
|
||||
}
|
||||
DcChat dcChat = dcContext.getChat(chatId);
|
||||
AlertDialog dialog = new AlertDialog.Builder(getContext())
|
||||
.setPositiveButton(R.string.remove_desktop, (d, which) -> {
|
||||
for (Integer toDelId : toDelIds) {
|
||||
dcContext.removeContactFromChat(chatId, toDelId);
|
||||
}
|
||||
mode.finish();
|
||||
})
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.setMessage(getString(dcChat.isBroadcast() ? R.string.ask_remove_from_broadcast : R.string.ask_remove_members, readableToDelList))
|
||||
.show();
|
||||
Util.redPositiveButton(dialog);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -321,12 +319,15 @@ public class ProfileSettingsFragment extends Fragment
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
if (requestCode==REQUEST_CODE_PICK_CONTACT && resultCode==Activity.RESULT_OK && data!=null) {
|
||||
List<String> selected = data.getStringArrayListExtra("contacts");
|
||||
for (String addr : selected) {
|
||||
if (addr!=null) {
|
||||
int toAddId = dcContext.createContact(null, addr);
|
||||
dcContext.addContactToChat(chatId, toAddId);
|
||||
if(selected == null) return;
|
||||
Util.runOnAnyBackgroundThread(() -> {
|
||||
for (String addr : selected) {
|
||||
if (addr!=null) {
|
||||
int toAddId = dcContext.createContact(null, addr);
|
||||
dcContext.addContactToChat(chatId, toAddId);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,9 +31,8 @@ public class ProfileSettingsItem extends LinearLayout {
|
||||
labelView.setText(label==null? "" : label);
|
||||
labelView.setCompoundDrawablesWithIntrinsicBounds(iconLeft, 0,0,0);
|
||||
|
||||
// we need different color getters as `labelColor` is `R.color.name` while default is `R.attr.name`
|
||||
if (labelColor != 0) {
|
||||
labelView.setTextColor(ContextCompat.getColor(getContext(), labelColor));
|
||||
labelView.setTextColor(labelColor);
|
||||
} else {
|
||||
labelView.setTextColor(ResUtil.getColor(getContext(), R.attr.emoji_text_color));
|
||||
}
|
||||
|
||||
@@ -6,13 +6,13 @@ import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_MAIL_PORT;
|
||||
import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_MAIL_SECURITY;
|
||||
import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_MAIL_SERVER;
|
||||
import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_MAIL_USER;
|
||||
import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_PROXY_ENABLED;
|
||||
import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_SEND_PASSWORD;
|
||||
import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_SEND_PORT;
|
||||
import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_SEND_SECURITY;
|
||||
import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_SEND_SERVER;
|
||||
import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_SEND_USER;
|
||||
import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_SERVER_FLAGS;
|
||||
import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_PROXY_ENABLED;
|
||||
import static org.thoughtcrime.securesms.connect.DcHelper.getContext;
|
||||
import static org.thoughtcrime.securesms.service.IPCAddAccountsService.ACCOUNT_DATA;
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package org.thoughtcrime.securesms;
|
||||
|
||||
import static org.thoughtcrime.securesms.util.MediaUtil.getMimeType;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
@@ -14,8 +16,6 @@ import java.io.InputStream;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.HashSet;
|
||||
|
||||
import static org.thoughtcrime.securesms.util.MediaUtil.getMimeType;
|
||||
|
||||
import de.cketti.safecontentresolver.SafeContentResolver;
|
||||
|
||||
public class ResolveMediaTask extends AsyncTask<Uri, Void, Uri> {
|
||||
|
||||
@@ -34,7 +34,6 @@ import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.ActionBar;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.core.content.pm.ShortcutManagerCompat;
|
||||
|
||||
import com.b44t.messenger.DcContext;
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.thoughtcrime.securesms;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
package org.thoughtcrime.securesms;
|
||||
|
||||
import static org.thoughtcrime.securesms.TransportOption.Type;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
@@ -9,8 +12,6 @@ import org.thoughtcrime.securesms.util.guava.Optional;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.thoughtcrime.securesms.TransportOption.Type;
|
||||
|
||||
public class TransportOptions {
|
||||
private final List<OnTransportChangedListener> listeners = new LinkedList<>();
|
||||
private final Context context;
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package org.thoughtcrime.securesms;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
@@ -10,6 +8,8 @@ import android.widget.BaseAdapter;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
package org.thoughtcrime.securesms;
|
||||
|
||||
import android.content.Context;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.widget.ListPopupWindow;
|
||||
import android.view.View;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ListView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.widget.ListPopupWindow;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
package org.thoughtcrime.securesms;
|
||||
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
@@ -20,10 +16,10 @@ import android.widget.Toast;
|
||||
import androidx.annotation.RequiresApi;
|
||||
import androidx.appcompat.app.ActionBar;
|
||||
import androidx.appcompat.widget.SearchView;
|
||||
import androidx.webkit.ProxyConfig;
|
||||
import androidx.webkit.ProxyController;
|
||||
import androidx.webkit.WebSettingsCompat;
|
||||
import androidx.webkit.WebViewFeature;
|
||||
import androidx.webkit.ProxyController;
|
||||
import androidx.webkit.ProxyConfig;
|
||||
|
||||
import org.thoughtcrime.securesms.util.DynamicTheme;
|
||||
import org.thoughtcrime.securesms.util.IntentUtils;
|
||||
@@ -254,24 +250,24 @@ public class WebViewActivity extends PassphraseRequiredActionBarActivity
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
super.onOptionsItemSelected(item);
|
||||
switch (item.getItemId()) {
|
||||
case android.R.id.home:
|
||||
finish();
|
||||
return true;
|
||||
case R.id.menu_search_up:
|
||||
if (lastQuery.isEmpty()) {
|
||||
webView.scrollTo(0, 0);
|
||||
} else {
|
||||
webView.findNext(false);
|
||||
}
|
||||
return true;
|
||||
case R.id.menu_search_down:
|
||||
if (lastQuery.isEmpty()) {
|
||||
webView.scrollTo(0, 1000000000);
|
||||
} else {
|
||||
webView.findNext(true);
|
||||
}
|
||||
return true;
|
||||
int itemId = item.getItemId();
|
||||
if (itemId == android.R.id.home) {
|
||||
finish();
|
||||
return true;
|
||||
} else if (itemId == R.id.menu_search_up) {
|
||||
if (lastQuery.isEmpty()) {
|
||||
webView.scrollTo(0, 0);
|
||||
} else {
|
||||
webView.findNext(false);
|
||||
}
|
||||
return true;
|
||||
} else if (itemId == R.id.menu_search_down) {
|
||||
if (lastQuery.isEmpty()) {
|
||||
webView.scrollTo(0, 1000000000);
|
||||
} else {
|
||||
webView.findNext(true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -289,16 +289,16 @@ public class WebxdcActivity extends WebViewActivity implements DcEventCenter.DcE
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
super.onOptionsItemSelected(item);
|
||||
switch (item.getItemId()) {
|
||||
case R.id.menu_add_to_home_screen:
|
||||
addToHomeScreen(this, dcAppMsg.getId());
|
||||
return true;
|
||||
case R.id.source_code:
|
||||
IntentUtils.showInBrowser(this, sourceCodeUrl);
|
||||
return true;
|
||||
case R.id.show_in_chat:
|
||||
showInChat();
|
||||
return true;
|
||||
int itemId = item.getItemId();
|
||||
if (itemId == R.id.menu_add_to_home_screen) {
|
||||
addToHomeScreen(this, dcAppMsg.getId());
|
||||
return true;
|
||||
} else if (itemId == R.id.source_code) {
|
||||
IntentUtils.showInBrowser(this, sourceCodeUrl);
|
||||
return true;
|
||||
} else if (itemId == R.id.show_in_chat) {
|
||||
showInChat();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -5,8 +5,6 @@ import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Color;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
@@ -15,7 +13,6 @@ import android.util.Log;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
@@ -352,7 +349,6 @@ public class WelcomeActivity extends BaseActionBarActivity implements DcEventCen
|
||||
}
|
||||
DcLot qrParsed = dcContext.checkQr(qrRaw);
|
||||
switch (qrParsed.getState()) {
|
||||
case DcContext.DC_QR_BACKUP:
|
||||
case DcContext.DC_QR_BACKUP2:
|
||||
final String finalQrRaw = qrRaw;
|
||||
new AlertDialog.Builder(this)
|
||||
@@ -364,6 +360,14 @@ public class WelcomeActivity extends BaseActionBarActivity implements DcEventCen
|
||||
.show();
|
||||
break;
|
||||
|
||||
case DcContext.DC_QR_BACKUP_TOO_NEW:
|
||||
new AlertDialog.Builder(this)
|
||||
.setTitle(R.string.multidevice_receiver_title)
|
||||
.setMessage(R.string.multidevice_receiver_needs_update)
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
.show();
|
||||
break;
|
||||
|
||||
default:
|
||||
new AlertDialog.Builder(this)
|
||||
.setMessage(R.string.qraccount_qr_code_cannot_be_used)
|
||||
|
||||
@@ -16,10 +16,9 @@ import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.connect.DcHelper;
|
||||
import org.thoughtcrime.securesms.mms.GlideRequests;
|
||||
|
||||
public class AccountSelectionListAdapter extends RecyclerView.Adapter
|
||||
public class AccountSelectionListAdapter extends RecyclerView.Adapter<AccountSelectionListAdapter.AccountViewHolder>
|
||||
{
|
||||
private final @NonNull AccountSelectionListFragment fragment;
|
||||
private final @NonNull Context context;
|
||||
private final @NonNull DcAccounts accounts;
|
||||
private @NonNull int[] accountList = new int[0];
|
||||
private int selectedAccountId;
|
||||
@@ -32,18 +31,7 @@ public class AccountSelectionListAdapter extends RecyclerView.Adapter
|
||||
return accountList.length;
|
||||
}
|
||||
|
||||
public abstract static class ViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
public ViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
}
|
||||
|
||||
public abstract void bind(@NonNull GlideRequests glideRequests, int accountId, DcContext dcContext, boolean selected, AccountSelectionListFragment fragment);
|
||||
public abstract void unbind(@NonNull GlideRequests glideRequests);
|
||||
}
|
||||
|
||||
public static class AccountViewHolder extends ViewHolder {
|
||||
|
||||
public static class AccountViewHolder extends RecyclerView.ViewHolder {
|
||||
AccountViewHolder(@NonNull final View itemView,
|
||||
@Nullable final ItemClickListener clickListener) {
|
||||
super(itemView);
|
||||
@@ -62,7 +50,6 @@ public class AccountSelectionListAdapter extends RecyclerView.Adapter
|
||||
getView().bind(glideRequests, accountId, dcContext, selected, fragment);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unbind(@NonNull GlideRequests glideRequests) {
|
||||
getView().unbind(glideRequests);
|
||||
}
|
||||
@@ -73,8 +60,8 @@ public class AccountSelectionListAdapter extends RecyclerView.Adapter
|
||||
@Nullable ItemClickListener clickListener)
|
||||
{
|
||||
super();
|
||||
Context context = fragment.requireActivity();
|
||||
this.fragment = fragment;
|
||||
this.context = fragment.getActivity();
|
||||
this.accounts = DcHelper.getAccounts(context);
|
||||
this.li = LayoutInflater.from(context);
|
||||
this.glideRequests = glideRequests;
|
||||
@@ -83,16 +70,15 @@ public class AccountSelectionListAdapter extends RecyclerView.Adapter
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public AccountSelectionListAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
public AccountViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
return new AccountViewHolder(li.inflate(R.layout.account_selection_list_item, parent, false), clickListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int i) {
|
||||
public void onBindViewHolder(@NonNull AccountViewHolder holder, int i) {
|
||||
int id = accountList[i];
|
||||
DcContext dcContext = accounts.getAccount(id);
|
||||
|
||||
ViewHolder holder = (ViewHolder) viewHolder;
|
||||
holder.unbind(glideRequests);
|
||||
holder.bind(glideRequests, id, dcContext, id == selectedAccountId, fragment);
|
||||
}
|
||||
|
||||
+23
-28
@@ -1,10 +1,14 @@
|
||||
package org.thoughtcrime.securesms.accounts;
|
||||
|
||||
import static com.b44t.messenger.DcContact.DC_CONTACT_ID_ADD_ACCOUNT;
|
||||
import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_PRIVATE_TAG;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Dialog;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.view.ContextMenu;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MenuItem;
|
||||
@@ -37,26 +41,12 @@ import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||
|
||||
import static com.b44t.messenger.DcContact.DC_CONTACT_ID_ADD_ACCOUNT;
|
||||
import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_PRIVATE_TAG;
|
||||
|
||||
public class AccountSelectionListFragment extends DialogFragment implements DcEventCenter.DcEventDelegate
|
||||
{
|
||||
private static final String TAG = AccountSelectionListFragment.class.getSimpleName();
|
||||
private RecyclerView recyclerView;
|
||||
private AccountSelectionListAdapter adapter;
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(Bundle icicle) {
|
||||
super.onActivityCreated(icicle);
|
||||
adapter = new AccountSelectionListAdapter(this, GlideApp.with(getActivity()), new ListClickListener());
|
||||
recyclerView.setAdapter(adapter);
|
||||
refreshData();
|
||||
DcEventCenter eventCenter = DcHelper.getEventCenter(requireActivity());
|
||||
eventCenter.addMultiAccountObserver(DcContext.DC_EVENT_CONNECTIVITY_CHANGED, this);
|
||||
eventCenter.addMultiAccountObserver(DcContext.DC_EVENT_INCOMING_MSG, this);
|
||||
eventCenter.addMultiAccountObserver(DcContext.DC_EVENT_MSGS_NOTICED, this);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
@@ -72,6 +62,14 @@ public class AccountSelectionListFragment extends DialogFragment implements DcEv
|
||||
recyclerView = ViewUtil.findById(view, R.id.recycler_view);
|
||||
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
|
||||
|
||||
adapter = new AccountSelectionListAdapter(this, GlideApp.with(getActivity()), new ListClickListener());
|
||||
recyclerView.setAdapter(adapter);
|
||||
refreshData();
|
||||
DcEventCenter eventCenter = DcHelper.getEventCenter(requireActivity());
|
||||
eventCenter.addMultiAccountObserver(DcContext.DC_EVENT_CONNECTIVITY_CHANGED, this);
|
||||
eventCenter.addMultiAccountObserver(DcContext.DC_EVENT_INCOMING_MSG, this);
|
||||
eventCenter.addMultiAccountObserver(DcContext.DC_EVENT_MSGS_NOTICED, this);
|
||||
|
||||
return builder.setView(view).create();
|
||||
}
|
||||
|
||||
@@ -102,13 +100,13 @@ public class AccountSelectionListFragment extends DialogFragment implements DcEv
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
|
||||
public void onCreateContextMenu(@NonNull ContextMenu menu, @NonNull View v, ContextMenu.ContextMenuInfo menuInfo) {
|
||||
super.onCreateContextMenu(menu, v, menuInfo);
|
||||
requireActivity().getMenuInflater().inflate(R.menu.account_item_context, menu);
|
||||
|
||||
AccountSelectionListItem listItem = (AccountSelectionListItem) v;
|
||||
int accountId = listItem.getAccountId();
|
||||
DcAccounts dcAccounts = DcHelper.getAccounts(getActivity());
|
||||
DcAccounts dcAccounts = DcHelper.getAccounts(requireActivity());
|
||||
|
||||
Util.redMenuItem(menu, R.id.delete);
|
||||
|
||||
@@ -129,16 +127,13 @@ public class AccountSelectionListFragment extends DialogFragment implements DcEv
|
||||
}
|
||||
|
||||
private void onContextItemSelected(MenuItem item, int accountId) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.delete:
|
||||
int itemId = item.getItemId();
|
||||
if (itemId == R.id.delete) {
|
||||
onDeleteAccount(accountId);
|
||||
break;
|
||||
case R.id.menu_mute_notifications:
|
||||
} else if (itemId == R.id.menu_mute_notifications) {
|
||||
onToggleMute(accountId);
|
||||
break;
|
||||
case R.id.menu_set_tag:
|
||||
} else if (itemId == R.id.menu_set_tag) {
|
||||
onSetTag(accountId);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -185,7 +180,7 @@ public class AccountSelectionListFragment extends DialogFragment implements DcEv
|
||||
if (TextUtils.isEmpty(name)) {
|
||||
name = contact.getAddr();
|
||||
}
|
||||
Recipient recipient = new Recipient(getContext(), contact, name);
|
||||
Recipient recipient = new Recipient(requireContext(), contact, name);
|
||||
avatar.setAvatar(GlideApp.with(activity), recipient, false);
|
||||
nameView.setText(name);
|
||||
addrView.setText(contact.getAddr());
|
||||
@@ -196,7 +191,7 @@ public class AccountSelectionListFragment extends DialogFragment implements DcEv
|
||||
sizeView.setText(Util.getPrettyFileSize(sizeBytes));
|
||||
});
|
||||
} catch (RpcException e) {
|
||||
e.printStackTrace();
|
||||
Log.e(TAG, "Error calling rpc.getAccountFileSize()", e);
|
||||
}
|
||||
});
|
||||
description.setText(activity.getString(R.string.delete_account_explain_with_name, name));
|
||||
@@ -226,7 +221,7 @@ public class AccountSelectionListFragment extends DialogFragment implements DcEv
|
||||
}
|
||||
|
||||
private void onToggleMute(int accountId) {
|
||||
DcAccounts dcAccounts = DcHelper.getAccounts(getActivity());
|
||||
DcAccounts dcAccounts = DcHelper.getAccounts(requireActivity());
|
||||
DcContext dcContext = dcAccounts.getAccount(accountId);
|
||||
dcContext.setMuted(!dcContext.isMuted());
|
||||
recyclerView.getAdapter().notifyDataSetChanged();
|
||||
@@ -236,7 +231,7 @@ public class AccountSelectionListFragment extends DialogFragment implements DcEv
|
||||
|
||||
@Override
|
||||
public void onItemClick(AccountSelectionListItem contact) {
|
||||
Activity activity = getActivity();
|
||||
Activity activity = requireActivity();
|
||||
AccountSelectionListFragment.this.dismiss();
|
||||
int accountId = contact.getAccountId();
|
||||
if (accountId == DC_CONTACT_ID_ADD_ACCOUNT) {
|
||||
|
||||
@@ -3,15 +3,17 @@ package org.thoughtcrime.securesms.animation;
|
||||
|
||||
import android.animation.Animator;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
public abstract class AnimationCompleteListener implements Animator.AnimatorListener {
|
||||
@Override
|
||||
public final void onAnimationStart(Animator animation) {}
|
||||
public final void onAnimationStart(@NonNull Animator animation) {}
|
||||
|
||||
@Override
|
||||
public abstract void onAnimationEnd(Animator animation);
|
||||
public abstract void onAnimationEnd(@NonNull Animator animation);
|
||||
|
||||
@Override
|
||||
public final void onAnimationCancel(Animator animation) {}
|
||||
public final void onAnimationCancel(@NonNull Animator animation) {}
|
||||
@Override
|
||||
public final void onAnimationRepeat(Animator animation) {}
|
||||
public final void onAnimationRepeat(@NonNull Animator animation) {}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ public class UriAttachment extends Attachment {
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
return other != null && other instanceof UriAttachment && ((UriAttachment) other).dataUri.equals(this.dataUri);
|
||||
return other instanceof UriAttachment && ((UriAttachment) other).dataUri.equals(this.dataUri);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -3,10 +3,11 @@ package org.thoughtcrime.securesms.audio;
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import androidx.annotation.NonNull;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.b44t.messenger.util.concurrent.ListenableFuture;
|
||||
import com.b44t.messenger.util.concurrent.SettableFuture;
|
||||
|
||||
@@ -45,7 +46,7 @@ public class AudioRecorder {
|
||||
throw new AssertionError("We can only record once at a time.");
|
||||
}
|
||||
|
||||
ParcelFileDescriptor fds[] = ParcelFileDescriptor.createPipe();
|
||||
ParcelFileDescriptor[] fds = ParcelFileDescriptor.createPipe();
|
||||
|
||||
captureUri = blobProvider.create(context, new ParcelFileDescriptor.AutoCloseInputStream(fds[0]),
|
||||
MediaUtil.AUDIO_AAC, "voice.aac", null);
|
||||
|
||||
@@ -337,7 +337,7 @@ public class AudioSlidePlayer {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
public void handleMessage(@NonNull Message msg) {
|
||||
AudioSlidePlayer player = playerReference.get();
|
||||
|
||||
if (player == null || player.mediaPlayer == null || !isPlayerActive(player.mediaPlayer)) {
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
package org.thoughtcrime.securesms.components;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.loader.app.LoaderManager;
|
||||
@@ -89,10 +88,11 @@ public class AttachmentTypeSelector extends PopupWindow {
|
||||
this.webxdcButton.setOnClickListener(new PropagatingClickListener(ADD_WEBXDC));
|
||||
this.recentRail.setListener(new RecentPhotoSelectedListener());
|
||||
|
||||
if (!Prefs.isLocationStreamingEnabled(context)) {
|
||||
// disable location streaming button for now
|
||||
//if (!Prefs.isLocationStreamingEnabled(context)) {
|
||||
this.locationButton.setVisibility(View.GONE);
|
||||
ViewUtil.findById(layout, R.id.location_button_label).setVisibility(View.GONE);
|
||||
}
|
||||
//}
|
||||
|
||||
if (!DcHelper.isWebrtcConfigOk(DcHelper.getContext(context))) {
|
||||
this.videoChatButton.setVisibility(View.GONE);
|
||||
@@ -188,13 +188,6 @@ public class AttachmentTypeSelector extends PopupWindow {
|
||||
animator.start();
|
||||
}
|
||||
|
||||
private void animateWindowInTranslate(@NonNull View contentView) {
|
||||
Animation animation = new TranslateAnimation(0, 0, contentView.getHeight(), 0);
|
||||
animation.setDuration(ANIMATION_DURATION);
|
||||
|
||||
getContentView().startAnimation(animation);
|
||||
}
|
||||
|
||||
private void animateWindowOutCircular(@Nullable View anchor, @NonNull View contentView) {
|
||||
Pair<Integer, Integer> coordinates = getClickOrigin(anchor, contentView);
|
||||
Animator animator = ViewAnimationUtils.createCircularReveal(getContentView(),
|
||||
@@ -206,20 +199,20 @@ public class AttachmentTypeSelector extends PopupWindow {
|
||||
animator.setDuration(ANIMATION_DURATION);
|
||||
animator.addListener(new Animator.AnimatorListener() {
|
||||
@Override
|
||||
public void onAnimationStart(Animator animation) {
|
||||
public void onAnimationStart(@NonNull Animator animation) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
public void onAnimationEnd(@NonNull Animator animation) {
|
||||
AttachmentTypeSelector.super.dismiss();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationCancel(Animator animation) {
|
||||
public void onAnimationCancel(@NonNull Animator animation) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationRepeat(Animator animation) {
|
||||
public void onAnimationRepeat(@NonNull Animator animation) {
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package org.thoughtcrime.securesms.components;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.graphics.PorterDuff;
|
||||
|
||||
@@ -2,7 +2,7 @@ package org.thoughtcrime.securesms.components;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.TypedArray;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.widget.AppCompatImageView;
|
||||
@@ -11,7 +11,6 @@ import android.util.AttributeSet;
|
||||
import com.bumptech.glide.load.engine.DiskCacheStrategy;
|
||||
|
||||
import org.thoughtcrime.securesms.ProfileActivity;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.contacts.avatars.ContactPhoto;
|
||||
import org.thoughtcrime.securesms.contacts.avatars.GeneratedContactPhoto;
|
||||
import org.thoughtcrime.securesms.mms.GlideRequests;
|
||||
@@ -30,11 +29,6 @@ public class AvatarImageView extends AppCompatImageView {
|
||||
public AvatarImageView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
setScaleType(ScaleType.CENTER_CROP);
|
||||
|
||||
if (attrs != null) {
|
||||
TypedArray typedArray = context.getTheme().obtainStyledAttributes(attrs, R.styleable.AvatarImageView, 0, 0);
|
||||
typedArray.recycle();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -52,7 +46,7 @@ public class AvatarImageView extends AppCompatImageView {
|
||||
.circleCrop()
|
||||
.into(this);
|
||||
if(quickContactEnabled) {
|
||||
setAvatarClickHandler(recipient, quickContactEnabled);
|
||||
setAvatarClickHandler(recipient);
|
||||
}
|
||||
} else {
|
||||
setImageDrawable(new GeneratedContactPhoto("+").asDrawable(getContext(), ThemeUtil.getDummyContactColor(getContext())));
|
||||
@@ -64,8 +58,8 @@ public class AvatarImageView extends AppCompatImageView {
|
||||
glideRequests.clear(this);
|
||||
}
|
||||
|
||||
private void setAvatarClickHandler(final Recipient recipient, boolean quickContactEnabled) {
|
||||
if (!recipient.isMultiUserRecipient() && quickContactEnabled) {
|
||||
private void setAvatarClickHandler(final Recipient recipient) {
|
||||
if (!recipient.isMultiUserRecipient()) {
|
||||
super.setOnClickListener(v -> {
|
||||
if(recipient.getAddress().isDcContact()) {
|
||||
Intent intent = new Intent(getContext(), ProfileActivity.class);
|
||||
|
||||
@@ -2,6 +2,7 @@ package org.thoughtcrime.securesms.components;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.net.Uri;
|
||||
import android.view.Gravity;
|
||||
@@ -32,10 +33,6 @@ public class AvatarSelector extends PopupWindow {
|
||||
|
||||
private final @NonNull LoaderManager loaderManager;
|
||||
private final @NonNull RecentPhotoViewRail recentRail;
|
||||
private final @NonNull ImageView imageButton;
|
||||
private final @NonNull ImageView cameraButton;
|
||||
private final @NonNull ImageView removeButton;
|
||||
private final @NonNull ImageView closeButton;
|
||||
|
||||
private @Nullable AttachmentClickedListener listener;
|
||||
|
||||
@@ -48,25 +45,25 @@ public class AvatarSelector extends PopupWindow {
|
||||
this.listener = listener;
|
||||
this.loaderManager = loaderManager;
|
||||
this.recentRail = ViewUtil.findById(layout, R.id.recent_photos);
|
||||
this.imageButton = ViewUtil.findById(layout, R.id.gallery_button);
|
||||
this.cameraButton = ViewUtil.findById(layout, R.id.camera_button);
|
||||
this.closeButton = ViewUtil.findById(layout, R.id.close_button);
|
||||
this.removeButton = ViewUtil.findById(layout, R.id.remove_button);
|
||||
ImageView imageButton = ViewUtil.findById(layout, R.id.gallery_button);
|
||||
ImageView cameraButton = ViewUtil.findById(layout, R.id.camera_button);
|
||||
ImageView closeButton = ViewUtil.findById(layout, R.id.close_button);
|
||||
ImageView removeButton = ViewUtil.findById(layout, R.id.remove_button);
|
||||
|
||||
this.imageButton.setOnClickListener(new PropagatingClickListener(ADD_GALLERY));
|
||||
this.cameraButton.setOnClickListener(new PropagatingClickListener(TAKE_PHOTO));
|
||||
this.closeButton.setOnClickListener(new CloseClickListener());
|
||||
this.removeButton.setOnClickListener(new PropagatingClickListener(REMOVE_PHOTO));
|
||||
imageButton.setOnClickListener(new PropagatingClickListener(ADD_GALLERY));
|
||||
cameraButton.setOnClickListener(new PropagatingClickListener(TAKE_PHOTO));
|
||||
closeButton.setOnClickListener(new CloseClickListener());
|
||||
removeButton.setOnClickListener(new PropagatingClickListener(REMOVE_PHOTO));
|
||||
this.recentRail.setListener(new RecentPhotoSelectedListener());
|
||||
if (!includeClear) {
|
||||
this.removeButton.setVisibility(View.GONE);
|
||||
removeButton.setVisibility(View.GONE);
|
||||
ViewUtil.findById(layout, R.id.remove_button_label).setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
setContentView(layout);
|
||||
setWidth(LinearLayout.LayoutParams.MATCH_PARENT);
|
||||
setHeight(LinearLayout.LayoutParams.WRAP_CONTENT);
|
||||
setBackgroundDrawable(new BitmapDrawable());
|
||||
setBackgroundDrawable(new BitmapDrawable(context.getResources(), (Bitmap) null));
|
||||
setAnimationStyle(0);
|
||||
setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED);
|
||||
setFocusable(true);
|
||||
@@ -88,7 +85,7 @@ public class AvatarSelector extends PopupWindow {
|
||||
getContentView().getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
|
||||
@Override
|
||||
public void onGlobalLayout() {
|
||||
getContentView().getViewTreeObserver().removeGlobalOnLayoutListener(this);
|
||||
getContentView().getViewTreeObserver().removeOnGlobalLayoutListener(this);
|
||||
|
||||
animateWindowInTranslate(getContentView());
|
||||
}
|
||||
@@ -167,8 +164,8 @@ public class AvatarSelector extends PopupWindow {
|
||||
}
|
||||
|
||||
public interface AttachmentClickedListener {
|
||||
public void onClick(int type);
|
||||
public void onQuickAttachment(Uri uri);
|
||||
void onClick(int type);
|
||||
void onQuickAttachment(Uri uri);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user