Compare commits

...

1416 commits
3.0.2 ... main

Author SHA1 Message Date
a06fb1657d
Add support for Nyastodon-style emoji reactions 2023-02-08 21:13:16 +09:00
Thomas
97ba87aba7 Release 3.17.0 2023-02-05 18:59:05 +01:00
Thomas
7603db8ce0 Missing media description for previews 2023-02-05 18:53:05 +01:00
Thomas
663e33466d Merge remote-tracking branch 'origin/develop' into develop 2023-02-05 16:50:54 +01:00
Thomas
cbed3f1ae1 Fix media cannot be downloaded or shared (Android 10) 2023-02-05 16:50:08 +01:00
Poesty Li
8bdaf8d410
Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (1077 of 1077 strings)

Co-authored-by: Poesty Li <poesty7450@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/zh_Hans/
Translation: Fedilab/Strings
2023-02-05 11:55:29 +01:00
Thomas
6595af849e Fix forward tags in replies 2023-02-05 11:55:19 +01:00
Thomas
4111d00025 Group mentions at the top 2023-02-05 11:00:34 +01:00
Thomas
f75d8258f4 Fix button sizes not updated 2023-02-04 17:53:25 +01:00
Thomas
7a11e156a5 Merge remote-tracking branch 'origin/develop' into develop 2023-02-04 11:23:56 +01:00
Thomas
8977990fea Cache messages 2023-02-04 11:23:31 +01:00
Poesty Li
bc44a9be15
Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (1077 of 1077 strings)

Co-authored-by: Poesty Li <poesty7450@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/zh_Hans/
Translation: Fedilab/Strings
2023-02-03 18:36:46 +01:00
Eduardo
88d9bf4629
Translated using Weblate (Portuguese)
Currently translated at 89.8% (968 of 1077 strings)

Co-authored-by: Eduardo <edu200399lim@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/pt/
Translation: Fedilab/Strings
2023-02-03 18:36:45 +01:00
josé m
65706e727c
Translated using Weblate (Galician)
Currently translated at 100.0% (1077 of 1077 strings)

Co-authored-by: josé m <correoxm@disroot.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/gl/
Translation: Fedilab/Strings
2023-02-03 18:36:45 +01:00
Thomas
b64fd393e9 Fix worker 2023-02-03 17:42:50 +01:00
Thomas
2b300ceae4 record cache work 2023-02-03 17:23:33 +01:00
Thomas
6e4bb95dda More deep link detection 2023-02-02 18:03:09 +01:00
Thomas
440ad039be Fix issues 2023-02-02 17:44:16 +01:00
Thomas
4c89a855c6 Some fixes 2023-02-02 14:18:52 +01:00
Thomas
0ca53b75d2 Fix crashes when replying 2023-02-02 14:03:13 +01:00
Oğuz Ersen
91eb579e2c
Translated using Weblate (Turkish)
Currently translated at 100.0% (1077 of 1077 strings)

Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/tr/
Translation: Fedilab/Strings
2023-02-02 11:40:27 +01:00
Ajeje Brazorf
1aad4f07df
Translated using Weblate (Sardinian)
Currently translated at 99.2% (1069 of 1077 strings)

Co-authored-by: Ajeje Brazorf <lmelonimamo@yahoo.it>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/sc/
Translation: Fedilab/Strings
2023-02-02 11:40:26 +01:00
claleb
335842c8a2
Translated using Weblate (German)
Currently translated at 100.0% (1077 of 1077 strings)

Co-authored-by: claleb <weblate@claleb.de>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/de/
Translation: Fedilab/Strings
2023-02-02 11:40:26 +01:00
Lukáš Jelínek
c10d078add
Translated using Weblate (Czech)
Currently translated at 99.9% (1076 of 1077 strings)

Co-authored-by: Lukáš Jelínek <devel@aiken.cz>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/cs/
Translation: Fedilab/Strings
2023-02-02 11:40:26 +01:00
Poesty Li
67cdceb90e
Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (1075 of 1075 strings)

Co-authored-by: Poesty Li <poesty7450@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/zh_Hans/
Translation: Fedilab/Strings
2023-02-01 19:01:52 +01:00
Thomas
ddbd3f8684 Release 3.16.4 2023-02-01 19:00:38 +01:00
Thomas
4ae8011eff Auto fetch messages 2023-02-01 18:52:55 +01:00
Thomas
d61dbb0315 Auto fetch messages 2023-02-01 17:56:20 +01:00
Thomas
3c13bf7199 Merge remote-tracking branch 'origin/develop' into develop 2023-02-01 15:16:42 +01:00
Thomas
b19cd7c0c9 Add settings 2023-02-01 15:14:37 +01:00
Dan
17438f6f5c
Translated using Weblate (Ukrainian)
Currently translated at 62.6% (668 of 1067 strings)

Co-authored-by: Dan <denqwerta@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/uk/
Translation: Fedilab/Strings
2023-02-01 13:54:31 +01:00
Oğuz Ersen
f05ab805ff
Translated using Weblate (Turkish)
Currently translated at 100.0% (1067 of 1067 strings)

Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/tr/
Translation: Fedilab/Strings
2023-02-01 13:54:31 +01:00
Lukáš Jelínek
212cd9d54e
Translated using Weblate (Czech)
Currently translated at 99.9% (1066 of 1067 strings)

Co-authored-by: Lukáš Jelínek <devel@aiken.cz>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/cs/
Translation: Fedilab/Strings
2023-02-01 13:54:31 +01:00
Dan
f4437b6955
Translated using Weblate (Ukrainian)
Currently translated at 15.4% (13 of 84 strings)

Co-authored-by: Dan <denqwerta@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/uk/
Translation: Fedilab/description
2023-02-01 13:54:07 +01:00
Thomas
e8950f03ae Fetch home in background to cache messages 2023-02-01 12:33:43 +01:00
0xd9a
0e16cb1730 update schedule dialog 2023-02-01 06:41:33 +05:30
Dan
67cfa9cf01
Translated using Weblate (Ukrainian)
Currently translated at 11.9% (10 of 84 strings)

Co-authored-by: Dan <denqwerta@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/uk/
Translation: Fedilab/description
2023-02-01 00:55:43 +01:00
Ajeje Brazorf
7bdf2aa1ad
Translated using Weblate (Sardinian)
Currently translated at 99.2% (1059 of 1067 strings)

Translated using Weblate (Sardinian)

Currently translated at 99.2% (1058 of 1066 strings)

Co-authored-by: Ajeje Brazorf <lmelonimamo@yahoo.it>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/sc/
Translation: Fedilab/Strings
2023-01-31 18:36:50 +01:00
Thomas
44676707f0 Automatically switch to tabs when searching 2023-01-31 18:36:37 +01:00
Thomas
d9e92b13b6 avoid a crash 2023-01-31 18:16:01 +01:00
Thomas
833ea5d0c3 Fix 103 response code for OG 2023-01-31 18:11:22 +01:00
Thomas
04c5f32c53 Merge remote-tracking branch 'origin/develop' into develop 2023-01-31 17:21:15 +01:00
Thomas
93d5995ec1 remove title for media description #771 2023-01-31 17:21:01 +01:00
Eduardo
d679d1fb73
Translated using Weblate (Portuguese)
Currently translated at 90.2% (962 of 1066 strings)

Co-authored-by: Eduardo <edu200399lim@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/pt/
Translation: Fedilab/Strings
2023-01-31 16:41:31 +01:00
Thomas
f8b0ed7f18 Fix some crashes 2023-01-31 15:00:40 +01:00
Poesty Li
d83f787956
Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (1066 of 1066 strings)

Co-authored-by: Poesty Li <poesty7450@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/zh_Hans/
Translation: Fedilab/Strings
2023-01-31 02:36:27 +01:00
Eduardo
b958e24dc9
Translated using Weblate (Portuguese)
Currently translated at 90.0% (960 of 1066 strings)

Co-authored-by: Eduardo <edu200399lim@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/pt/
Translation: Fedilab/Strings
2023-01-31 02:36:27 +01:00
josé m
e61de6eb1d
Translated using Weblate (Galician)
Currently translated at 100.0% (1066 of 1066 strings)

Co-authored-by: josé m <correoxm@disroot.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/gl/
Translation: Fedilab/Strings
2023-01-31 02:36:27 +01:00
Lukáš Jelínek
b89212a4f6
Translated using Weblate (Czech)
Currently translated at 99.9% (1065 of 1066 strings)

Co-authored-by: Lukáš Jelínek <devel@aiken.cz>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/cs/
Translation: Fedilab/Strings
2023-01-31 02:36:26 +01:00
Thomas
c37d8ab34f Release 3.16.3 2023-01-30 18:18:23 +01:00
Thomas
ca5b37edfe Fix dynamic colors 2023-01-30 18:15:12 +01:00
Thomas
408e51c0a6 Peertube 2FA support 2023-01-30 17:02:24 +01:00
Thomas
9fd834eb44 Merge remote-tracking branch 'origin/develop' into develop 2023-01-29 17:56:48 +01:00
Thomas
58f3d01c87 Release 3.16.2 2023-01-29 17:56:40 +01:00
Thomas
de46b38991 Open profiles only trough avatars 2023-01-29 17:17:57 +01:00
Thomas
926caf2f3f Player layout only for peertube 2023-01-29 16:06:08 +01:00
Poesty Li
8bbe897483
Translated using Weblate (Chinese (Simplified))
Currently translated at 62.2% (664 of 1066 strings)

Co-authored-by: Poesty Li <poesty7450@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/zh_Hans/
Translation: Fedilab/Strings
2023-01-29 08:08:34 +01:00
Oğuz Ersen
59ba9134e7
Translated using Weblate (Turkish)
Currently translated at 100.0% (1066 of 1066 strings)

Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/tr/
Translation: Fedilab/Strings
2023-01-29 08:08:34 +01:00
claleb
83e68742be
Translated using Weblate (German)
Currently translated at 100.0% (1066 of 1066 strings)

Co-authored-by: claleb <weblate@claleb.de>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/de/
Translation: Fedilab/Strings
2023-01-29 08:08:34 +01:00
Thomas
9a38da9475 fix release note 2023-01-28 18:00:02 +01:00
Thomas
c8d0931d8e Release 3.16.1 2023-01-28 17:55:55 +01:00
Thomas
4d643ae28f Fix a crash for notification with Peertube 2023-01-28 17:46:46 +01:00
Thomas
33b8dd36e4 Add support to edit media 2023-01-28 16:47:56 +01:00
Thomas
25d3803e69 Fix peertube support 2023-01-28 16:26:55 +01:00
Thomas
7b08bf77bf Merge remote-tracking branch 'origin/develop' into develop 2023-01-28 15:49:37 +01:00
Thomas
3f1af73b0e avoid a crash with old peertube instances 2023-01-28 15:49:28 +01:00
Oğuz Ersen
a22dd088a5
Translated using Weblate (Turkish)
Currently translated at 100.0% (1064 of 1064 strings)

Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/tr/
Translation: Fedilab/Strings
2023-01-28 01:56:17 +01:00
josé m
e88c53d950
Translated using Weblate (Galician)
Currently translated at 100.0% (1064 of 1064 strings)

Co-authored-by: josé m <correoxm@disroot.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/gl/
Translation: Fedilab/Strings
2023-01-28 01:56:17 +01:00
claleb
a160d3e212
Translated using Weblate (German)
Currently translated at 100.0% (1064 of 1064 strings)

Co-authored-by: claleb <weblate@claleb.de>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/de/
Translation: Fedilab/Strings
2023-01-28 01:56:16 +01:00
Lukáš Jelínek
dacfba7043
Translated using Weblate (Czech)
Currently translated at 99.9% (1063 of 1064 strings)

Co-authored-by: Lukáš Jelínek <devel@aiken.cz>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/cs/
Translation: Fedilab/Strings
2023-01-28 01:56:16 +01:00
Thomas
9683fee1e6 Release 3.16.0 2023-01-27 18:35:27 +01:00
Thomas
575329586f Some fixes 2023-01-27 18:19:24 +01:00
Thomas
a866f5524a Og values when sharing 2023-01-27 16:42:12 +01:00
Thomas
654f7850de Fixes and improvements 2023-01-27 16:30:45 +01:00
Thomas
b52ab37aed Fix Text cleared when adding a media 2023-01-27 12:10:21 +01:00
Thomas
554335aa6e Release notes + fix a bad behavior when adding a Mastodon account from a Peertube one 2023-01-27 11:36:25 +01:00
Thomas
96abece6da Fix a crash 2023-01-27 11:02:18 +01:00
Thomas
8103bf4a16 Fix cross actions 2023-01-27 10:33:41 +01:00
Thomas
e4affdc9d7 Fix a crash 2023-01-26 18:16:26 +01:00
Thomas
90a6a6ceaa Merge remote-tracking branch 'origin/develop' into develop 2023-01-26 18:06:04 +01:00
Thomas
a97448438a playstore flavor 2023-01-26 18:05:41 +01:00
0xd9a
557e973fca update peertube register ui 2023-01-26 22:32:31 +05:30
Thomas
98385aa706 some improvements 2023-01-26 17:41:07 +01:00
Thomas
7119c12467 Remove context dependency 2023-01-26 16:47:28 +01:00
Thomas
3d1d9534be some code changes 2023-01-26 15:57:03 +01:00
Thomas
b94c08d029 some code changes 2023-01-26 15:39:23 +01:00
Thomas
42cf16b545 some code changes 2023-01-26 15:27:27 +01:00
Thomas
bebe315b08 Some layout changes 2023-01-26 15:19:44 +01:00
Thomas
6a359bbbf8 Redo upload 2023-01-26 12:38:21 +01:00
Thomas
42bdcaf6b6 Support proxy for Peertube 2023-01-26 12:08:31 +01:00
Eduardo
27641128c3
Translated using Weblate (Portuguese)
Currently translated at 90.2% (959 of 1063 strings)

Co-authored-by: Eduardo <edu200399lim@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/pt/
Translation: Fedilab/Strings
2023-01-26 11:54:29 +01:00
0xd9a
be0a85cb3a keep side buttons of compose page in position 2023-01-26 15:49:39 +05:30
0xd9a
f11c0e3d58 fix: empty space on top of compose 2023-01-26 15:49:01 +05:30
0xd9a
58e7346f71 update some peertube UI 2023-01-26 08:38:16 +05:30
Thomas
fc34de1da4 remove spinner lib 2023-01-25 18:02:35 +01:00
Thomas
bf8543bc77 Some cleaning 2023-01-25 17:23:49 +01:00
Thomas
8b26deb064 More update on view 2023-01-25 15:59:17 +01:00
Thomas
6ef2683e5e redo notification 2023-01-25 15:37:51 +01:00
Thomas
e0b12ab0e2 Change alert dialogs 2023-01-25 15:14:42 +01:00
Thomas
5ce553f8cf Some fixes 2023-01-25 12:18:02 +01:00
Thomas
44ff9225bc Merge remote-tracking branch 'origin/peertube_integration' into peertube_integration 2023-01-25 11:55:41 +01:00
Thomas
206d5c7e74 Drawer menu 2023-01-25 11:55:30 +01:00
0xd9a
50698f7325 update peertube drawer 2023-01-25 13:31:56 +05:30
Thomas
6e8381396f Fix a bug 2023-01-24 18:23:59 +01:00
Thomas
e87a347354 working 2023-01-24 18:08:58 +01:00
Thomas
7b071eb9eb Clean / update license 2023-01-24 15:09:21 +01:00
Thomas
77fbebf4a7 improvements 2023-01-24 15:03:02 +01:00
Thomas
c09a7a3c2b improvements 2023-01-23 18:06:25 +01:00
Thomas
1b429a31a2 Fix authentication 2023-01-23 17:05:54 +01:00
Thomas
82a5bfebb4 Some changes 2023-01-23 15:01:44 +01:00
Thomas
4c5232039a fusion 2023-01-23 12:12:22 +01:00
Thomas
74afdc0a7a Some changes 2023-01-23 09:31:32 +01:00
gnu-ewm
1de94be096
Translated using Weblate (Polish)
Currently translated at 86.2% (917 of 1063 strings)

Co-authored-by: gnu-ewm <gnu.ewm@protonmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/pl/
Translation: Fedilab/Strings
2023-01-23 09:22:14 +01:00
gnu-ewm
5c6745dacc
Translated using Weblate (Polish)
Currently translated at 3.7% (3 of 80 strings)

Co-authored-by: gnu-ewm <gnu.ewm@protonmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/pl/
Translation: Fedilab/description
2023-01-22 21:21:37 +01:00
Thomas
66161f4eb3 Some changes 2023-01-22 18:51:52 +01:00
Thomas
d77dd2c349 Split files 2023-01-22 16:48:14 +01:00
Thomas
e9571221be Changes 2023-01-22 15:22:59 +01:00
Oğuz Ersen
a33ddf3e51
Translated using Weblate (Turkish)
Currently translated at 100.0% (1063 of 1063 strings)

Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/tr/
Translation: Fedilab/Strings
2023-01-20 15:27:06 +01:00
Ajeje Brazorf
84073c8df4
Translated using Weblate (Sardinian)
Currently translated at 99.2% (1055 of 1063 strings)

Co-authored-by: Ajeje Brazorf <lmelonimamo@yahoo.it>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/sc/
Translation: Fedilab/Strings
2023-01-20 15:27:06 +01:00
Eduardo
1e9b701f58
Translated using Weblate (Portuguese)
Currently translated at 90.1% (958 of 1063 strings)

Co-authored-by: Eduardo <edu200399lim@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/pt/
Translation: Fedilab/Strings
2023-01-20 15:27:05 +01:00
Oliebol
b48d7adaed
Translated using Weblate (Dutch)
Currently translated at 99.9% (1062 of 1063 strings)

Co-authored-by: Oliebol <schrijfmedan@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/nl/
Translation: Fedilab/Strings
2023-01-20 15:27:05 +01:00
josé m
b6a4fb03fc
Translated using Weblate (Galician)
Currently translated at 100.0% (1063 of 1063 strings)

Co-authored-by: josé m <correoxm@disroot.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/gl/
Translation: Fedilab/Strings
2023-01-20 15:27:05 +01:00
ButterflyOfFire
05dfc73d94
Translated using Weblate (French)
Currently translated at 97.8% (1040 of 1063 strings)

Co-authored-by: ButterflyOfFire <ButterflyOfFire@protonmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/fr/
Translation: Fedilab/Strings
2023-01-20 15:27:04 +01:00
claleb
850805b562
Translated using Weblate (German)
Currently translated at 100.0% (1063 of 1063 strings)

Co-authored-by: claleb <weblate@claleb.de>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/de/
Translation: Fedilab/Strings
2023-01-20 15:27:04 +01:00
Lukáš Jelínek
bf5e092f7d
Translated using Weblate (Czech)
Currently translated at 99.8% (1061 of 1063 strings)

Co-authored-by: Lukáš Jelínek <devel@aiken.cz>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/cs/
Translation: Fedilab/Strings
2023-01-20 15:27:03 +01:00
Thomas
f2799e939c Release 3.15.2 2023-01-19 17:40:18 +01:00
Thomas
ff6244883a Fix a crash 2023-01-19 17:05:28 +01:00
Thomas
13fa111394 Merge remote-tracking branch 'origin/develop' into develop 2023-01-19 16:55:10 +01:00
Thomas
f8e22c4a9d Fix a crash 2023-01-19 16:54:39 +01:00
Thomas
fdec78fd61 Fix #758 - Display instance of accounts in dialog when sharing 2023-01-19 16:54:23 +01:00
Oğuz Ersen
2e262e3156
Translated using Weblate (Turkish)
Currently translated at 100.0% (1060 of 1060 strings)

Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/tr/
Translation: Fedilab/Strings
2023-01-18 20:51:48 +01:00
josé m
3d11a064bd
Translated using Weblate (Galician)
Currently translated at 100.0% (1060 of 1060 strings)

Co-authored-by: josé m <correoxm@disroot.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/gl/
Translation: Fedilab/Strings
2023-01-18 20:51:48 +01:00
ButterflyOfFire
688ff330db
Translated using Weblate (French)
Currently translated at 97.4% (1033 of 1060 strings)

Co-authored-by: ButterflyOfFire <ButterflyOfFire@protonmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/fr/
Translation: Fedilab/Strings
2023-01-18 20:51:48 +01:00
Ettore Atalan
4ded712634
Translated using Weblate (German)
Currently translated at 100.0% (1060 of 1060 strings)

Co-authored-by: Ettore Atalan <atalanttore@googlemail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/de/
Translation: Fedilab/Strings
2023-01-18 20:51:48 +01:00
Lukáš Jelínek
a7a8cb6c90
Translated using Weblate (Czech)
Currently translated at 99.8% (1058 of 1060 strings)

Co-authored-by: Lukáš Jelínek <devel@aiken.cz>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/cs/
Translation: Fedilab/Strings
2023-01-18 20:51:48 +01:00
Thomas
c2d270696d Release 3.15.1 2023-01-18 17:27:14 +01:00
Thomas
47c66185a3 Release 3.15.1 2023-01-18 17:19:18 +01:00
Thomas
b83ffa4dcf Fix theme 2023-01-18 17:17:31 +01:00
Thomas
c994ccca0c Merge branch 'develop' of https://codeberg.org/tom79/Fedilab into develop 2023-01-18 15:42:38 +01:00
Thomas
d3bb4a285b Improve notifications 2023-01-18 15:42:20 +01:00
0xd9a
5b4f7d70b6 Update some dialogs 2023-01-18 20:07:03 +05:30
Oliebol
e50c0fa9fe
Translated using Weblate (Dutch)
Currently translated at 99.6% (1051 of 1055 strings)

Co-authored-by: Oliebol <schrijfmedan@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/nl/
Translation: Fedilab/Strings
2023-01-17 18:32:07 +01:00
Oğuz Ersen
0da6ff2c0c
Translated using Weblate (Turkish)
Currently translated at 100.0% (1053 of 1053 strings)

Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/tr/
Translation: Fedilab/Strings
2023-01-17 18:32:07 +01:00
Ajeje Brazorf
f72e9cb26f
Translated using Weblate (Sardinian)
Currently translated at 99.2% (1049 of 1057 strings)

Translated using Weblate (Sardinian)

Currently translated at 99.2% (1047 of 1055 strings)

Translated using Weblate (Sardinian)

Currently translated at 99.2% (1045 of 1053 strings)

Co-authored-by: Ajeje Brazorf <lmelonimamo@yahoo.it>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/sc/
Translation: Fedilab/Strings
2023-01-17 18:32:07 +01:00
josé m
60bafb2d32
Translated using Weblate (Galician)
Currently translated at 100.0% (1059 of 1059 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (1053 of 1053 strings)

Co-authored-by: josé m <correoxm@disroot.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/gl/
Translation: Fedilab/Strings
2023-01-17 18:32:07 +01:00
claleb
d103844496
Translated using Weblate (German)
Currently translated at 99.9% (1058 of 1059 strings)

Translated using Weblate (German)

Currently translated at 100.0% (1053 of 1053 strings)

Co-authored-by: claleb <weblate@claleb.de>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/de/
Translation: Fedilab/Strings
2023-01-17 18:32:07 +01:00
Lukáš Jelínek
e134d23594
Translated using Weblate (Czech)
Currently translated at 99.8% (1051 of 1053 strings)

Co-authored-by: Lukáš Jelínek <devel@aiken.cz>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/cs/
Translation: Fedilab/Strings
2023-01-17 18:32:07 +01:00
Thomas
7bc983d345 Release 3.15.0 2023-01-17 18:31:50 +01:00
Thomas
255eeac0a5 - Add several targeted languages for translator 2023-01-17 18:08:10 +01:00
Thomas
3b30708954 Some fixes 2023-01-17 16:41:39 +01:00
Thomas
e0e2f7789b Some fixes 2023-01-17 14:36:51 +01:00
Thomas
ef5a211f57 Merge branch 'develop' of https://codeberg.org/tom79/Fedilab into develop 2023-01-17 14:19:54 +01:00
Thomas
939023b71e Some fixes 2023-01-17 14:19:46 +01:00
0xd9a
89c30f16f0 Update poll compose dialog 2023-01-17 16:59:41 +05:30
Thomas
f8641a953a Release 3.14.6 2023-01-16 18:13:09 +01:00
Thomas
a1f97d7cfa Hide single media with preview is now a setting (default: disabled) 2023-01-16 16:49:48 +01:00
Thomas
21abe0e297 Merge remote-tracking branch 'origin/develop' into develop 2023-01-16 16:34:17 +01:00
Thomas
d5c51e6dca Add support for maths. 2023-01-16 16:33:20 +01:00
Thomas
25ad71080e improvements 2023-01-16 14:35:14 +01:00
Thomas
4584630883 do maths 2023-01-16 13:56:25 +01:00
Eduardo Lima
5733eed8bc
Translated using Weblate (Portuguese)
Currently translated at 90.3% (946 of 1047 strings)

Co-authored-by: Eduardo Lima <edu200399lim@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/pt/
Translation: Fedilab/Strings
2023-01-16 07:51:19 +01:00
josé m
e0deba141a
Translated using Weblate (Galician)
Currently translated at 100.0% (1047 of 1047 strings)

Co-authored-by: josé m <correoxm@disroot.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/gl/
Translation: Fedilab/Strings
2023-01-16 07:51:19 +01:00
nichu42
1a66bd5d89
Translated using Weblate (German)
Currently translated at 100.0% (1047 of 1047 strings)

Co-authored-by: nichu42 <nroediger@nic-site.de>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/de/
Translation: Fedilab/Strings
2023-01-16 07:51:18 +01:00
Thomas
72a79766b8 Release 3.14.5 2023-01-15 18:47:22 +01:00
Thomas
7751646d50 Fix copy/paste 2023-01-15 18:38:26 +01:00
Thomas
97e15dd37f Fixes and improvements 2023-01-15 16:44:00 +01:00
Thomas
ce9d4c2cd3 Fixes and improvements 2023-01-15 16:04:51 +01:00
Thomas
3ab25e3333 Fix some crashes 2023-01-15 14:48:23 +01:00
Thomas
80f6fb2382 Fix a crash 2023-01-15 12:30:33 +01:00
Thomas
1768a85cbd clean fix 2023-01-15 12:06:38 +01:00
Thomas
eaecabe7b7 Release 3.14.4 2023-01-14 18:10:42 +01:00
Thomas
ae7394888d Improve media activity 2023-01-14 17:48:05 +01:00
Thomas
27423a6ab5 Improve behavior 2023-01-14 16:21:16 +01:00
Thomas
a5d1e8efe0 Fix icon bug colors 2023-01-14 11:15:49 +01:00
Thomas
3a8f037be5 Fix icon bug colors 2023-01-14 11:15:05 +01:00
Thomas
f5b0eacfab Merge remote-tracking branch 'origin/develop' into develop 2023-01-14 10:46:31 +01:00
Thomas
0740f6399b Fix issue #751 - Boost color not applied 2023-01-14 10:46:03 +01:00
Thomas
8dfd55fe10 Fix cross account actions 2023-01-14 10:44:09 +01:00
Oliebol
3046a8a391
Translated using Weblate (Dutch)
Currently translated at 100.0% (1047 of 1047 strings)

Co-authored-by: Oliebol <schrijfmedan@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/nl/
Translation: Fedilab/Strings
2023-01-14 08:54:18 +01:00
Hosted Weblate
ef8bf95c28
Update translation files
Updated by "Remove blank strings" hook in Weblate.

Update translation files

Updated by "Remove blank strings" hook in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/
Translation: Fedilab/Strings
2023-01-14 08:54:18 +01:00
Oğuz Ersen
7e1a8c1af3
Translated using Weblate (Turkish)
Currently translated at 100.0% (1047 of 1047 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (1042 of 1042 strings)

Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/tr/
Translation: Fedilab/Strings
2023-01-14 08:54:18 +01:00
Eduardo Lima
7c9b67584d
Translated using Weblate (Gaelic)
Currently translated at 32.8% (342 of 1042 strings)

Translated using Weblate (Portuguese)

Currently translated at 75.9% (791 of 1042 strings)

Co-authored-by: Eduardo Lima <edu200399lim@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/gd/
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/pt/
Translation: Fedilab/Strings
2023-01-14 08:54:17 +01:00
joenepraat
fda91e7d3d
Translated using Weblate (Dutch)
Currently translated at 100.0% (1042 of 1042 strings)

Co-authored-by: joenepraat <joenepraat@posteo.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/nl/
Translation: Fedilab/Strings
2023-01-14 08:54:17 +01:00
josé m
dcbaa32aa2
Translated using Weblate (Galician)
Currently translated at 100.0% (1042 of 1042 strings)

Co-authored-by: josé m <correoxm@disroot.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/gl/
Translation: Fedilab/Strings
2023-01-14 08:54:16 +01:00
claleb
71c7d0a1fa
Translated using Weblate (German)
Currently translated at 100.0% (1047 of 1047 strings)

Translated using Weblate (German)

Currently translated at 100.0% (1042 of 1042 strings)

Co-authored-by: claleb <weblate@claleb.de>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/de/
Translation: Fedilab/Strings
2023-01-14 08:54:16 +01:00
Lukáš Jelínek
b1d9d3016f
Translated using Weblate (Czech)
Currently translated at 99.8% (1045 of 1047 strings)

Translated using Weblate (Czech)

Currently translated at 99.8% (1040 of 1042 strings)

Co-authored-by: Lukáš Jelínek <devel@aiken.cz>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/cs/
Translation: Fedilab/Strings
2023-01-14 08:54:16 +01:00
Thomas
447ad45fc6 Release 3.14.3 2023-01-13 18:07:35 +01:00
Thomas
d3f721f7cc Fix follow button colors 2023-01-13 17:26:25 +01:00
Thomas
107ac13e15 Fix issue #745 - Update library for bottom buttons. 2023-01-13 16:19:50 +01:00
Thomas
d70c285bea Merge branch 'develop' 2023-01-12 17:54:31 +01:00
Thomas
bb2b66ce6a Release 3.14.2 2023-01-12 17:52:34 +01:00
Thomas
849967fe97 Merge branch 'develop' of https://codeberg.org/tom79/Fedilab into develop 2023-01-12 17:47:49 +01:00
Thomas
bb68512502 Fix media cannot be downloaded 2023-01-12 17:11:27 +01:00
Thomas
ae31abaa3b Bot and reply icon indicators more visible 2023-01-12 15:58:59 +01:00
Lukáš Jelínek
80927bfa9c
Translated using Weblate (Czech)
Currently translated at 99.7% (1037 of 1040 strings)

Co-authored-by: Lukáš Jelínek <devel@aiken.cz>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/cs/
Translation: Fedilab/Strings
2023-01-12 14:57:31 +01:00
Thomas
1ef01af199 Some cleaning 2023-01-12 14:55:53 +01:00
Thomas
d5a5f08727 Instance directory 2023-01-12 14:35:44 +01:00
Thomas
e03c02cc35 Merge remote-tracking branch 'origin/develop' into develop 2023-01-12 11:18:37 +01:00
Thomas
c37f4bb643 Familiar followers on profiles 2023-01-12 11:13:52 +01:00
Thomas
098e2d87ec Some fixes 2023-01-12 09:54:43 +01:00
ssantos
fd6d487060
Translated using Weblate (Portuguese)
Currently translated at 73.6% (765 of 1039 strings)

Co-authored-by: ssantos <ssantos@web.de>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/pt/
Translation: Fedilab/Strings
2023-01-12 03:50:57 +01:00
Thomas
af10d647b9 Merge branch 'develop' 2023-01-11 18:30:08 +01:00
Thomas
31025af9ab Release 3.14.1 2023-01-11 18:23:33 +01:00
Thomas
8162e3f171 Some fixes 2023-01-11 18:22:29 +01:00
Thomas
316e750004 Apply suggestion is search tab activity 2023-01-11 18:07:54 +01:00
Thomas
edc4f1357e NSFW for Pixelfed view 2023-01-11 18:04:37 +01:00
Thomas
ac503cdf0c Automatically switch to account tab if no results for tags 2023-01-11 17:51:21 +01:00
Thomas
bc8dfec325 Tag cannot be pinned 2023-01-11 17:35:46 +01:00
Thomas
39f248e0a6 Fix videos cannot be downloaded 2023-01-11 17:07:47 +01:00
Thomas
f966874550 Some fixes 2023-01-11 16:51:42 +01:00
Thomas
7704e15e31 Preload media 2023-01-11 16:26:31 +01:00
Thomas
b0e01e5bf1 Search bar: Display suggestion when starting by @ or # 2023-01-10 16:51:02 +01:00
Thomas
4ec8496124 Merge remote-tracking branch 'origin/develop' into develop 2023-01-10 12:12:57 +01:00
Thomas
b54c36627c Search bar: Display suggestion when starting by @ or # 2023-01-10 12:12:43 +01:00
Ajeje Brazorf
884e8d35de
Translated using Weblate (Sardinian)
Currently translated at 98.8% (1027 of 1039 strings)

Co-authored-by: Ajeje Brazorf <lmelonimamo@yahoo.it>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/sc/
Translation: Fedilab/Strings
2023-01-10 08:48:33 +01:00
Mikhail Kobuk
8154c3425e
Translated using Weblate (Russian)
Currently translated at 74.8% (778 of 1039 strings)

Co-authored-by: Mikhail Kobuk <arktixord@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ru/
Translation: Fedilab/Strings
2023-01-10 08:48:33 +01:00
Oliebol
7e76d68466
Translated using Weblate (Dutch)
Currently translated at 100.0% (1039 of 1039 strings)

Co-authored-by: Oliebol <schrijfmedan@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/nl/
Translation: Fedilab/Strings
2023-01-10 08:48:33 +01:00
josé m
a01ffab237
Translated using Weblate (Galician)
Currently translated at 100.0% (1039 of 1039 strings)

Co-authored-by: josé m <correoxm@disroot.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/gl/
Translation: Fedilab/Strings
2023-01-10 08:48:32 +01:00
Thomas
d97a78362c Fix crashes 2023-01-09 17:37:56 +01:00
Thomas
4ccd299fda Merge remote-tracking branch 'origin/develop' into develop 2023-01-09 17:37:47 +01:00
Thomas
1fe0701342 Fix issue #737 and #738 - Jumps with timeline 2023-01-09 17:37:35 +01:00
Oliebol
902d5176ff
Translated using Weblate (Dutch)
Currently translated at 4.2% (3 of 71 strings)

Co-authored-by: Oliebol <schrijfmedan@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/nl/
Translation: Fedilab/description
2023-01-09 11:49:18 +01:00
Oğuz Ersen
0a2effe591
Translated using Weblate (Turkish)
Currently translated at 100.0% (1039 of 1039 strings)

Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/tr/
Translation: Fedilab/Strings
2023-01-08 15:49:24 +01:00
claleb
e6139c129f
Translated using Weblate (German)
Currently translated at 100.0% (1039 of 1039 strings)

Co-authored-by: claleb <weblate@claleb.de>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/de/
Translation: Fedilab/Strings
2023-01-08 15:49:23 +01:00
Lukáš Jelínek
fafb7dc301
Translated using Weblate (Czech)
Currently translated at 99.5% (1034 of 1039 strings)

Co-authored-by: Lukáš Jelínek <devel@aiken.cz>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/cs/
Translation: Fedilab/Strings
2023-01-08 15:49:23 +01:00
Thomas
8c98b9e46d Merge branch 'develop' 2023-01-07 17:48:43 +01:00
Oğuz Ersen
1a8108d5e0
Translated using Weblate (Turkish)
Currently translated at 100.0% (1036 of 1036 strings)

Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/tr/
Translation: Fedilab/Strings
2023-01-07 17:48:19 +01:00
josé m
466da9a0b3
Translated using Weblate (Galician)
Currently translated at 100.0% (1036 of 1036 strings)

Co-authored-by: josé m <correoxm@disroot.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/gl/
Translation: Fedilab/Strings
2023-01-07 17:48:19 +01:00
Jean-Luc Tibaux
da122028c9
Translated using Weblate (French)
Currently translated at 98.8% (1024 of 1036 strings)

Co-authored-by: Jean-Luc Tibaux <eugentoptic@outlook.de>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/fr/
Translation: Fedilab/Strings
2023-01-07 17:48:19 +01:00
claleb
000552c090
Translated using Weblate (German)
Currently translated at 100.0% (1036 of 1036 strings)

Co-authored-by: claleb <weblate@claleb.de>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/de/
Translation: Fedilab/Strings
2023-01-07 17:48:19 +01:00
Thomas
47e43193b8 Release 3.14.0 2023-01-07 17:47:57 +01:00
Thomas
4057a04302 Merge remote-tracking branch 'origin/develop' into develop 2023-01-07 17:04:24 +01:00
Thomas
6df271c319 Fix urls 2023-01-07 17:03:50 +01:00
Thomas
32f9264558 Fix a crash for long messages 2023-01-07 15:36:57 +01:00
Thomas
3ea4559f69 Option to align left message bottom buttons 2023-01-07 15:27:33 +01:00
Jean-Luc Tibaux
cd4df2d29a
Translated using Weblate (German)
Currently translated at 38.5% (27 of 70 strings)

Co-authored-by: Jean-Luc Tibaux <eugentoptic@outlook.de>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/de/
Translation: Fedilab/description
2023-01-07 08:51:16 +01:00
Thomas
e23d2caf00 Release 3.13.7 2023-01-06 18:37:26 +01:00
Thomas
566b50d394 Merge remote-tracking branch 'origin/develop' into develop 2023-01-06 18:22:08 +01:00
Thomas
d77f1fc9f6 Pixelfed view 2023-01-06 18:21:41 +01:00
Thomas
c052e376e2 Fix reactions displayed in all notif tabs 2023-01-06 16:27:26 +01:00
Thomas
7e1d9b8910 Fix issue #730 2023-01-06 15:57:05 +01:00
Thomas
17d6152af3 Some fixes 2023-01-06 09:52:46 +01:00
Ajeje Brazorf
caa14ecaa9
Translated using Weblate (Sardinian)
Currently translated at 98.5% (1019 of 1034 strings)

Co-authored-by: Ajeje Brazorf <lmelonimamo@yahoo.it>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/sc/
Translation: Fedilab/Strings
2023-01-06 06:51:02 +01:00
josé m
56b82461b5
Translated using Weblate (Galician)
Currently translated at 100.0% (1034 of 1034 strings)

Co-authored-by: josé m <correoxm@disroot.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/gl/
Translation: Fedilab/Strings
2023-01-06 06:51:02 +01:00
Thomas
1e807725e1 release notes 2023-01-05 19:01:27 +01:00
Thomas
8fe26abec7 release notes 2023-01-05 18:53:49 +01:00
Thomas
9e701f82ba release notes 2023-01-05 15:15:39 +01:00
Cilian
97e3d7ed19
Translated using Weblate (Russian)
Currently translated at 72.8% (753 of 1034 strings)

Co-authored-by: Cilian <arusivv@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ru/
Translation: Fedilab/Strings
2023-01-04 22:51:06 +01:00
Виталий
1c650b56f1
Translated using Weblate (Russian)
Currently translated at 72.8% (753 of 1034 strings)

Co-authored-by: Виталий <remove4kebab@protonmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ru/
Translation: Fedilab/Strings
2023-01-04 22:51:05 +01:00
claleb
31bdafe5fd
Translated using Weblate (German)
Currently translated at 100.0% (1034 of 1034 strings)

Co-authored-by: claleb <weblate@claleb.de>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/de/
Translation: Fedilab/Strings
2023-01-04 22:51:05 +01:00
Lukáš Jelínek
ca85e500a5
Translated using Weblate (Czech)
Currently translated at 99.6% (1030 of 1034 strings)

Co-authored-by: Lukáš Jelínek <devel@aiken.cz>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/cs/
Translation: Fedilab/Strings
2023-01-04 22:51:05 +01:00
Thomas
229262d478 clean 2023-01-04 14:34:22 +01:00
Thomas
12611a116b Merge remote-tracking branch 'origin/develop' into develop 2023-01-04 11:54:04 +01:00
Thomas
9d6a2057ab Add tags in any when pinned / Fix quotes with tags breaking lines 2023-01-04 11:53:51 +01:00
Thomas
785257cc6c Fix potential crashes 2023-01-04 11:12:17 +01:00
Cilian
4e9af2abb2
Translated using Weblate (Russian)
Currently translated at 66.0% (683 of 1034 strings)

Co-authored-by: Cilian <arusivv@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ru/
Translation: Fedilab/Strings
2023-01-03 20:46:20 +01:00
Виталий
b45a007797
Translated using Weblate (Russian)
Currently translated at 66.0% (683 of 1034 strings)

Co-authored-by: Виталий <remove4kebab@protonmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ru/
Translation: Fedilab/Strings
2023-01-03 20:46:20 +01:00
Виталий
e726b6a540
Translated using Weblate (Russian)
Currently translated at 65.9% (682 of 1034 strings)

Co-authored-by: Виталий <remove4kebab@protonmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ru/
Translation: Fedilab/Strings
2023-01-03 20:45:55 +01:00
Cilian
f6eedc3eb5
Translated using Weblate (Russian)
Currently translated at 65.9% (682 of 1034 strings)

Co-authored-by: Cilian <arusivv@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ru/
Translation: Fedilab/Strings
2023-01-03 20:45:55 +01:00
Cilian
db8d57b18d
Translated using Weblate (Russian)
Currently translated at 65.7% (680 of 1034 strings)

Co-authored-by: Cilian <arusivv@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ru/
Translation: Fedilab/Strings
2023-01-03 20:45:25 +01:00
Виталий
f3391b1ac6
Translated using Weblate (Russian)
Currently translated at 65.7% (680 of 1034 strings)

Co-authored-by: Виталий <remove4kebab@protonmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ru/
Translation: Fedilab/Strings
2023-01-03 20:45:25 +01:00
Cilian
d6a5d2a1c7
Translated using Weblate (Russian)
Currently translated at 65.6% (679 of 1034 strings)

Co-authored-by: Cilian <arusivv@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ru/
Translation: Fedilab/Strings
2023-01-03 20:45:04 +01:00
Виталий
f7205fbbbb
Translated using Weblate (Russian)
Currently translated at 65.6% (679 of 1034 strings)

Co-authored-by: Виталий <remove4kebab@protonmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ru/
Translation: Fedilab/Strings
2023-01-03 20:45:03 +01:00
Виталий
090fbce96a
Translated using Weblate (Russian)
Currently translated at 65.4% (677 of 1034 strings)

Co-authored-by: Виталий <remove4kebab@protonmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ru/
Translation: Fedilab/Strings
2023-01-03 20:44:30 +01:00
Cilian
10ce384282
Translated using Weblate (Russian)
Currently translated at 65.4% (677 of 1034 strings)

Co-authored-by: Cilian <arusivv@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ru/
Translation: Fedilab/Strings
2023-01-03 20:44:30 +01:00
Cilian
9dbf8ccdc0
Translated using Weblate (Russian)
Currently translated at 65.3% (676 of 1034 strings)

Co-authored-by: Cilian <arusivv@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ru/
Translation: Fedilab/Strings
2023-01-03 20:43:46 +01:00
Виталий
ba4456f305
Translated using Weblate (Russian)
Currently translated at 65.3% (676 of 1034 strings)

Co-authored-by: Виталий <remove4kebab@protonmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ru/
Translation: Fedilab/Strings
2023-01-03 20:43:45 +01:00
Thomas
299df2cd59 3.13.6 2023-01-03 18:12:15 +01:00
Thomas
a78a3580b3 Merge remote-tracking branch 'origin/develop' into develop 2023-01-03 17:30:04 +01:00
Thomas
886f066071 Fix issue #607 - Issue with fetchmore 2023-01-03 17:29:53 +01:00
Oğuz Ersen
f140b2883a
Translated using Weblate (Turkish)
Currently translated at 100.0% (1034 of 1034 strings)

Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/tr/
Translation: Fedilab/Strings
2023-01-03 14:51:02 +01:00
RintanBroadleaf
5480ff91d2
Translated using Weblate (Japanese)
Currently translated at 100.0% (1034 of 1034 strings)

Co-authored-by: RintanBroadleaf <rintanbroadleaf@outlook.jp>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ja/
Translation: Fedilab/Strings
2023-01-03 14:51:02 +01:00
claleb
3210530975
Translated using Weblate (German)
Currently translated at 100.0% (1034 of 1034 strings)

Co-authored-by: claleb <weblate@claleb.de>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/de/
Translation: Fedilab/Strings
2023-01-03 14:51:02 +01:00
Lukáš Jelínek
807530f8d6
Translated using Weblate (Czech)
Currently translated at 99.2% (1026 of 1034 strings)

Co-authored-by: Lukáš Jelínek <devel@aiken.cz>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/cs/
Translation: Fedilab/Strings
2023-01-03 14:51:01 +01:00
Thomas
a81f27faff Fix expand media with fit preview images when sensitive 2023-01-03 14:22:28 +01:00
Thomas
2ebbc27c0a Fix some issues 2023-01-03 14:10:42 +01:00
Thomas
1edd554fde Fix issue #712 - Empty notifications 2023-01-03 13:42:46 +01:00
Thomas
580024e1b9 Fix issue #710 - Fav/Boost markers with shared message from conversations are not applied in timeline 2023-01-03 11:31:12 +01:00
Thomas
d9f477a57f Fix issue #715 - Custom emoji not displayed in notifications 2023-01-03 10:59:25 +01:00
Thomas
aea0f8ca83 Merge remote-tracking branch 'origin/develop' into develop 2023-01-03 09:07:49 +01:00
Thomas
df5354ec1e Fix issue #719 - Wrong instance emojis with cross compose 2023-01-03 09:07:41 +01:00
claleb
66acb1b8d8
Translated using Weblate (German)
Currently translated at 100.0% (1030 of 1030 strings)

Co-authored-by: claleb <weblate@claleb.de>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/de/
Translation: Fedilab/Strings
2023-01-02 17:28:19 +01:00
Thomas
537bb3f622 Release 3.13.5 2023-01-02 17:28:09 +01:00
Thomas
da2ce8bce4 Merge remote-tracking branch 'origin/develop' into develop 2023-01-02 16:21:05 +01:00
Thomas
508f3c6253 comment #702 - Add post local only (Glitch) 2023-01-02 16:20:58 +01:00
Thomas
64e50bd8b5 Fix crashes 2023-01-02 15:06:31 +01:00
Oğuz Ersen
ccdbc2f45a
Translated using Weblate (Turkish)
Currently translated at 100.0% (1030 of 1030 strings)

Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/tr/
Translation: Fedilab/Strings
2023-01-02 07:51:07 +01:00
Lukáš Jelínek
6a98b4db48
Translated using Weblate (Czech)
Currently translated at 99.2% (1022 of 1030 strings)

Co-authored-by: Lukáš Jelínek <devel@aiken.cz>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/cs/
Translation: Fedilab/Strings
2023-01-02 07:51:07 +01:00
Oğuz Ersen
0ec4e0c51b
Translated using Weblate (Turkish)
Currently translated at 100.0% (1027 of 1027 strings)

Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/tr/
Translation: Fedilab/Strings
2023-01-01 18:23:09 +01:00
claleb
0d1107ec15
Translated using Weblate (German)
Currently translated at 100.0% (1027 of 1027 strings)

Co-authored-by: claleb <weblate@claleb.de>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/de/
Translation: Fedilab/Strings
2023-01-01 18:23:09 +01:00
Thomas
cbc5eddc9c Release 3.13.4 2023-01-01 18:23:00 +01:00
Thomas
61798a7ce1 Release 3.13.4 2023-01-01 18:20:18 +01:00
Thomas
7303e7faa8 Spoiler text when editing 2023-01-01 16:46:59 +01:00
Thomas
95f4059509 Merge remote-tracking branch 'origin/develop' into develop 2023-01-01 11:55:41 +01:00
Thomas
c590ab48f5 Some cleaning 2023-01-01 11:55:32 +01:00
Thomas
8fb7e4dc71 comment issue #702 - Add Bubble timeline 2023-01-01 11:54:43 +01:00
claleb
a6f25737f7
Translated using Weblate (German)
Currently translated at 24.2% (16 of 66 strings)

Co-authored-by: claleb <weblate@claleb.de>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/de/
Translation: Fedilab/description
2023-01-01 05:48:40 +01:00
Oğuz Ersen
f4748cef95
Translated using Weblate (Turkish)
Currently translated at 100.0% (1021 of 1021 strings)

Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/tr/
Translation: Fedilab/Strings
2023-01-01 04:50:23 +01:00
Oliebol
e450589f76
Translated using Weblate (Dutch)
Currently translated at 99.8% (1019 of 1021 strings)

Co-authored-by: Oliebol <schrijfmedan@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/nl/
Translation: Fedilab/Strings
2023-01-01 04:50:23 +01:00
claleb
ec9e0dbbda
Translated using Weblate (German)
Currently translated at 100.0% (1021 of 1021 strings)

Co-authored-by: claleb <weblate@claleb.de>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/de/
Translation: Fedilab/Strings
2023-01-01 04:50:23 +01:00
Lukáš Jelínek
56e372a2f6
Translated using Weblate (Czech)
Currently translated at 99.6% (1017 of 1021 strings)

Co-authored-by: Lukáš Jelínek <devel@aiken.cz>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/cs/
Translation: Fedilab/Strings
2023-01-01 04:50:23 +01:00
Thomas
f976b6dd72 Add Bubble timeline support 2022-12-31 18:12:31 +01:00
claleb
f81ba544a3
Translated using Weblate (German)
Currently translated at 21.2% (14 of 66 strings)

Co-authored-by: claleb <weblate@claleb.de>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/de/
Translation: Fedilab/description
2022-12-31 16:50:31 +01:00
Thomas
818f32ffb5 some fixes 2022-12-31 15:10:11 +01:00
Thomas
112701dd86 Improve interactions 2022-12-31 14:59:23 +01:00
Thomas
c3006080ba Merge branch 'develop' 2022-12-30 18:12:09 +01:00
Thomas
12fae6059a update release notes 2022-12-30 18:11:48 +01:00
Thomas
90b9291dab Release 3.13.3 2022-12-30 18:06:28 +01:00
Thomas
b1c22713b1 Merge remote-tracking branch 'origin/develop' into develop 2022-12-30 18:00:15 +01:00
Thomas
a859f3cbef comment #702 - Fix custom emoji reactions 2022-12-30 17:59:33 +01:00
Thomas
31929850c3 comment #702 - Allow to disable some icons 2022-12-30 17:53:26 +01:00
Thomas
e5c4efb4e9 comment #702 - Allow to format the text when composing 2022-12-30 17:40:03 +01:00
0xd9a
7b84049014 Update link actions dialog 2022-12-30 20:41:52 +05:30
Thomas
2164c2fe91 comment #702 - Separated settings 2022-12-30 16:01:51 +01:00
Eduardo Lima
4d5be03db6
Translated using Weblate (Portuguese)
Currently translated at 12.3% (8 of 65 strings)

Co-authored-by: Eduardo Lima <edu200399lim@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/pt/
Translation: Fedilab/description
2022-12-30 15:50:20 +01:00
Eduardo Lima
1defbdad83
Translated using Weblate (Portuguese)
Currently translated at 75.0% (755 of 1006 strings)

Co-authored-by: Eduardo Lima <edu200399lim@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/pt/
Translation: Fedilab/Strings
2022-12-30 15:49:45 +01:00
Thomas
9466a76071 comment #702 - Enable extra features per account 2022-12-30 12:28:03 +01:00
Thomas
d55baa92af comment #702 - Improve reactions and quotes 2022-12-30 12:10:52 +01:00
Thomas
23cd690f33 comment #702 - Support quotes 2022-12-29 19:02:15 +01:00
Thomas
cfcab79cf8 Some fixes 2022-12-29 17:27:11 +01:00
Thomas
6ff29f3514 Fix issue #697 - Media not displayed for instances that doe not support media sizes. 2022-12-29 17:22:10 +01:00
Thomas
3a87f65b33 Merge remote-tracking branch 'origin/develop' into develop 2022-12-29 17:08:40 +01:00
Thomas
f1940f5f24 Fix issue when account is null 2022-12-29 17:08:15 +01:00
Thomas
4b1897921a Fix spoiler with media 2022-12-29 14:28:35 +01:00
Hosted Weblate
7fc812073e
Update translation files
Updated by "Remove blank strings" hook in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/
Translation: Fedilab/Strings
2022-12-29 06:50:49 +01:00
GunChleoc
bbf1f20a67
Translated using Weblate (Gaelic)
Currently translated at 33.0% (332 of 1006 strings)

Co-authored-by: GunChleoc <fios@foramnagaidhlig.net>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/gd/
Translation: Fedilab/Strings
2022-12-29 06:50:48 +01:00
Oğuz Ersen
4e12d3fcdd
Translated using Weblate (Turkish)
Currently translated at 100.0% (1006 of 1006 strings)

Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/tr/
Translation: Fedilab/Strings
2022-12-29 06:50:48 +01:00
Eduardo Lima
8cc8e01614
Translated using Weblate (Portuguese)
Currently translated at 73.9% (744 of 1006 strings)

Co-authored-by: Eduardo Lima <edu200399lim@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/pt/
Translation: Fedilab/Strings
2022-12-29 06:50:48 +01:00
aqC3ALziMWG1
b91f249efc
Translated using Weblate (German)
Currently translated at 100.0% (1006 of 1006 strings)

Co-authored-by: aqC3ALziMWG1 <weblate@claleb.de>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/de/
Translation: Fedilab/Strings
2022-12-29 06:50:47 +01:00
Lukáš Jelínek
51fc16f4a2
Translated using Weblate (Czech)
Currently translated at 99.6% (1002 of 1006 strings)

Co-authored-by: Lukáš Jelínek <devel@aiken.cz>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/cs/
Translation: Fedilab/Strings
2022-12-29 06:50:47 +01:00
Thomas
5766bfce32 Merge branch 'develop' 2022-12-28 18:01:57 +01:00
Thomas
05a7ac4081 Release 3.13.2 2022-12-28 18:01:31 +01:00
Thomas
07d358fa91 Fix issue #682 - Smaller size when media are hidden with fit preview images 2022-12-28 17:53:16 +01:00
Thomas
639641c80a Release notes 2022-12-28 16:21:26 +01:00
Thomas
b72964c851 Fix emoji not displayed 2022-12-28 16:20:14 +01:00
Thomas
3e16d0c310 Fix issue #694 - Home muted not working with no filters 2022-12-28 15:36:39 +01:00
Thomas
d34425f5b3 Merge remote-tracking branch 'origin/develop' into develop 2022-12-28 15:10:29 +01:00
Thomas
a7cc493922 Fix issue #690 - Crash when visiting a profile with a lot of media 2022-12-28 15:10:23 +01:00
Thomas
b6c908b249 Release notes 2022-12-28 15:01:58 +01:00
Thomas
fc4e7fddbe Fix DeepL pro URL 2022-12-28 15:01:25 +01:00
Paulo Marinho
00009707b2
Translated using Weblate (Portuguese)
Currently translated at 7.8% (5 of 64 strings)

Co-authored-by: Paulo Marinho <paulomarinho77@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/pt/
Translation: Fedilab/description
2022-12-28 12:51:00 +01:00
Thomas
2c48032127 Request notification for Android 13+ 2022-12-28 11:58:53 +01:00
Thomas
20c031f39e Issue with media 2022-12-28 11:44:36 +01:00
Thomas
f34bfabc5e Merge branch 'develop' 2022-12-27 18:00:52 +01:00
Thomas
e265078210 Secure zip 2022-12-27 18:00:24 +01:00
Thomas
7dfedbdaa4 Merge branch 'develop' 2022-12-27 17:43:00 +01:00
Thomas
eb78c80925 Merge remote-tracking branch 'origin/develop' into develop 2022-12-27 17:39:34 +01:00
Thomas
d70231cd78 Release 3.13.1 2022-12-27 17:39:29 +01:00
Oğuz Ersen
5ca727705b
Translated using Weblate (Turkish)
Currently translated at 100.0% (998 of 998 strings)

Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/tr/
Translation: Fedilab/Strings
2022-12-27 16:58:49 +01:00
RintanBroadleaf
01e5893c95
Translated using Weblate (Japanese)
Currently translated at 99.8% (997 of 998 strings)

Co-authored-by: RintanBroadleaf <rintanbroadleaf@outlook.jp>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ja/
Translation: Fedilab/Strings
2022-12-27 16:58:49 +01:00
josé m
4d91c400ab
Translated using Weblate (Galician)
Currently translated at 100.0% (998 of 998 strings)

Co-authored-by: josé m <correoxm@disroot.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/gl/
Translation: Fedilab/Strings
2022-12-27 16:58:49 +01:00
Lukáš Jelínek
608843b20a
Translated using Weblate (Czech)
Currently translated at 99.5% (994 of 998 strings)

Co-authored-by: Lukáš Jelínek <devel@aiken.cz>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/cs/
Translation: Fedilab/Strings
2022-12-27 16:58:49 +01:00
Thomas
852be8c608 Fix issue #691 - Suggested accounts cannot be followed 2022-12-27 16:58:38 +01:00
Thomas
4be595ea54 Add deepl support 2022-12-27 16:50:08 +01:00
Thomas
089d6b9ba8 Merge branch 'develop' 2022-12-26 18:16:45 +01:00
Thomas
b9eca58ccb Release 3.13.0 2022-12-26 18:13:50 +01:00
Thomas
48009141dd Fix name in reorder timelines for Nitter 2022-12-26 17:56:26 +01:00
Thomas
ac087eccfd Fix issue #686 - Users with on char username are not linked 2022-12-26 17:53:57 +01:00
Thomas
6bb3573eb4 Merge remote-tracking branch 'origin/develop' into develop 2022-12-26 15:59:03 +01:00
Thomas
fdd1fd1eb8 Fix issue #677 - Channel sounds not applied 2022-12-26 15:58:56 +01:00
aqC3ALziMWG1
3386f3cc29
Translated using Weblate (German)
Currently translated at 100.0% (998 of 998 strings)

Co-authored-by: aqC3ALziMWG1 <weblate@claleb.de>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/de/
Translation: Fedilab/Strings
2022-12-26 15:29:14 +01:00
josé m
188a09c57d
Translated using Weblate (Galician)
Currently translated at 100.0% (995 of 995 strings)

Co-authored-by: josé m <correoxm@disroot.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/gl/
Translation: Fedilab/Strings
2022-12-26 15:29:14 +01:00
Thomas
da18537883 Fix issue #680 - Fix link color issues. 2022-12-26 15:28:23 +01:00
Thomas
4b1792040e Fix issue #685 - Bouncing Timeline on refresh 2022-12-26 15:14:54 +01:00
Thomas
e7c3f04fd0 Merge remote-tracking branch 'origin/develop' into develop 2022-12-26 11:43:33 +01:00
Thomas
9f666bafc6 Fix issue #681 - Remove left margin - Default disabled. 2022-12-26 11:43:23 +01:00
3raven
a5fed1e7f0
Translated using Weblate (French)
Currently translated at 100.0% (62 of 62 strings)

Co-authored-by: 3raven <elise_declerck@laposte.net>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/fr/
Translation: Fedilab/description
2022-12-26 09:49:11 +01:00
3raven
67db19e8b9
Translated using Weblate (French)
Currently translated at 99.7% (993 of 995 strings)

Co-authored-by: 3raven <elise_declerck@laposte.net>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/fr/
Translation: Fedilab/Strings
2022-12-26 08:48:18 +01:00
Thomas
7a8f07d758 Release 3.12.3 2022-12-25 18:15:41 +01:00
Thomas
70e8756974 Fix issue #672 - Support pagination for search / trending 2022-12-25 18:07:25 +01:00
Thomas
e91a2f7984 Fix issue #672 - Support pagination for search / trending 2022-12-25 17:56:31 +01:00
Thomas
f38ae254c1 Fix issue #678 - Wrong instance fetched for instances.social 2022-12-25 16:40:08 +01:00
Thomas
da367ac0c0 Fix issue #675 - Chars sizes not applied for Android 5 2022-12-25 16:34:41 +01:00
Thomas
4e76f2476f Merge remote-tracking branch 'origin/develop' into develop 2022-12-25 16:26:26 +01:00
Thomas
de4faeadbc Fix issue #645 - Open with another account when there are only two accounts 2022-12-25 16:26:21 +01:00
Thomas
7a3c34b749 Fix notifications follow request not removed from cache 2022-12-25 16:21:26 +01:00
Kalle Kniivilä
77a489287b
Translated using Weblate (Esperanto)
Currently translated at 64.0% (637 of 995 strings)

Co-authored-by: Kalle Kniivilä <kalle.kniivila@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/eo/
Translation: Fedilab/Strings
2022-12-25 11:49:02 +01:00
Thomas
e94fd10d90 Merge remote-tracking branch 'origin/develop' into develop 2022-12-25 10:59:19 +01:00
Thomas
1fb129eada Fix #676 - Rollback to previous changes 2022-12-25 10:57:48 +01:00
0xd9a
78447a4c90 fix: hidden buttons in compose can be pressed 2022-12-24 22:27:24 +05:30
Thomas
ef2aafed67 Release 3.12.2 2022-12-24 16:54:54 +01:00
Thomas
c80942e02d Release 3.12.2 2022-12-24 16:53:51 +01:00
Thomas
9819e2d9d3 Fix crashes 2022-12-24 16:52:07 +01:00
Thomas
7030b1e20a Fix crashes 2022-12-24 16:50:40 +01:00
Thomas
c5030087d4 release notes 2022-12-24 16:25:56 +01:00
Thomas
1c9ebf14f9 Merge remote-tracking branch 'origin/develop' into develop 2022-12-24 16:24:00 +01:00
Thomas
e919e98b68 Fix issue #665 - Adding description failed when sharing 2022-12-24 16:23:46 +01:00
0xd9a
626e05b6a0 Update compose UI 2022-12-24 19:23:16 +05:30
0xd9a
c63afc8097 Use 'chip' for description button in compose 2022-12-24 16:20:21 +05:30
Thomas
c1814aa5e9 Update release notes 2022-12-24 10:36:47 +01:00
Thomas
0c60c9dbed Merge remote-tracking branch 'origin/develop' into develop 2022-12-24 10:32:18 +01:00
Thomas
209387820a Fix issue #674 - Fix fail when displaying thread from remote instances 2022-12-24 10:32:12 +01:00
0xd9a
136be83ed5 Update compose UI 2022-12-24 15:00:01 +05:30
Thomas
eb9b5d41a3 Release notes 2022-12-23 18:36:04 +01:00
Thomas
45dad375ad Fix #671 - Improve toggle for blocked accounts 2022-12-23 18:32:56 +01:00
Thomas
c9479aee20 Merge remote-tracking branch 'origin/develop' into develop 2022-12-23 18:08:18 +01:00
Thomas
9dc1b881e3 Fix #669 - Improve regex 2022-12-23 18:08:07 +01:00
0xd9a
f7f2ac542e Update screenshots 2022-12-23 22:24:13 +05:30
0xd9a
ebb809a0dd Remove scrim color in profile activity 2022-12-23 22:21:14 +05:30
Thomas
fbf7577ef7 Merge remote-tracking branch 'origin/develop' into develop 2022-12-23 17:34:41 +01:00
Thomas
ba7c404699 some fixes 2022-12-23 17:34:00 +01:00
Thomas
e5f36c3e43 switch lib 2022-12-23 11:36:03 +01:00
Ajeje Brazorf
f658696c34
Translated using Weblate (Sardinian)
Currently translated at 99.2% (988 of 995 strings)

Co-authored-by: Ajeje Brazorf <lmelonimamo@yahoo.it>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/sc/
Translation: Fedilab/Strings
2022-12-23 05:48:49 +01:00
Eduardo Lima
d9ed8bc3ea
Translated using Weblate (Portuguese)
Currently translated at 69.5% (692 of 995 strings)

Co-authored-by: Eduardo Lima <edu200399lim@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/pt/
Translation: Fedilab/Strings
2022-12-23 05:48:49 +01:00
ButterflyOfFire
ba4874a067
Translated using Weblate (French)
Currently translated at 99.6% (992 of 995 strings)

Translated using Weblate (Arabic)

Currently translated at 86.4% (860 of 995 strings)

Co-authored-by: ButterflyOfFire <ButterflyOfFire@protonmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ar/
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/fr/
Translation: Fedilab/Strings
2022-12-23 05:48:48 +01:00
Eduardo Lima
51a09b05b1
Translated using Weblate (Portuguese)
Currently translated at 70.6% (703 of 995 strings)

Co-authored-by: Eduardo Lima <edu200399lim@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/pt/
Translation: Fedilab/Strings
2022-12-22 07:50:55 +01:00
Oğuz Ersen
4bc128dbf9
Translated using Weblate (Turkish)
Currently translated at 100.0% (995 of 995 strings)

Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/tr/
Translation: Fedilab/Strings
2022-12-21 22:21:04 +01:00
Thomas
5e619d7e5c Rename Nitter instances 2022-12-21 18:58:40 +01:00
Thomas
5de4360f38 Merge remote-tracking branch 'origin/develop' into develop 2022-12-21 18:32:22 +01:00
Thomas
8c44f338da Rename Nitter instances 2022-12-21 18:31:21 +01:00
Thomas
8e93b2d2bc Release notes 2022-12-21 15:15:22 +01:00
Oğuz Ersen
29cf55338f
Translated using Weblate (Turkish)
Currently translated at 100.0% (994 of 994 strings)

Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/tr/
Translation: Fedilab/Strings
2022-12-21 15:12:59 +01:00
Ajeje Brazorf
0001aa0c2c
Translated using Weblate (Sardinian)
Currently translated at 99.3% (988 of 994 strings)

Co-authored-by: Ajeje Brazorf <lmelonimamo@yahoo.it>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/sc/
Translation: Fedilab/Strings
2022-12-21 15:12:59 +01:00
Screenshared
f51c2532ea
Translated using Weblate (Italian)
Currently translated at 98.9% (982 of 992 strings)

Co-authored-by: Screenshared <gian18400@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/it/
Translation: Fedilab/Strings
2022-12-21 15:12:59 +01:00
josé m
506286c3b6
Translated using Weblate (Galician)
Currently translated at 99.8% (991 of 992 strings)

Co-authored-by: josé m <correoxm@disroot.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/gl/
Translation: Fedilab/Strings
2022-12-21 15:12:59 +01:00
Kalle Kniivilä
c9c3d34535
Translated using Weblate (Esperanto)
Currently translated at 64.1% (636 of 992 strings)

Co-authored-by: Kalle Kniivilä <kalle.kniivila@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/eo/
Translation: Fedilab/Strings
2022-12-21 15:12:59 +01:00
Lukáš Jelínek
b2e9a08e95
Translated using Weblate (Czech)
Currently translated at 99.4% (989 of 994 strings)

Translated using Weblate (Czech)

Currently translated at 99.4% (987 of 992 strings)

Co-authored-by: Lukáš Jelínek <devel@aiken.cz>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/cs/
Translation: Fedilab/Strings
2022-12-21 15:12:59 +01:00
Thomas
4fa8959f11 Fix issue #663 - Support nav & status bar colors for Android 5 2022-12-21 15:12:44 +01:00
Thomas
f4a38504cd Fix issue #662 - Fix nav bar color in light mode 2022-12-21 14:49:01 +01:00
Thomas
fa2355b25f Release 3.12.1 2022-12-20 17:39:27 +01:00
Thomas
3a1671ae38 Respect blank spaces between words 2022-12-20 14:03:48 +01:00
Thomas
b428cf4de9 Group reblogs 2022-12-20 10:24:03 +01:00
Thomas
611c22a5c8 Display translate icon only when language is different 2022-12-20 09:53:34 +01:00
Thomas
d7a2a6b855 Fix jumps with media preview for some devices 2022-12-19 16:20:42 +01:00
Thomas
221bf45f27 Fix issue #654 - Truncated gimini links 2022-12-19 15:09:14 +01:00
Thomas
9cefa6ab41 Merge remote-tracking branch 'origin/develop' into develop 2022-12-19 14:27:19 +01:00
Thomas
898c5f7cee Fix issue #658 - Toggle cw does not honor choice 2022-12-19 14:26:56 +01:00
Thomas
fbeea6a8b8 Fix issue #658 2022-12-19 14:19:22 +01:00
Thomas
625f15fb32 Allow to get a quote 2022-12-19 12:42:29 +01:00
Oğuz Ersen
d0171236a8
Translated using Weblate (Turkish)
Currently translated at 100.0% (992 of 992 strings)

Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/tr/
Translation: Fedilab/Strings
2022-12-19 05:50:35 +01:00
Kalle Kniivilä
867f5dbae7
Translated using Weblate (Esperanto)
Currently translated at 64.1% (636 of 992 strings)

Co-authored-by: Kalle Kniivilä <kalle.kniivila@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/eo/
Translation: Fedilab/Strings
2022-12-19 05:50:35 +01:00
Lukáš Jelínek
c0f103b97c
Translated using Weblate (Czech)
Currently translated at 99.3% (986 of 992 strings)

Co-authored-by: Lukáš Jelínek <devel@aiken.cz>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/cs/
Translation: Fedilab/Strings
2022-12-19 05:50:35 +01:00
Kalle Kniivilä
5e40051659
Translated using Weblate (Esperanto)
Currently translated at 5.0% (3 of 59 strings)

Co-authored-by: Kalle Kniivilä <kalle.kniivila@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/eo/
Translation: Fedilab/description
2022-12-19 04:49:42 +01:00
Thomas
8e3b146a77 Merge branch 'develop' 2022-12-18 15:43:47 +01:00
Thomas
a63f1a9300 Fix issue #650 2022-12-18 15:42:48 +01:00
Thomas
a5fd4cf841 Fix issue #650 2022-12-18 15:42:14 +01:00
Thomas
324b67c6fa Add release notes 2022-12-18 15:37:34 +01:00
Thomas
aa6652c350 Release 3.12.0 2022-12-18 15:36:35 +01:00
Thomas
15bbb83c65 Fix top notification badges 2022-12-18 15:28:42 +01:00
Thomas
4dd9924857 clean 2022-12-18 15:24:02 +01:00
Thomas
dcb584eeb4 Fix solarized 2022-12-18 15:23:11 +01:00
Thomas
8dedd7a907 Fix solarized 2022-12-18 11:53:28 +01:00
Thomas
4ed081491f Start release notes 2022-12-18 11:45:08 +01:00
Thomas
3fcb0cc6e0 Fix theme bar color 2022-12-18 11:38:51 +01:00
Thomas
769c713a55 Themed icons for Android 13 2022-12-18 11:10:26 +01:00
Thomas
9491d8aa76 Fix solarized dark theme 2022-12-18 10:51:04 +01:00
Thomas
5e4dac1456 Fix filters 2022-12-18 10:36:55 +01:00
Thomas
eae0df43c0 Merge remote-tracking branch 'origin/develop' into develop 2022-12-18 10:04:29 +01:00
Thomas
52ccfdb860 Export/Import all data 2022-12-18 10:03:29 +01:00
Ajeje Brazorf
a108fb7805
Translated using Weblate (Sardinian)
Currently translated at 99.4% (986 of 991 strings)

Co-authored-by: Ajeje Brazorf <lmelonimamo@yahoo.it>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/sc/
Translation: Fedilab/Strings
2022-12-18 06:51:01 +01:00
Oliebol
30508bdc4a
Translated using Weblate (Dutch)
Currently translated at 100.0% (991 of 991 strings)

Co-authored-by: Oliebol <schrijfmedan@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/nl/
Translation: Fedilab/Strings
2022-12-17 09:48:08 +01:00
Thomas
376daf7c63 Merge branch 'develop' 2022-12-16 18:21:27 +01:00
Screenshared
0d9b5b4300
Translated using Weblate (Italian)
Currently translated at 97.9% (971 of 991 strings)

Co-authored-by: Screenshared <gian18400@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/it/
Translation: Fedilab/Strings
2022-12-16 18:21:15 +01:00
jy-fr
0a46f218be
Translated using Weblate (French)
Currently translated at 99.7% (989 of 991 strings)

Co-authored-by: jy-fr <jy.jurie@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/fr/
Translation: Fedilab/Strings
2022-12-16 18:21:15 +01:00
Codimp
8409fbd080
Translated using Weblate (French)
Currently translated at 99.7% (989 of 991 strings)

Co-authored-by: Codimp <contact@lithio.fr>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/fr/
Translation: Fedilab/Strings
2022-12-16 18:21:15 +01:00
Lukáš Jelínek
09a223074a
Translated using Weblate (Czech)
Currently translated at 99.2% (984 of 991 strings)

Co-authored-by: Lukáš Jelínek <devel@aiken.cz>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/cs/
Translation: Fedilab/Strings
2022-12-16 18:21:15 +01:00
Thomas
f858a870bd Release 3.11.3 2022-12-16 18:16:04 +01:00
Thomas
43c6fe4f7b Fix sensitive media not hidden whe clicking on the eye icon 2022-12-16 17:57:47 +01:00
Thomas
84b33751a2 Merge remote-tracking branch 'origin/develop' into develop 2022-12-16 17:26:34 +01:00
Thomas
0cbf0bfbd4 Some fixes 2022-12-16 17:15:46 +01:00
Codimp
29117125ef
Translated using Weblate (French)
Currently translated at 94.7% (54 of 57 strings)

Co-authored-by: Codimp <contact@lithio.fr>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/fr/
Translation: Fedilab/description
2022-12-16 14:50:10 +01:00
Thomas
30f21c035d Fix a crash when app takes long to load 2022-12-16 10:46:13 +01:00
Thomas
3c7129f47a Add more targeted languages in picker for translations 2022-12-16 10:33:56 +01:00
Thomas
d0342143ef Add acct to notifications 2022-12-16 10:06:43 +01:00
Thomas
1cf3519951 Fix a crash when changing language 2022-12-16 09:48:39 +01:00
Thomas
295243d781 fix counter colors 2022-12-16 09:40:41 +01:00
Thomas
81dd820d0a fix default link color 2022-12-16 09:31:01 +01:00
Thomas
e0953ff5af fix a crash 2022-12-16 09:15:40 +01:00
Thomas
2a675da7c2 Merge branch 'develop' 2022-12-15 18:26:43 +01:00
Thomas
4ec3a430bd Release 3.11.2 2022-12-15 18:25:05 +01:00
Thomas
8ff8223378 Release 3.11.2 2022-12-15 18:19:19 +01:00
Thomas
f35ac8ae6b Improve filters 2022-12-15 18:17:27 +01:00
Thomas
c50df7fc5b Merge branch 'develop' of https://codeberg.org/tom79/Fedilab into develop 2022-12-15 16:53:13 +01:00
Thomas
c04462e19b Fix a crash 2022-12-15 16:52:51 +01:00
Hosted Weblate
b212e90bf0
Update translation files
Updated by "Remove blank strings" hook in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/
Translation: Fedilab/Strings
2022-12-15 13:32:27 +01:00
Screenshared
852f4e7f7a
Translated using Weblate (Italian)
Currently translated at 96.5% (957 of 991 strings)

Co-authored-by: Screenshared <gian18400@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/it/
Translation: Fedilab/Strings
2022-12-15 13:32:27 +01:00
Thomas
d7976734ce Fix issue #636 - Freeze with the app. 2022-12-15 10:46:31 +01:00
Oğuz Ersen
edf4f01309
Translated using Weblate (Turkish)
Currently translated at 100.0% (991 of 991 strings)

Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/tr/
Translation: Fedilab/Strings
2022-12-15 09:48:26 +01:00
Lukáš Jelínek
a1542f8cf8
Translated using Weblate (Czech)
Currently translated at 98.0% (972 of 991 strings)

Co-authored-by: Lukáš Jelínek <devel@aiken.cz>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/cs/
Translation: Fedilab/Strings
2022-12-15 09:48:26 +01:00
Thomas
15829da776 Release 3.11.1 2022-12-14 15:08:10 +01:00
Thomas
8ae3ff3b35 Merge remote-tracking branch 'origin/develop' into develop 2022-12-14 14:49:08 +01:00
Thomas
a55401df77 Mute from lists 2022-12-14 14:48:32 +01:00
Thomas
d8de016407 Allow to mute/unmute from the list with a new icon 2022-12-14 14:29:20 +01:00
Thomas
807ff6c9da Some changes 2022-12-14 12:15:41 +01:00
Thomas
7a93b22f77 Display home muted 2022-12-14 11:55:19 +01:00
Ajeje Brazorf
83f0699d47
Translated using Weblate (Sardinian)
Currently translated at 99.4% (980 of 985 strings)

Co-authored-by: Ajeje Brazorf <lmelonimamo@yahoo.it>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/sc/
Translation: Fedilab/Strings
2022-12-14 11:49:08 +01:00
Lukáš Jelínek
7d03f5b6c0
Translated using Weblate (Czech)
Currently translated at 98.6% (972 of 985 strings)

Co-authored-by: Lukáš Jelínek <devel@aiken.cz>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/cs/
Translation: Fedilab/Strings
2022-12-14 11:49:08 +01:00
Thomas
93fce1f56e Allow to mute/unmute from profile 2022-12-14 11:21:00 +01:00
Thomas
5e11438f0c Manage accounts 2022-12-14 10:40:29 +01:00
Thomas
7f1098e345 Create table / update db 2022-12-14 09:55:04 +01:00
Thomas
12981deafb Merge branch 'develop' 2022-12-13 18:03:00 +01:00
Thomas
0772f47b13 Release 3.11.0 2022-12-13 18:01:14 +01:00
Thomas
269b83607c Fix issue #629 - Remove animations after refresh 2022-12-13 16:28:26 +01:00
Thomas
a7563d2859 Merge remote-tracking branch 'origin/develop' into develop 2022-12-13 16:09:04 +01:00
Thomas
1d350f46d6 Fix issue #550 - Quick account switch 2022-12-13 16:08:44 +01:00
Thomas
167c3e6251 Fix some crashes 2022-12-13 12:04:35 +01:00
Thomas
770eef7629 Convert to java 2022-12-13 10:48:06 +01:00
Oğuz Ersen
c5bc6413b4
Translated using Weblate (Turkish)
Currently translated at 100.0% (985 of 985 strings)

Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/tr/
Translation: Fedilab/Strings
2022-12-13 09:48:52 +01:00
Lukáš Jelínek
79adda7059
Translated using Weblate (Czech)
Currently translated at 98.6% (972 of 985 strings)

Co-authored-by: Lukáš Jelínek <devel@aiken.cz>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/cs/
Translation: Fedilab/Strings
2022-12-13 09:48:52 +01:00
Thomas
5f977d0422 Release 3.10.2 2022-12-12 18:36:56 +01:00
Thomas
6fc8275aee Automatically attach tag to message when composing from a tag timeline 2022-12-12 18:29:49 +01:00
Thomas
c59b1e6f3f Fix tag colors 2022-12-12 18:19:27 +01:00
Thomas
bd8d3405b2 Fix contact not added when composing 2022-12-12 18:13:06 +01:00
Thomas
2c32113476 Some fixes when resuming 2022-12-12 17:30:23 +01:00
Thomas
792b0ca77e Fix issue #599 - Edit messages in thread are duplicated 2022-12-12 16:15:58 +01:00
Thomas
9846d9ce79 Small fix in login 2022-12-12 15:50:47 +01:00
Thomas
173043a684 Fix issue #614 - background color for Android 5 2022-12-12 15:36:05 +01:00
Thomas
202e527b5f Fix issue #603 - Fix status bar color 2022-12-12 14:51:34 +01:00
Thomas
5a0eff4ae8 Fix issue #623 - Allow to display the translate button at the bottom. 2022-12-12 12:18:19 +01:00
Thomas
1b643bcb1d Fix issue #615 - add reverse option for tags + Change label descriptions 2022-12-12 11:57:41 +01:00
Thomas
83ffc82851 Merge remote-tracking branch 'origin/develop' into develop 2022-12-12 09:19:52 +01:00
Thomas
f6c0d8345b Fix issue #622 - Rollback to previous view for notifications 2022-12-12 09:17:50 +01:00
Lukáš Jelínek
529fbaede8
Translated using Weblate (Czech)
Currently translated at 98.8% (967 of 978 strings)

Co-authored-by: Lukáš Jelínek <devel@aiken.cz>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/cs/
Translation: Fedilab/Strings
2022-12-12 02:51:26 +01:00
josé m
072240edd0
Translated using Weblate (Galician)
Currently translated at 7.5% (4 of 53 strings)

Co-authored-by: josé m <correoxm@disroot.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/gl/
Translation: Fedilab/description
2022-12-11 17:49:41 +01:00
Thomas
536e6d9c47 Merge remote-tracking branch 'origin/develop' into develop 2022-12-11 17:10:05 +01:00
Thomas
34a1ae16d8 Fix issue #621 - Mentions in bio does not open the correct account 2022-12-11 17:09:57 +01:00
josé m
8310b03b61
Translated using Weblate (Galician)
Currently translated at 100.0% (978 of 978 strings)

Co-authored-by: josé m <correoxm@disroot.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/gl/
Translation: Fedilab/Strings
2022-12-11 11:53:49 +01:00
Eric
4dab4f34a4
Translated using Weblate (Chinese (Simplified))
Currently translated at 65.3% (639 of 978 strings)

Co-authored-by: Eric <hamburger1024@duck.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/zh_Hans/
Translation: Fedilab/Strings
2022-12-11 11:53:49 +01:00
Ajeje Brazorf
7cf79d3304
Translated using Weblate (Sardinian)
Currently translated at 99.4% (973 of 978 strings)

Co-authored-by: Ajeje Brazorf <lmelonimamo@yahoo.it>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/sc/
Translation: Fedilab/Strings
2022-12-11 11:53:49 +01:00
Lukáš Jelínek
89467ce58b
Translated using Weblate (Czech)
Currently translated at 98.7% (966 of 978 strings)

Co-authored-by: Lukáš Jelínek <devel@aiken.cz>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/cs/
Translation: Fedilab/Strings
2022-12-11 11:53:49 +01:00
Oğuz Ersen
ea2756f013
Translated using Weblate (Turkish)
Currently translated at 100.0% (978 of 978 strings)

Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/tr/
Translation: Fedilab/Strings
2022-12-11 11:53:49 +01:00
Eduardo Lima
6cd4fc7d78
Translated using Weblate (Portuguese)
Currently translated at 71.5% (697 of 974 strings)

Co-authored-by: Eduardo Lima <edu200399lim@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/pt/
Translation: Fedilab/Strings
2022-12-11 11:53:48 +01:00
Thomas
6da23a9da3 Fix issue #617 - Update counters 2022-12-11 11:53:40 +01:00
Thomas
bd66462968 Fix issue #617 2022-12-11 11:36:39 +01:00
Thomas
7fc8f96eef Fix visibility for description warning 2022-12-10 19:01:02 +01:00
Thomas
2ec7142561 Fix a display issue with notifications 2022-12-10 18:36:13 +01:00
Thomas
c36d6f4bdd Fix a display issue with notifications 2022-12-10 17:01:31 +01:00
Thomas
57551a716e Release 3.10.1 2022-12-10 10:57:28 +01:00
Thomas
2edb2759e5 Merge remote-tracking branch 'origin/develop' into develop 2022-12-10 10:38:47 +01:00
Thomas
a8eb33f3dd Allow to check remote conversations 2022-12-10 10:38:01 +01:00
Thomas
dbda1e13d2 Merge branch 'develop' into check_remote_context 2022-12-10 10:08:22 +01:00
Hosted Weblate
0f2b5db07b
Update translation files
Updated by "Remove blank strings" hook in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/
Translation: Fedilab/Strings
2022-12-10 00:19:30 +01:00
Oğuz Ersen
ebd4f9ba89
Translated using Weblate (Turkish)
Currently translated at 100.0% (974 of 974 strings)

Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/tr/
Translation: Fedilab/Strings
2022-12-10 00:19:29 +01:00
Ajeje Brazorf
550f93b735
Translated using Weblate (Sardinian)
Currently translated at 98.5% (960 of 974 strings)

Co-authored-by: Ajeje Brazorf <lmelonimamo@yahoo.it>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/sc/
Translation: Fedilab/Strings
2022-12-10 00:19:29 +01:00
Eduardo Lima
e6a499fcc5
Translated using Weblate (Portuguese)
Currently translated at 71.3% (695 of 974 strings)

Co-authored-by: Eduardo Lima <edu200399lim@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/pt/
Translation: Fedilab/Strings
2022-12-10 00:19:29 +01:00
ButterflyOfFire
fd482317dd
Translated using Weblate (Gaelic)
Currently translated at 28.8% (281 of 974 strings)

Translated using Weblate (Silesian)

Currently translated at 62.0% (604 of 974 strings)

Translated using Weblate (Russian)

Currently translated at 61.9% (603 of 974 strings)

Translated using Weblate (Portuguese)

Currently translated at 71.3% (695 of 974 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 68.6% (669 of 974 strings)

Translated using Weblate (Korean)

Currently translated at 62.0% (604 of 974 strings)

Translated using Weblate (Hungarian)

Currently translated at 61.7% (601 of 974 strings)

Co-authored-by: ButterflyOfFire <ButterflyOfFire@protonmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/gd/
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/hu/
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ko/
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/nb_NO/
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/pt/
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ru/
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/szl/
Translation: Fedilab/Strings
2022-12-10 00:19:28 +01:00
Lukáš Jelínek
62356ff873
Translated using Weblate (Czech)
Currently translated at 98.4% (959 of 974 strings)

Co-authored-by: Lukáš Jelínek <devel@aiken.cz>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/cs/
Translation: Fedilab/Strings
2022-12-10 00:19:28 +01:00
Thomas
002bc4886b Merge branch 'develop' 2022-12-09 18:15:26 +01:00
Thomas
6710ef2e1f Release 3.10.0 2022-12-09 18:14:07 +01:00
Thomas
7546d79533 Check status 2022-12-09 18:07:44 +01:00
Thomas
d45ac1b9f9 Fix icon 2022-12-09 17:08:39 +01:00
Thomas
70f9324b8c avoid a crash 2022-12-09 15:37:35 +01:00
Thomas
dda3296154 Changes action icons 2022-12-09 15:36:27 +01:00
Thomas
165f85c8af Fix issue #613 2022-12-09 14:28:53 +01:00
Thomas
c68b4b6b2e Fix issue #366 - Text with links not displayed 2022-12-09 11:55:50 +01:00
Thomas
e7dd2ac5d2 Fix crashes 2022-12-09 11:34:14 +01:00
Thomas
52fa2b0815 Customize notifications and conversations 2022-12-09 10:59:03 +01:00
Thomas
335d87ad11 Fix typo 2022-12-09 10:20:08 +01:00
Thomas
b6d513713e Merge remote-tracking branch 'origin/develop' into develop 2022-12-09 10:18:54 +01:00
Thomas
ae80a27db9 Allow to reset customizations 2022-12-09 10:01:57 +01:00
ButterflyOfFire
c61f4bc49c
Translated using Weblate (Arabic)
Currently translated at 82.1% (776 of 945 strings)

Co-authored-by: ButterflyOfFire <ButterflyOfFire@protonmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ar/
Translation: Fedilab/Strings
2022-12-09 06:49:56 +01:00
Thomas
d9ed098464 Change colors 2022-12-08 18:56:06 +01:00
Thomas
5337841da0 Pref settings customization of messages 2022-12-08 18:10:51 +01:00
Thomas
724813407d Fix typo 2022-12-08 10:31:58 +01:00
Thomas
6fa23d1bc3 Allow to enable or disable the cardview presentation in settings 2022-12-08 10:20:03 +01:00
Thomas
49df8bda8c Release 3.9.7 2022-12-07 18:40:15 +01:00
Thomas
63e09ee9a4 Release 3.9.7 2022-12-07 18:37:18 +01:00
Thomas
98f8b269b0 Some fixes 2022-12-07 18:12:32 +01:00
Thomas
8ca6f69da7 Theme changes 2022-12-07 17:40:00 +01:00
Thomas
201252b71d Theme changes 2022-12-07 17:39:27 +01:00
Thomas
b6f74cb297 Add Dracula theme 2022-12-07 12:46:34 +01:00
Thomas
6cfe8b7b95 Release 3.9.6 2022-12-06 17:59:28 +01:00
Thomas
c0f3b0f86b Release 3.9.6 2022-12-06 17:55:51 +01:00
Thomas
7ccb1c96b2 Fix issue #607 - Fetch more broken 2022-12-06 17:50:25 +01:00
Thomas
03d6c7f911 Fix issue #604 - Jumps when scrolling up with media 2022-12-06 15:59:31 +01:00
Thomas
83638e9a92 Beta release 3.9.5 2022-12-05 17:34:37 +01:00
Thomas
2cb08046f5 Fix issue #288 - Custom Emoji not always displayed 2022-12-05 16:23:13 +01:00
Thomas
ffb6596c99 Fix issue #598 - Avoid jumps with fit preview images. 2022-12-05 09:01:37 +01:00
Thomas
0c6fe112c9 Fix issue #592 - Second search clears term field 2022-12-04 18:46:51 +01:00
Thomas
427073a369 Fix issue #591 2022-12-04 18:39:41 +01:00
Thomas
65156e0a84 Fix issue when refreshing notifications + fix an issue with cache and DM 2022-12-04 18:25:10 +01:00
Thomas
5290173184 Merge branch 'develop' 2022-12-04 15:50:14 +01:00
Thomas
468f825dc0 Release 3.9.4 2022-12-04 15:49:38 +01:00
Thomas
15ce78b85a Fix a crash 2022-12-04 15:00:28 +01:00
Thomas
0b2eb64a72 Merge branch 'develop' 2022-12-03 19:45:04 +01:00
Thomas
88f5ed27bd Release 3.9.3 2022-12-03 19:44:10 +01:00
Thomas
5c899e6fba Release 3.9.3 2022-12-03 19:42:47 +01:00
Thomas
7ada093a0f Merge branch 'develop' 2022-12-03 18:44:07 +01:00
Thomas
29a5678a47 Release 3.9.2 2022-12-03 18:43:36 +01:00
Thomas
d66c257370 Some fixes 2022-12-03 18:40:00 +01:00
Thomas
77b6c478d1 Some improvements 2022-12-03 18:05:37 +01:00
Thomas
27120026c2 Some improvements 2022-12-03 17:47:59 +01:00
Thomas
7576dc8bee Fix issue #577 2022-12-03 14:49:01 +01:00
Thomas
674ece5e4c Fix issue #577 2022-12-03 14:47:48 +01:00
Thomas
2e3adc0262 Fix issue #578 2022-12-03 14:37:56 +01:00
Thomas
1ea8f1fd45 Fix issue #573 2022-12-03 14:10:16 +01:00
Thomas
dc4f6f5751 Fix issue #583 2022-12-03 14:02:44 +01:00
Thomas
c76cc66643 Merge remote-tracking branch 'origin/develop' into develop 2022-12-03 11:48:20 +01:00
Thomas
bf54150e31 Fix some color issues 2022-12-03 11:48:08 +01:00
Lukáš Jelínek
ce6523e9a1
Translated using Weblate (Czech)
Currently translated at 21.7% (10 of 46 strings)

Co-authored-by: Lukáš Jelínek <devel@aiken.cz>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/cs/
Translation: Fedilab/description
2022-12-03 11:48:07 +01:00
Thomas
27102284c4 Merge remote-tracking branch 'origin/develop' into develop 2022-12-03 11:24:46 +01:00
Thomas
191dc85d36 Fix issue #581 - List cannot be hidden. 2022-12-03 11:24:25 +01:00
Micha
ef3572abfe
Translated using Weblate (German)
Currently translated at 28.2% (13 of 46 strings)

Co-authored-by: Micha <weblate@slow.pictures>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/de/
Translation: Fedilab/description
2022-12-02 21:53:58 +01:00
Micha
06ee3f9038
Translated using Weblate (German)
Currently translated at 100.0% (945 of 945 strings)

Co-authored-by: Micha <weblate@slow.pictures>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/de/
Translation: Fedilab/Strings
2022-12-02 21:53:49 +01:00
Thomas
4c1a8a6372 Release 3.9.1 2022-12-02 18:25:47 +01:00
Thomas
b02172242e Release 3.9.1 2022-12-02 18:22:45 +01:00
Thomas
360e075bdf Merge remote-tracking branch 'origin/develop' into develop 2022-12-02 18:18:19 +01:00
Thomas
6f3512354f more place for icons 2022-12-02 18:18:13 +01:00
Micha
344f61d928
Translated using Weblate (German)
Currently translated at 100.0% (946 of 946 strings)

Co-authored-by: Micha <weblate@slow.pictures>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/de/
Translation: Fedilab/Strings
2022-12-02 16:36:50 +01:00
ButterflyOfFire
e2d0c21f48
Translated using Weblate (Arabic)
Currently translated at 80.5% (762 of 946 strings)

Co-authored-by: ButterflyOfFire <ButterflyOfFire@protonmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ar/
Translation: Fedilab/Strings
2022-12-02 16:36:50 +01:00
Thomas
90cc5b0e06 Fix issue #563 2022-12-02 16:36:23 +01:00
Thomas
0f876f501b some fixes. 2022-12-02 16:14:57 +01:00
Thomas
4e2701cb5e remove data-base 2022-12-02 15:53:58 +01:00
Thomas
95beb7f3c1 Remove built-in browser 2022-12-02 15:48:23 +01:00
Thomas
403fb1aba7 Fix color issue 2022-12-02 10:40:23 +01:00
Thomas
360d7a6952 Fix cards with long title 2022-12-02 10:23:06 +01:00
Thomas
c2c780f58e Some fixes with the theme 2022-12-02 09:57:23 +01:00
Thomas
5fdb654aa2 Merge remote-tracking branch 'origin/develop' into develop 2022-12-01 18:26:56 +01:00
Thomas
774a73c624 Fix #566 #565 #564 2022-12-01 18:26:46 +01:00
Oğuz Ersen
e83c161409
Translated using Weblate (Turkish)
Currently translated at 100.0% (946 of 946 strings)

Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/tr/
Translation: Fedilab/Strings
2022-12-01 17:55:05 +01:00
Ajeje Brazorf
d6d6459954
Translated using Weblate (Sardinian)
Currently translated at 99.4% (941 of 946 strings)

Co-authored-by: Ajeje Brazorf <lmelonimamo@yahoo.it>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/sc/
Translation: Fedilab/Strings
2022-12-01 17:55:04 +01:00
Oliebol
b2e5c1202a
Translated using Weblate (Dutch)
Currently translated at 100.0% (946 of 946 strings)

Co-authored-by: Oliebol <schrijfmedan@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/nl/
Translation: Fedilab/Strings
2022-12-01 17:55:04 +01:00
Xosé M
d0a4429fe7
Translated using Weblate (Galician)
Currently translated at 100.0% (946 of 946 strings)

Co-authored-by: Xosé M <correoxm@disroot.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/gl/
Translation: Fedilab/Strings
2022-12-01 17:55:03 +01:00
Micha
bc6904f49d
Translated using Weblate (German)
Currently translated at 99.2% (939 of 946 strings)

Co-authored-by: Micha <weblate@slow.pictures>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/de/
Translation: Fedilab/Strings
2022-12-01 17:55:03 +01:00
Murat H
f39869bb9e
Translated using Weblate (German)
Currently translated at 99.2% (939 of 946 strings)

Co-authored-by: Murat H <karabela81sta@googlemail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/de/
Translation: Fedilab/Strings
2022-12-01 17:55:03 +01:00
Lukáš Jelínek
1e660c5d01
Translated using Weblate (Czech)
Currently translated at 91.8% (869 of 946 strings)

Co-authored-by: Lukáš Jelínek <devel@aiken.cz>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/cs/
Translation: Fedilab/Strings
2022-12-01 17:55:02 +01:00
Thomas
e1e5284a47 Release 3.9.0 2022-11-30 18:15:32 +01:00
Thomas
9959904853 Some fixes 2022-11-30 17:07:23 +01:00
Thomas
0ff17dd96f Header more visible 2022-11-30 16:52:54 +01:00
Thomas
4730f7fb53 Header more visible 2022-11-30 16:16:54 +01:00
Thomas
506f5fcf49 Fix some issues 2022-11-30 16:07:12 +01:00
Thomas
d10549ddd1 Merge remote-tracking branch 'origin/develop' into develop 2022-11-30 15:52:47 +01:00
Thomas
bd5fccf2db Fix issue 558 - App doesn't remember position on profiles/fav/bookmarks etc. 2022-11-30 15:52:41 +01:00
Murat H
46e38c3581
Translated using Weblate (German)
Currently translated at 100.0% (934 of 934 strings)

Co-authored-by: Murat H <karabela81sta@googlemail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/de/
Translation: Fedilab/Strings
2022-11-30 15:27:31 +01:00
Thomas
ef24d7586b Upgrade libs 2022-11-30 15:27:23 +01:00
Thomas
65202df92a Merge remote-tracking branch 'origin/develop' into develop 2022-11-30 15:08:07 +01:00
Thomas
349d8578f0 some fixes 2022-11-30 15:06:34 +01:00
Thomas
29752106d2 Add black theme 2022-11-30 12:12:55 +01:00
Thomas
0c2a6e2aad Switch between themes 2022-11-30 11:49:13 +01:00
Thomas
13b9a43bc3 Split activities 2022-11-30 11:00:53 +01:00
Murat H
1e3933f5df
Translated using Weblate (German)
Currently translated at 100.0% (934 of 934 strings)

Co-authored-by: Murat H <karabela81sta@googlemail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/de/
Translation: Fedilab/Strings
2022-11-30 09:38:48 +01:00
LostInWeb
2de89425f2
Translated using Weblate (German)
Currently translated at 100.0% (934 of 934 strings)

Co-authored-by: LostInWeb <weblate@lostinweb.eu>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/de/
Translation: Fedilab/Strings
2022-11-30 09:38:47 +01:00
LostInWeb
20dbd48c4e
Translated using Weblate (German)
Currently translated at 100.0% (934 of 934 strings)

Co-authored-by: LostInWeb <weblate@lostinweb.eu>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/de/
Translation: Fedilab/Strings
2022-11-30 09:30:09 +01:00
Micha
845bf93bea
Translated using Weblate (German)
Currently translated at 100.0% (934 of 934 strings)

Co-authored-by: Micha <weblate@slow.pictures>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/de/
Translation: Fedilab/Strings
2022-11-30 09:30:09 +01:00
Murat H
24c6803af7
Translated using Weblate (German)
Currently translated at 100.0% (934 of 934 strings)

Co-authored-by: Murat H <karabela81sta@googlemail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/de/
Translation: Fedilab/Strings
2022-11-30 09:30:08 +01:00
joenepraat
6b7f8b6d8a
Translated using Weblate (Dutch)
Currently translated at 100.0% (934 of 934 strings)

Co-authored-by: joenepraat <joenepraat@posteo.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/nl/
Translation: Fedilab/Strings
2022-11-30 08:15:04 +01:00
ButterflyOfFire
ade0a24d78
Translated using Weblate (German)
Currently translated at 99.7% (932 of 934 strings)

Co-authored-by: ButterflyOfFire <ButterflyOfFire@protonmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/de/
Translation: Fedilab/Strings
2022-11-30 08:15:04 +01:00
Thomas
7d6f7167fd Fix colors 2022-11-29 18:31:31 +01:00
Ajeje Brazorf
d33397068c
Translated using Weblate (Sardinian)
Currently translated at 99.4% (929 of 934 strings)

Co-authored-by: Ajeje Brazorf <lmelonimamo@yahoo.it>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/sc/
Translation: Fedilab/Strings
2022-11-29 18:26:04 +01:00
Oliebol
98f68de5f8
Translated using Weblate (Dutch)
Currently translated at 97.7% (913 of 934 strings)

Co-authored-by: Oliebol <schrijfmedan@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/nl/
Translation: Fedilab/Strings
2022-11-29 18:26:04 +01:00
Thomas
1dbf3a050c Fix calendar 2022-11-29 16:24:23 +01:00
Thomas
9a10a7aaf6 switch between themes 2022-11-29 15:18:46 +01:00
Thomas
c8a4ffa922 some improvements 2022-11-29 14:30:46 +01:00
Thomas
d98ab320f1 Some fixes 2022-11-29 12:15:20 +01:00
Thomas
542477f37f Some cosmetic 2022-11-29 12:11:20 +01:00
Thomas
1fbce05dbd Improvements 2022-11-29 11:06:37 +01:00
Thomas
635dc94b8d new colors 2022-11-29 10:23:19 +01:00
Thomas
f29122e3ef change colors 2022-11-29 09:44:11 +01:00
Thomas
9f670f5e5e Fix some colors 2022-11-29 08:39:31 +01:00
Thomas
22902ac070 Fix some crashes 2022-11-29 08:33:35 +01:00
Mi Klo
468702553c
Translated using Weblate (Polish)
Currently translated at 81.5% (762 of 934 strings)

Co-authored-by: Mi Klo <peertube@miklobit.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/pl/
Translation: Fedilab/Strings
2022-11-28 22:29:10 +01:00
Cathelijne
bbb0aa7afc
Translated using Weblate (Dutch)
Currently translated at 97.3% (909 of 934 strings)

Co-authored-by: Cathelijne <weblate@hornstra.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/nl/
Translation: Fedilab/Strings
2022-11-28 22:29:10 +01:00
Lon
6556f9aaef
Translated using Weblate (Dutch)
Currently translated at 97.3% (909 of 934 strings)

Co-authored-by: Lon <schrijfmedan@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/nl/
Translation: Fedilab/Strings
2022-11-28 22:29:09 +01:00
malfisya
1dad39145b
Translated using Weblate (Indonesian)
Currently translated at 65.9% (616 of 934 strings)

Co-authored-by: malfisya <ems1000.syahrin@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/id/
Translation: Fedilab/Strings
2022-11-28 22:29:09 +01:00
Xosé M
d9d93026b3
Translated using Weblate (Galician)
Currently translated at 100.0% (934 of 934 strings)

Co-authored-by: Xosé M <correoxm@disroot.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/gl/
Translation: Fedilab/Strings
2022-11-28 22:29:09 +01:00
jy-fr
2e5fa92af6
Translated using Weblate (French)
Currently translated at 98.9% (924 of 934 strings)

Co-authored-by: jy-fr <jy.jurie@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/fr/
Translation: Fedilab/Strings
2022-11-28 22:29:08 +01:00
ButterflyOfFire
fdec0c5a58
Translated using Weblate (French)
Currently translated at 98.9% (924 of 934 strings)

Co-authored-by: ButterflyOfFire <ButterflyOfFire@protonmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/fr/
Translation: Fedilab/Strings
2022-11-28 22:29:08 +01:00
Leandro Leites Barrios
dc40026c82
Translated using Weblate (Spanish)
Currently translated at 62.3% (582 of 934 strings)

Co-authored-by: Leandro Leites Barrios <laloleites@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/es/
Translation: Fedilab/Strings
2022-11-28 22:29:08 +01:00
Murat H
7a48cd236a
Translated using Weblate (German)
Currently translated at 100.0% (934 of 934 strings)

Co-authored-by: Murat H <karabela81sta@googlemail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/de/
Translation: Fedilab/Strings
2022-11-28 22:29:07 +01:00
Micha
540ebf9de8
Translated using Weblate (German)
Currently translated at 100.0% (934 of 934 strings)

Co-authored-by: Micha <weblate@slow.pictures>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/de/
Translation: Fedilab/Strings
2022-11-28 22:29:07 +01:00
LostInWeb
96eed3a75b
Translated using Weblate (German)
Currently translated at 100.0% (934 of 934 strings)

Co-authored-by: LostInWeb <weblate@lostinweb.eu>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/de/
Translation: Fedilab/Strings
2022-11-28 22:29:06 +01:00
Lukáš Jelínek
fcaaa39def
Translated using Weblate (Czech)
Currently translated at 84.0% (785 of 934 strings)

Co-authored-by: Lukáš Jelínek <devel@aiken.cz>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/cs/
Translation: Fedilab/Strings
2022-11-28 22:29:06 +01:00
dtalens
d70ae7df94
Translated using Weblate (Catalan)
Currently translated at 88.7% (829 of 934 strings)

Co-authored-by: dtalens <databio@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ca/
Translation: Fedilab/Strings
2022-11-28 22:29:06 +01:00
Thomas
db3d317a55 some changes 2022-11-28 18:39:48 +01:00
Thomas
11ea166a0d Replacements 2022-11-28 17:06:27 +01:00
Thomas
216887800b Replacements 2022-11-28 16:46:13 +01:00
Thomas
abf1da579c Replacements 2022-11-28 16:34:59 +01:00
Thomas
8a883de5a0 Replacements 2022-11-28 15:56:58 +01:00
Thomas
0ab66d34c1 Replacements 2022-11-28 15:29:54 +01:00
Thomas
ee22181a91 Fix icon colors 2022-11-28 15:14:37 +01:00
Thomas
320f913c63 remove useless elements 2022-11-28 15:03:17 +01:00
Thomas
4ea542c1f8 Some changes 2022-11-28 11:46:48 +01:00
Thomas
ccf7ac5cff Remove cyanea 2022-11-28 10:37:57 +01:00
Thomas
da4ed393a9 Add a note 2022-11-27 17:14:23 +01:00
Thomas
2e3d5b6b94 Release notes for 3.8.1 2022-11-27 17:10:51 +01:00
Thomas
8307cb8e75 Remove cache messages when muting 2022-11-27 16:52:26 +01:00
Thomas
a796d54166 Live remove when muting tags 2022-11-27 16:47:28 +01:00
Thomas
c7420a8760 Fix some crashes 2022-11-27 16:30:51 +01:00
Thomas
ab9b367a38 Hide messages instead of removing them and add fetch more support 2022-11-27 12:27:31 +01:00
Thomas
6f288acbc9 Remove fake user agent 2022-11-27 11:48:14 +01:00
Thomas
6f8ca561bf Fix #517 - force to rescan 2022-11-27 11:47:14 +01:00
Thomas
72f123d26b Fix authentication with external browser does not grant admin scope 2022-11-27 09:53:06 +01:00
Thomas
58dcdbf050 Fix issue #517 - Media not displayed in public gallery for some devices 2022-11-27 09:28:33 +01:00
Thomas
4398873c08 Inverse display name and acct for art 2022-11-27 09:03:47 +01:00
Thomas
f1358df54c Merge remote-tracking branch 'origin/develop' into develop 2022-11-27 08:19:11 +01:00
Thomas
88b6093a53 Fix issue #545 - Open with does not work 2022-11-27 08:18:45 +01:00
Murat H
03725c6072
Translated using Weblate (German)
Currently translated at 16.2% (7 of 43 strings)

Co-authored-by: Murat H <karabela81sta@googlemail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/de/
Translation: Fedilab/description
2022-11-26 19:48:26 +01:00
Vri 🌈
e6b0098427
Translated using Weblate (German)
Currently translated at 99.1% (926 of 934 strings)

Co-authored-by: Vri 🌈 <weblate@vrifox.cc>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/de/
Translation: Fedilab/Strings
2022-11-26 18:28:47 +01:00
Oğuz Ersen
28637fb035
Translated using Weblate (Turkish)
Currently translated at 100.0% (934 of 934 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (933 of 933 strings)

Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/tr/
Translation: Fedilab/Strings
2022-11-26 18:28:47 +01:00
Murat H
3868bd83c9
Translated using Weblate (German)
Currently translated at 99.2% (926 of 933 strings)

Co-authored-by: Murat H <karabela81sta@googlemail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/de/
Translation: Fedilab/Strings
2022-11-26 18:28:47 +01:00
dtalens
ccf11c29c6
Translated using Weblate (Catalan)
Currently translated at 87.0% (812 of 933 strings)

Co-authored-by: dtalens <databio@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ca/
Translation: Fedilab/Strings
2022-11-26 18:28:47 +01:00
Thomas
c147240384 Fix issue #544 - Jump in profiles 2022-11-26 18:28:00 +01:00
Thomas
487057bbc8 Fix issue #544 - Jump in profiles 2022-11-26 18:10:47 +01:00
Thomas
c0f556290d Fix issue go to top on profiles 2022-11-26 17:56:56 +01:00
Thomas
d96c83a282 Muted tags 2022-11-26 16:46:26 +01:00
Thomas
7dc57d27a4 Set AKKOMA instance as PLEROMA 2022-11-26 11:20:15 +01:00
Thomas
27f1d594bb Merge branch 'develop' 2022-11-25 18:21:33 +01:00
Thomas
5bc122cb5e Merge remote-tracking branch 'origin/develop' into develop 2022-11-25 18:21:07 +01:00
Thomas
401eb4f1ae Release 3.8.0 2022-11-25 18:21:03 +01:00
Thomas
f029f785cc Avoid crash with friendica and suggestions 2022-11-25 17:48:56 +01:00
Thomas
99644a7e64 Some improvements 2022-11-25 17:30:04 +01:00
Thomas
66fb64c5d1 Improve blocked domains for admins 2022-11-25 16:39:52 +01:00
Oğuz Ersen
2a1dbc1802
Translated using Weblate (Turkish)
Currently translated at 100.0% (916 of 916 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (915 of 915 strings)

Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/tr/
Translation: Fedilab/Strings
2022-11-25 15:13:31 +01:00
Thomas
5d0d838471 Fix issue #527 - Visibility set to unlisted after changing language 2022-11-25 15:13:25 +01:00
Thomas
e66fbf5fd7 Domain blocks for admin (create/update) 2022-11-25 15:03:14 +01:00
Thomas
23d2626370 Fix issue #529 - Lists are ordered alphabetically 'ASC' by default can be reverted with a button 2022-11-25 10:08:57 +01:00
Thomas
099b18014e Fix issue #532 - Make filtered messages smaller 2022-11-25 09:27:58 +01:00
Thomas
39f5a83105 Fix issue #536 - Set as single line 2022-11-25 09:22:44 +01:00
Thomas
6acf279023 Merge remote-tracking branch 'origin/develop' into develop 2022-11-25 09:04:38 +01:00
Thomas
d2644b22a7 Fix issue #538 - Open a message with another account 2022-11-25 09:04:24 +01:00
Thomas
bfa50d19c4 Fix a crash when long pressing URLs 2022-11-25 08:29:11 +01:00
Zekovski
6d39c6a45f
Translated using Weblate (French)
Currently translated at 97.8% (894 of 914 strings)

Co-authored-by: Zekovski <zekovski@e.email>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/fr/
Translation: Fedilab/Strings
2022-11-25 07:45:55 +01:00
Oğuz Ersen
b044246457
Translated using Weblate (Turkish)
Currently translated at 100.0% (914 of 914 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (898 of 898 strings)

Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/tr/
Translation: Fedilab/Strings
2022-11-25 07:45:55 +01:00
Ajeje Brazorf
0fa5ed41ce
Translated using Weblate (Sardinian)
Currently translated at 98.9% (889 of 898 strings)

Co-authored-by: Ajeje Brazorf <lmelonimamo@yahoo.it>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/sc/
Translation: Fedilab/Strings
2022-11-25 07:45:55 +01:00
RintanBroadleaf
ce9a15d034
Translated using Weblate (Japanese)
Currently translated at 100.0% (898 of 898 strings)

Co-authored-by: RintanBroadleaf <rintanbroadleaf@outlook.jp>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ja/
Translation: Fedilab/Strings
2022-11-25 07:45:55 +01:00
Xosé M
824be3d2d1
Translated using Weblate (Galician)
Currently translated at 100.0% (898 of 898 strings)

Co-authored-by: Xosé M <correoxm@disroot.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/gl/
Translation: Fedilab/Strings
2022-11-25 07:45:55 +01:00
Murat H
f38f93b85b
Translated using Weblate (German)
Currently translated at 99.5% (910 of 914 strings)

Translated using Weblate (German)

Currently translated at 98.3% (883 of 898 strings)

Co-authored-by: Murat H <karabela81sta@googlemail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/de/
Translation: Fedilab/Strings
2022-11-25 07:45:55 +01:00
RintanBroadleaf
6bf67ecbfd
Translated using Weblate (Japanese)
Currently translated at 19.0% (8 of 42 strings)

Co-authored-by: RintanBroadleaf <rintanbroadleaf@outlook.jp>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/ja/
Translation: Fedilab/description
2022-11-25 07:45:43 +01:00
Murat H
99d6eb0fd0
Translated using Weblate (German)
Currently translated at 14.2% (6 of 42 strings)

Co-authored-by: Murat H <karabela81sta@googlemail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/de/
Translation: Fedilab/description
2022-11-25 07:45:43 +01:00
Thomas
f9b87f762b Fix issue #534 - Allow to filter notifications for admin/moderators 2022-11-24 17:33:20 +01:00
Thomas
0b690838bb Fix issue #533 - Add an option to keep notifications when muting 2022-11-24 16:44:24 +01:00
Thomas
b5a304be56 Add some endpoints + ui 2022-11-24 12:32:33 +01:00
Thomas
52ba7ef31c fix url 2022-11-24 11:35:50 +01:00
Thomas
f96de62fef Add api endpoints 2022-11-24 11:24:55 +01:00
Thomas
c6bd8ac265 Add new endpoints and fix migration to v2 2022-11-24 10:53:44 +01:00
Thomas
e32b3bf6da Fix admin with api/v2 2022-11-24 10:35:50 +01:00
Thomas
f70e190863 Merge branch 'main' into develop 2022-11-23 19:17:02 +01:00
Thomas
2d3bb92925 Templates 2022-11-23 19:15:17 +01:00
Thomas
40e6f75251 Merge remote-tracking branch 'origin/develop' into develop 2022-11-23 16:19:06 +01:00
Thomas
132cb89b2a Fix issue #522 - Notifications lost their content and fallback to default view. 2022-11-23 16:19:01 +01:00
Xosé M
637bb92a41
Translated using Weblate (Galician)
Currently translated at 100.0% (895 of 895 strings)

Co-authored-by: Xosé M <correoxm@disroot.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/gl/
Translation: Fedilab/Strings
2022-11-23 15:57:12 +01:00
Thomas
9d864857da Fix issue #490 - Remove grouped notifications for Android 5 & 6 2022-11-23 15:57:06 +01:00
Thomas
9c728f24c3 Fix error message when adding the first list 2022-11-23 15:49:31 +01:00
Thomas
4f8377d9d9 Fix issue #524 - List cannot be removed from "Manage timelines" 2022-11-23 15:42:43 +01:00
Thomas
80023219b3 Fix some crashes 2022-11-23 12:13:24 +01:00
Thomas
43fe552ee4 issue template 2022-11-23 10:58:12 +01:00
Thomas
db6470a787 issue template 2022-11-23 10:56:45 +01:00
Thomas
1c19b8815e Merge remote-tracking branch 'origin/develop' into develop 2022-11-23 10:52:16 +01:00
Thomas
0e0fb6e13c Fix crashes from bug reports. 2022-11-23 10:52:09 +01:00
Xosé M
14135ea5ef
Translated using Weblate (Galician)
Currently translated at 100.0% (895 of 895 strings)

Co-authored-by: Xosé M <correoxm@disroot.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/gl/
Translation: Fedilab/Strings
2022-11-23 09:09:34 +01:00
Lukáš Jelínek
2b3590353a
Translated using Weblate (Czech)
Currently translated at 85.4% (765 of 895 strings)

Co-authored-by: Lukáš Jelínek <devel@aiken.cz>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/cs/
Translation: Fedilab/Strings
2022-11-23 09:09:34 +01:00
Oğuz Ersen
86ce8f451d
Translated using Weblate (Turkish)
Currently translated at 100.0% (895 of 895 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (894 of 894 strings)

Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/tr/
Translation: Fedilab/Strings
2022-11-23 09:09:34 +01:00
Thomas
a389681b86 Fix issue #518 - Remove serif font 2022-11-23 09:09:28 +01:00
Thomas
a14bebc721 Release 3.7.5 2022-11-23 09:08:08 +01:00
Thomas
48c9f1e48c Release 3.7.5 2022-11-22 18:14:16 +01:00
Thomas
900e78f5e8 Fix issue #514 - Add about and privacy links into About the instance. 2022-11-22 17:14:00 +01:00
Thomas
9d4a576bc1 Fix automatically hide after x seconds 2022-11-22 16:42:05 +01:00
Thomas
a1d1058ff3 Merge remote-tracking branch 'origin/develop' into develop 2022-11-22 15:27:25 +01:00
Thomas
047086f5e5 Fix issue #510 - Add support for gemini links 2022-11-22 15:27:13 +01:00
Oğuz Ersen
969a35bac2
Translated using Weblate (Turkish)
Currently translated at 100.0% (891 of 891 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (890 of 890 strings)

Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/tr/
Translation: Fedilab/Strings
2022-11-22 15:04:13 +01:00
Xosé M
e8f4fe981a
Translated using Weblate (Galician)
Currently translated at 89.6% (799 of 891 strings)

Translated using Weblate (Galician)

Currently translated at 82.6% (736 of 890 strings)

Co-authored-by: Xosé M <correoxm@disroot.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/gl/
Translation: Fedilab/Strings
2022-11-22 15:04:13 +01:00
Thomas
c729b091e8 Fix issue #512 - Drafts removed when no changes after opening them 2022-11-22 15:04:04 +01:00
Thomas
5f1cd06566 Fix issue #513 - Add the ability to check blocked domains and to unblock them. 2022-11-22 14:50:21 +01:00
Thomas
2d80e89982 Merge branch 'fix_cache_notification' into develop 2022-11-22 13:44:44 +01:00
Thomas
28e10ddc82 Fix pagination from db 2022-11-22 12:32:16 +01:00
Thomas
0bcb4e0fca Fix #515 - set resolve to false when searching accounts 2022-11-22 11:03:43 +01:00
Thomas
1b8304d230 Fix #515 - set resolve to false when searching accounts 2022-11-22 09:44:58 +01:00
Thomas
f647c308a2 Fix a crash if app is killed 2022-11-22 09:41:10 +01:00
Thomas
59472e7f67 Fix db calls 2022-11-22 09:33:55 +01:00
Thomas
020d218df9 add suggestions 2022-11-21 19:06:03 +01:00
Thomas
0796ff7b69 Add classes and logic 2022-11-21 17:43:29 +01:00
Thomas
59a21008f1 Fix issue #497 - Filter view is not syncing after edition 2022-11-21 14:46:53 +01:00
Thomas
03f0ac4be3 Fix issue #498 - Keep searched word in search field 2022-11-21 14:23:54 +01:00
Thomas
43781d1618 Merge remote-tracking branch 'origin/develop' into develop 2022-11-21 14:09:27 +01:00
Thomas
e8ab16747d Fix issue #500 - Crash due to proxy - Disable DNS check 2022-11-21 14:09:10 +01:00
Cárlisson Galdino
ae3cca3a2d
Translated using Weblate (Portuguese)
Currently translated at 75.4% (670 of 888 strings)

Co-authored-by: Cárlisson Galdino <cordeis@vivaldi.net>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/pt/
Translation: Fedilab/Strings
2022-11-21 12:29:25 +01:00
ButterflyOfFire
bbf3ce3a79
Translated using Weblate (French)
Currently translated at 99.5% (884 of 888 strings)

Co-authored-by: ButterflyOfFire <ButterflyOfFire@protonmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/fr/
Translation: Fedilab/Strings
2022-11-21 12:29:24 +01:00
Thomas
495bc70ffb Fix a crash when writing an unsupported domain 2022-11-21 11:11:14 +01:00
Thomas
e8018a6560 Fix issue #501 - Disabling "attach media when sharing" not honored 2022-11-21 10:19:51 +01:00
Thomas
5160cd65c5 Fix issue #503 - Wrong URL displayed when long pressing a link that has been transformed 2022-11-21 09:55:42 +01:00
Thomas
9b45f57f87 Release 3.7.4 2022-11-20 18:11:04 +01:00
Thomas
e3c288fcac Theme issue for accounts in list 2022-11-20 17:41:21 +01:00
Thomas
6f72dd7c2d Merge remote-tracking branch 'origin/develop' into develop 2022-11-20 16:30:18 +01:00
Thomas
b38eb3bb09 Fix some color issues 2022-11-20 16:30:13 +01:00
Eric
91ca5216be
Translated using Weblate (Chinese (Simplified))
Currently translated at 69.0% (612 of 886 strings)

Co-authored-by: Eric <hamburger1024@mailbox.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/zh_Hans/
Translation: Fedilab/Strings
2022-11-20 16:00:09 +01:00
Oğuz Ersen
cd0b57c1b0
Translated using Weblate (Turkish)
Currently translated at 100.0% (888 of 888 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (886 of 886 strings)

Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/tr/
Translation: Fedilab/Strings
2022-11-20 16:00:09 +01:00
Ajeje Brazorf
2d29ddfe96
Translated using Weblate (Sardinian)
Currently translated at 99.3% (880 of 886 strings)

Co-authored-by: Ajeje Brazorf <lmelonimamo@yahoo.it>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/sc/
Translation: Fedilab/Strings
2022-11-20 16:00:09 +01:00
Thomas
99e3cdda1a Fix issue #488 - Copy content of a message doesn't work 2022-11-20 16:00:03 +01:00
Thomas
fa760ba959 Add the ability to timed-mute from profiles 2022-11-20 15:55:30 +01:00
Thomas
3f8f15256d Fix issue #496 - wrong label for new reports and user sign-up 2022-11-20 15:37:09 +01:00
Thomas
b334a5b655 Fix issue #486 - Empty images when sharing from another app. 2022-11-20 12:07:54 +01:00
Thomas
2f9b1e9bcf Avoid empty page 2022-11-20 11:39:49 +01:00
Thomas
d95db5b1b8 Fix issue #491 - Download and share media don't work for Android 10 2022-11-20 11:07:42 +01:00
Thomas
b70103526b Fix an issue with mentions 2022-11-20 10:55:36 +01:00
Thomas
731f8d97fb Merge remote-tracking branch 'origin/develop' into develop 2022-11-20 10:21:02 +01:00
Thomas
d76fcd0f7a Fix issue #485 - Add a delete icon on items + rename menu item 2022-11-20 10:20:52 +01:00
Oğuz Ersen
ac55d2945c
Translated using Weblate (Turkish)
Currently translated at 100.0% (885 of 885 strings)

Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/tr/
Translation: Fedilab/Strings
2022-11-20 10:06:30 +01:00
RintanBroadleaf
41ed974815
Translated using Weblate (Japanese)
Currently translated at 100.0% (885 of 885 strings)

Co-authored-by: RintanBroadleaf <rintanbroadleaf@outlook.jp>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ja/
Translation: Fedilab/Strings
2022-11-20 10:06:30 +01:00
ButterflyOfFire
3d30588dae
Translated using Weblate (French)
Currently translated at 100.0% (885 of 885 strings)

Translated using Weblate (Arabic)

Currently translated at 83.2% (737 of 885 strings)

Co-authored-by: ButterflyOfFire <ButterflyOfFire@protonmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ar/
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/fr/
Translation: Fedilab/Strings
2022-11-20 10:06:30 +01:00
Thomas
0e8354b0c1 Fix issue #478 - Tags cannot be followed when clicking on them. 2022-11-20 10:04:22 +01:00
Thomas
6d99ab479f Merge remote-tracking branch 'origin/develop' into develop 2022-11-20 09:45:10 +01:00
Thomas
3a3f6aa347 Fix issue #493 - Crash when adding account to a list from profile 2022-11-20 09:45:05 +01:00
Oğuz Ersen
c7c733ad9f
Translated using Weblate (Turkish)
Currently translated at 100.0% (883 of 883 strings)

Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/tr/
Translation: Fedilab/Strings
2022-11-19 18:14:34 +01:00
Ajeje Brazorf
403fdf4ce2
Translated using Weblate (Sardinian)
Currently translated at 99.2% (876 of 883 strings)

Co-authored-by: Ajeje Brazorf <lmelonimamo@yahoo.it>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/sc/
Translation: Fedilab/Strings
2022-11-19 18:14:34 +01:00
ButterflyOfFire
d713490d48
Translated using Weblate (Arabic)
Currently translated at 83.2% (735 of 883 strings)

Co-authored-by: ButterflyOfFire <ButterflyOfFire@protonmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ar/
Translation: Fedilab/Strings
2022-11-19 18:14:34 +01:00
Bai
3117cfe33b
Translated using Weblate (Turkish)
Currently translated at 100.0% (882 of 882 strings)

Co-authored-by: Bai <batuhanakkurt000@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/tr/
Translation: Fedilab/Strings
2022-11-19 18:14:34 +01:00
Thomas
9d8c815a1a Release 3.7.3 2022-11-19 18:13:16 +01:00
Thomas
90ed830b33 Fix saving media 2022-11-19 17:59:26 +01:00
Thomas
aa4aefe9dc Merge branch 'check_profiles_remotely' into develop 2022-11-19 17:43:42 +01:00
Thomas
98c1a7e1b5 Comment #477 - Display remote media timeline 2022-11-19 17:43:27 +01:00
Thomas
4263d6f842 Comment #477 - Add button to display messages remotely 2022-11-19 17:17:23 +01:00
Thomas
fdc365dc00 Comment #477 - Allow remote actions 2022-11-19 16:50:55 +01:00
Thomas
a57659bd69 Comment #477 - Add logic for visiting remote profiles 2022-11-19 16:44:23 +01:00
Thomas
ad9048300c Merge pull request 'Use correct tense of "choose".' (#483) from trem/Fedilab:develop into develop
Reviewed-on: https://codeberg.org/tom79/Fedilab/pulls/483
2022-11-19 14:19:53 +00:00
trem
ef0137838a Use correct tense of "choose".
"Chose" is the past tense, whereas in such descriptions, one uses the present tense (in the infinitive form), which is "choose".
2022-11-19 14:09:18 +00:00
Thomas
86c332a326 put values 2022-11-19 12:08:31 +01:00
Thomas
9298f22b5d Fix issue #482 - Warn when the app fails to add account into a list 2022-11-19 11:58:58 +01:00
Thomas
26bc658bee More fixes 2022-11-19 11:44:36 +01:00
Thomas
e9b465d9f4 Fix patterns 2022-11-19 11:39:16 +01:00
Thomas
d06f7b4cde Fix issue #464 - More restrictive pattern 2022-11-19 11:36:50 +01:00
Thomas
65b353da5c Merge remote-tracking branch 'origin/develop' into develop 2022-11-19 11:27:09 +01:00
Thomas
b3e2af6e3c fix media not stored 2022-11-19 11:26:54 +01:00
ButterflyOfFire
e1ddb2cd7c
Translated using Weblate (English)
Currently translated at 100.0% (882 of 882 strings)

Co-authored-by: ButterflyOfFire <ButterflyOfFire@protonmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/en/
Translation: Fedilab/Strings
2022-11-19 08:27:19 +01:00
Oğuz Ersen
967d9b0a72
Translated using Weblate (Turkish)
Currently translated at 100.0% (882 of 882 strings)

Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/tr/
Translation: Fedilab/Strings
2022-11-19 08:24:48 +01:00
ButterflyOfFire
b5cc8b4b26
Translated using Weblate (French)
Currently translated at 98.7% (871 of 882 strings)

Co-authored-by: ButterflyOfFire <ButterflyOfFire@protonmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/fr/
Translation: Fedilab/Strings
2022-11-19 08:24:48 +01:00
Oğuz Ersen
5d68c223ad
Translated using Weblate (Turkish)
Currently translated at 100.0% (869 of 869 strings)

Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/tr/
Translation: Fedilab/Strings
2022-11-18 19:18:05 +01:00
Ajeje Brazorf
0b1b913120
Translated using Weblate (Sardinian)
Currently translated at 99.1% (862 of 869 strings)

Co-authored-by: Ajeje Brazorf <lmelonimamo@yahoo.it>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/sc/
Translation: Fedilab/Strings
2022-11-18 19:18:05 +01:00
Thomas
f2a4fdb2db Release 3.7.2 2022-11-18 19:17:58 +01:00
Thomas
7878b51907 Comment #467 #464 - extends warns to notifications 2022-11-18 19:07:48 +01:00
Thomas
b584a37281 Comment #467 #464 - hide or remove message in timelines 2022-11-18 17:40:25 +01:00
Thomas
58c3a5fc35 Comment #467 #464 - apply theme on buttons 2022-11-18 16:05:31 +01:00
Thomas
b09e21a589 Comment #467 #464 - fix api calls 2022-11-18 15:52:25 +01:00
Thomas
d886693c75 Comment #467 #464 - fix some theme colors / bugs 2022-11-17 19:16:14 +01:00
Thomas
536af42e27 Comment #467 #464 - fix some theme colors / bugs 2022-11-17 19:03:36 +01:00
Thomas
74599d8a7f Comment #467 #464 - Support API endpoints 2022-11-17 18:43:48 +01:00
Thomas
8bf21db632 Comment #467 #464 - Start migration to api/v2 for filters 2022-11-17 17:27:25 +01:00
Thomas
9dc4b46fdb Order notification by date 2022-11-17 14:06:48 +01:00
Thomas
a946ea49d1 Fix issue #469 - Crashes with pinned and Pixelfed 2022-11-17 13:43:18 +01:00
Thomas
ba53e174ab Fix issue #471 - Takes value from reblog if not null 2022-11-17 13:32:19 +01:00
Thomas
47dfc3f33c Merge remote-tracking branch 'origin/develop' into develop 2022-11-17 12:00:58 +01:00
Thomas
c72b888078 Fix issue #471 - Fix counter issue for fab/boost with remote instances 2022-11-17 12:00:54 +01:00
Oğuz Ersen
871ba79200
Translated using Weblate (Turkish)
Currently translated at 100.0% (866 of 866 strings)

Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/tr/
Translation: Fedilab/Strings
2022-11-17 11:42:24 +01:00
Ajeje Brazorf
8b21ff4b18
Translated using Weblate (Sardinian)
Currently translated at 99.4% (861 of 866 strings)

Co-authored-by: Ajeje Brazorf <lmelonimamo@yahoo.it>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/sc/
Translation: Fedilab/Strings
2022-11-17 11:42:24 +01:00
Jipem
6c75032eda
Translated using Weblate (French)
Currently translated at 98.4% (853 of 866 strings)

Co-authored-by: Jipem <web+weblate@jipem.me>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/fr/
Translation: Fedilab/Strings
2022-11-17 11:42:24 +01:00
Thomas
4b106ffba4 Fix issue #475 - Support notifications when edited 2022-11-17 11:42:06 +01:00
Thomas
2593d08d20 Fix issue #472 - Allow to browse Mastodon instances before registering 2022-11-17 10:55:01 +01:00
Thomas
5b164d60da Fix issue #473 - Transparent background 2022-11-17 09:37:49 +01:00
Thomas
96a0d5e485 Fix issue #473 - Transparent background 2022-11-17 09:04:46 +01:00
Thomas
a6e5254043 Fix issue #474 - Give a fixed width to instance logo 2022-11-17 08:57:18 +01:00
Thomas
d283340518 Release 3.7.1 2022-11-16 17:58:18 +01:00
Thomas
aa768127ea Merge remote-tracking branch 'origin/develop' into develop 2022-11-16 17:42:09 +01:00
Thomas
962a59ac4f Fix issue #449 - Fix draft issues 2022-11-16 17:41:47 +01:00
Oğuz Ersen
14286d7049
Translated using Weblate (Turkish)
Currently translated at 100.0% (864 of 864 strings)

Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/tr/
Translation: Fedilab/Strings
2022-11-16 17:29:50 +01:00
Ajeje Brazorf
7f4e4d1303
Translated using Weblate (Sardinian)
Currently translated at 99.4% (859 of 864 strings)

Co-authored-by: Ajeje Brazorf <lmelonimamo@yahoo.it>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/sc/
Translation: Fedilab/Strings
2022-11-16 17:29:50 +01:00
Thomas
869b4d25e2 Fix issue #460 - Specific messages when a feature is not supported. 2022-11-16 17:29:38 +01:00
Thomas
9a64dd60b0 Open link with the app. 2022-11-16 17:22:26 +01:00
Thomas
2fa46290a1 Fix issue #442 - Tags not filtered 2022-11-16 15:49:20 +01:00
Thomas
1dae37549b Fix issue #463 - Add reply counter when counters are enabled 2022-11-16 14:39:58 +01:00
Thomas
7500f1cd7b Fix issue #459 - Remove offset for compose view 2022-11-16 14:36:20 +01:00
Thomas
23cecbf3c4 Reset notification marker when clearing cache 2022-11-16 14:24:29 +01:00
Thomas
bf0c44e905 fix typo 2022-11-16 12:10:42 +01:00
Thomas
3bca0e6864 fix typo 2022-11-16 12:05:01 +01:00
Thomas
ada128bd2b add open collective 2022-11-16 12:01:31 +01:00
Thomas
da64af1e12 Add issue template 2022-11-16 11:53:37 +01:00
Thomas
7dc9248543 Release 3.7.0 2022-11-15 18:27:17 +01:00
Thomas
ac4a2dccfd Update release notes 2022-11-15 18:21:18 +01:00
Thomas
aa8e0f13bc Fix issue #403 - Freezes 2022-11-15 18:11:22 +01:00
Thomas
393d2990f0 Fix issue #403 - Freezes 2022-11-15 18:02:49 +01:00
Thomas
fe10411618 typo 2022-11-15 16:25:33 +01:00
Thomas
9b2307e2dc Prepare release notes 2022-11-15 16:24:50 +01:00
Thomas
5e1dffa65e Some fixes 2022-11-15 16:11:36 +01:00
Thomas
f1d26f9de7 Merge remote-tracking branch 'origin/develop' into develop 2022-11-15 15:44:17 +01:00
Thomas
81c012c8f0 Language selector 2022-11-15 15:43:53 +01:00
Thomas
197a8d56e1 New layout 2022-11-15 15:04:24 +01:00
Hosted Weblate
0fb495e1cf
Update translation files
Updated by "Remove blank strings" hook in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/
Translation: Fedilab/Strings
2022-11-15 14:25:33 +01:00
Oğuz Ersen
82b33f4d5c
Translated using Weblate (Turkish)
Currently translated at 100.0% (854 of 854 strings)

Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/tr/
Translation: Fedilab/Strings
2022-11-15 14:25:33 +01:00
Ajeje Brazorf
4fe37dc23d
Translated using Weblate (Sardinian)
Currently translated at 99.5% (850 of 854 strings)

Co-authored-by: Ajeje Brazorf <lmelonimamo@yahoo.it>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/sc/
Translation: Fedilab/Strings
2022-11-15 14:25:33 +01:00
Zekovski
806cbbcb4d
Translated using Weblate (French)
Currently translated at 97.0% (829 of 854 strings)

Co-authored-by: Zekovski <zekovski@e.email>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/fr/
Translation: Fedilab/Strings
2022-11-15 14:25:33 +01:00
Thomas
ae71b2ba71 Fix issue #457 - Update list name and sync them. 2022-11-15 14:25:25 +01:00
Thomas
cdbfb17d94 Follow Hashtags 2022-11-15 10:51:46 +01:00
Thomas
170dbbd0cf Add endpoints 2022-11-15 09:00:08 +01:00
Thomas
510ba7ba47 Fix issue #418 - Define favorite languages in settings to reduce the list when composing 2022-11-14 18:47:14 +01:00
Thomas
cdaba2f34d Some fixes 2022-11-14 17:18:55 +01:00
Thomas
03f8c33cb2 Fix issue #445 - Timelines not reloaded when applying filters 2022-11-14 17:18:40 +01:00
Thomas
5b9534adc2 Fix some color issues 2022-11-14 15:15:29 +01:00
Thomas
e7dd79d8e0 Ask restart when theme is changed 2022-11-14 12:15:43 +01:00
Thomas
e9b62b71d1 Ask restart when theme is changed 2022-11-14 10:37:53 +01:00
Thomas
f66fda968e Improve cache clear 2022-11-14 10:08:18 +01:00
Thomas
13f180e6f3 change error message 2022-11-14 09:08:02 +01:00
Thomas
f851be8ab9 Beta release 3.6.5 2022-11-13 18:41:45 +01:00
Thomas
49333097cc Fix some issue with admins 2022-11-13 18:34:08 +01:00
Thomas
966b0bce43 Fix an issue #450 2022-11-13 18:33:34 +01:00
Thomas
f78184216d Fix an issue when following/unfollowing in a list of accounts 2022-11-13 16:07:21 +01:00
Thomas
89851a68bc Fix issue #419 - Add theme 2022-11-13 12:16:58 +01:00
Thomas
aa6f87facb Fix issue with icon when following 2022-11-13 12:14:13 +01:00
Thomas
2fc7eada97 Merge remote-tracking branch 'origin/develop' into develop 2022-11-13 11:26:43 +01:00
Thomas
e51764ae42 Fix issue #442 - mentions starting with a "(" 2022-11-13 11:26:26 +01:00
Oğuz Ersen
7ac2edf157
Translated using Weblate (Turkish)
Currently translated at 100.0% (848 of 848 strings)

Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/tr/
Translation: Fedilab/Strings
2022-11-13 10:56:03 +01:00
Cilian
16cad99fab
Translated using Weblate (Russian)
Currently translated at 68.2% (579 of 848 strings)

Co-authored-by: Cilian <arusivv@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ru/
Translation: Fedilab/Strings
2022-11-13 10:56:03 +01:00
RintanBroadleaf
406e0d19c5
Translated using Weblate (Japanese)
Currently translated at 100.0% (848 of 848 strings)

Co-authored-by: RintanBroadleaf <rintanbroadleaf@outlook.jp>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ja/
Translation: Fedilab/Strings
2022-11-13 10:56:03 +01:00
Zekovski
3aa310fafb
Translated using Weblate (French)
Currently translated at 100.0% (819 of 819 strings)

Co-authored-by: Zekovski <zekovski@e.email>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/fr/
Translation: Fedilab/Strings
2022-11-13 10:56:03 +01:00
Thomas
dd4d0abf12 Fix issue #446 - Add theme 2022-11-13 10:55:25 +01:00
Thomas
435c34604b Fix issue #448 - Issue with regex for whole word 2022-11-13 10:49:04 +01:00
Thomas
6063246b96 apply changes 2022-11-12 18:57:07 +01:00
Thomas
144dddcc0f Some fixes with admin 2022-11-12 18:27:37 +01:00
Thomas
e110dc71ff Some fixes with admin 2022-11-12 18:02:55 +01:00
Thomas
f213b0ddcb Display reports 2022-11-12 17:30:06 +01:00
Thomas
2d87254ac0 Add reports 2022-11-12 17:14:58 +01:00
Thomas
d7f58dab36 Add reports 2022-11-12 12:15:16 +01:00
Thomas
9a79b9dc7d Merge branch 'develop' into improve_admin 2022-11-12 10:29:32 +01:00
Thomas
39c49fad77 Fix crash with trends 2022-11-12 09:49:48 +01:00
Thomas
e9fd84d7eb Release 3.6.4 2022-11-11 16:59:16 +01:00
Thomas
74b69b60e8 some change with moderation 2022-11-11 16:42:22 +01:00
Thomas
3dd06cb1a1 Merge branch 'develop' into improve_admin 2022-11-11 16:36:11 +01:00
Thomas
1da9fc96b3 some change with moderation 2022-11-11 16:36:00 +01:00
Thomas
90a99cc1c8 Fix issue #436 - Improve tags search 2022-11-11 11:52:57 +01:00
Thomas
d18dce9919 Fix issue #430 - Update json payload 2022-11-11 11:07:05 +01:00
Thomas
0c27c839d3 Fix issue #430 - Store instance 2022-11-11 10:50:03 +01:00
Thomas
f71a73abc8 Fix issue #430 - Encoding URL does not allow to login 2022-11-11 10:45:33 +01:00
Thomas
f7c7ea98ad Fix issue #430 - Filter down instances from helper. 2022-11-10 18:55:41 +01:00
Thomas
9ed4964793 Release 3.6.3 2022-11-10 17:49:56 +01:00
Thomas
fbd9596dd9 Merge pull request 'Fix share feature' (#434) from Augier/Fedilab:fix-share into develop
Reviewed-on: https://codeberg.org/tom79/Fedilab/pulls/434
2022-11-10 17:37:17 +01:00
Thomas
a4ade2a0f0 Fix issue #429 2022-11-10 17:25:48 +01:00
Christophe Henry
32ea2cdb0a Fix share feature 2022-11-10 17:16:46 +01:00
Thomas
95f0db6413 Fix issue #429 2022-11-10 16:27:27 +01:00
Thomas
da5ff2320d Fix messages/notifications not in the right order 2022-11-10 16:02:56 +01:00
Thomas
6c59e5f32e Replace with id but allow to quickly clear the cache 2022-11-10 13:57:20 +01:00
Thomas
a10b404677 Release 3.6.2 2022-11-09 17:51:26 +01:00
Thomas
47320711bc Merge remote-tracking branch 'origin/develop' into develop 2022-11-09 17:35:11 +01:00
Thomas
22f390c659 Fix issue #432 - Wrong URL when sharing a boost. 2022-11-09 17:34:47 +01:00
Thomas
4d27fd47a1 Fix order in notifications 2022-11-09 17:31:05 +01:00
Thomas
230ed4b2ba Improve and avoid last empty when coming back 2022-11-09 10:59:49 +01:00
Zekovski
a018db2eb2
Translated using Weblate (French)
Currently translated at 100.0% (31 of 31 strings)

Co-authored-by: Zekovski <zekovski@e.email>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/fr/
Translation: Fedilab/description
2022-11-08 18:17:38 +01:00
Oğuz Ersen
525bd886d5
Translated using Weblate (Turkish)
Currently translated at 100.0% (815 of 815 strings)

Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/tr/
Translation: Fedilab/Strings
2022-11-08 18:16:54 +01:00
Zekovski
c6d3b4021d
Translated using Weblate (French)
Currently translated at 100.0% (815 of 815 strings)

Co-authored-by: Zekovski <zekovski@e.email>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/fr/
Translation: Fedilab/Strings
2022-11-08 18:16:54 +01:00
Thomas
e93f194bb5 Release 3.6.1 2022-11-08 18:10:53 +01:00
Thomas
86e371b4f5 Fix some issues 2022-11-08 14:33:15 +01:00
Thomas
fa989a4084 Fix issue #115 - Allow to set replies in "unlisted" (enabled by default) 2022-11-08 10:40:02 +01:00
Thomas
59a8b5da17 Fix issue #409 - Title sizes 2022-11-08 09:52:20 +01:00
Thomas
d4aee3ff4e Notifications not deleted from cache 2022-11-07 14:53:48 +01:00
Thomas
ee68f4fc7d Fix filters 2022-11-07 10:42:09 +01:00
Thomas
2625101883 Comment issue #414 - Display app when available 2022-11-07 10:41:59 +01:00
Thomas
c640505fe6 Comment issue #412 - Filters not applied 2022-11-07 10:01:10 +01:00
Thomas
730468ee72 Merge remote-tracking branch 'origin/develop' into develop 2022-11-07 09:16:18 +01:00
Thomas
1d7aed393f Comment issue #405 - Allow to increase max indentation 2022-11-07 09:16:06 +01:00
ButterflyOfFire
66ed92045e
Translated using Weblate (French)
Currently translated at 100.0% (813 of 813 strings)

Translated using Weblate (Arabic)

Currently translated at 79.2% (644 of 813 strings)

Co-authored-by: ButterflyOfFire <ButterflyOfFire@protonmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ar/
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/fr/
Translation: Fedilab/Strings
2022-11-06 21:03:46 +01:00
Thomas
c47e8ea806 Fix issue #407 - Increase size of the button to display content 2022-11-06 18:12:07 +01:00
Thomas
c527e3ae25 Fix issue #410 - Remove messages from cache and in timelines for blocked accounts 2022-11-06 18:08:54 +01:00
Thomas
51e031f065 Fix quoted text 2022-11-06 11:27:12 +01:00
Thomas
0dead60a4c Add quotes in messages 2022-11-05 18:45:47 +01:00
Thomas
84d30676fc Add quotes in messages 2022-11-05 18:21:49 +01:00
Thomas
3f9e221025 Fix mentions 2022-11-05 17:06:57 +01:00
Thomas
865cf0686d Some other fixes 2022-11-05 15:38:08 +01:00
Thomas
908d56109c Some other fixes 2022-11-05 15:36:22 +01:00
Thomas
6d3148bd51 Fix some crashes 2022-11-05 15:06:21 +01:00
Thomas
92157dc8dc Fix some crashes 2022-11-05 14:57:41 +01:00
Thomas
c2a08c6df8 Merge remote-tracking branch 'origin/develop' into develop 2022-11-05 11:39:46 +01:00
Thomas
a15d0142d0 Fix issue #402 - Silent notification 2022-11-05 11:39:39 +01:00
Lukáš Jelínek
2fcf4b418b
Translated using Weblate (Czech)
Currently translated at 88.9% (723 of 813 strings)

Co-authored-by: Lukáš Jelínek <devel@aiken.cz>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/cs/
Translation: Fedilab/Strings
2022-11-05 01:03:44 +01:00
Thomas
cfffd02779 Improve pattern 2022-11-04 19:02:48 +01:00
Thomas
4d3c94c7fd Comment issue #366 - Make text clickable 2022-11-04 16:48:16 +01:00
Thomas
60a1b2bfa4 Fix issue #276 - Problem when sharing text with URL 2022-11-04 15:49:47 +01:00
Thomas
3883af2f78 release note++ 2022-11-03 17:23:25 +01:00
Thomas
829b348a18 release note+ 2022-11-03 17:21:20 +01:00
Thomas
2d3f66093f Prepare release 3.6.0 2022-11-03 17:19:38 +01:00
Thomas
88e2f0cb7c Fix issue #391 - Add an icon when a media description is available. 2022-11-03 17:07:47 +01:00
Thomas
209d698223 Improve art timeline 2022-11-03 16:53:42 +01:00
Thomas
539acd053b Merge remote-tracking branch 'origin/develop' into develop 2022-11-03 12:14:12 +01:00
Thomas
4384938a0a Fix issue #387 2022-11-03 12:14:06 +01:00
Thomas
edc8b0c7de Some fixes 2022-11-03 11:50:23 +01:00
Trendyne
02fdfe32b8
Translated using Weblate (Icelandic)
Currently translated at 21.1% (172 of 813 strings)

Co-authored-by: Trendyne <eiko@chiru.no>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/is/
Translation: Fedilab/Strings
2022-11-03 11:06:43 +01:00
Thomas
7dfa1f681b ui issue with edit date 2022-11-02 19:13:05 +01:00
Thomas
b566ba9fdd Some improvements with theme 2022-11-02 18:59:51 +01:00
Thomas
db066c6ba6 Some fixes 2022-11-02 18:37:29 +01:00
Thomas
1dbc5b7a89 Get token when classic way failed (openId) 2022-11-02 16:47:42 +01:00
Thomas
8613f57c87 Avoid empty timelines 2022-11-02 15:48:58 +01:00
Thomas
0854642d81 Avoid empty timelines 2022-11-02 12:44:42 +01:00
Thomas
f8736b1510 Merge branch 'develop' of https://codeberg.org/tom79/Fedilab into develop 2022-11-02 10:57:45 +01:00
Weblate
f777764ffc
Added translation using Weblate (Icelandic)
Co-authored-by: Weblate <noreply@weblate.org>
2022-11-02 10:03:23 +01:00
Oğuz Ersen
b0da78e32f
Translated using Weblate (Turkish)
Currently translated at 100.0% (813 of 813 strings)

Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/tr/
Translation: Fedilab/Strings
2022-11-02 10:03:23 +01:00
Ajeje Brazorf
f0ff8b62ca
Translated using Weblate (Sardinian)
Currently translated at 99.5% (809 of 813 strings)

Translated using Weblate (Sardinian)

Currently translated at 99.6% (807 of 810 strings)

Co-authored-by: Ajeje Brazorf <lmelonimamo@yahoo.it>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/sc/
Translation: Fedilab/Strings
2022-11-02 10:03:23 +01:00
Thomas
efb63388d9 Fix typo 2022-11-01 16:25:54 +01:00
Thomas
f7ad5b333f Release 3.5.3 2022-11-01 16:17:35 +01:00
Thomas
a114f3c377 some fixes with Nitter 2022-11-01 16:09:05 +01:00
Thomas
c3132d9415 Improve layout for edited messages 2022-11-01 16:01:53 +01:00
Thomas
164fe2fb13 Merge remote-tracking branch 'origin/develop' into develop 2022-11-01 11:15:30 +01:00
Thomas
13a1a2a7a4 Message history 2022-11-01 11:15:13 +01:00
Oğuz Ersen
6237ffe2e3
Translated using Weblate (Turkish)
Currently translated at 100.0% (810 of 810 strings)

Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/tr/
Translation: Fedilab/Strings
2022-11-01 03:14:33 +01:00
sal0max
04af57a382
Translated using Weblate (German)
Currently translated at 99.3% (805 of 810 strings)

Co-authored-by: sal0max <msal.coding@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/de/
Translation: Fedilab/Strings
2022-11-01 03:14:32 +01:00
GunChleoc
160807e32e
Translated using Weblate (Gaelic)
Currently translated at 31.3% (253 of 808 strings)

Co-authored-by: GunChleoc <fios@foramnagaidhlig.net>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/gd/
Translation: Fedilab/Strings
2022-11-01 03:14:32 +01:00
nichu42
5a0389b5ba
Translated using Weblate (German)
Currently translated at 97.4% (787 of 808 strings)

Co-authored-by: nichu42 <nroediger@nic-site.de>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/de/
Translation: Fedilab/Strings
2022-11-01 03:14:32 +01:00
Thomas
0189dad4d3 Merge remote-tracking branch 'origin/develop' into develop 2022-10-31 18:05:56 +01:00
Thomas
2b546afa45 Add listener 2022-10-31 18:05:32 +01:00
Thomas
0618e1b5d1 Add the logic 2022-10-31 16:17:16 +01:00
Thomas
5656d79296 Prepare entity and api endpoints 2022-10-31 11:43:57 +01:00
Thomas
dcd5d97cd5 some fixes 2022-10-31 11:34:38 +01:00
GunChleoc
550d434de3
Added translation using Weblate (Gaelic)
Co-authored-by: GunChleoc <fios@foramnagaidhlig.net>
2022-10-30 22:36:41 +01:00
Joan Pujolar
fc7597ac6f
Translated using Weblate (Catalan)
Currently translated at 100.0% (808 of 808 strings)

Translated using Weblate (Catalan)

Currently translated at 87.7% (706 of 805 strings)

Co-authored-by: Joan Pujolar <joan.pujolar@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ca/
Translation: Fedilab/Strings
2022-10-30 18:17:09 +01:00
Oğuz Ersen
0f84a7042c
Translated using Weblate (Turkish)
Currently translated at 100.0% (808 of 808 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (805 of 805 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (803 of 803 strings)

Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/tr/
Translation: Fedilab/Strings
2022-10-30 18:17:09 +01:00
Ajeje Brazorf
9719e65f91
Translated using Weblate (Sardinian)
Currently translated at 99.3% (803 of 808 strings)

Translated using Weblate (Sardinian)

Currently translated at 99.1% (798 of 805 strings)

Translated using Weblate (Sardinian)

Currently translated at 99.1% (796 of 803 strings)

Co-authored-by: Ajeje Brazorf <lmelonimamo@yahoo.it>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/sc/
Translation: Fedilab/Strings
2022-10-30 18:17:09 +01:00
Thomas
e999abea81 Release 3.5.2 2022-10-30 18:16:52 +01:00
Thomas
72fd064f8a Some fixes 2022-10-30 18:12:51 +01:00
Thomas
365179def8 Fix #385 - crash with scheduled messages 2022-10-30 17:30:22 +01:00
Thomas
1e74ee172e remove useless launcher 2022-10-29 19:10:56 +02:00
Thomas
b0bde6e66d translate 2022-10-29 19:03:31 +02:00
Thomas
ec77f4b7b6 some improvements 2022-10-29 16:35:15 +02:00
Thomas
345ed2afd6 Fix issue #378 - Allow to pin & unpin messages 2022-10-29 16:28:27 +02:00
Thomas
f94b568d0a Fix issue #378 - Allow to pin & unpin messages 2022-10-29 11:00:18 +02:00
Thomas
5458d93bcf Fix issue #379 - Media displayed several times in notifications 2022-10-29 10:48:49 +02:00
Thomas
c592f1cc01 Fix issue #380 - Double launcher icon 2022-10-29 10:35:21 +02:00
Thomas
8914f2fb3c Fix issue #380 - Double launcher icon 2022-10-29 10:29:15 +02:00
Oğuz Ersen
77d3312b06
Translated using Weblate (Turkish)
Currently translated at 100.0% (801 of 801 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (797 of 797 strings)

Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/tr/
Translation: Fedilab/Strings
2022-10-28 18:06:43 +02:00
Ajeje Brazorf
5e3fa5cfbc
Translated using Weblate (Sardinian)
Currently translated at 99.3% (796 of 801 strings)

Translated using Weblate (Sardinian)

Currently translated at 99.3% (792 of 797 strings)

Co-authored-by: Ajeje Brazorf <lmelonimamo@yahoo.it>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/sc/
Translation: Fedilab/Strings
2022-10-28 18:06:43 +02:00
Thomas
a4ae4172f1 Release 3.5.1 2022-10-28 18:06:03 +02:00
Thomas
cebddab6a3 Fix issue #376 - Button to load media more visible 2022-10-28 17:49:55 +02:00
Thomas
a81879fb36 Fix an issue with media timelines 2022-10-28 17:19:24 +02:00
Thomas
3dbfe33983 Fix an offset issue 2022-10-27 17:50:57 +02:00
Thomas
7020644b3d Fix issue #373 - Allow to change icon 2022-10-27 16:16:58 +02:00
Thomas
aaa44d899e Fix issue #364 - Silent notifications when fetching 2022-10-27 10:47:56 +02:00
Thomas
8bc3c7918c Fix issue #366 - Issues with cards 2022-10-26 17:59:29 +02:00
Thomas
9f68db32ec Fix issue #367 - Fix notification aggregation with pagination 2022-10-26 17:08:40 +02:00
Thomas
15921978d3 Fix issue #368 - Allow to enable/disable media in notifications for boost/fav 2022-10-26 16:48:57 +02:00
Thomas
8b336f1012 Allow to turn off aggregate notifications 2022-10-26 16:40:08 +02:00
Thomas
94faf3bbcb Merge remote-tracking branch 'origin/develop' into develop 2022-10-26 16:24:48 +02:00
Thomas
0007cb70f3 Fix issue #371 - Camera not working on Android 11. 2022-10-26 16:24:34 +02:00
Ajeje Brazorf
c064187289
Translated using Weblate (Sardinian)
Currently translated at 99.3% (787 of 792 strings)

Co-authored-by: Ajeje Brazorf <lmelonimamo@yahoo.it>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/sc/
Translation: Fedilab/Strings
2022-10-26 10:25:13 +02:00
Thomas
6bc184d49c Fix issue #369 - Spoiler removed when adding a media 2022-10-26 10:25:04 +02:00
Thomas
d76d6990fd Fix crash when changing led color 2022-10-26 10:05:50 +02:00
Thomas
4700c757a8 Merge remote-tracking branch 'origin/develop' into develop 2022-10-26 09:45:42 +02:00
Thomas
2d51946fd6 Fix issue #362 - Crash with notifications 2022-10-26 09:45:31 +02:00
Eric
0418d5653b
Translated using Weblate (Chinese (Simplified))
Currently translated at 76.5% (605 of 790 strings)

Co-authored-by: Eric <hamburger1024@mailbox.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/zh_Hans/
Translation: Fedilab/Strings
2022-10-26 03:08:47 +02:00
Oğuz Ersen
018f60fac9
Translated using Weblate (Turkish)
Currently translated at 100.0% (790 of 790 strings)

Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/tr/
Translation: Fedilab/Strings
2022-10-26 03:08:46 +02:00
Ajeje Brazorf
9c726195e8
Translated using Weblate (Sardinian)
Currently translated at 99.3% (785 of 790 strings)

Co-authored-by: Ajeje Brazorf <lmelonimamo@yahoo.it>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/sc/
Translation: Fedilab/Strings
2022-10-26 03:08:46 +02:00
Thomas
23ce0c4b06 Fix issue #361 - Allow to turn off remember position in settings 2022-10-25 11:16:26 +02:00
Thomas
f3422871bc Fix pagination on profiles 2022-10-25 10:32:10 +02:00
Thomas
b340ed25c7 change release notes 2022-10-24 18:02:09 +02:00
Thomas
e508e40849 Release 3.5.0 2022-10-24 18:00:23 +02:00
Thomas
dbaf2a379a Remove old settings + fix scroll with fav. 2022-10-24 17:49:26 +02:00
Thomas
c23be87ff4 Fix watermark 2022-10-24 10:59:31 +02:00
Thomas
4da83ef20a Merge branch 'develop' of https://codeberg.org/tom79/Fedilab into develop 2022-10-24 09:56:01 +02:00
Thomas
e85ac8ed33 Settings for icon size 2022-10-24 09:55:54 +02:00
Zekovski
ae366a1887
Translated using Weblate (French)
Currently translated at 100.0% (26 of 26 strings)

Co-authored-by: Zekovski <zekovski@e.email>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/fr/
Translation: Fedilab/description
2022-10-24 01:04:57 +02:00
Thomas
ea31842dba Fix crashes 2022-10-23 11:59:50 +02:00
Thomas
e8e5af7abe Release 3.4.3 2022-10-22 18:35:05 +02:00
Thomas
50fca052b3 Change link colors for cards 2022-10-22 16:45:05 +02:00
Thomas
03222e742c Theme improvements 2022-10-22 16:39:43 +02:00
Thomas
da887298df Fix some crashes 2022-10-22 11:53:09 +02:00
Thomas
4dc8695c75 Same logic for notifications and conversations 2022-10-21 16:47:39 +02:00
Thomas
382a198572 Delay loading of other timelines + display when available 2022-10-21 16:33:57 +02:00
Thomas
3d4f075c9c Fix cached 2022-10-21 15:29:21 +02:00
Thomas
aedb81d0e5 Merge remote-tracking branch 'origin/develop' into develop 2022-10-20 17:29:09 +02:00
Thomas
f9c3393c5e Some improvements with timelines 2022-10-20 17:29:04 +02:00
Thomas
50f9cb2b7b Clean code 2022-10-20 16:36:47 +02:00
Thomas
86f39fb4ee Fix an issue with mentions (compose) 2022-10-20 16:18:22 +02:00
Ajeje Brazorf
2df6ae0c65
Translated using Weblate (Sardinian)
Currently translated at 99.6% (784 of 787 strings)

Co-authored-by: Ajeje Brazorf <lmelonimamo@yahoo.it>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/sc/
Translation: Fedilab/Strings
2022-10-20 16:03:05 +02:00
Thomas Schneider
5ecfc87395
Translated using Weblate (French)
Currently translated at 100.0% (787 of 787 strings)

Co-authored-by: Thomas Schneider <tom79@tutanota.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/fr/
Translation: Fedilab/Strings
2022-10-20 16:03:05 +02:00
Zekovski
932d35785a
Translated using Weblate (French)
Currently translated at 100.0% (787 of 787 strings)

Co-authored-by: Zekovski <zekovski@e.email>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/fr/
Translation: Fedilab/Strings
2022-10-20 16:03:04 +02:00
Thomas
4b3236e97e Fix button sizes for messages 2022-10-20 12:18:53 +02:00
Thomas
9ad5177486 Fix colors for notifications 2022-10-19 11:35:00 +02:00
Thomas
f403d38c81 Fix some messages displayed multiple time 2022-10-18 17:53:12 +02:00
Thomas
b1629a40fe Merge remote-tracking branch 'origin/develop' into develop 2022-10-18 17:49:44 +02:00
Thomas
d8adaf40b8 Fix issue #356 - Wrong background for messages 2022-10-18 17:49:33 +02:00
Oğuz Ersen
521b1324fc
Translated using Weblate (Turkish)
Currently translated at 100.0% (787 of 787 strings)

Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/tr/
Translation: Fedilab/Strings
2022-10-17 17:51:35 +02:00
Hosted Weblate
346f3f582e
Update translation files
Updated by "Remove blank strings" hook in Weblate.

Update translation files

Updated by "Remove blank strings" hook in Weblate.

Update translation files

Updated by "Remove blank strings" hook in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/
Translation: Fedilab/Strings
2022-10-17 17:51:35 +02:00
ButterflyOfFire
b38aad2d05
Translated using Weblate (Berber)
Currently translated at 72.5% (570 of 786 strings)

Translated using Weblate (Arabic)

Currently translated at 80.6% (634 of 786 strings)

Co-authored-by: ButterflyOfFire <ButterflyOfFire@protonmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ar/
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ber/
Translation: Fedilab/Strings
2022-10-17 17:51:35 +02:00
Thomas
fd7ec5bb36 Merge remote-tracking branch 'origin/develop' into develop 2022-10-17 17:51:30 +02:00
Thomas
b7ee38e37b Fix notifications not removed from cache 2022-10-17 17:51:26 +02:00
Thomas
b0eb52cf94 Fix issue #349 - Message content set to null when sharing 2022-10-17 15:55:15 +02:00
Thomas
2ebcdaf330 Fix issue #351 - Issues when sharing 2022-10-17 15:46:05 +02:00
ButterflyOfFire
fb3c990e2f
Translated using Weblate (Armenian)
Currently translated at 0.0% (0 of 25 strings)

Translated using Weblate (Arabic)

Currently translated at 12.0% (3 of 25 strings)

Co-authored-by: ButterflyOfFire <ButterflyOfFire@protonmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/ar/
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/hy/
Translation: Fedilab/description
2022-10-17 02:55:21 +02:00
Thomas
9ceb991758 Fix issue #350 - Issue with URLs when transformed to alternative front-end. 2022-10-16 16:35:32 +02:00
Thomas
a7008cdaa2 Fix issue #354 - Sharing a single media does not prompt the accounts 2022-10-16 11:39:16 +02:00
Thomas
e0207251d1 Merge remote-tracking branch 'origin/develop' into develop 2022-10-16 11:29:29 +02:00
Thomas
4d1aff63a8 Fix issue #353 - Add a message that allows to open context when media are in fullscreen. 2022-10-16 11:29:24 +02:00
ButterflyOfFire
8fb6b8769e
Translated using Weblate (Breton)
Currently translated at 26.7% (210 of 786 strings)

Translation: Fedilab/Strings
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/br/
2022-10-12 19:59:36 +02:00
Hosted Weblate
ad59567442
Update translation files
Updated by "Cleanup translation files" hook in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/
Translation: Fedilab/description
2022-10-12 19:51:18 +02:00
ButterflyOfFire
47b73aab48
Translated using Weblate (Kabyle)
Currently translated at 0.0% (0 of 25 strings)

Translated using Weblate (French)

Currently translated at 100.0% (25 of 25 strings)

Translated using Weblate (Arabic)

Currently translated at 8.0% (2 of 25 strings)

Translated using Weblate (Vietnamese)

Currently translated at 72.0% (18 of 25 strings)

Translated using Weblate (French)

Currently translated at 92.0% (23 of 25 strings)

Translated using Weblate (German)

Currently translated at 12.0% (3 of 25 strings)

Co-authored-by: ButterflyOfFire <ButterflyOfFire@protonmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/ar/
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/de/
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/fr/
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/kab/
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/vi/
Translation: Fedilab/description
2022-10-12 19:51:18 +02:00
Eric
78df7737cd
Translated using Weblate (Chinese (Simplified))
Currently translated at 13.3% (2 of 15 strings)

Co-authored-by: Eric <hamburger1024@firemail.cc>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/zh_Hans/
Translation: Fedilab/description
2022-10-12 19:51:17 +02:00
Burak Orcun OZKABLAN
5a0b0d1aa5
Translated using Weblate (Turkish)
Currently translated at 100.0% (15 of 15 strings)

Co-authored-by: Burak Orcun OZKABLAN <borcunozkablan@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/tr/
Translation: Fedilab/description
2022-10-12 19:51:17 +02:00
mastoduy
280e34aeb1
Translated using Weblate (Vietnamese)
Currently translated at 100.0% (13 of 13 strings)

Translated using Weblate (Vietnamese)

Currently translated at 100.0% (9 of 9 strings)

Co-authored-by: mastoduy <duy@tutamail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/vi/
Translation: Fedilab/description
2022-10-12 19:51:16 +02:00
Oğuz Ersen
c7084a1acf
Translated using Weblate (Turkish)
Currently translated at 100.0% (14 of 14 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (13 of 13 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (12 of 12 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (10 of 10 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (9 of 9 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (8 of 8 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (7 of 7 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (5 of 5 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (4 of 4 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (4 of 4 strings)

Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/tr/
Translation: Fedilab/description
2022-10-12 19:51:16 +02:00
Ajeje Brazorf
bbad77490a
Translated using Weblate (Sardinian)
Currently translated at 100.0% (8 of 8 strings)

Translated using Weblate (Sardinian)

Currently translated at 100.0% (7 of 7 strings)

Translated using Weblate (Sardinian)

Currently translated at 100.0% (5 of 5 strings)

Translated using Weblate (Sardinian)

Currently translated at 100.0% (4 of 4 strings)

Translated using Weblate (Sardinian)

Currently translated at 100.0% (4 of 4 strings)

Co-authored-by: Ajeje Brazorf <lmelonimamo@yahoo.it>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/sc/
Translation: Fedilab/description
2022-10-12 19:51:16 +02:00
Hosted Weblate
e288c62f53
Update translation files
Updated by "Remove blank strings" hook in Weblate.

Translation: Fedilab/Strings
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/
2022-10-12 09:18:00 +02:00
Hosted Weblate
63a309b4a5
Update translation files
Updated by "Remove blank strings" hook in Weblate.

Translation: Fedilab/Strings
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/
2022-10-12 09:17:57 +02:00
ButterflyOfFire
69b43b486a
Translated using Weblate (Ukrainian)
Currently translated at 76.2% (599 of 786 strings)

Translation: Fedilab/Strings
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/uk/
2022-10-12 09:17:54 +02:00
Oğuz Ersen
09d170b3dc
Translated using Weblate (Turkish)
Currently translated at 100.0% (786 of 786 strings)

Translation: Fedilab/Strings
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/tr/
2022-10-12 09:17:54 +02:00
ButterflyOfFire
2a03c2dfdd
Translated using Weblate (Serbian)
Currently translated at 72.7% (572 of 786 strings)

Translation: Fedilab/Strings
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/sr/
2022-10-12 09:17:53 +02:00
ButterflyOfFire
26d9d36f83
Translated using Weblate (Slovenian)
Currently translated at 72.7% (572 of 786 strings)

Translation: Fedilab/Strings
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/sl/
2022-10-12 09:17:53 +02:00
ButterflyOfFire
953bda5aaf
Translated using Weblate (Sinhala)
Currently translated at 72.7% (572 of 786 strings)

Translation: Fedilab/Strings
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/si/
2022-10-12 09:17:52 +02:00
Ajeje Brazorf
6a888249c7
Translated using Weblate (Sardinian)
Currently translated at 99.6% (783 of 786 strings)

Translation: Fedilab/Strings
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/sc/
2022-10-12 09:17:52 +02:00
ButterflyOfFire
843b513625
Translated using Weblate (Russian)
Currently translated at 72.7% (572 of 786 strings)

Translation: Fedilab/Strings
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ru/
2022-10-12 09:17:51 +02:00
ButterflyOfFire
bec8012f49
Translated using Weblate (Norwegian Bokmål)
Currently translated at 81.6% (642 of 786 strings)

Translation: Fedilab/Strings
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/nb_NO/
2022-10-12 09:17:51 +02:00
ButterflyOfFire
a90e99fa27
Translated using Weblate (Dutch)
Currently translated at 72.6% (571 of 786 strings)

Translation: Fedilab/Strings
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/nl/
2022-10-12 09:17:50 +02:00
ButterflyOfFire
83ec415e67
Translated using Weblate (Kabyle)
Currently translated at 73.0% (574 of 786 strings)

Translation: Fedilab/Strings
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/kab/
2022-10-12 09:17:50 +02:00
ButterflyOfFire
d6faffb219
Translated using Weblate (Italian)
Currently translated at 76.5% (602 of 786 strings)

Translation: Fedilab/Strings
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/it/
2022-10-12 09:17:50 +02:00
ButterflyOfFire
9ef395b73f
Translated using Weblate (Hindi)
Currently translated at 72.7% (572 of 786 strings)

Translation: Fedilab/Strings
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/hi/
2022-10-12 09:17:50 +02:00
ButterflyOfFire
06522a6a27
Translated using Weblate (Galician)
Currently translated at 72.7% (572 of 786 strings)

Translation: Fedilab/Strings
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/gl/
2022-10-12 09:17:49 +02:00
Zekovski
c1763eee91
Translated using Weblate (French)
Currently translated at 100.0% (786 of 786 strings)

Translation: Fedilab/Strings
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/fr/
2022-10-12 09:17:49 +02:00
ButterflyOfFire
7c58c8a573
Translated using Weblate (Basque)
Currently translated at 72.7% (572 of 786 strings)

Translation: Fedilab/Strings
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/eu/
2022-10-12 09:17:49 +02:00
ButterflyOfFire
da45cf8a13
Translated using Weblate (Welsh)
Currently translated at 72.7% (572 of 786 strings)

Translation: Fedilab/Strings
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/cy/
2022-10-12 09:17:48 +02:00
ButterflyOfFire
1e469a44bc
Translated using Weblate (Berber)
Currently translated at 72.3% (569 of 786 strings)

Translation: Fedilab/Strings
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ber/
2022-10-12 09:17:48 +02:00
ButterflyOfFire
56b6907352
Translated using Weblate (Arabic)
Currently translated at 76.5% (602 of 786 strings)

Translation: Fedilab/Strings
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ar/
2022-10-12 09:17:48 +02:00
Thomas
3dad1b23f3 Some changes for channels & priority 2022-10-10 18:20:26 +02:00
Zekovski
78c397e90c
Translated using Weblate (French)
Currently translated at 100.0% (782 of 782 strings)

Translation: Fedilab/Strings
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/fr/
2022-10-10 15:24:04 +02:00
ButterflyOfFire
adfea8d3d4
Translated using Weblate (Arabic)
Currently translated at 76.8% (601 of 782 strings)

Translation: Fedilab/Strings
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ar/
2022-10-10 15:24:04 +02:00
Thomas
a14ffbc094 Fix attach media to a reply. 2022-10-09 18:27:35 +02:00
Thomas
99d2976993 Fix a regression when adding media to a reply 2022-10-09 12:03:08 +02:00
Thomas
a14962d977 Fix counters 2022-10-08 18:00:22 +02:00
Thomas
6fe0b25afa Release 3.4.1 2022-10-08 17:51:06 +02:00
Thomas
5957daf956 Allow to disable counters in settings 2022-10-08 17:46:25 +02:00
Thomas
116f5a01a1 Fix message that remain in drafts 2022-10-08 17:21:43 +02:00
Thomas
eea7e83f85 Fix notifications in double and messages not removed from cache 2022-10-08 11:59:17 +02:00
Thomas
6b2d3670d3 Release 3.4.0 2022-10-07 19:04:07 +02:00
Thomas
10f2ac396c Fix issue #338 #315 - Copy/Paste in threads 2022-10-07 18:49:54 +02:00
Thomas
12e1360cc1 Fix issue #339 #333 Notification issues 2022-10-07 15:29:30 +02:00
Thomas
73324a9ee4 Graphic changes 2022-10-07 12:03:38 +02:00
Thomas
c9b5d10167 Merge remote-tracking branch 'origin/develop' into develop 2022-10-07 11:34:26 +02:00
Thomas
6032870902 Fix issue #342 - set as unique 2022-10-07 11:34:20 +02:00
Thomas
9885aa2235 Fix issue #342 2022-10-07 11:27:28 +02:00
Oğuz Ersen
e44dc92cde
Translated using Weblate (Turkish)
Currently translated at 100.0% (782 of 782 strings)

Translation: Fedilab/Strings
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/tr/
2022-10-07 11:25:09 +02:00
Ajeje Brazorf
63c7099988
Translated using Weblate (Sardinian)
Currently translated at 99.6% (779 of 782 strings)

Translation: Fedilab/Strings
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/sc/
2022-10-07 11:25:09 +02:00
Thomas
95e83305e4 Release 3.4-beta-3 2022-10-06 18:37:01 +02:00
Thomas
b3c6cd57a0 Some fixes 2022-10-06 18:07:45 +02:00
Thomas
d27faa3113 some fixes 2022-10-06 17:01:24 +02:00
Thomas
b3ed8661c4 Fix issue #341 2022-10-06 14:27:02 +02:00
Thomas
79a1b41d50 Fix issue #343 2022-10-06 10:48:26 +02:00
Thomas
40be73bd9b Fix issue #342 2022-10-06 10:25:36 +02:00
Thomas
d82aba862b Fix issue #345 2022-10-06 10:19:59 +02:00
Thomas
ec63b15dc7 Fix sending media 2022-10-06 09:59:36 +02:00
Thomas
d18f9e37b7 Release 3.4-beta-2 2022-10-05 18:27:06 +02:00
Thomas
63a5423d7d Fix issue #340 2022-10-05 17:48:09 +02:00
Thomas
68f779c943 Update domains only if built-in browser is used 2022-10-05 17:35:19 +02:00
Thomas
919a11ec61 Fix some issues with markers 2022-10-05 17:26:15 +02:00
Thomas
f11ea8fc2b Merge remote-tracking branch 'origin/develop' into develop 2022-10-05 17:09:36 +02:00
Thomas
e14572506c Fix #336 - talkback issues 2022-10-05 17:09:31 +02:00
Oğuz Ersen
82b6b6ca39
Translated using Weblate (Turkish)
Currently translated at 100.0% (775 of 775 strings)

Translation: Fedilab/Strings
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/tr/
2022-10-05 16:06:30 +02:00
Ajeje Brazorf
dffddd5a4d
Translated using Weblate (Sardinian)
Currently translated at 99.8% (774 of 775 strings)

Translation: Fedilab/Strings
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/sc/
2022-10-05 16:06:30 +02:00
Thomas
5e5257b01c Display media (always/wifi/ask) 2022-10-05 16:05:53 +02:00
Thomas
dc8243fd19 Fix issue when sending messages with images 2022-10-05 11:46:10 +02:00
Thomas
a7675fbe03 Release 3.4-beta-1 2022-10-04 17:44:34 +02:00
Thomas
4f212676de Improve search 2022-10-04 17:32:51 +02:00
Thomas
d2f9c13f2e Delete cache for all timelines after 7 days 2022-10-04 15:13:22 +02:00
Thomas
fd9d9ba2e0 cache count 2022-10-04 11:19:01 +02:00
Thomas
a93bfd6389 settings cache 2022-10-04 10:13:11 +02:00
Thomas
891cef5f67 Merge remote-tracking branch 'origin/develop' into develop 2022-10-04 09:51:03 +02:00
Thomas
87082d4241 Some fixes 2022-10-04 09:50:39 +02:00
Thomas
51b4689e33 Fix issue #330 - Crash with Friendica 2022-10-04 09:48:37 +02:00
Thomas
77dcb6db31 Fix counters 2022-10-04 09:37:20 +02:00
Thomas
a2406f23a5 Detects tab with tag 2022-10-03 18:51:41 +02:00
Thomas
d8f8c2dc0d Some improvements with counters and pagination 2022-10-03 17:48:12 +02:00
Thomas
900a91f13f Last fix with pagination and remote calls 2022-10-03 11:31:27 +02:00
Thomas
eca5cecd93 some changes 2022-10-02 12:18:13 +02:00
Thomas
e55c154139 Add counter for new messages 2022-10-01 17:14:56 +02:00
Thomas
e2be4871e0 Add counter for new messages 2022-10-01 17:00:03 +02:00
Thomas
204cb84dca Implement cache for conversations 2022-09-30 18:54:01 +02:00
Thomas
c4dbe80a05 Some fixes with cache and notifications 2022-09-30 16:57:49 +02:00
Thomas
bb4851e424 Some fixes with cache and notifications 2022-09-30 16:47:40 +02:00
Thomas
ea1df98d15 fix pagination issue to bottom 2022-09-30 14:49:43 +02:00
Thomas
3d3f0039a3 Some fixes 2022-09-30 12:19:01 +02:00
Thomas
866920933e Fix media profiles 2022-09-30 11:44:25 +02:00
Thomas
a96299ab70 improve notifications cache 2022-09-30 10:07:23 +02:00
Thomas
9a665f3c8a cache for notifications 2022-09-29 17:59:53 +02:00
Thomas
62b0caec11 Some fixes 2022-09-29 11:34:30 +02:00
Thomas
086be24686 Fix behavior with min and max ids 2022-09-28 18:07:25 +02:00
Thomas
2dc19277a7 some fixes with fetch more 2022-09-27 18:01:06 +02:00
Thomas
a8f0125a8f some fixes with fetch more 2022-09-27 11:19:49 +02:00
Thomas
d349062fea cache 2022-09-26 17:09:28 +02:00
Thomas
60b48c594a cache 2022-09-26 17:08:00 +02:00
Thomas
70c581ba21 cache 2022-09-26 10:17:25 +02:00
Thomas
29b3107889 remove quickload 2022-09-25 11:23:08 +02:00
Thomas
3587408123 improve cache 2022-09-24 17:26:44 +02:00
Thomas
03bf06b6a0 improve cache 2022-09-24 15:27:57 +02:00
Thomas
550187afc5 avoid crash in debug for pictures 2022-09-21 16:37:10 +02:00
Thomas
4d4d27e512 Fix compose 2022-09-21 16:31:15 +02:00
Thomas
927433a7bf Fix notification refresh + Post messages 2022-09-21 15:49:13 +02:00
Oğuz Ersen
a69e0524ce
Translated using Weblate (Turkish)
Currently translated at 100.0% (771 of 771 strings)

Translation: Fedilab/Strings
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/tr/
2022-09-20 22:16:31 +02:00
Thomas
bd43af4ab8 Fix issue #324 & #325 - Error messages with action on Friendica 2022-09-20 16:11:55 +02:00
Thomas
f4bfe12abe Fix issue #326 2022-09-20 11:43:47 +02:00
Thomas
dcb41be114 fix some crashes 2022-09-20 09:51:53 +02:00
Thomas
1cb52f167f Accept/Reject follow requests from notifications 2022-09-20 07:48:04 +02:00
RintanBroadleaf
f91acaaf8e
Translated using Weblate (Japanese)
Currently translated at 99.8% (770 of 771 strings)

Translation: Fedilab/Strings
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ja/
2022-09-19 11:21:34 +02:00
mastoduy
ebd25b5a33
Translated using Weblate (Vietnamese)
Currently translated at 100.0% (771 of 771 strings)

Translation: Fedilab/Strings
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/vi/
2022-09-17 05:17:06 +02:00
Thomas
2e3639dcb4 Release 3.3.2 2022-09-16 18:54:23 +02:00
Thomas
62a4a63386 Release 3.3.2 2022-09-16 17:43:29 +02:00
Thomas
ed3579ba65 Fix an issue with cache and home TL 2022-09-15 17:37:22 +02:00
Thomas
cfb3c42839 Merge branch 'develop' of https://codeberg.org/tom79/Fedilab into develop 2022-09-15 16:06:12 +02:00
Thomas
97ebb9c36e Fix Nitter issues + invalid ssl certificate for onion (no longer supported for Google) 2022-09-15 16:06:05 +02:00
Ajeje Brazorf
c238e23239
Translated using Weblate (Sardinian)
Currently translated at 99.6% (768 of 771 strings)

Translation: Fedilab/Strings
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/sc/
2022-09-15 12:20:08 +02:00
Thomas
1e65074a4b Release notes 3.3.1 2022-09-14 18:39:57 +02:00
Thomas
e2ff85f8be Release 3.3.1 2022-09-14 18:38:59 +02:00
Thomas
564e0c682c Allow to edit Nitter accounts with a long click on tabs 2022-09-14 18:35:22 +02:00
Thomas
7e30ba8fb3 Speed-up Nitter 2022-09-14 18:07:51 +02:00
Thomas
8645f6d59b fix visibility when displaying counters 2022-09-14 17:24:51 +02:00
Thomas
a658d17e2c Fix offset with pinned 2022-09-14 11:27:27 +02:00
Thomas
9f6ca2270d fix a crash 2022-09-14 10:29:44 +02:00
Thomas
3db4084688 Merge branch 'develop' of https://codeberg.org/tom79/Fedilab into develop 2022-09-13 17:56:20 +02:00
Thomas
641c7eff0e Release notes 2022-09-13 17:56:14 +02:00
Thomas
2f89e88330 Release 3.3.0 2022-09-13 17:55:30 +02:00
Oğuz Ersen
fbf942645b
Translated using Weblate (Turkish)
Currently translated at 100.0% (769 of 769 strings)

Translation: Fedilab/Strings
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/tr/
2022-09-13 17:40:32 +02:00
Ajeje Brazorf
448ec81ed5
Translated using Weblate (Sardinian)
Currently translated at 99.6% (766 of 769 strings)

Translation: Fedilab/Strings
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/sc/
2022-09-13 17:40:32 +02:00
ButterflyOfFire
c470025cf2
Translated using Weblate (French)
Currently translated at 98.5% (758 of 769 strings)

Translation: Fedilab/Strings
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/fr/
2022-09-13 17:40:32 +02:00
Thomas
05074439c9 Fix issue #114 - Allow to display counters in timelines 2022-09-13 17:40:23 +02:00
Thomas
4e480812bf Fix an issue with TL in a list 2022-09-13 11:35:03 +02:00
Thomas
0b76f3a219 Dev release - 3.2.1 2022-09-12 18:53:05 +02:00
Thomas
f8349503c9 condition error 2022-09-12 18:19:18 +02:00
Thomas
05efea29ef Fix issue #321 2022-09-12 18:19:00 +02:00
Thomas
76801bf640 Fix issue #14 2022-09-12 17:21:04 +02:00
Thomas
cdc1f93390 Last fixes 2022-09-12 16:58:11 +02:00
Thomas
ca6025f14b some changes 2022-09-12 16:08:57 +02:00
Thomas
16de400fc1 UI changes 2022-09-12 15:51:27 +02:00
Thomas
b9001ccd7c Implement logic 2022-09-12 15:34:54 +02:00
Thomas
2092119475 prepare settings 2022-09-12 09:35:44 +02:00
Thomas
4220338374 prepare settings 2022-09-12 09:18:42 +02:00
Thomas
9a929c2296 Change url 2022-09-10 19:08:42 +02:00
Thomas
2f27806c53 Merge remote-tracking branch 'origin/develop' into develop 2022-09-10 18:30:57 +02:00
Thomas
399be26280 Fix push notifications for Google release 2022-09-10 18:30:51 +02:00
Thomas
882c1bf6cd Merge pull request 'Bump android-embedded_fcm_distributor to 2.1.3' (#320) from s1m/Fedilab:bump/unifiedpush into main
Reviewed-on: https://codeberg.org/tom79/Fedilab/pulls/320
2022-09-10 15:22:01 +02:00
sim
3130d7b827 Bump android-embedded_fcm_distributor to 2.1.3 2022-09-10 14:46:13 +02:00
Eric
b4ad38c526
Translated using Weblate (Chinese (Simplified))
Currently translated at 78.1% (596 of 763 strings)

Translation: Fedilab/Strings
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/zh_Hans/
2022-09-10 11:21:35 +02:00
Oğuz Ersen
fc2d0eb501
Translated using Weblate (Turkish)
Currently translated at 100.0% (763 of 763 strings)

Translation: Fedilab/Strings
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/tr/
2022-09-10 11:21:35 +02:00
Ajeje Brazorf
1b7b8c3480
Translated using Weblate (Sardinian)
Currently translated at 99.6% (760 of 763 strings)

Translation: Fedilab/Strings
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/sc/
2022-09-10 11:21:35 +02:00
Thomas
054a8f4cc0 Release 3.2.0 2022-09-09 19:00:50 +02:00
Thomas
76df8b78ad Release 3.2.0 2022-09-09 18:58:56 +02:00
Thomas
62b7fffce8 Profile media in a grid 2022-09-09 17:34:03 +02:00
Thomas
e68db78dc4 Profile media in a grid 2022-09-09 17:24:57 +02:00
Thomas
c3a00df067 Fix an issue with URLs 2022-09-09 15:19:37 +02:00
Thomas
9c6f477a17 Release 3.1.2 2022-09-08 18:44:25 +02:00
Thomas
619f60e780 Fix issue #298 - Change distributor in settings 2022-09-08 18:40:41 +02:00
Thomas
50e422e012 Fix issue #297 2022-09-08 17:58:49 +02:00
Thomas
987b83944d Release 3.1.2 2022-09-08 17:42:03 +02:00
Thomas
55ba4018e4 Merge remote-tracking branch 'origin/develop' into develop 2022-09-08 17:34:15 +02:00
Thomas
dad0022e18 Fix issue #310 2022-09-08 17:34:03 +02:00
Oğuz Ersen
77926ca58b
Translated using Weblate (Turkish)
Currently translated at 100.0% (761 of 761 strings)

Translation: Fedilab/Strings
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/tr/
2022-09-08 17:18:16 +02:00
Ajeje Brazorf
4403b263b6
Translated using Weblate (Sardinian)
Currently translated at 99.7% (759 of 761 strings)

Translation: Fedilab/Strings
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/sc/
2022-09-08 17:18:16 +02:00
Thomas
514bc0794e Fix issue #303 - Visibility not correctly applied after reordering lists. 2022-09-08 15:46:19 +02:00
Thomas
f5aa8a03e5 Fix issue #319 - Fix jumps when setting fit preview images 2022-09-08 14:40:45 +02:00
Thomas
a23b788229 Fix issue #308 2022-09-08 12:16:50 +02:00
Thomas
7b0ce01fa3 Color issue 2022-09-08 11:31:10 +02:00
Thomas
b60780bcb0 Fix issue #317 2022-09-08 08:49:42 +02:00
Thomas
9ce6c56771 Fix issue #318 - Crashes when replying with Friendica 2022-09-08 08:40:30 +02:00
Thomas
22d393919a Fix Peertube videos 2022-09-07 19:16:38 +02:00
Thomas
c9516e7763 Fix issue #302 - Respect visibility of accounts when replying 2022-09-07 18:35:48 +02:00
Thomas
2ba5234bb4 Fix issue #141 - Add video icon for gif 2022-09-07 18:10:15 +02:00
Thomas
501c545a14 Avoid some crashes when using drafts 2022-09-07 18:08:22 +02:00
Thomas
331a5433ad Fix issue #300 - Crash when removing a message in thread 2022-09-07 17:53:03 +02:00
Thomas
2180da64b7 Fix issue #299 - Crashes with pinned timelines 2022-09-07 17:42:10 +02:00
Thomas
b7d966a873 Fix issue #276 2022-09-07 16:18:51 +02:00
Thomas
e0ce8f30f8 noHistory for activities 2022-09-06 18:26:49 +02:00
Thomas
d0d193dcc4 add home button 2022-09-06 18:22:54 +02:00
Thomas
90263e96b8 export/import settings 2022-09-06 14:55:47 +02:00
Thomas
7f28d208a3 export settings 2022-09-06 11:30:19 +02:00
0xd9a
190b800a6e Update dependencies 2022-08-20 16:22:47 +05:30
0xd9a
9e71d9d3b0 Update settings page 2022-08-20 16:20:22 +05:30
Oğuz Ersen
5ed1fc7a02
Translated using Weblate (Turkish)
Currently translated at 100.0% (743 of 743 strings)

Translation: Fedilab/Strings
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/tr/
2022-08-06 21:20:18 +02:00
mastoduy
fa47801318
Translated using Weblate (Vietnamese)
Currently translated at 100.0% (743 of 743 strings)

Translation: Fedilab/Strings
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/vi/
2022-08-05 16:15:54 +02:00
Ajeje Brazorf
01fde1d02c
Translated using Weblate (Sardinian)
Currently translated at 99.7% (741 of 743 strings)

Translation: Fedilab/Strings
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/sc/
2022-08-04 12:20:16 +02:00
Thomas
a8617342c3 Update release notes 2022-08-02 11:31:59 +02:00
Thomas
249b36f987 Fix issue #285 - Allow to set the fetch time for delayed. 2022-08-02 11:29:40 +02:00
Thomas
784041f693 fix other theme issues 2022-08-02 10:58:25 +02:00
Thomas
3338e2881f Fix issue #275 2022-08-02 10:45:03 +02:00
Thomas
0a15ab2cf8 some fixes 2022-08-02 10:40:27 +02:00
Thomas
83bacc12ea Prepare release 3.1.0 2022-08-01 18:35:40 +02:00
Thomas
e622c9afbd Merge remote-tracking branch 'origin/develop' into develop 2022-08-01 18:26:38 +02:00
Thomas
e29a722cfb Improve theming 2022-08-01 18:21:05 +02:00
Oğuz Ersen
9c33c4dccf
Translated using Weblate (Turkish)
Currently translated at 100.0% (739 of 739 strings)

Translation: Fedilab/Strings
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/tr/
2022-08-01 17:17:10 +02:00
Thomas
e178ce1045 some changes 2022-08-01 14:29:23 +02:00
0xd9a
f936bc2c35 move emoji reaction buttons 2022-08-01 17:35:54 +05:30
Thomas
e6a0a7f46d Merge remote-tracking branch 'origin/develop' into develop 2022-08-01 11:30:06 +02:00
Thomas
3703254c6f Fix issues #291 #208 #277 #99 - Add error messages coming from the API with a button to edit the draft for a resend. 2022-08-01 11:30:00 +02:00
mastoduy
ef8e4dea05
Translated using Weblate (Vietnamese)
Currently translated at 100.0% (737 of 737 strings)

Translation: Fedilab/Strings
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/vi/
2022-08-01 11:19:48 +02:00
Thomas
77f22390e1 Merge remote-tracking branch 'origin/develop' into develop 2022-08-01 10:44:04 +02:00
Thomas
3a9e885cef Fix issue #290 - Share settings do not work 2022-08-01 10:43:58 +02:00
0xd9a
4c1d4871d4 Update 'fetch more' drawer 2022-07-31 17:45:42 +05:30
Thomas
745de828bb Fix issue #287 - crash with deleting / redrafting a reply 2022-07-31 11:21:49 +02:00
Thomas
51c3bc56f3 clean 2022-07-31 11:13:20 +02:00
Oğuz Ersen
2854f45ae2
Translated using Weblate (Turkish)
Currently translated at 100.0% (737 of 737 strings)

Translation: Fedilab/Strings
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/tr/
2022-07-30 21:20:11 +02:00
Thomas
3dd2e45987 Fix #253 - Missing messages 2022-07-30 19:29:53 +02:00
Thomas
f597d52a44 Merge branch 'main' into develop 2022-07-30 18:59:11 +02:00
Thomas
efe387088e Merge branch 'main' into develop 2022-07-30 18:55:11 +02:00
Thomas
298371d776 Merge pull request 'Add Dark Elephant theme' (#289) from s1m/Fedilab:theme/dark-elephant into main
Reviewed-on: https://codeberg.org/tom79/Fedilab/pulls/289
2022-07-30 18:52:59 +02:00
Thomas
fa6a4a92d1 Merge remote-tracking branch 'origin/develop' into develop 2022-07-30 18:47:37 +02:00
Thomas
2553b4835b Some fixes 2022-07-30 18:47:30 +02:00
sim
9e14e03994 Add Dark Elephant theme 2022-07-30 11:37:27 +02:00
Thomas
7e2b1423a6 Merge pull request 'Don't show instance search results if there aren't any.' (#284) from nolan/Fedilab:instance-a11y into develop
Reviewed-on: https://codeberg.org/tom79/Fedilab/pulls/284
2022-07-30 10:36:02 +02:00
RintanBroadleaf
316b815d01
Translated using Weblate (Japanese)
Currently translated at 94.4% (695 of 736 strings)

Translation: Fedilab/Strings
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ja/
2022-07-28 13:19:15 +02:00
Thomas
18bc812cf1 Fix issue #276 - Search OG when there is only one URL 2022-07-27 15:54:24 +02:00
Nolan Darilek
f429017122 Don't show instance search results if there aren't any. 2022-07-26 15:19:59 -05:00
Thomas
74921e6d16 Fix issue #279 - Improve behavior 2022-07-26 19:08:10 +02:00
Thomas
21ccde5c6a Merge pull request 'Enable DOM storage so account authorization pages requiring \local storage work.' (#282) from nolan/Fedilab:enable-dom-storage into develop
Reviewed-on: https://codeberg.org/tom79/Fedilab/pulls/282
2022-07-26 19:01:50 +02:00
Thomas
cdbc684316 Merge pull request 'Allow debug and release builds to be installed concurrently' (#281) from nolan/Fedilab:develop into develop
Reviewed-on: https://codeberg.org/tom79/Fedilab/pulls/281
2022-07-26 18:52:33 +02:00
Nolan Darilek
6b677824d8 Enable DOM storage so account authorization pages requiring \local storage work. 2022-07-26 11:48:57 -05:00
Thomas
c108b9f219 Merge remote-tracking branch 'origin/develop' into develop 2022-07-26 18:47:04 +02:00
Thomas
9f28f64e74 Fix issue #279 2022-07-26 18:46:58 +02:00
Nolan Darilek
1fcefad951 Update build configuration so debug and release builds can be installed concurrently. 2022-07-26 10:08:59 -05:00
mastoduy
b54ee03d95
Translated using Weblate (Vietnamese)
Currently translated at 100.0% (736 of 736 strings)

Translation: Fedilab/Strings
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/vi/
2022-07-26 16:25:08 +02:00
Thomas
14117b73a3 Release 3.0.11 2022-07-25 19:00:32 +02:00
Thomas
9ac9c3adc4 Change the adapter position 2022-07-25 17:35:27 +02:00
Thomas
16ef4513c6 Fix issue #241 - Don't force message to the character limit 2022-07-25 17:25:05 +02:00
Thomas
4a5d98bde7 Fix issue #239 - Cross follow does not work 2022-07-25 17:00:21 +02:00
Thomas
a82bbd25e3 Cant subscribe to notifications for an account 2022-07-25 16:54:54 +02:00
Thomas
d2b7ce3909 Fix null value 2022-07-25 16:44:46 +02:00
Thomas
27a67445c9 Comment issue #276 - Only fetch OG when there is only a URL. 2022-07-25 16:01:00 +02:00
Thomas
7f48b03781 Comment issue #276 - Fix crashes when sharing only text 2022-07-25 15:50:17 +02:00
Thomas
d7bd889d35 Fix issue #275 - Wrong account open for reactions 2022-07-25 15:33:57 +02:00
Thomas
f3e8e8a506 Some fixes 2022-07-25 15:17:48 +02:00
Thomas
0bf5199144 Fix issue #271 & #212 - Card not displayed for boosts 2022-07-24 11:40:49 +02:00
Thomas
b6678bb645 Fix issue #272 2022-07-23 12:07:40 +02:00
Thomas
1dc3d43669 Fix issue #273 2022-07-23 11:50:01 +02:00
Thomas
f8e3a54cb2 Merge remote-tracking branch 'origin/develop' into develop 2022-07-22 11:05:33 +02:00
Thomas
c3710c8a3d Fix issue #270 2022-07-22 11:05:24 +02:00
Oğuz Ersen
772c9904eb
Translated using Weblate (Turkish)
Currently translated at 100.0% (736 of 736 strings)

Translation: Fedilab/Strings
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/tr/
2022-07-22 03:04:09 +02:00
Ajeje Brazorf
e2b0445d82
Translated using Weblate (Sardinian)
Currently translated at 100.0% (736 of 736 strings)

Translation: Fedilab/Strings
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/sc/
2022-07-22 03:04:08 +02:00
Thomas
03723659f3 put fdroid release version 2022-07-21 18:30:28 +02:00
Thomas
83ad77f3ea Merge branch 'develop' into main 2022-07-21 16:19:00 +02:00
Thomas
07a819a9c2 Release 3.0.10 2022-07-21 14:46:56 +02:00
Thomas
3d2b1b6b7d Fix non updated counter with cache 2022-07-21 14:33:37 +02:00
Thomas
2da0b1bba8 Merge remote-tracking branch 'origin/develop' into develop 2022-07-21 10:31:57 +02:00
Thomas
1f332dbf3a Add Emoji keyboard for compose 2022-07-21 10:31:52 +02:00
Oğuz Ersen
0b11783232
Translated using Weblate (Turkish)
Currently translated at 100.0% (734 of 734 strings)

Translation: Fedilab/Strings
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/tr/
2022-07-21 09:01:25 +02:00
Ajeje Brazorf
c788a9fb2b
Translated using Weblate (Sardinian)
Currently translated at 100.0% (734 of 734 strings)

Translation: Fedilab/Strings
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/sc/
2022-07-21 09:01:25 +02:00
Thomas
3488795520 Add release notes 2022-07-21 09:01:17 +02:00
Thomas
c033064d13 Fix issue #263 - Custom emoji for Friendica 2022-07-20 17:13:07 +02:00
Thomas
b060dcb38d Merge remote-tracking branch 'origin/develop' into develop 2022-07-20 14:24:16 +02:00
Thomas
6876b75366 Fix issue #267 - Crash with reactions 2022-07-20 14:24:09 +02:00
Ajeje Brazorf
abbfb1a573
Translated using Weblate (Sardinian)
Currently translated at 100.0% (729 of 729 strings)

Translation: Fedilab/Strings
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/sc/
2022-07-20 12:08:00 +02:00
Thomas
25b18e390a Merge remote-tracking branch 'origin/develop' into develop 2022-07-20 12:07:53 +02:00
Thomas
71aaaadccb Set instance max chars 2022-07-20 12:07:44 +02:00
Oğuz Ersen
c18f1a1372
Translated using Weblate (Turkish)
Currently translated at 100.0% (729 of 729 strings)

Translation: Fedilab/Strings
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/tr/
2022-07-20 10:11:08 +02:00
Thomas
10e66a3e7e Fix issue #262 - Long press to store media 2022-07-20 10:10:59 +02:00
Thomas
c97c2e465b Fix preview with focus issue 2022-07-20 09:42:16 +02:00
Thomas
e0c94e114c Fix some bad behaviors with span 2022-07-20 09:33:34 +02:00
Thomas
10fefbe6d9 Merge remote-tracking branch 'origin/main' into main 2022-07-19 18:39:13 +02:00
Thomas
92a9479c95 Merge branch 'develop' into main 2022-07-19 18:39:03 +02:00
Thomas
5cac98090f Release 3.0.9 2022-07-19 18:34:02 +02:00
Thomas
18c3424ed3 Fix issue #244 - Add support for setting post language 2022-07-19 18:18:03 +02:00
Thomas
eaac079d89 Fix issue #252 - Empty timelines for Tags 2022-07-19 16:43:29 +02:00
Thomas
8a0460536c Add emoji reactions for Pleroma 2022-07-19 15:49:47 +02:00
Thomas
cf1a1b3e53 Fix issue #234 - Reactions in notifications for Pleroma 2022-07-19 14:28:25 +02:00
Thomas
f5bf2ad0b0 Some fixes 2022-07-19 11:51:19 +02:00
Thomas
192c2c6469 Some fixes 2022-07-19 11:19:50 +02:00
Thomas
f2b4c8aa69 Fix README.md 2022-07-19 09:16:11 +02:00
Thomas
6484f85ce4 Fix issue #259 - Themes can't be selected 2022-07-19 09:13:51 +02:00
Thomas
57ef875968 Fix link 2022-07-19 09:08:51 +02:00
Thomas
4b61922969 Fix issue #260 - Add privacy icon in messages 2022-07-19 08:35:37 +02:00
Thomas
2a47056606 Release 3.0.8 2022-07-18 19:11:41 +02:00
Thomas
7589f91e07 Fix theming 2022-07-18 18:50:42 +02:00
Thomas
c3a7bbadbd Fix issue #250 2022-07-18 18:08:23 +02:00
Thomas
3cfade2f39 Fix focus point - Not apply it when fit preview is turned on 2022-07-18 17:55:55 +02:00
Thomas
6c3356d2be Some fixes 2022-07-18 17:46:55 +02:00
Thomas
ef58c7bc40 Fix #256 - Can share with one account 2022-07-18 17:46:29 +02:00
Thomas
17f727fd9f Fix #258 - Wrong selection after a second search. 2022-07-18 15:28:23 +02:00
Thomas
65002bf235 some changes 2022-07-18 14:39:47 +02:00
Thomas
8e0808dcda some changes 2022-07-18 14:13:12 +02:00
Thomas
dd924cba20 some tries 2022-07-18 11:43:23 +02:00
Thomas
f316830c1b Merge pull request 'Keep the screen on when displaying images' (#254) from Augier/Fedilab:keep-screen-awake-display-images into main
Reviewed-on: https://codeberg.org/tom79/Fedilab/pulls/254
2022-07-17 18:22:32 +02:00
Christophe Henry
fe4eb61df0 Keep the screen on when displaying images 2022-07-17 17:53:10 +02:00
Thomas
96680343e0 some fixes 2022-07-16 09:21:43 +02:00
Thomas
dc1155d7c2 Release 3.0.7 2022-07-15 18:27:44 +02:00
Thomas
7a5cb3a3d5 Merge remote-tracking branch 'origin/develop' into develop 2022-07-15 18:19:24 +02:00
Thomas
b360a9a827 Fix an issue with media not hidden 2022-07-15 18:18:53 +02:00
Thomas
27b05d5b6b Fix issue #248 - nsfw no respected when posting 2022-07-15 18:12:29 +02:00
Thomas
61ddd2a22d some fixes 2022-07-15 17:34:19 +02:00
Thomas
2db7b4b87c Fix mentions 2022-07-14 11:04:27 +02:00
Thomas
d58a92f167 Remove remote fetch accounts 2022-07-13 18:55:24 +02:00
Thomas
2436c839dc Some tries 2022-07-13 12:56:07 +02:00
Thomas
c17322c699 Some tries 2022-07-13 12:50:48 +02:00
Thomas
455e5666a9 Some tries 2022-07-13 09:27:10 +02:00
mastoduy
d4e8df47a6
Translated using Weblate (Vietnamese)
Currently translated at 100.0% (727 of 727 strings)

Translation: Fedilab/Strings
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/vi/
2022-07-13 00:14:38 +02:00
Ajeje Brazorf
346ac0610c
Translated using Weblate (Sardinian)
Currently translated at 100.0% (727 of 727 strings)

Translation: Fedilab/Strings
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/sc/
2022-07-13 00:14:38 +02:00
Thomas
aa3c6f07e7 Some tries 2022-07-11 18:15:55 +02:00
Thomas
270e722a38 Some tries 2022-07-11 17:40:37 +02:00
Thomas
3b15c34e18 Some tries 2022-07-11 16:54:51 +02:00
Thomas
0bdee201e7 Some tries 2022-07-11 16:40:50 +02:00
Thomas
941dd21561 Some changes 2022-07-11 13:34:01 +02:00
Thomas
aff9d093a2 Merge remote-tracking branch 'origin/develop' into develop 2022-07-11 09:13:21 +02:00
Thomas
94c3dbcf25 Add edit profile in main settings 2022-07-11 09:13:16 +02:00
Oğuz Ersen
28ef0860ac
Translated using Weblate (Turkish)
Currently translated at 100.0% (726 of 726 strings)

Translation: Fedilab/Strings
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/tr/
2022-07-11 07:34:40 +02:00
Thomas
13d8876626 Fix issue #241 - Store instance info in sharedpref 2022-07-11 07:34:33 +02:00
Thomas
1437976f38 Fix issue #236 - Wrong custom emoji displayed when filtering 2022-07-10 18:36:25 +02:00
Thomas
993ecc2382 Fix issue #238 2022-07-10 18:17:40 +02:00
Thomas
eb1be4f514 Some fixes 2022-07-10 17:46:14 +02:00
Thomas
425d19f2d6 Fix issue #237 - CW not filtered 2022-07-10 17:45:56 +02:00
Thomas
938c2a6a9f Some cleaning 2022-07-10 12:28:09 +02:00
Thomas
79875b68f2 Merge remote-tracking branch 'origin/develop' into develop 2022-07-10 12:20:27 +02:00
Thomas
c17e2c4ba4 Fix Nitter Pagination + Allow to share through Nitter 2022-07-10 12:20:18 +02:00
mastoduy
a11633f127
Translated using Weblate (Vietnamese)
Currently translated at 100.0% (724 of 724 strings)

Translation: Fedilab/Strings
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/vi/
2022-07-10 11:34:47 +02:00
Thomas
b158d01311 Allow to reset language 2022-07-10 11:34:41 +02:00
Thomas
a632618a66 Some improvements 2022-07-10 10:41:07 +02:00
Thomas
867d2ed492 Merge branch 'develop' into main 2022-07-09 17:45:33 +02:00
Thomas
ea8f497902 Release 3.0.6 2022-07-09 17:41:12 +02:00
Thomas
dc3f464ea4 Turn off crash reports set to true by default 2022-07-09 17:35:52 +02:00
Thomas
a80bdd6ac3 Add trends 2022-07-09 17:34:08 +02:00
Thomas
461a3fe90f back to viewpager 2022-07-09 15:30:39 +02:00
Thomas
82681f1af5 Merge remote-tracking branch 'origin/fetch_more_both_direction' into fetch_more_both_direction 2022-07-09 11:14:55 +02:00
Thomas
e7a451da8d Fix issue #233 - Issue with polls 2022-07-09 11:14:50 +02:00
0xd9a
ba2c4f1fc4 Update 'fetch more' drawer 2022-07-08 23:46:14 +05:30
Thomas
91501ab46a Fix issue #163 - Fetch more has now two buttons (down or up) 2022-07-08 19:02:18 +02:00
Thomas
4467853b71 Fix issue #222 - Profiles truncated when long bio + missing fields 2022-07-08 10:20:40 +02:00
Thomas
17ed03af91 Fix issue #215 - Only last notification is displayed 2022-07-07 18:19:55 +02:00
Thomas
b8addbc3f1 Some fixes 2022-07-07 14:38:24 +02:00
Thomas
0ef6602408 Merge branch 'develop' of https://codeberg.org/tom79/Fedilab into develop 2022-07-07 14:36:47 +02:00
Thomas
828f79d3c3 Some fixes 2022-07-07 11:47:02 +02:00
Artem
824aebb2b6
Translated using Weblate (Ukrainian)
Currently translated at 79.5% (576 of 724 strings)

Translation: Fedilab/Strings
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/uk/
2022-07-06 22:21:10 +02:00
Thomas
e7f8d99621 Some fixes 2022-07-06 16:51:09 +02:00
Thomas
965676484a Fix issue #225 - Set Focus on images 2022-07-05 19:03:05 +02:00
Thomas
6219c010d0 Fix issue #226 - Crashes when long pressing links on some messages 2022-07-05 07:44:43 +02:00
Thomas
0f513f00c4 Fix issue #219 - Use focus point for image preview 2022-07-04 18:48:54 +02:00
Thomas
383702bf6a small fix 2022-07-04 17:53:33 +02:00
Thomas
17ae8a243a Merge branch 'develop' into main 2022-07-03 16:18:30 +02:00
Thomas
df23e3db9c Release 3.0.5 2022-07-03 16:18:20 +02:00
Thomas
a0522dd52b Merge remote-tracking branch 'origin/main' into main 2022-07-03 16:16:03 +02:00
asereze
4f59c7f36c Correcting Sardinian name 2022-07-03 16:15:28 +02:00
Thomas
9d42d717cc Release 3.0.5 2022-07-03 16:15:12 +02:00
Thomas
39f3fe8601 little fix 2022-07-03 15:57:29 +02:00
Thomas
499f10ea39 Share feature 2022-07-03 12:13:15 +02:00
Thomas
1a37063295 Some fixes 2022-07-02 18:39:03 +02:00
Thomas
b7265d6de3 Some fixes 2022-07-02 17:25:06 +02:00
Thomas
13575706de Fix an issue 2022-07-02 14:53:54 +02:00
Thomas
bbbc8e00cc Fix issue #217 - Invisible poll items due to "<" 2022-07-02 11:09:35 +02:00
Thomas
b039670d53 Fix date 2022-07-02 11:01:14 +02:00
Thomas
8aaf5bfb25 some fixes 2022-07-02 10:01:46 +02:00
Thomas
aae5c8e3ca Fix issue #213 2022-07-01 18:29:32 +02:00
Thomas
f5486a3232 small update 2022-07-01 09:37:17 +02:00
Thomas
f382081a5d Merge remote-tracking branch 'origin/develop' into develop 2022-07-01 09:31:57 +02:00
Thomas
951fceaa4d Fix an issue with Pleroma & date parsing 2022-07-01 09:31:47 +02:00
Ajeje Brazorf
7d9813918d
Translated using Weblate (Sardinian)
Currently translated at 100.0% (724 of 724 strings)

Translation: Fedilab/Strings
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/sc/
2022-06-30 20:19:48 +02:00
1948 changed files with 100911 additions and 31518 deletions

View file

@ -0,0 +1,41 @@
---
name: "Bug"
about: "Something isn't working"
labels:
- Bug
---
<!-- Please, describe the issue here -->
## # Steps for reproducing the issue
<!-- Step, to reproduce it -->
---
<!-- The instance you are using -->
Instance:
<!-- Your social network -->
<!-- Put a x between brackets like: - [x] Mastodon -->
- [ ] Mastodon
- [ ] Pleroma
- [ ] Friendica
- [ ] Pixelfed
<!-- If you know the version of Fedilab that you are using (can be found in about page) -->
Version of Fedilab:
<!-- Your Android version -->
Android version:
<!-- If you read our contributing advice -->
[ ] - I read
the [contributing page](https://codeberg.org/tom79/Fedilab/src/branch/main/CONTRIBUTING.md)

View file

@ -0,0 +1,26 @@
---
name: "Feature"
about: "A new feature or an enhancement to an existing feature"
labels:
- Feature
---
## # Describe the improvement
<!-- Your social network -->
<!-- Put a x between brackets like: - [x] Mastodon -->
- [ ] Mastodon
- [ ] Pleroma
- [ ] Friendica
- [ ] Pixelfed
<!-- Describe the improvement here -->
<!-- If you read our contributing advice -->
[ ] - I read
the [contributing page](https://codeberg.org/tom79/Fedilab/src/branch/main/CONTRIBUTING.md)

2
.gitignore vendored
View file

@ -10,3 +10,5 @@
local.properties
/cropper/build/
/build/
/app/fdroid/release/
/app/playstore/release/

View file

@ -8,4 +8,14 @@ tools for helping in translations. New translations will be automatically merged
If you're submiting a merge request and your work adds new strings to the app, make sure they only
exist in the default strings.xml file (res/values/strings.xml). If you add or modify strings of
other languages, it will interfere with weblate's translations.
other languages, it will interfere with weblate's translations.
### Issues and Reports:
Before creating an issue please take a moment and search the repository issues to avoid duplicates.
For bug reports, please provide as much details as possible to better debug the problem. The
important part is how to reproduce the bug and steps to reproduce it.
### Pull Requests
Please target the develop branch and not the main branch.

View file

@ -1,23 +1,24 @@
[![Translation status](https://hosted.weblate.org/widgets/fedilab/-/strings/svg-badge.svg)](https://hosted.weblate.org/engage/fedilab/)
&nbsp;&nbsp;&nbsp;[![License: GPL v3](https://img.shields.io/badge/License-GPL%20v3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)
# Fedilab is a multi-accounts client for Mastodon, Pleroma, Peertube, GNU Social, Friendica and Pixelfed
# Fedilab is a multi-accounts client for Mastodon, Pleroma, Friendica and Pixelfed
## Donate
[<img alt="Donate using Liberapay" src="https://img.shields.io/liberapay/patrons/tom79.svg?logo=liberapay"/>](https://liberapay.com/tom79/donate)
## Download
[<img alt='Get it on Google Play' src='./images/get-it-on-play.png' height="80"/>](https://play.google.com/store/apps/details?id=app.fedilab.android)
&nbsp;&nbsp;[<img alt='Get it on F-Droid' src='./images/get-it-on-fdroid.png' height="80"/>](https://f-droid.org/app/fr.gouv.etalab.mastodon)
<img src='https://img.shields.io/f-droid/v/fr.gouv.etalab.mastodon?include_prereleases' />
## Resources
[WIKI](https://fedilab.app/wiki/home/)
[Release notes](https://framagit.org/tom79/fedilab/tags)
[Release notes](https://codeberg.org/tom79/Fedilab/tags)
Lead developer: [toot.fedilab.app/@apps](https://toot.fedilab.app/@apps)

View file

@ -1,16 +1,20 @@
import java.util.regex.Matcher
import java.util.regex.Pattern
plugins {
id 'com.android.application'
id 'kotlin-android'
id 'androidx.navigation.safeargs.kotlin'
}
def flavor
android {
compileSdk 31
compileSdk 33
defaultConfig {
minSdk 21
targetSdk 31
versionCode 393
versionName "3.0.2"
targetSdk 33
versionCode 477
versionName "3.17.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
flavorDimensions "default"
@ -19,8 +23,12 @@ android {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
debug {
applicationIdSuffix '.debug'
}
}
compileOptions {
coreLibraryDesugaringEnabled true
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
@ -55,6 +63,21 @@ android {
java.srcDirs = ['src/main/java', 'src/fdroid/java']
res.srcDirs = ['src/main/res', 'src/fdroid/res']
}
main {
res.srcDirs = [
'src/main/res/layouts/mastodon',
'src/main/res/layouts/peertube',
'src/main/res/layouts',
'src/main/layout',
'src/main/res/drawables/mastodon',
'src/main/res/drawables/peertube',
'src/main/res/drawables',
'src/main/res/menus/mastodon',
'src/main/res/menus/peertube',
'src/main/res/menus',
'src/main/res'
]
}
}
configurations {
all {
@ -70,62 +93,140 @@ allprojects {
}
dependencies {
implementation project(':autoimageslider')
implementation 'androidx.appcompat:appcompat:1.4.2'
implementation 'com.google.android.material:material:1.6.1'
implementation 'androidx.appcompat:appcompat:1.6.0'
implementation 'com.google.android.material:material:1.7.0'
implementation 'com.jaredrummler:colorpicker:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation "com.google.code.gson:gson:2.8.6"
implementation "com.google.code.gson:gson:2.9.1"
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
implementation 'com.squareup.retrofit2:converter-simplexml:2.9.0'
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
implementation 'androidx.preference:preference:1.2.0'
implementation "org.conscrypt:conscrypt-android:2.5.2"
implementation 'com.github.evozi:Cyanea:1.0.7'
implementation 'com.vanniktech:emoji-one:0.6.0'
implementation 'com.github.GrenderG:Toasty:1.5.2'
implementation 'org.framagit.tom79:SparkButton:1.0.13'
implementation "com.github.bumptech.glide:glide:4.12.0"
implementation 'com.github.mergehez:ArgPlayer:v3.1'
implementation ("com.github.bumptech.glide:recyclerview-integration:4.12.0") {
implementation "com.github.bumptech.glide:glide:4.14.2"
implementation "com.github.bumptech.glide:okhttp3-integration:4.14.2"
implementation("com.github.bumptech.glide:recyclerview-integration:4.14.2") {
// Excludes the support library because it's already included by Glide.
transitive = false
}
implementation "org.jsoup:jsoup:1.15.1"
implementation 'com.github.mergehez:ArgPlayer:v3.1'
implementation project(path: ':mytransl')
implementation project(path: ':ratethisapp')
implementation project(path: ':sparkbutton')
implementation 'com.burhanrashid52:photoeditor:1.5.1'
implementation project(path: ':cropper')
implementation("com.vanniktech:android-image-cropper:4.3.3")
implementation project(path: ':mathjaxandroid')
annotationProcessor "com.github.bumptech.glide:compiler:4.12.0"
implementation 'jp.wasabeef:glide-transformations:4.3.0'
implementation 'com.github.penfeizhou.android.animation:apng:2.22.0'
implementation 'com.github.penfeizhou.android.animation:gif:2.22.0'
implementation 'com.google.android.exoplayer:exoplayer:2.16.1'
implementation 'com.github.penfeizhou.android.animation:glide-plugin:2.23.0'
implementation 'com.google.android.exoplayer:exoplayer:2.18.1'
implementation "androidx.viewpager2:viewpager2:1.0.0"
implementation 'com.github.piasy:rxandroidaudio:1.7.0'
implementation 'com.github.piasy:AudioProcessor:1.7.0'
implementation "androidx.work:work-runtime:2.7.1"
implementation 'app.futured.hauler:hauler:5.0.0'
implementation "com.github.chrisbanes:PhotoView:2.3.0"
implementation "ch.acra:acra-mail:5.9.3"
implementation "ch.acra:acra-mail:5.9.6"
implementation "ch.acra:acra-limiter:5.9.3"
implementation "ch.acra:acra-dialog:5.9.3"
implementation "ch.acra:acra-dialog:5.9.6"
implementation "com.madgag.spongycastle:bctls-jdk15on:1.58.0.0"
implementation 'com.github.UnifiedPush:android-connector:2.0.0'
implementation 'com.github.UnifiedPush:android-connector:2.0.1'
// implementation 'com.github.UnifiedPush:android-foss_embedded_fcm_distributor:1.0.0-beta1'
playstoreImplementation 'com.github.UnifiedPush:android-embedded_fcm_distributor:1.1.0'
playstoreImplementation('com.github.UnifiedPush:android-embedded_fcm_distributor:2.1.3') {
exclude group: 'com.google.firebase', module: 'firebase-core'
exclude group: 'com.google.firebase', module: 'firebase-analytics'
exclude group: 'com.google.firebase', module: 'firebase-measurement-connector'
}
implementation 'com.burhanrashid52:photoeditor:1.5.1'
implementation 'androidx.multidex:multidex:2.0.1'
implementation 'com.github.PhilJay:MPAndroidChart:v3.1.0'
implementation 'androidx.lifecycle:lifecycle-livedata:2.4.1'
implementation 'androidx.lifecycle:lifecycle-viewmodel:2.4.1'
implementation 'androidx.navigation:navigation-fragment:2.4.2'
implementation 'androidx.navigation:navigation-ui:2.4.2'
implementation 'androidx.lifecycle:lifecycle-livedata:2.5.1'
implementation 'androidx.lifecycle:lifecycle-viewmodel:2.5.1'
implementation 'androidx.navigation:navigation-fragment:2.5.3'
implementation 'androidx.navigation:navigation-ui:2.5.3'
testImplementation 'junit:junit:'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
// debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.8.1'
androidTestImplementation 'androidx.test.ext:junit:1.1.4'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.0'
// debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.8.1'
implementation 'com.r0adkll:slidableactivity:2.1.0'
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
implementation 'androidx.vectordrawable:vectordrawable:1.1.0'
implementation "androidx.fragment:fragment:1.5.5"
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
implementation 'androidx.browser:browser:1.4.0'
implementation 'androidx.documentfile:documentfile:1.0.1'
implementation 'com.github.amoskorir:avatarimagegenerator:1.5.0'
implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.1.0'
implementation 'com.google.android.exoplayer:extension-mediasession:2.18.1'
implementation "com.github.mabbas007:TagsEditText:1.0.5"
implementation "net.gotev:uploadservice:4.7.0"
implementation "net.gotev:uploadservice-okhttp:4.7.0"
implementation 'androidx.media:media:1.6.0'
implementation 'com.github.mancj:MaterialSearchBar:0.8.5'
implementation 'com.github.vkay94:DoubleTapPlayerView:1.0.0'
//************ CAST **************///
//---> Google libs (google_full)
playstoreImplementation "com.google.android.gms:play-services-cast-tv:19.0.1"
playstoreImplementation "com.google.android.gms:play-services-cast:21.0.1"
playstoreImplementation "androidx.mediarouter:mediarouter:1.3.0"
playstoreImplementation 'com.google.android.gms:play-services-cast-framework:21.0.1'
playstoreImplementation "com.google.android.gms:play-services-cast-tv:19.0.1"
playstoreImplementation "com.google.android.gms:play-services-cast:21.0.1"
playstoreImplementation "androidx.mediarouter:mediarouter:1.3.0"
playstoreImplementation 'com.google.android.gms:play-services-cast-framework:21.0.1'
//----> Other flavors
fdroidImplementation 'su.litvak.chromecast:api-v2:0.11.3'
fdroidImplementation 'com.fasterxml.jackson.core:jackson-core:2.12.0'
fdroidImplementation 'org.slf4j:slf4j-simple:1.7.30'
fdroidImplementation 'com.github.evozi:Cyanea:1.0.7'
fdroidImplementation 'su.litvak.chromecast:api-v2:0.11.3'
fdroidImplementation 'com.fasterxml.jackson.core:jackson-core:2.12.0'
fdroidImplementation 'org.slf4j:slf4j-simple:1.7.30'
}
def getCurrentFlavor() {
Gradle gradle = getGradle()
String tskReqStr = gradle.getStartParameter().getTaskRequests().toString()
println("tskReqStr:" +tskReqStr)
Pattern pattern
if( tskReqStr.contains( "assemble" ) ) // to run ./gradlew assembleRelease to build APK
pattern = Pattern.compile("assemble(\\w+)(Release|Debug)")
else if( tskReqStr.contains( "bundle" ) ) // to run ./gradlew bundleRelease to build .aab
pattern = Pattern.compile("assemble(\\w+)(Release|Debug)")
else
pattern = Pattern.compile("generate(\\w+)(Release|Debug)")
Matcher matcher = pattern.matcher( tskReqStr )
println(tskReqStr)
if( matcher.find() )
return matcher.group(1).toLowerCase()
else
{
println "NO MATCH FOUND"
return ""
}
}
println("Flavor: ${getCurrentFlavor()}")
if ( getCurrentFlavor() == "playstore" ){
apply plugin: 'com.google.gms.google-services'
}

View file

@ -1,15 +1,15 @@
package app.fedilab.android;
import static org.junit.Assert.assertEquals;
import android.content.Context;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.platform.app.InstrumentationRegistry;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
/**
* Instrumented test, which will execute on an Android device.
*

View file

@ -0,0 +1,68 @@
{
"project_info": {
"project_number": "479837431022",
"project_id": "pc-api-4835782490875392372-140",
"storage_bucket": "pc-api-4835782490875392372-140.appspot.com"
},
"client": [
{
"client_info": {
"mobilesdk_app_id": "1:479837431022:android:1102a97a55202beb547fff",
"android_client_info": {
"package_name": "app.fedilab.android"
}
},
"oauth_client": [
{
"client_id": "479837431022-mettpakdcso72c35djvikfc57l4i7n53.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyCklTEEgLUxy__0Vzcr5_H179kYPXGjmGo"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": [
{
"client_id": "479837431022-mettpakdcso72c35djvikfc57l4i7n53.apps.googleusercontent.com",
"client_type": 3
}
]
}
}
},
{
"client_info": {
"mobilesdk_app_id": "1:479837431022:android:529536f519b8f4ce547fff",
"android_client_info": {
"package_name": "app.fedilab.android.debug"
}
},
"oauth_client": [
{
"client_id": "479837431022-mettpakdcso72c35djvikfc57l4i7n53.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyCklTEEgLUxy__0Vzcr5_H179kYPXGjmGo"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": [
{
"client_id": "479837431022-mettpakdcso72c35djvikfc57l4i7n53.apps.googleusercontent.com",
"client_type": 3
}
]
}
}
}
],
"configuration_version": "1"
}

View file

@ -0,0 +1,3 @@
<resources>
<string name="app_name" translatable="false">Fedilab dbg</string>
</resources>

View file

@ -0,0 +1,19 @@
<shortcuts xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<shortcut
android:shortcutId="compose"
android:enabled="true"
android:icon="@drawable/ic_baseline_add_comment_24"
android:shortcutShortLabel="@string/compose_shortcut_short_label1"
tools:targetApi="n_mr1">
<intent
android:action="app.fedilab.android.shorcut.compose"
android:targetClass="app.fedilab.android.activities.MainActivity"
android:targetPackage="fr.gouv.etalab.mastodon.debug" />
<categories android:name="android.shortcut.conversation" />
<capability-binding android:key="actions.intent.CREATE_MESSAGE" />
</shortcut>
</shortcuts>

View file

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path
name="my_images"
path="Android/data/fr.gouv.etalab.mastodon.debug/files/Pictures" />
<cache-path
name="*"
path="." />
</paths>

View file

@ -0,0 +1,211 @@
package app.fedilab.android.activities;
/* Copyright 2023 Thomas Schneider
*
* This file is a part of Fedilab
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* Fedilab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see <http://www.gnu.org/licenses>. */
import static app.fedilab.android.peertube.helper.Helper.CAST_ID;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.webkit.MimeTypeMap;
import androidx.appcompat.app.AlertDialog;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import org.jetbrains.annotations.NotNull;
import java.io.IOException;
import java.security.GeneralSecurityException;
import app.fedilab.android.R;
import app.fedilab.android.databinding.ActivityPeertubeBinding;
import app.fedilab.android.mastodon.activities.BaseBarActivity;
import app.fedilab.android.peertube.client.data.VideoData;
import app.fedilab.android.peertube.helper.Helper;
import su.litvak.chromecast.api.v2.ChromeCast;
import su.litvak.chromecast.api.v2.MediaStatus;
import su.litvak.chromecast.api.v2.Status;
public class BasePeertubeActivity extends BaseBarActivity {
protected ActivityPeertubeBinding binding;
protected VideoData.Video peertube;
protected ExoPlayer player;
protected String videoURL;
protected String subtitlesStr;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityPeertubeBinding.inflate(getLayoutInflater());
View view = binding.getRoot();
setContentView(view);
binding.minController.castPlay.setOnClickListener(v -> {
binding.minController.castLoader.setVisibility(View.VISIBLE);
if (PeertubeBaseMainActivity.chromeCast != null) {
new Thread(() -> {
try {
int icon = -1;
if (PeertubeBaseMainActivity.chromeCast.getMediaStatus().playerState == MediaStatus.PlayerState.PLAYING) {
PeertubeBaseMainActivity.chromeCast.pause();
icon = R.drawable.ic_baseline_play_arrow_32;
} else if (PeertubeBaseMainActivity.chromeCast.getMediaStatus().playerState == MediaStatus.PlayerState.PAUSED) {
PeertubeBaseMainActivity.chromeCast.play();
icon = R.drawable.ic_baseline_pause_32;
}
if (icon != -1) {
Handler mainHandler = new Handler(Looper.getMainLooper());
int finalIcon = icon;
Runnable myRunnable = () -> binding.minController.castPlay.setImageResource(finalIcon);
mainHandler.post(myRunnable);
}
Handler mainHandler = new Handler(Looper.getMainLooper());
Runnable myRunnable = () -> binding.minController.castLoader.setVisibility(View.GONE);
mainHandler.post(myRunnable);
} catch (IOException e) {
e.printStackTrace();
}
}).start();
}
});
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.action_cast) {
if (PeertubeBaseMainActivity.chromeCasts != null && PeertubeBaseMainActivity.chromeCasts.size() > 0) {
String[] chromecast_choice = new String[PeertubeBaseMainActivity.chromeCasts.size()];
AlertDialog.Builder alt_bld = new MaterialAlertDialogBuilder(this);
alt_bld.setTitle(R.string.chromecast_choice);
int i = 0;
for (ChromeCast cc : PeertubeBaseMainActivity.chromeCasts) {
chromecast_choice[i] = cc.getTitle();
i++;
}
i = 0;
for (ChromeCast cc : PeertubeBaseMainActivity.chromeCasts) {
if (PeertubeBaseMainActivity.chromecastActivated && cc.isConnected()) {
break;
}
i++;
}
alt_bld.setSingleChoiceItems(chromecast_choice, i, (dialog, position) -> {
PeertubeBaseMainActivity.chromeCast = PeertubeBaseMainActivity.chromeCasts.get(position);
new Thread(() -> {
if (PeertubeBaseMainActivity.chromeCast != null) {
Intent intentBC = new Intent(Helper.RECEIVE_CAST_SETTINGS);
Bundle b = new Bundle();
if (PeertubeBaseMainActivity.chromecastActivated) {
b.putInt("displayed", 0);
intentBC.putExtras(b);
LocalBroadcastManager.getInstance(BasePeertubeActivity.this).sendBroadcast(intentBC);
Handler mainHandler = new Handler(Looper.getMainLooper());
Runnable myRunnable = () -> {
binding.doubleTapPlayerView.setVisibility(View.VISIBLE);
binding.minController.castMiniController.setVisibility(View.GONE);
};
mainHandler.post(myRunnable);
} else {
b.putInt("displayed", 1);
b.putSerializable("castedTube", peertube);
intentBC.putExtras(b);
LocalBroadcastManager.getInstance(BasePeertubeActivity.this).sendBroadcast(intentBC);
try {
Handler mainHandler = new Handler(Looper.getMainLooper());
Runnable myRunnable = () -> {
invalidateOptionsMenu();
binding.minController.castLoader.setVisibility(View.VISIBLE);
player.setPlayWhenReady(false);
binding.doubleTapPlayerView.setVisibility(View.GONE);
binding.minController.castMiniController.setVisibility(View.VISIBLE);
dialog.dismiss();
if (videoURL != null) {
if (player != null && player.getCurrentPosition() > 0) {
videoURL += "?start=" + (player.getCurrentPosition() / 1000);
}
}
};
mainHandler.post(myRunnable);
if (!PeertubeBaseMainActivity.chromeCast.isConnected()) {
PeertubeBaseMainActivity.chromeCast.connect();
}
myRunnable = this::invalidateOptionsMenu;
mainHandler.post(myRunnable);
Status status = PeertubeBaseMainActivity.chromeCast.getStatus();
if (PeertubeBaseMainActivity.chromeCast.isAppAvailable(CAST_ID) && !status.isAppRunning(CAST_ID)) {
PeertubeBaseMainActivity.chromeCast.launchApp(CAST_ID);
}
if (videoURL != null) {
String mime = MimeTypeMap.getFileExtensionFromUrl(videoURL);
PeertubeBaseMainActivity.chromeCast.setRequestTimeout(60000);
PeertubeBaseMainActivity.chromeCast.load(peertube.getTitle(), null, videoURL, mime);
PeertubeBaseMainActivity.chromeCast.play();
binding.minController.castPlay.setImageResource(R.drawable.ic_baseline_pause_32);
}
myRunnable = () -> binding.minController.castLoader.setVisibility(View.GONE);
mainHandler.post(myRunnable);
} catch (IOException | GeneralSecurityException e) {
e.printStackTrace();
}
}
Handler mainHandler = new Handler(Looper.getMainLooper());
Runnable myRunnable = () -> {
invalidateOptionsMenu();
dialog.dismiss();
};
mainHandler.post(myRunnable);
}
}).start();
});
alt_bld.setPositiveButton(R.string.close, (dialog, id) -> dialog.dismiss());
AlertDialog alert = alt_bld.create();
alert.show();
}
}
return super.onOptionsItemSelected(item);
}
@Override
public boolean onCreateOptionsMenu(@NotNull Menu menu) {
getMenuInflater().inflate(R.menu.video_menu, menu);
MenuItem castItem = menu.findItem(R.id.action_cast);
if (PeertubeBaseMainActivity.chromeCasts != null && PeertubeBaseMainActivity.chromeCasts.size() > 0) {
castItem.setVisible(true);
if (PeertubeBaseMainActivity.chromeCast != null && PeertubeBaseMainActivity.chromeCast.isConnected()) {
castItem.setIcon(R.drawable.ic_baseline_cast_connected_24);
} else {
castItem.setIcon(R.drawable.ic_baseline_cast_24);
}
}
return true;
}
}

View file

@ -0,0 +1,263 @@
package app.fedilab.android.activities;
/* Copyright 2023 Thomas Schneider
*
* This file is a part of Fedilab
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* Fedilab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see <http://www.gnu.org/licenses>. */
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.view.View;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import java.io.IOException;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import app.fedilab.android.R;
import app.fedilab.android.databinding.ActivityMainPeertubeBinding;
import app.fedilab.android.mastodon.activities.BaseActivity;
import app.fedilab.android.peertube.client.data.VideoData;
import app.fedilab.android.peertube.helper.Helper;
import su.litvak.chromecast.api.v2.ChromeCast;
import su.litvak.chromecast.api.v2.ChromeCasts;
import su.litvak.chromecast.api.v2.ChromeCastsListener;
import su.litvak.chromecast.api.v2.MediaStatus;
public abstract class PeertubeBaseMainActivity extends BaseActivity implements ChromeCastsListener {
public static List<ChromeCast> chromeCasts;
public static ChromeCast chromeCast;
public static boolean chromecastActivated = false;
protected ActivityMainPeertubeBinding binding;
private BroadcastReceiver manage_chromecast;
private VideoData.Video castedTube;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityMainPeertubeBinding.inflate(getLayoutInflater());
View view = binding.getRoot();
setContentView(view);
ChromeCastsListener chromeCastsListener = this;
ChromeCasts.registerListener(chromeCastsListener);
binding.castClose.setOnClickListener(v -> {
Intent intentBC = new Intent(Helper.RECEIVE_CAST_SETTINGS);
Bundle b = new Bundle();
b.putInt("displayed", 0);
intentBC.putExtras(b);
LocalBroadcastManager.getInstance(PeertubeBaseMainActivity.this).sendBroadcast(intentBC);
});
binding.castTogglePlay.setOnClickListener(v -> {
if (chromeCast != null) {
new Thread(() -> {
try {
Handler mainHandler = new Handler(Looper.getMainLooper());
Runnable myRunnable = () -> binding.castTogglePlay.setVisibility(View.GONE);
mainHandler.post(myRunnable);
int icon = -1;
if (chromeCast.getMediaStatus().playerState == MediaStatus.PlayerState.PLAYING) {
chromeCast.pause();
icon = R.drawable.ic_baseline_play_arrow_32;
} else if (chromeCast.getMediaStatus().playerState == MediaStatus.PlayerState.PAUSED) {
chromeCast.play();
icon = R.drawable.ic_baseline_pause_32;
}
if (icon != -1) {
int finalIcon = icon;
myRunnable = () -> binding.castTogglePlay.setImageResource(finalIcon);
mainHandler.post(myRunnable);
}
myRunnable = () -> binding.castTogglePlay.setVisibility(View.VISIBLE);
mainHandler.post(myRunnable);
} catch (IOException e) {
e.printStackTrace();
}
}).start();
}
});
manage_chromecast = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Bundle b = intent.getExtras();
assert b != null;
int state = b.getInt("state_asked", -1);
int displayed = b.getInt("displayed", -1);
castedTube = (VideoData.Video) b.getSerializable("castedTube");
if (state == 1) {
discoverCast();
} else if (state == 0) {
new Thread(() -> {
try {
if (chromeCast != null) {
chromeCast.stopApp();
chromeCast.disconnect();
}
} catch (IOException e) {
e.printStackTrace();
}
}).start();
}
if (displayed == 1) {
chromecastActivated = true;
if (castedTube != null) {
binding.castInfo.setVisibility(View.VISIBLE);
Helper.loadGiF(PeertubeBaseMainActivity.this, castedTube.getThumbnailPath(), binding.castView);
binding.castTitle.setText(castedTube.getTitle());
binding.castDescription.setText(castedTube.getDescription());
}
} else if (displayed == 0) {
chromecastActivated = false;
binding.castInfo.setVisibility(View.GONE);
new Thread(() -> {
try {
if (chromeCast != null) {
chromeCast.stopApp();
}
} catch (IOException e) {
e.printStackTrace();
}
}).start();
}
}
};
LocalBroadcastManager.getInstance(PeertubeBaseMainActivity.this).registerReceiver(manage_chromecast, new IntentFilter(Helper.RECEIVE_CAST_SETTINGS));
}
@Override
public void newChromeCastDiscovered(ChromeCast chromeCast) {
if (chromeCasts == null) {
chromeCasts = new ArrayList<>();
chromeCasts.add(chromeCast);
} else {
boolean canBeAdded = true;
for (ChromeCast cast : chromeCasts) {
if (cast.getName().compareTo(chromeCast.getName()) == 0) {
canBeAdded = false;
break;
}
}
if (canBeAdded) {
chromeCasts.add(chromeCast);
}
}
try {
if (chromeCast.isAppRunning(Helper.CAST_ID) && chromeCast.getMediaStatus() != null && chromeCast.getMediaStatus().playerState != null) {
if (binding.castInfo.getVisibility() == View.GONE) {
binding.castInfo.setVisibility(View.VISIBLE);
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void chromeCastRemoved(ChromeCast chromeCast) {
}
@Override
public void onDestroy() {
super.onDestroy();
ChromeCasts.unregisterListener(this);
if (manage_chromecast != null) {
LocalBroadcastManager.getInstance(PeertubeBaseMainActivity.this).unregisterReceiver(manage_chromecast);
new Thread(() -> {
if (chromeCasts != null && chromeCasts.size() > 0) {
for (ChromeCast cast : chromeCasts) {
try {
cast.stopApp();
cast.disconnect();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}).start();
}
if (chromeCasts != null) {
chromeCasts = null;
}
if (chromeCast != null) {
chromeCast = null;
}
}
//Method for discovering cast devices
public void discoverCast() {
new Thread(() -> {
if (chromeCasts != null) {
for (ChromeCast cast : chromeCasts) {
try {
cast.disconnect();
} catch (IOException e) {
e.printStackTrace();
}
}
chromeCasts = null;
}
chromeCasts = new ArrayList<>();
try {
List<NetworkInterface> interfaces;
interfaces = Collections.list(NetworkInterface.getNetworkInterfaces());
for (NetworkInterface ni : interfaces) {
if ((!ni.isLoopback()) && ni.isUp() && (ni.getName().equals("wlan0"))) {
Enumeration<InetAddress> inetAddressEnumeration = ni.getInetAddresses();
while (inetAddressEnumeration.hasMoreElements()) {
InetAddress inetAddress = inetAddressEnumeration.nextElement();
ChromeCasts.restartDiscovery(inetAddress);
int tryFind = 0;
while (ChromeCasts.get().isEmpty() && tryFind < 5) {
try {
//noinspection BusyWait
Thread.sleep(1000);
tryFind++;
} catch (InterruptedException ignored) {
}
}
}
}
}
ChromeCasts.stopDiscovery();
Handler mainHandler = new Handler(Looper.getMainLooper());
Runnable myRunnable = this::invalidateOptionsMenu;
mainHandler.post(myRunnable);
} catch (IOException e) {
e.printStackTrace();
}
}).start();
}
}

View file

@ -0,0 +1,52 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/castMiniController"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/black"
android:visibility="gone">
<ImageView
android:id="@+id/cast_play"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/play"
android:src="@drawable/ic_baseline_play_arrow_32"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/cast_loader"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent">
<TextView
android:id="@+id/cast_loader_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/please_wait"
android:textColor="?colorAccent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/cast_loader_small"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ProgressBar
android:id="@+id/cast_loader_small"
android:layout_width="wrap_content"
android:layout_height="18dp"
android:layout_gravity="center"
android:layout_marginStart="5dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/cast_loader_text"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/action_cast"
android:icon="@drawable/ic_baseline_cast_24"
android:title="@string/cast"
android:visible="false"
app:showAsAction="always" />
</menu>

View file

@ -0,0 +1,19 @@
<shortcuts xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<shortcut
android:shortcutId="compose"
android:enabled="true"
android:icon="@drawable/ic_baseline_add_comment_24"
android:shortcutShortLabel="@string/compose_shortcut_short_label1"
tools:targetApi="n_mr1">
<intent
android:action="app.fedilab.android.shorcut.compose"
android:targetClass="app.fedilab.android.activities.MainActivity"
android:targetPackage="fr.gouv.etalab.mastodon" />
<categories android:name="android.shortcut.conversation" />
<capability-binding android:key="actions.intent.CREATE_MESSAGE" />
</shortcut>
</shortcuts>

View file

@ -2,7 +2,7 @@
<paths>
<external-path
name="my_images"
path="Android/data/fr.gouv.etalab.mastodon.test/files/Pictures" />
path="Android/data/fr.gouv.etalab.mastodon/files/Pictures" />
<cache-path
name="*"

View file

@ -3,7 +3,9 @@
xmlns:tools="http://schemas.android.com/tools"
package="app.fedilab.android">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
tools:ignore="ScopedStorage" />
@ -11,37 +13,171 @@
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-feature
android:name="android.hardware.camera"
android:required="false" />
<queries>
<intent>
<action android:name="android.media.action.IMAGE_CAPTURE" />
</intent>
</queries>
<application
android:name=".MainApplication"
tools:replace="android:allowBackup"
android:name="app.fedilab.android.MainApplication"
android:allowBackup="false"
android:icon="@mipmap/ic_launcher"
android:usesCleartextTraffic="true"
android:label="@string/app_name"
android:configChanges="orientation|screenSize"
android:roundIcon="@mipmap/ic_launcher_round"
android:icon="@mipmap/ic_launcher_bubbles"
android:label="@string/app_name"
android:largeHeap="true"
android:requestLegacyExternalStorage="true"
android:roundIcon="@mipmap/ic_launcher_bubbles_round"
android:supportsRtl="true"
android:theme="@style/AppThemeDark"
>
android:theme="@style/AppTheme"
android:usesCleartextTraffic="true"
tools:replace="android:allowBackup">
<activity
android:name=".activities.MainActivity"
android:configChanges="orientation|screenSize"
android:exported="true"
>
android:configChanges="orientation|screenSize|keyboardHidden|screenLayout|smallestScreenSize"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.LAUNCHER" />
<data android:mimeType="image/*" />
<data android:mimeType="video/*" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND_MULTIPLE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="image/*" />
<data android:mimeType="video/*" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<!-- The app is a good candidate for URL in https://domain.name/@xxxxxx-->
<!-- It should cover every URLs for statuses but some others not related to mastodon matching this scheme -->
<data
android:host="*"
android:pathPrefix="/@"
android:scheme="https" />
</intent-filter>
</activity>
<activity
<activity-alias
android:name=".activities.MainActivity.Bubbles"
android:enabled="true"
android:exported="true"
android:icon="@mipmap/ic_launcher_bubbles"
android:roundIcon="@mipmap/ic_launcher_bubbles_round"
android:targetActivity=".activities.MainActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data
android:name="android.app.shortcuts"
android:resource="@xml/compose_shortcuts" />
</activity-alias>
<activity-alias
android:name=".activities.MainActivity.Fediverse"
android:enabled="false"
android:exported="true"
android:icon="@mipmap/ic_launcher_fediverse"
android:roundIcon="@mipmap/ic_launcher_fediverse_round"
android:targetActivity=".activities.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data
android:name="android.app.shortcuts"
android:resource="@xml/compose_shortcuts" />
</activity-alias>
<activity-alias
android:name=".activities.MainActivity.Hero"
android:enabled="false"
android:exported="true"
android:icon="@mipmap/ic_launcher_hero"
android:roundIcon="@mipmap/ic_launcher_hero_round"
android:targetActivity=".activities.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data
android:name="android.app.shortcuts"
android:resource="@xml/compose_shortcuts" />
</activity-alias>
<activity-alias
android:name=".activities.MainActivity.Atom"
android:enabled="false"
android:exported="true"
android:icon="@mipmap/ic_launcher_atom"
android:roundIcon="@mipmap/ic_launcher_atom_round"
android:targetActivity=".activities.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data
android:name="android.app.shortcuts"
android:resource="@xml/compose_shortcuts" />
</activity-alias>
<activity-alias
android:name=".activities.MainActivity.BrainCrash"
android:enabled="false"
android:exported="true"
android:icon="@mipmap/ic_launcher_crash"
android:roundIcon="@mipmap/ic_launcher_crash_round"
android:targetActivity=".activities.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data
android:name="android.app.shortcuts"
android:resource="@xml/compose_shortcuts" />
</activity-alias>
<activity-alias
android:name=".activities.MainActivity.Mastalab"
android:enabled="false"
android:exported="true"
android:icon="@mipmap/ic_launcher_mastalab"
android:roundIcon="@mipmap/ic_launcher_mastalab_round"
android:targetActivity=".activities.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data
android:name="android.app.shortcuts"
android:resource="@xml/compose_shortcuts" />
</activity-alias>
<activity
android:name=".activities.LoginActivity"
android:configChanges="orientation|screenSize"
android:exported="true"
android:windowSoftInputMode="stateAlwaysHidden">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
@ -50,58 +186,71 @@
android:scheme="fedilab" />
</intent-filter>
</activity>
<activity
android:name=".activities.WebviewConnectActivity"
android:name=".mastodon.activities.StatusHistoryActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/status_history"
android:theme="@style/AppThemeBar" />
<activity
android:name=".mastodon.activities.ContextActivity"
android:configChanges="keyboardHidden|orientation|screenSize" />
<activity
android:name=".activities.ContextActivity"
android:name=".mastodon.activities.DraftActivity"
android:configChanges="keyboardHidden|orientation|screenSize" />
<activity
android:name=".activities.DraftActivity"
android:name=".mastodon.imageeditor.EditImageActivity"
android:configChanges="keyboardHidden|orientation|screenSize" />
<activity
android:name=".imageeditor.EditImageActivity"
android:configChanges="keyboardHidden|orientation|screenSize" />
<activity
android:name=".activities.ComposeActivity"
android:name=".mastodon.activities.ComposeActivity"
android:configChanges="orientation|screenSize"
android:label="@string/compose" />
<activity
android:name=".activities.StatusInfoActivity"
android:name=".mastodon.activities.StatusInfoActivity"
android:configChanges="keyboardHidden|orientation|screenSize" />
<activity
android:name=".activities.FollowRequestActivity"
android:name=".mastodon.activities.FollowRequestActivity"
android:configChanges="keyboardHidden|orientation|screenSize" />
<activity
android:name=".activities.WebviewActivity"
android:configChanges="keyboardHidden|orientation|screenSize" />
<activity
android:name=".activities.ProfileActivity"
android:name=".mastodon.activities.ProfileActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/account" />
<activity
android:name=".activities.AdminAccountActivity"
android:name=".mastodon.activities.admin.AdminAccountActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/account" />
<activity
android:name=".activities.ScheduledActivity"
android:name=".mastodon.activities.AccountReportActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/account"
android:theme="@style/AppThemeBar" />
<activity
android:name=".mastodon.activities.admin.AdminReportActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/report"
android:theme="@style/AppThemeBar" />
<activity
android:name=".mastodon.activities.ScheduledActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/scheduled" />
<activity
android:name="com.theartofdev.edmodo.cropper.CropImageActivity"
android:name="com.canhub.cropper.CropImageActivity"
android:theme="@style/Base.Theme.AppCompat" />
<service
android:name=".services.PostMessageService"
android:label="@string/post_message" />
<activity
android:name=".activities.SearchResultTabActivity"
android:name=".mastodon.activities.SearchResultTabActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:theme="@style/AppThemeBar"
android:label="@string/search" />
android:label="@string/search"
android:theme="@style/AppThemeBar" />
<activity
android:name=".activities.ReorderTimelinesActivity"
android:name=".mastodon.activities.TrendsActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/trending"
android:theme="@style/AppThemeBar" />
<activity
android:name=".mastodon.activities.ReorderTimelinesActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/reorder_timelines"
android:theme="@style/AppThemeBar" />
@ -112,84 +261,86 @@
android:theme="@style/AppThemeBar" />
<activity
android:name=".activities.PartnerShipActivity"
android:name=".mastodon.activities.admin.AdminDomainBlockActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/blocked_domains"
android:theme="@style/AppThemeBar" />
<activity
android:name=".mastodon.activities.SuggestionActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/Suggestions"
android:theme="@style/AppThemeBar" />
<activity
android:name=".mastodon.activities.DirectoryActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/Directory"
android:theme="@style/AppThemeBar" />
<activity
android:name=".mastodon.activities.PartnerShipActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/action_about"
android:theme="@style/AppThemeBar" />
<activity
android:name=".activities.ActionActivity"
android:name=".mastodon.activities.ActionActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/interactions"
android:theme="@style/AppThemeBar" />
<activity
android:name=".activities.AdminActionActivity"
android:name=".mastodon.activities.admin.AdminActionActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/administration"
android:theme="@style/AppThemeBar" />
<activity
android:name=".activities.MastodonListActivity"
android:name=".mastodon.activities.MastodonListActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/action_lists"
android:theme="@style/AppThemeBar" />
<activity
android:name=".activities.SettingsActivity"
android:name=".mastodon.activities.FollowedTagActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/followed_tags"
android:theme="@style/AppThemeBar" />
<activity
android:name=".mastodon.activities.SettingsActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/settings"
android:theme="@style/AppThemeBar" />
<activity
android:name=".activities.InstanceActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/action_about_instance"
android:theme="@style/DialogDark" />
<activity
android:name=".activities.InstanceProfileActivity"
android:excludeFromRecents="true"
android:theme="@style/DialogDark" />
<activity
android:name=".activities.ProxyActivity"
android:excludeFromRecents="true"
android:theme="@style/DialogDark" />
<activity
android:name=".activities.HashTagActivity"
android:name=".mastodon.activities.HashTagActivity"
android:configChanges="keyboardHidden|orientation|screenSize" />
<activity
android:name=".activities.AnnouncementActivity"
android:name=".mastodon.activities.AnnouncementActivity"
android:configChanges="keyboardHidden|orientation|screenSize" />
<activity
android:name=".activities.MediaActivity"
android:name=".mastodon.activities.MediaActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:theme="@style/TransparentDark" />
android:theme="@style/Transparent" />
<activity
android:name=".activities.InstanceHealthActivity"
android:excludeFromRecents="true"
android:theme="@style/DialogDark" />
<activity
android:name=".activities.ReportActivity"
android:theme="@style/AppThemeBarDark"
android:name=".mastodon.activities.ReportActivity"
android:theme="@style/AppThemeBar"
android:windowSoftInputMode="stateVisible" />
<activity
android:name=".activities.CustomSharingActivity"
android:name=".mastodon.activities.CustomSharingActivity"
android:label="@string/settings_title_custom_sharing"
android:windowSoftInputMode="stateVisible"
android:theme="@style/AppThemeBarDark" />
<activity
android:name=".activities.FilterActivity"
android:label="@string/filters"
android:theme="@style/AppThemeBarDark"
android:theme="@style/AppThemeBar"
android:windowSoftInputMode="stateVisible" />
<activity
android:name=".activities.EditProfileActivity"
android:name=".mastodon.activities.FilterActivity"
android:label="@string/filters"
android:theme="@style/AppThemeBar"
android:windowSoftInputMode="stateVisible" />
<activity
android:name=".mastodon.activities.EditProfileActivity"
android:label="@string/edit_profile"
android:theme="@style/AppThemeBarDark"
android:theme="@style/AppThemeBar"
android:windowSoftInputMode="stateVisible" />
<activity
android:name=".activities.CacheActivity"
android:name=".mastodon.activities.CacheActivity"
android:label="@string/action_cache"
android:theme="@style/AppThemeBarDark" />
android:theme="@style/AppThemeBar" />
<provider
android:name="androidx.core.content.FileProvider"
@ -202,7 +353,7 @@
</provider>
<receiver
android:name=".broadcastreceiver.ToastMessage"
android:name=".mastodon.broadcastreceiver.ToastMessage"
android:exported="false">
<intent-filter>
<action android:name="RECEIVE_TOAST_MESSAGE" />
@ -210,7 +361,7 @@
</receiver>
<receiver
android:name=".services.CustomReceiver"
android:name=".mastodon.services.CustomReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
@ -221,5 +372,105 @@
<action android:name="org.unifiedpush.android.connector.REGISTRATION_REFUSED" />
</intent-filter>
</receiver>
<activity
android:name=".peertube.activities.PeertubeMainActivity"
android:configChanges="keyboardHidden|orientation|screenSize" />
<activity
android:name=".peertube.activities.PeertubeActivity"
android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"
android:launchMode="singleTask"
android:resizeableActivity="true"
android:supportsPictureInPicture="true"
tools:targetApi="n" />
<activity
android:name=".peertube.activities.PeertubeEditUploadActivity"
android:configChanges="orientation|screenSize"
android:exported="false"
android:windowSoftInputMode="stateAlwaysHidden" />
<activity
android:name=".peertube.activities.ShowChannelActivity"
android:configChanges="orientation|screenSize"
android:windowSoftInputMode="stateAlwaysHidden" />
<activity
android:name=".peertube.activities.ShowAccountActivity"
android:configChanges="orientation|screenSize"
android:windowSoftInputMode="stateAlwaysHidden" />
<activity
android:name=".peertube.activities.AccountActivity"
android:configChanges="orientation|screenSize"
android:windowSoftInputMode="stateAlwaysHidden" />
<activity
android:name=".peertube.activities.MyAccountActivity"
android:configChanges="orientation|screenSize"
android:windowSoftInputMode="stateAlwaysHidden" />
<activity
android:name=".peertube.activities.SearchActivity"
android:configChanges="orientation|screenSize"
android:windowSoftInputMode="stateAlwaysHidden" />
<activity
android:name=".peertube.activities.AllPlaylistsActivity"
android:configChanges="orientation|screenSize"
android:windowSoftInputMode="stateAlwaysHidden" />
<activity
android:name=".peertube.activities.AllLocalPlaylistsActivity"
android:configChanges="orientation|screenSize"
android:windowSoftInputMode="stateAlwaysHidden" />
<activity
android:name=".peertube.activities.PlaylistsActivity"
android:configChanges="orientation|screenSize"
android:windowSoftInputMode="stateAlwaysHidden" />
<activity
android:name=".peertube.activities.VideosTimelineActivity"
android:configChanges="orientation|screenSize"
android:windowSoftInputMode="stateAlwaysHidden" />
<activity
android:name=".peertube.activities.SepiaSearchActivity"
android:configChanges="orientation|screenSize"
android:label="@string/sepia_search"
android:windowSoftInputMode="stateAlwaysHidden" />
<activity
android:name=".peertube.activities.ManageInstancesActivity"
android:configChanges="orientation|screenSize"
android:label="@string/instances_picker"
android:windowSoftInputMode="stateAlwaysHidden" />
<activity
android:name=".peertube.activities.WebviewActivity"
android:configChanges="keyboardHidden|orientation|screenSize" />
<activity
android:name=".peertube.activities.LoginActivity"
android:configChanges="orientation|screenSize"
android:exported="true"
android:windowSoftInputMode="stateAlwaysHidden">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:host="backtotubelab"
android:scheme="tubelab" />
</intent-filter>
</activity>
<activity
android:name=".peertube.activities.SettingsActivity"
android:configChanges="orientation|screenSize"
android:label="@string/settings"
android:windowSoftInputMode="stateAlwaysHidden" />
<activity
android:name=".peertube.activities.PeertubeUploadActivity"
android:configChanges="orientation|screenSize"
android:label="@string/upload_video"
android:windowSoftInputMode="stateAlwaysHidden" />
<service
android:name=".peertube.services.RetrieveInfoService"
android:exported="false" />
</application>
</manifest>

View file

@ -0,0 +1,20 @@
{
"1": "Music",
"2": "Films",
"3": "Vehicles",
"4": "Art",
"5": "Sports",
"6": "Travels",
"7": "Gaming",
"8": "People",
"9": "Comedy",
"10": "Entertainment",
"11": "News & Politics",
"12": "How To",
"13": "Education",
"14": "Activism",
"15": "Science & Technology",
"16": "Animals",
"17": "Kids",
"18": "Food"
}

View file

@ -0,0 +1,199 @@
{
"aa": "Afar",
"ab": "Abkhazian",
"af": "Afrikaans",
"ak": "Akan",
"am": "Amharic",
"ar": "Arabic",
"an": "Aragonese",
"ase": "American Sign Language",
"as": "Assamese",
"av": "Avaric",
"avk": "Kotava",
"ay": "Aymara",
"az": "Azerbaijani",
"ba": "Bashkir",
"bm": "Bambara",
"be": "Belarusian",
"bn": "Bengali",
"bfi": "British Sign Language",
"bi": "Bislama",
"bo": "Tibetan",
"bs": "Bosnian",
"br": "Breton",
"bg": "Bulgarian",
"bzs": "Brazilian Sign Language",
"ca": "Catalan",
"cs": "Czech",
"ch": "Chamorro",
"ce": "Chechen",
"cv": "Chuvash",
"kw": "Cornish",
"co": "Corsican",
"cr": "Cree",
"cse": "Czech Sign Language",
"csl": "Chinese Sign Language",
"cy": "Welsh",
"da": "Danish",
"de": "German",
"dv": "Dhivehi",
"dsl": "Danish Sign Language",
"dz": "Dzongkha",
"el": "Greek",
"en": "English",
"eo": "Esperanto",
"et": "Estonian",
"eu": "Basque",
"ee": "Ewe",
"fo": "Faroese",
"fa": "Persian",
"fj": "Fijian",
"fi": "Finnish",
"fr": "French",
"fy": "Western Frisian",
"fsl": "French Sign Language",
"ff": "Fulah",
"gd": "Scottish Gaelic",
"ga": "Irish",
"gl": "Galician",
"gv": "Manx",
"gn": "Guarani",
"gsg": "German Sign Language",
"gu": "Gujarati",
"ht": "Haitian",
"ha": "Hausa",
"sh": "Serbo-Croatian",
"he": "Hebrew",
"hz": "Herero",
"hi": "Hindi",
"ho": "Hiri Motu",
"hr": "Croatian",
"hu": "Hungarian",
"hy": "Armenian",
"ig": "Igbo",
"ii": "Sichuan Yi",
"iu": "Inuktitut",
"id": "Indonesian",
"ik": "Inupiaq",
"is": "Icelandic",
"it": "Italian",
"jv": "Javanese",
"jbo": "Lojban",
"ja": "Japanese",
"jsl": "Japanese Sign Language",
"kab": "Kabyle",
"kl": "Kalaallisut",
"kn": "Kannada",
"ks": "Kashmiri",
"ka": "Georgian",
"kr": "Kanuri",
"kk": "Kazakh",
"km": "Khmer",
"ki": "Kikuyu",
"rw": "Kinyarwanda",
"ky": "Kirghiz",
"kv": "Komi",
"kg": "Kongo",
"ko": "Korean",
"kj": "Kuanyama",
"ku": "Kurdish",
"lo": "Lao",
"la": "Latin",
"lv": "Latvian",
"li": "Limburgan",
"ln": "Lingala",
"lt": "Lithuanian",
"lb": "Luxembourgish",
"lu": "Luba-Katanga",
"lg": "Ganda",
"mh": "Marshallese",
"ml": "Malayalam",
"mr": "Marathi",
"mk": "Macedonian",
"mg": "Malagasy",
"mt": "Maltese",
"mn": "Mongolian",
"mi": "Maori",
"ms": "Malay (macrolanguage)",
"my": "Burmese",
"na": "Nauru",
"nv": "Navajo",
"nr": "South Ndebele",
"nd": "North Ndebele",
"ng": "Ndonga",
"ne": "Nepali (macrolanguage)",
"nl": "Dutch",
"nn": "Norwegian Nynorsk",
"nb": "Norwegian Bokmål",
"no": "Norwegian",
"ny": "Nyanja",
"oc": "Occitan",
"oj": "Ojibwa",
"or": "Oriya (macrolanguage)",
"om": "Oromo",
"os": "Ossetian",
"pa": "Panjabi",
"pks": "Pakistan Sign Language",
"pl": "Polish",
"pt": "Portuguese",
"ps": "Pushto",
"qu": "Quechua",
"rm": "Romansh",
"ro": "Romanian",
"rsl": "Russian Sign Language",
"rn": "Rundi",
"ru": "Russian",
"sg": "Sango",
"sdl": "Saudi Arabian Sign Language",
"sfs": "South African Sign Language",
"si": "Sinhala",
"sk": "Slovak",
"sl": "Slovenian",
"se": "Northern Sami",
"sm": "Samoan",
"sn": "Shona",
"sd": "Sindhi",
"so": "Somali",
"st": "Southern Sotho",
"es": "Spanish",
"sq": "Albanian",
"sc": "Sardinian",
"sr": "Serbian",
"ss": "Swati",
"su": "Sundanese",
"sw": "Swahili (macrolanguage)",
"sv": "Swedish",
"swl": "Swedish Sign Language",
"ty": "Tahitian",
"ta": "Tamil",
"tt": "Tatar",
"te": "Telugu",
"tg": "Tajik",
"tl": "Tagalog",
"th": "Thai",
"ti": "Tigrinya",
"tlh": "Klingon",
"to": "Tonga (Tonga Islands)",
"tn": "Tswana",
"ts": "Tsonga",
"tk": "Turkmen",
"tr": "Turkish",
"tw": "Twi",
"ug": "Uighur",
"uk": "Ukrainian",
"ur": "Urdu",
"uz": "Uzbek",
"ve": "Venda",
"vi": "Vietnamese",
"wa": "Walloon",
"wo": "Wolof",
"xh": "Xhosa",
"yi": "Yiddish",
"yo": "Yoruba",
"za": "Zhuang",
"zh": "Chinese",
"zu": "Zulu",
"zxx": "No linguistic content",
"zh-Hans": "Simplified Chinese",
"zh-Hant": "Traditional Chinese"
}

View file

@ -0,0 +1,730 @@
[
{
"code": "aa",
"language": "Afaraf"
},
{
"code": "ab",
"language": "аҧсуа бызшәа"
},
{
"code": "ae",
"language": "avesta"
},
{
"code": "af",
"language": "Afrikaans"
},
{
"code": "ak",
"language": "Akan"
},
{
"code": "am",
"language": "አማርኛ"
},
{
"code": "an",
"language": "aragonés"
},
{
"code": "ar",
"language": "اللغة العربية"
},
{
"code": "as",
"language": "অসমীয়া"
},
{
"code": "av",
"language": "авар мацӀ"
},
{
"code": "ay",
"language": "aymar aru"
},
{
"code": "az",
"language": "azərbaycan dili"
},
{
"code": "ba",
"language": "башҡорт теле"
},
{
"code": "be",
"language": "беларуская мова"
},
{
"code": "bg",
"language": "български език"
},
{
"code": "bh",
"language": "भोजपुरी"
},
{
"code": "bi",
"language": "Bislama"
},
{
"code": "bm",
"language": "bamanankan"
},
{
"code": "bn",
"language": "বাংলা"
},
{
"code": "bo",
"language": "བོད་ཡིག"
},
{
"code": "br",
"language": "brezhoneg"
},
{
"code": "bs",
"language": "bosanski jezik"
},
{
"code": "ca",
"language": "Català"
},
{
"code": "ce",
"language": "нохчийн мотт"
},
{
"code": "ch",
"language": "Chamoru"
},
{
"code": "co",
"language": "corsu"
},
{
"code": "cr",
"language": "ᓀᐦᐃᔭᐍᐏᐣ"
},
{
"code": "cs",
"language": "čeština"
},
{
"code": "cu",
"language": "ѩзыкъ словѣньскъ"
},
{
"code": "cv",
"language": "чӑваш чӗлхи"
},
{
"code": "cy",
"language": "Cymraeg"
},
{
"code": "da",
"language": "dansk"
},
{
"code": "de",
"language": "Deutsch"
},
{
"code": "dv",
"language": "Dhivehi"
},
{
"code": "dz",
"language": "རྫོང་ཁ"
},
{
"code": "ee",
"language": "Eʋegbe"
},
{
"code": "el",
"language": "Ελληνικά"
},
{
"code": "en",
"language": "English"
},
{
"code": "eo",
"language": "Esperanto"
},
{
"code": "es",
"language": "Español"
},
{
"code": "et",
"language": "eesti"
},
{
"code": "eu",
"language": "euskara"
},
{
"code": "fa",
"language": "فارسی"
},
{
"code": "ff",
"language": "Fulfulde"
},
{
"code": "fi",
"language": "suomi"
},
{
"code": "fj",
"language": "Vakaviti"
},
{
"code": "fo",
"language": "føroyskt"
},
{
"code": "fr",
"language": "Français"
},
{
"code": "fy",
"language": "Frysk"
},
{
"code": "ga",
"language": "Gaeilge"
},
{
"code": "gd",
"language": "Gàidhlig"
},
{
"code": "gl",
"language": "galego"
},
{
"code": "gu",
"language": "ગુજરાતી"
},
{
"code": "gv",
"language": "Gaelg"
},
{
"code": "ha",
"language": "هَوُسَ"
},
{
"code": "he",
"language": "עברית"
},
{
"code": "hi",
"language": "हिन्दी"
},
{
"code": "ho",
"language": "Hiri Motu"
},
{
"code": "hr",
"language": "Hrvatski"
},
{
"code": "ht",
"language": "Kreyòl ayisyen"
},
{
"code": "hu",
"language": "magyar"
},
{
"code": "hy",
"language": "Հայերեն"
},
{
"code": "hz",
"language": "Otjiherero"
},
{
"code": "ia",
"language": "Interlingua"
},
{
"code": "id",
"language": "Bahasa Indonesia"
},
{
"code": "ie",
"language": "Interlingue"
},
{
"code": "ig",
"language": "Asụsụ Igbo"
},
{
"code": "ii",
"language": "ꆈꌠ꒿ Nuosuhxop"
},
{
"code": "ik",
"language": "Iñupiaq"
},
{
"code": "io",
"language": "Ido"
},
{
"code": "is",
"language": "Íslenska"
},
{
"code": "it",
"language": "Italiano"
},
{
"code": "iu",
"language": "ᐃᓄᒃᑎᑐᑦ"
},
{
"code": "ja",
"language": "日本語"
},
{
"code": "jv",
"language": "basa Jawa"
},
{
"code": "ka",
"language": "ქართული"
},
{
"code": "kg",
"language": "Kikongo"
},
{
"code": "ki",
"language": "Gĩkũyũ"
},
{
"code": "kj",
"language": "Kuanyama"
},
{
"code": "kk",
"language": "қазақ тілі"
},
{
"code": "kl",
"language": "kalaallisut"
},
{
"code": "km",
"language": "ខេមរភាសា"
},
{
"code": "kn",
"language": "ಕನ್ನಡ"
},
{
"code": "ko",
"language": "한국어"
},
{
"code": "kr",
"language": "Kanuri"
},
{
"code": "ks",
"language": "कश्मीरी"
},
{
"code": "ku",
"language": "Kurmancî"
},
{
"code": "kv",
"language": "коми кыв"
},
{
"code": "kw",
"language": "Kernewek"
},
{
"code": "ky",
"language": "Кыргызча"
},
{
"code": "la",
"language": "latine"
},
{
"code": "lb",
"language": "Lëtzebuergesch"
},
{
"code": "lg",
"language": "Luganda"
},
{
"code": "li",
"language": "Limburgs"
},
{
"code": "ln",
"language": "Lingála"
},
{
"code": "lo",
"language": "ພາສາ"
},
{
"code": "lt",
"language": "lietuvių kalba"
},
{
"code": "lu",
"language": "Tshiluba"
},
{
"code": "lv",
"language": "latviešu valoda"
},
{
"code": "mg",
"language": "fiteny malagasy"
},
{
"code": "mh",
"language": "Kajin M̧ajeļ"
},
{
"code": "mi",
"language": "te reo Māori"
},
{
"code": "mk",
"language": "македонски јазик"
},
{
"code": "ml",
"language": "മലയാളം"
},
{
"code": "mn",
"language": "Монгол хэл"
},
{
"code": "mr",
"language": "मराठी"
},
{
"code": "ms",
"language": "Bahasa Melayu"
},
{
"code": "mt",
"language": "Malti"
},
{
"code": "my",
"language": "ဗမာစာ"
},
{
"code": "na",
"language": "Ekakairũ Naoero"
},
{
"code": "nb",
"language": "Norsk bokmål"
},
{
"code": "nd",
"language": "isiNdebele"
},
{
"code": "ne",
"language": "नेपाली"
},
{
"code": "ng",
"language": "Owambo"
},
{
"code": "nl",
"language": "Nederlands"
},
{
"code": "nn",
"language": "Norsk Nynorsk"
},
{
"code": "no",
"language": "Norsk"
},
{
"code": "nr",
"language": "isiNdebele"
},
{
"code": "nv",
"language": "Diné bizaad"
},
{
"code": "ny",
"language": "chiCheŵa"
},
{
"code": "oc",
"language": "occitan"
},
{
"code": "oj",
"language": "ᐊᓂᔑᓈᐯᒧᐎᓐ"
},
{
"code": "om",
"language": "Afaan Oromoo"
},
{
"code": "or",
"language": "ଓଡ଼ିଆ"
},
{
"code": "os",
"language": "ирон æвзаг"
},
{
"code": "pa",
"language": "ਪੰਜਾਬੀ"
},
{
"code": "pi",
"language": "पाऴि"
},
{
"code": "pl",
"language": "Polski"
},
{
"code": "ps",
"language": "پښتو"
},
{
"code": "pt",
"language": "Português"
},
{
"code": "qu",
"language": "Runa Simi"
},
{
"code": "rm",
"language": "rumantsch grischun"
},
{
"code": "rn",
"language": "Ikirundi"
},
{
"code": "ro",
"language": "Română"
},
{
"code": "ru",
"language": "Русский"
},
{
"code": "rw",
"language": "Ikinyarwanda"
},
{
"code": "sa",
"language": "संस्कृतम्"
},
{
"code": "sc",
"language": "sardu"
},
{
"code": "sd",
"language": "सिन्धी"
},
{
"code": "se",
"language": "Davvisámegiella"
},
{
"code": "sg",
"language": "yângâ tî sängö"
},
{
"code": "si",
"language": "සිංහල"
},
{
"code": "sk",
"language": "slovenčina"
},
{
"code": "sl",
"language": "slovenščina"
},
{
"code": "sn",
"language": "chiShona"
},
{
"code": "so",
"language": "Soomaaliga"
},
{
"code": "sq",
"language": "Shqip"
},
{
"code": "sr",
"language": "српски језик"
},
{
"code": "ss",
"language": "SiSwati"
},
{
"code": "st",
"language": "Sesotho"
},
{
"code": "su",
"language": "Basa Sunda"
},
{
"code": "sv",
"language": "Svenska"
},
{
"code": "sw",
"language": "Kiswahili"
},
{
"code": "ta",
"language": "தமிழ்"
},
{
"code": "te",
"language": "తెలుగు"
},
{
"code": "tg",
"language": "тоҷикӣ"
},
{
"code": "th",
"language": "ไทย"
},
{
"code": "ti",
"language": "ትግርኛ"
},
{
"code": "tk",
"language": "Türkmen"
},
{
"code": "tl",
"language": "Wikang Tagalog"
},
{
"code": "tn",
"language": "Setswana"
},
{
"code": "to",
"language": "faka Tonga"
},
{
"code": "tr",
"language": "Türkçe"
},
{
"code": "ts",
"language": "Xitsonga"
},
{
"code": "tt",
"language": "татар теле"
},
{
"code": "tw",
"language": "Twi"
},
{
"code": "ty",
"language": "Reo Tahiti"
},
{
"code": "ug",
"language": "ئۇيغۇرچە‎"
},
{
"code": "uk",
"language": "Українська"
},
{
"code": "ur",
"language": "اردو"
},
{
"code": "uz",
"language": "Ўзбек"
},
{
"code": "ve",
"language": "Tshivenḓa"
},
{
"code": "vi",
"language": "Tiếng Việt"
},
{
"code": "vo",
"language": "Volapük"
},
{
"code": "wa",
"language": "walon"
},
{
"code": "wo",
"language": "Wollof"
},
{
"code": "xh",
"language": "isiXhosa"
},
{
"code": "yi",
"language": "ייִדיש"
},
{
"code": "yo",
"language": "Yorùbá"
},
{
"code": "za",
"language": "Saɯ cueŋƅ"
},
{
"code": "zh",
"language": "中文"
},
{
"code": "zu",
"language": "isiZulu"
}
]

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,392 @@
[
{
"version": "3.17.0",
"code": "477",
"note": "Added:\n- Peertube 2FA support\n- Cache home in background (default disabled -> New settings category and per account) / change frequency\n- Auto-fetch missing messages for the Home (default disabled -> in Settings - Timelines)\n- Automatically switch between tabs when searching\n- More deep links detection\n- Allow to group mentions at the top (default: disabled)\n\n\nFixed:\n- Dynamic color for Android 12+\n- Missing media description for previews\n- Fix a crash when replying\n- Fix button size not changed\n- Forward tags in replies\n- Media cannot be downloaded or shared with Android 10\n- Some crashes"
},
{
"version": "3.16.4",
"code": "476",
"note": "Added:\n- Cache home in background (default disabled -> New settings category and per account) / change frequency\n- Auto-fetch missing messages for the Home (default disabled -> in Settings - Timelines)\n- Automatically switch between tabs when searching\n\nFixed:\n- Some crashes"
},
{
"version": "3.16.3",
"code": "475",
"note": "Added:\n- Peertube 2FA support\n\nFixed:\n- Dynamic color for Android 12+"
},
{
"version": "3.16.2",
"code": "474",
"note": "Added:\n- Peertube support\n- Compose shortcut (long press launcher)\n- Long press compose button to write with another account\n- Edit description and focus for media (for the next Mastodon release)\n\nChanged:\n- Cross actions with two accounts display a dialog\n- Order & compact og values when sharing > title - url - content\n- Tap on top message (user info) open threads\n\nFixed:\n- Text cleared when adding a media\n- Fix Maths not working with quotes\n- Fix crashes"
},
{
"version": "3.16.1",
"code": "473",
"note": "Changed:\n- Edit description and focus for media (for the next Mastodon release)\n\nChanged:\n- Peertube: remove role support to avoid crashes with older instances\n\nFixed:\n- Fix some crashes"
},
{
"version": "3.16.0",
"code": "472",
"note": "Changed:\n- Peertube support\n- Compose shortcut\n- Long press compose button to write with another account\n\nChanged:\n- Cross actions with two accounts display a dialog\n- Order & compact og values when sharing > title - url - content\n\nFixed:\n- Text cleared when adding a media\n- Fix crashes"
},
{
"version": "3.15.2",
"code": "471",
"note": "Changed:\n- Add instance name when sharing\n\nFixed:\n- Fix a crash when removing media\n- Other minor fixes"
},
{
"version": "3.15.1",
"code": "470",
"note": "Changed:\n- Material dialogs\n\nFixed:\n- Light theme issues"
},
{
"version": "3.15.0",
"code": "469",
"note": "Added:\n- Maths support (view and compose)\n- Filter DMs in HOME (long press on the tab)\n- Filter languages for users in home timeline (from their profile)\n- Add several targeted languages for translator\n\nChanged:\n- Hide single media with preview is now a setting (default: disabled)\n- Group items in menu of messages\n\nFixed:\n- Cross-actions didn't display account instances"
},
{
"version": "3.14.6",
"code": "468",
"note": "Added:\n- Maths support (view and compose)\n\nChanged:\n- Hide single media with preview is now a setting (default: disabled)"
},
{
"version": "3.14.5",
"code": "467",
"note": "Changed:\n- Allow to swipe media for profiles\n\nFixed:\n- Fix crashes with pinch zoom\n- Copy/Paste in threads\n- Fix crash when checking redirection on http links\n- Display menu in media viewer resets pinch-zoom"
},
{
"version": "3.14.4",
"code": "466",
"note": "Changed:\n- Media viewer (pinch zoom)\n\nFixed:\n- Cross account actions (long press)\n- Boost color\n- Buttons not visible with custom themes.\n- Fix some bad behaviors with media viewer"
},
{
"version": "3.14.3",
"code": "465",
"note": "Added:\n- Display date of the message instead of the boost (default: disabled)\n- Allow to disable release notes popup in Settings\n\nFixed:\n- Fix timelines slow down and stuttering after some scrolls\n- Fix color issues with follow buttons\n- Fix import from settings (import from login was OK)"
},
{
"version": "3.14.2",
"code": "464",
"note": "Added:\n- Display familiar followers on profiles\n- Display and filter Instance directory\n\nChanged:\n- Bot and reply icon indicators more visible\n- Single media are hidden with link previews\n\nFixed:\n- Fix a crash with Art timelines\n- Friendica: media cannot be downloaded/shared\n- Fix a crash with pinned timelines"
},
{
"version": "3.14.1",
"code": "463",
"note": "Added:\n- Search bar: display suggestions when starting by \"@\" or \"#\"\n\nChanged:\n- Preload media in timelines to avoid jumps\n- Search: Automatically switch to account tab if no results for tags\n\nFixed:\n- Fix jumps with the fetch more feature\n- Fix videos cannot be saved\n- Tags cannot be pinned when there are no custom tabs\n- PixelFed view: NSFW not honored\n- Fix crashes"
},
{
"version": "3.14.0",
"code": "462",
"note": "Added:\n\n- Add Bubble timeline support in extra-features with filters\n- Allow to display public profiles by default to get all messages (Settings > Interface)\n- Glitch: Allow to post messages locally (Can be turned off in Settings)\n- Pixelfed: Custom layout to display Media fully (Also works for other software when there are media)\n- Allow to align left action buttons in messages\n\nChanged:\n- Full rework on links in messages (also mentions and tags)\n- Add pinned tag in \"any\" to avoid to lose it when renaming timeline\n\nFixed:\n- Links to messages not handled by the app\n- CW when editing a message\n- Fix push notifications with several accounts\n- New messages or edition notifications not pushed\n- Fix quotes with tags/mentions\n- Fix notifications\n- Fix sending multiple media\n- Fix crashes"
},
{
"version": "3.13.7",
"code": "461",
"note": "Added:\n- Pixelfed: Custom layout to display Media fully \n*(Settings > Timelines > Pixelfed Presentation) - Also works for other softwares when there are media\n\nChanged:\n- Add pinned tag in \"any\" to avoid to lose it when renaming timeline\n\nFixed:\n- Fix push notifications with several accounts\n- Fix quotes with tags/mentions\n- Fix notifications\n- Fix sending multiple media\n- Some crashes"
},
{
"version": "3.13.6",
"code": "460",
"note": "Fixed:\n- Cross-compose: Wrong instance emojis\n- Custom emojis not displayed in notifications\n- Fav/Boost markers with shared messages\n- Empty notifications\n- Fix cw removed when replying\n- Fix expand media with fit preview images when sensitive\n- Fix an issue with fetch more displayed too often (cache clear will help or wait new messages)"
},
{
"version": "3.13.5",
"code": "459",
"note": "Added:\n- Glitch: Allow to post messages locally (Can be turned off in Settings)\n\nFixed:\n- Crashes"
},
{
"version": "3.13.4",
"code": "458",
"note": "Added:\n- Add Bubble timeline support in extra-features with filters\n- Allow to display public profiles by default to get all messages (Settings > Interface)\n\nChanged:\n- Full rework on links in messages (also mentions and tags)\n\nFixed:\n- Spoiler text when editing\n- Fix watermarks"
},
{
"version": "3.13.3",
"code": "457",
"note": "Added:\n- Allow to enable extra features in Settings\n- Customizable settings for extra features\n- Support quotes, reactions with messages\n- Support text format (html, markdown, etc.) when composing\n\nFixed:\n- CW not working with media\n- Media not displayed for older instances\n- Some crashes\n"
},
{
"version": "3.13.2",
"code": "456",
"note": "Changed:\n- Hidden media smaller with preview images\n\nFixed:\n- Issue with Media for Android 11+\n- Crash when not setting a translation key\n- Fix DeepL for API pro\n- Crash when visiting a profile with a lot of media\n- Home muted accounts not working without filters\n- Animated custom emoji not displayed"
},
{
"version": "3.13.1",
"code": "455",
"note": "Added:\n- DeepL translation support free/pro keys\n\nChanged:\n- Hide buttons for media when editing\n\nFixed:\n- GIF loaded as static images\n- Suggested accounts cannot be followed"
},
{
"version": "3.13.0",
"code": "454",
"note": "Added:\n- Post random quotes\n- Group reblogs in home timeline\n- Rename Nitter timelines\n- Android 13 support\n- Pagination with search / trending\n- Allow to remove left margin in messages (default: disabled)\n\nChanged:\n- Display translate button only when language is different\n- Respect blank spaces between words in messages\n- Focus button more accessible when editing media\n- Visual feedback for block on account list\n- Visual changes with compose / top bar\n- Use custom Nitter timeline name in manage timelines\n\nFixed:\n- Behavior with cw toggle\n- Truncated gimini links\n- Nav buttons not visible with media (Light theme)\n- Status bar with Android 5\n- Fix links not clickable\n- Fix deep links\n- Fix remote threads not fetched for some instances\n- Adding description to shared media\n- Open with another accounts\n- Chars size not respected for Android 5-6\n- Wrong instance fetched for instances.social\n- Bouncing Timeline on refresh\n- Links to mentions, tags, urls, not visible.\n- Custom channel sounds not applied\n- users with short username are not linked\n- Fix crashes"
},
{
"version": "3.12.3",
"code": "453",
"note": "Added:\n- Pagination with search / trending\n\nFixed:\n- Long press on Nitter tabs\n- Open with another accounts\n- Chars size not respected for Android 5-6\n- Wrong instance fetched for instances.social"
},
{
"version": "3.12.2",
"code": "452",
"note": "Added:\n- Rename Nitter timelines\n- Android 13 support\n\nChanged:\n- Visual feedback for block on account list\n- Visual changes with compose / top bar\n\nFixed:\n- Nav buttons not visible with media (Light theme)\n- Status bar with Android 5\n- Fix links not clickable\n- Fix deep links\n- Fix remote threads not fetched for some instances\n- Adding description to shared media\n- Fix crashes"
},
{
"version": "3.12.1",
"code": "451",
"note": "Added:\n- Post random quotes\n- Group reblogs in home timeline\n\nChanged:\n- Display translate button only when language is different\n- Respect blank spaces between words in messages\n- Focus button more accessible when editing media\n\nFixed:\n- Behavior with cw toggle\n- Truncated gimini links"
},
{
"version": "3.12.0",
"code": "450",
"note": "Added:\n- Full data import/export feature\n- Android 13 themed icon support\n\nFixed:\n- Fix a regression with filters\n- Fix dark solarized theme\n- Fix hide link previews for CW\n- Fix status bar color for all themes\n- Fix language in compose \"...\"\n- Fix add all home muted accounts from lists\n- Fix top notification badges"
},
{
"version": "3.11.3",
"code": "449",
"note": "Added:\n- Add more targeted languages in picker for translations\n- Add account name in push notifications\n\nFixed:\n- Fix a crash when changing language\n- Fix counter colors\n- Fix default link color\n- Fix a crash when clicking on mentions"
},
{
"version": "3.11.2",
"code": "448",
"note": "Added:\n- Mute/Unmute accounts in the Home timeline from their messages or their profiles\n- Add all users from a list to \"Muted home\" in one click\n- Display/Manage users that are muted for home\n\nFixed:\n- Timeline crashes"
},
{
"version": "3.11.0",
"code": "446",
"note": "Added:\n- Display all messages in threads from remote instances (when possible)\n- Allow to unmute/unfollow/unpin a tag from tag timelines\n- Display most used accounts in header menu for an easy switch\n- Automatically add the tag when composing from a tag timeline\n- Add a translate button at the bottom of messages (default: disabled)\n- Add account role in profiles\n- Translate morse\n\nChanged:\n- Disable animations after a refresh\n\nFixed:\n- Contact not working when composing\n- Status bar for black theme\n- Message duplicated in conversations when edited\n- Color issue on Android 5\n- Several crashes"
},
{
"version": "3.10.2",
"code": "445",
"note": "Added:\n- Allow to unmute/unfollow/unpin a tag from tag timelines\n- Automatically add the tag when composing from a tag timeline\n- Add a translate button at the bottom of messages (default: disabled)\n- Add account role in profiles\n\nFixed:\n- Contact not working when composing\n- Status bar for black theme\n- Message duplicated in conversations when edited\n- Color issue on Android 5"
},
{
"version": "3.10.1",
"code": "444",
"note": "Added:\n- Display all messages in threads from remote instances (when possible)\n* Only public messages for instances using the Mastodon API\n* A dedicated button is displayed at the top right when conditions are filled."
},
{
"version": "3.10.0",
"code": "443",
"note": "Added:\n- Dracula theme\n- Customize message colors\n- Enable/Disable Card presentation\n\nChanged:\n- Colors for some themes\n- Space between buttons\n\nFixed:\n- Animated profile pictures not displayed\n- Mentions broken in profile bio and fields\n- Jumps with fit preview images when scrolling up\n- Fetch more button broken with cache\n- Tag patterns in URL break the link\n- Typo in followed tags"
},
{
"version": "3.9.7",
"code": "442",
"note": "Added:\n- Dracula theme\n\nChanged:\n- Colors for Light/Dark/Black themes\n\nFixed:\n- Animated profile pictures not displayed\n- Mentions broken in profile bio and fields\n- Tag patterns in URL break the link\n- Typo in followed tags"
},
{
"version": "3.9.6",
"code": "441",
"note": "Fixed:\n- Jumps with fit preview images when scrolling up\n- Fetch more button broken with cache"
},
{
"version": "3.9.5",
"code": "440",
"note": "Fixed:\n- Custom emoji are not always displayed\n- Jumps in timeline when using \"fit preview images\"\n- Dark theme: timeline buttons without toggle"
},
{
"version": "3.9.4",
"code": "439",
"note": "Changed:\n- Remove card presentation\n- Link color for black theme\n\nFixed:\n- Crash when changing the theme"
},
{
"version": "3.9.3",
"code": "438",
"note": "Added:\n- New design with 5 themes\n\nChanged:\n- Remove built-in browser support\n- Fit preview image displays images vertically\n- Add counters next to images\n\nFixed:\n- Jumps in timelines\n- Replies to wrong messages with followed instances\n- Bug with delete&redraft with a media\n- List cannot be hidden\n- Some crashes"
},
{
"version": "3.9.1",
"code": "436",
"note": "Changed:\n- Remove built-in browser support\n- More spaces between action buttons in messages\n\nFixed:\n- Text size issue\n- Text overlap\n- Wrong background for solarized black\n- Mix between light and dark theme\n- Save button hidden"
},
{
"version": "3.9.0",
"code": "435",
"note": "Added:\n- Migrate to Material Design 3\n- 5 Themes (Light, Dark, Solarized Light/Dark, Black)\n- Automatically switch between Light/Dark\n- Light and Dark theme can be defined for time-based switch\n- Android 12+: Dynamic color\n\nFixed:\n- Jumps in timelines\n"
},
{
"version": "3.8.1",
"code": "434",
"note": "Added:\n- Mute tags with long press in timelines\n\nChanged:\n- Muted account messages are now removed from cache\n\nFixed:\n- Open with another account\n- Fix jumps in profiles\n- Media not displayed in album -> force indexation\n- Built-in browser does not give admin scope\n- Some crashes"
},
{
"version": "3.8.0",
"code": "433",
"note": "Added:\n- List of blocked domains (allow to unblock)\n- Support gemini links\n- Suggested followers\n- Mod/Adm: Manage instance blocked domains\n- Open messages with another account\n- Allow to disable notifications for admins\n- Sort lists\n\nChanged:\n- Allow search term to be edited\n\nFixed:\n- Drafts deleted with no warning\n- Remove lists from \"Manage timelines\"\n- App crashes when proxy is set\n- Filter not synced after being edited\n- Some crashes / improvements"
},
{
"version": "3.7.5",
"code": "432",
"note": "Added:\n- List of blocked domains (allow to unblock)\n- Support gemini links\n- Suggested followers\n\nChanged:\n- Allow search term to be edited\n\nFixed:\n- Drafts deleted with no warning\n- App crashes when proxy is set\n- Filter not synced after being edited\n- Some crashes"
},
{
"version": "3.7.4",
"code": "431",
"note": "Added:\n- Full support to new filters for Mastodon 4\n- Visit profiles without being authenticated / Allow to display all their messages\n\nChanged:\n- Compose view takes the whole width even in threads\n- Accounts can be timed-mute from their profile\n\nFixed:\n- Draft stored when replying \"no\" or dialog prompted without changes\n- Empty pages when starting the app\n- Saving and sharing media fails on some devices\n- Add support for admin notifications\n- Copying content of a message"
},
{
"version": "3.7.3",
"code": "430",
"note": "Added:\n- Visit profiles without being authenticated / Allow to display all their messages\n\nFixed:\n- Saving media fails on some devices"
},
{
"version": "3.7.2",
"code": "429",
"note": "Added:\n- Full support to new filters for Mastodon 4"
},
{
"version": "3.7.1",
"code": "428",
"note": "Added:\n- Support to open links containing /@display_name/ in their path (works on older devices)\n- Display reply count when counters are enabled\n- Add support for filtering profile messages\n\nChanged:\n- Compose view takes the whole width even in threads\n- Reset push notification marker when clearing cache\n\nFixed:\n- Draft stored when replying \"no\" or dialog prompted without changes\n- Filters not working with tags\n- Add a specific error message for followed tags\n- Empty pages when starting the app"
},
{
"version": "3.7.0",
"code": "427",
"note": "Added:\n- Follow tags (dedicated entry in menu)\n- Reduce the list of languages when composing (Settings > Compose)\n- Language indicator when composing\n- Replies are automatically set to first message language\n- Two new Light themes\n- More moderation features\n- List name can be edited\n\nFixed:\n- Filter not working\n- Crash with trends\n- Issue with themes\n- Some content lost when sending messages (mentions)\n- Fix freezes in timelines\n- Some other fixes"
},
{
"version": "3.6.5",
"code": "426",
"note": "- Two new Light themes\n- More moderation features\n\nFixed:\n- Filter not working\n- Crash with trends\n- Some content lost when sending messages (mentions)\n- Some other fixes"
},
{
"version": "3.6.4",
"code": "425",
"note": "Changed:\n- Tag search ordered by popularity\n\nFixed:\n- Unable to get client ID on some devices\n- Issue with messages/notifications not correctly displayed\n- Notifications not received\n- Friendica: issues with mentions and tags (open browser)\n- Improve sharing behaviour"
},
{
"version": "3.6.3",
"code": "424",
"note": "Fixed:\n- Issue with messages/notifications not correctly displayed\n- Friendica: issues with mentions and tags (open browser)\n- Improve sharing behaviour\n"
},
{
"version": "3.6.2",
"code": "423",
"note": "Fixed:\n- Order of notifications\n- URL when sharing boosted message\n- Blank pages when restarting\n- Fix some crashes"
},
{
"version": "3.6.1",
"code": "422",
"note": "Added:\n- Display client in detailed messages\n- Visual support for quotes starting with \">\"\n- Increase indentations for threads (zero to 20, default 5)\n- Visibility for public replies set to unlisted (can be disabled)\n\nChanged:\n- Reduce title size when text size is increased\n\nFixed:\n- Filters are not applied\n- Blocking an account doesn't remove messages in cache\n- Fix some crashes"
},
{
"version": "3.6.0",
"code": "421",
"note": "Added:\n- Edit messages (if your instance supports that feature)\n- Pin/Unpin messages\n- Set the default language for translations\n- Change app icon (Settings > Interface)\n- Allow to disable \"remember position\" in timelines\n- Allow to disable notification aggregation in settings\n- Icon on media previews if a description is available\n\nChanged:\n- Allow to disable/enable media for notifications\n\nFixed:\n- Post loses \"spoiler message\" when adding a media\n- Camera not working on Android 11\n- Notification aggregation\n- Vibrations when fetching new notifications\n- Fix an issue with media timelines\n- Fix some theme issues\n- Fix an issue with built-in browser & openId\n- Bad behaviours with Art Timelines\n- Some crashes"
},
{
"version": "3.5.3",
"code": "420",
"note": "- Edit messages (if your instance support that feature)\n- Some fixes"
},
{
"version": "3.5.2",
"code": "419",
"note": "Added:\n- Pin/Unpin messages\n- Set the default language for translations\n\nChanged:\n- Allow to disable/enable media for notifications\n\nFixed:\n- Wrong images in notification timeline\n- Double icon bug\n- Fix some crashes"
},
{
"version": "3.5.1",
"code": "418",
"note": "Added:\n- Change app icon (Settings > Interface)\n- Allow to disable \"remember position\" in timelines\n- Allow to disable notification aggregation in settings\n\nChanged:\n- Allow to disable/enable media for notifications\n\nFixed:\n- Post loses \"spoiler message\" when adding a media\n- Camera not working on Android 11\n- Notification aggregation\n- Vibrations when fetching new notifications\n- Fix an issue with media timelines\n- Some crashes"
},
{
"version": "3.5.0",
"code": "417",
"note": "Changed:\n- Swipe between timelines\n- Improve cache\n- Button sizes can be changed in settings\n- French translation\n\nFixed:\n- Pleroma: Emoji reactions\n- Sharing (several fixes)\n- Theme issues\n- Rendering issue for links\n- Notifications not removed from cache\n- Issue with watermarks\n- Pagination with bookmarks/favourites\n- Some crashes"
},
{
"version": "3.4.2",
"code": "415",
"note": "Fixed:\n- Attach media to a reply"
},
{
"version": "3.4.1",
"code": "414",
"note": "Added:\n- Disable counters in settings\nFixed:\n- Duplicated messages from cache\n- Notifications in double\n- Drafts not automatically removed\n- Messages not removed from cache after deletion"
},
{
"version": "3.4.0",
"code": "413",
"note": "Added:\n- New cache mechanism (can be disabled in settings)\n- Set thumbnails load behavior Always/Wifi only /ask\n- Add counters for new messages in timelines\nFixed:\n- Contextual menu not working in threads\n- Tag search issue with Friendica\n- Notifications click open the wrong tab\n- Encoding issue with media descriptions\n- Some other fixes."
},
{
"version": "3.3.2",
"code": "409",
"note": "- Fix an issue with cache and home timeline\n- Nitter timelines use the custom instance from settings\n- Fix Nitter issues (only RT)\n- No longer accepts invalid certificate for onion URLs(Google)\n- Fix some crashes"
},
{
"version": "3.3.1",
"code": "408",
"note": "- Improve speed for Nitter instances\n- Allow to edit Nitter accounts with a long press on tabs\n- Fix pagination issue with pinned timelines\n- Fix some crashes\n- Fix visibility when displaying counters"
},
{
"version": "3.3.0",
"code": "407",
"note": "Added:\n- Settings to set all timelines at the top (default disabled)\n- Settings to display timelines in a list (default disabled)\n- Display counters for fav/reblog in timelines (default disabled)\n\nFixed:\n- Visibility issue when replying\n- Some theme issues when composing\n- Some crashes"
},
{
"version": "3.2.0",
"code": "405",
"note": "Added:\n- Export Settings\n- Propagate manual reordering of lists in timeline to \"Lists\" submenu\n- Allow to change the push distributor in settings\n\nChanged:\n- Improve fit preview images\n- Improve notifications\n- Profile media displayed in a grid\n\nFixed:\n- Some Peertube videos not working\n- Respect the default visibility account when replying\n- Discriminate gif from images\n- App crashes when opening external instance timeline\n- Remove button in thread composer crashes the app\n- Back button opens a lot of old activities before closing the app\n- Problems with sharing\n- Reorder Lists with UI issue on change the visibility\n- Link is not shown correctly in posts from Friendica"
},
{
"version": "3.1.0",
"code": "402",
"note": "Added:\n- New theme: Dark Elephant from S1m\n- Error messages from server side when posting fails\n\nChanged:\n- Fetch more buttons more visible\n\nFixed:\n- Issue when fetching missing messages\n- Some issues with themes\n- Too much lost space with reaction (Pleroma)\n- Delete and redraft crashes\n- Crash when playing a video\n- Other crash fixes"
},
{
"version": "3.0.11",
"code": "401",
"note": "Added:\n- New theme: Dark Elephant from S1m\n- Error messages from server side when posting fails\n- Allow to set the fetch time for delayed notifications\n\nChanged:\n- Fetch more buttons more visible\n\nFixed:\n- Issue when fetching missing messages\n- Some issues with themes\n- Too much lost space with reaction (Pleroma)\n- Delete and redraft crashes\n- Crash when playing a video\n- Other crash fixes"
},
{
"version": "3.0.10",
"code": "400",
"note": "Added:\n- Allow to define the max chars count when not detected (In about the instance)\n- Add emoji one picker when composing (must be enabled in settings)\n- Add release notes with the ability to translate them\n\nFixed:\n- Friendica custom emojis not displayed\n- Long press to store media\n- Some bug fixes"
},
{
"version": "3.0.9",
"code": "399",
"note": "Added:\n- Set compose language (from compose menu -> three vertical dots)\n- Add reactions support for Pleroma\n- Add privacy indicator at the top right\n\nChanged\n- Improve the scrolling behaviour\n- Scroll to top (tab reselection) will fetch new messages and then scroll to top\n\nFixed:\n- Empty tag timelines\n- Remove focus point for fit media preview\n- Fix cannot share with one account\n- Fix black theme\n- Theme cannot be selected\n- Fix some button colors"
},
{
"version": "3.0.8",
"code": "398",
"note": "- Keep improving the scroll behaviour\n- Scroll to top (tab reselection) will fetch new messages and then scroll to top\n- Remove focus point for fit media preview\n- Fix cannot share with one account\n- Fix black theme\n- Fix some button colors"
},
{
"version": "3.0.7",
"code": "397",
"note": "- Fix some bugs reported."
},
{
"version": "3.0.6",
"code": "396",
"note": "Added:\n- Allow to set a focus point on previews (media editor)\n- Respect the focus point with previews\n- Pagination with the fetch more button support reading up or down\n- Add trends\n\nFixed:\n- Only last push notification is displayed (not grouped)\n- Bad behavior with the right/left scroll\n- Fix long profiles not fully displayed\n- Issues with some polls\n- Some crashes\n- Some bad behaviors"
},
{
"version": "3.0.5",
"code": "395",
"note": "- Fix some bugs\n- Allow to share with the app"
},
{
"version": "3.0.4",
"code": "394",
"note": "- Fix crashes for some Pleroma instances"
},
{
"version": "3.0.2",
"code": "393",
"note": "- Some bug fixes\n- Improve pinned timelines"
},
{
"version": "3.0.1",
"code": "391",
"note": "Some quick fixes"
},
{
"version": "3.0.0",
"code": "390",
"note": "New version of Fedilab with new feature.\n- You can now compose threads\n- See the whole thread when replying\n- Cache support\n- New design"
}
]

View file

@ -1,13 +0,0 @@
base_theme,2
author,Fedilab
name,Breeze Dark - Yellow
theme_boost_header_color,-14012878
theme_statuses_color,-14473687
theme_link_color,-12734743
theme_icons_color,-4340793
pref_color_background,-15658735
pref_color_navigation_bar,true
pref_color_status_bar,true
theme_accent,-148405
theme_text_color,-1052431
theme_primary,-13552069
1 base_theme 2
2 author Fedilab
3 name Breeze Dark - Yellow
4 theme_boost_header_color -14012878
5 theme_statuses_color -14473687
6 theme_link_color -12734743
7 theme_icons_color -4340793
8 pref_color_background -15658735
9 pref_color_navigation_bar true
10 pref_color_status_bar true
11 theme_accent -148405
12 theme_text_color -1052431
13 theme_primary -13552069

View file

@ -1,15 +0,0 @@
base_theme,2
author,Roboron
name,Cyberpunk Neon
theme_boost_header_color,-16776697,
theme_text_header_1_line,-1441575,
theme_text_header_2_line,-5242717,
theme_statuses_color,-16181197,
theme_link_color,-1441575,
theme_icons_color,-16138810,
pref_color_background,-16774370,
pref_color_navigation_bar,true,
pref_color_status_bar,true,
theme_accent,-1441575,
theme_text_color,-16138810,
theme_primary,-16774370,
1 base_theme,2
2 author,Roboron
3 name,Cyberpunk Neon
4 theme_boost_header_color,-16776697,
5 theme_text_header_1_line,-1441575,
6 theme_text_header_2_line,-5242717,
7 theme_statuses_color,-16181197,
8 theme_link_color,-1441575,
9 theme_icons_color,-16138810,
10 pref_color_background,-16774370,
11 pref_color_navigation_bar,true,
12 pref_color_status_bar,true,
13 theme_accent,-1441575,
14 theme_text_color,-16138810,
15 theme_primary,-16774370,

View file

@ -1,15 +0,0 @@
base_theme,2
author,Jøta Seth
name,Grey Orange
theme_boost_header_color,-14869219
theme_text_header_1_line,-1
theme_text_header_2_line,-1
theme_statuses_color,-14145496
theme_link_color,-26624
theme_icons_color,-26624
pref_color_background,-13092808
pref_color_navigation_bar,true
pref_color_status_bar,true
theme_accent,-26624
theme_text_color,-1
theme_primary,-14408668
1 base_theme 2
2 author Jøta Seth
3 name Grey Orange
4 theme_boost_header_color -14869219
5 theme_text_header_1_line -1
6 theme_text_header_2_line -1
7 theme_statuses_color -14145496
8 theme_link_color -26624
9 theme_icons_color -26624
10 pref_color_background -13092808
11 pref_color_navigation_bar true
12 pref_color_status_bar true
13 theme_accent -26624
14 theme_text_color -1
15 theme_primary -14408668

View file

@ -1,15 +0,0 @@
base_theme,2
author,@AntoineD@h.kher.nl
name,Gruvbox OLED
theme_boost_header_color,-16777216
theme_text_header_1_line,-265785
theme_text_header_2_line,-6777062
theme_statuses_color,-16777216
theme_link_color,-2647775
theme_icons_color,-7175308
pref_color_background,-16777216
pref_color_navigation_bar,true
pref_color_status_bar,true
theme_accent,-9921174
theme_text_color,-265785
theme_primary,-16777216
1 base_theme 2
2 author @AntoineD@h.kher.nl
3 name Gruvbox OLED
4 theme_boost_header_color -16777216
5 theme_text_header_1_line -265785
6 theme_text_header_2_line -6777062
7 theme_statuses_color -16777216
8 theme_link_color -2647775
9 theme_icons_color -7175308
10 pref_color_background -16777216
11 pref_color_navigation_bar true
12 pref_color_status_bar true
13 theme_accent -9921174
14 theme_text_color -265785
15 theme_primary -16777216

View file

@ -1,15 +0,0 @@
base_theme,2
author,AngryTux
name,Less Angry Orange
theme_boost_header_color,-15855063
theme_text_header_1_line,-2128640
theme_text_header_2_line,-5329234
theme_statuses_color,-1
theme_link_color,-12146699
theme_icons_color,-2128640
pref_color_background,-15987700
pref_color_navigation_bar,true
pref_color_status_bar,true
theme_accent,-3968000
theme_text_color,-197380
theme_primary,-14408668
1 base_theme 2
2 author AngryTux
3 name Less Angry Orange
4 theme_boost_header_color -15855063
5 theme_text_header_1_line -2128640
6 theme_text_header_2_line -5329234
7 theme_statuses_color -1
8 theme_link_color -12146699
9 theme_icons_color -2128640
10 pref_color_background -15987700
11 pref_color_navigation_bar true
12 pref_color_status_bar true
13 theme_accent -3968000
14 theme_text_color -197380
15 theme_primary -14408668

View file

@ -1,15 +0,0 @@
base_theme,2
author,Mondstern
name,Mondstern Fedilab
theme_boost_header_color,-1,
theme_text_header_1_line,-13855804,
theme_text_header_2_line,-16227945,
theme_statuses_color,-14935012,
theme_link_color,-15542685,
theme_icons_color,-10723999,
pref_color_background,-15921907,
pref_color_navigation_bar,false,
pref_color_status_bar,false,
theme_accent,-15542685,
theme_text_color,-1,
theme_primary,-14474461,
1 base_theme,2
2 author,Mondstern
3 name,Mondstern Fedilab
4 theme_boost_header_color,-1,
5 theme_text_header_1_line,-13855804,
6 theme_text_header_2_line,-16227945,
7 theme_statuses_color,-14935012,
8 theme_link_color,-15542685,
9 theme_icons_color,-10723999,
10 pref_color_background,-15921907,
11 pref_color_navigation_bar,false,
12 pref_color_status_bar,false,
13 theme_accent,-15542685,
14 theme_text_color,-1,
15 theme_primary,-14474461,

View file

@ -1,13 +0,0 @@
base_theme,2
author,Fedilab
name,Nocturnal
theme_boost_header_color,-12895429
theme_statuses_color,-13553359
theme_link_color,-16747570
theme_icons_color,-10158118
pref_color_background,-14606047
pref_color_navigation_bar,true
pref_color_status_bar,true
theme_accent,-13136013
theme_text_color,-2236963
theme_primary,-14013910
1 base_theme 2
2 author Fedilab
3 name Nocturnal
4 theme_boost_header_color -12895429
5 theme_statuses_color -13553359
6 theme_link_color -16747570
7 theme_icons_color -10158118
8 pref_color_background -14606047
9 pref_color_navigation_bar true
10 pref_color_status_bar true
11 theme_accent -13136013
12 theme_text_color -2236963
13 theme_primary -14013910

View file

@ -1,15 +0,0 @@
base_theme,2
author,Jøta Seth
name,Photon Dark
theme_boost_header_color,-14145496
theme_text_header_1_line,-1
theme_text_header_2_line,-1
theme_statuses_color,-14935012
theme_link_color,-14059009
theme_icons_color,-9474193
pref_color_background,-15921907
pref_color_navigation_bar,true
pref_color_status_bar,true
theme_accent,-14059009
theme_text_color,-1
theme_primary,-14474461
1 base_theme 2
2 author Jøta Seth
3 name Photon Dark
4 theme_boost_header_color -14145496
5 theme_text_header_1_line -1
6 theme_text_header_2_line -1
7 theme_statuses_color -14935012
8 theme_link_color -14059009
9 theme_icons_color -9474193
10 pref_color_background -15921907
11 pref_color_navigation_bar true
12 pref_color_status_bar true
13 theme_accent -14059009
14 theme_text_color -1
15 theme_primary -14474461

View file

@ -1,15 +0,0 @@
base_theme,2
author,Fedilab
name,Solarized Dark - Purple
theme_boost_header_color,-16506327
theme_text_header_1_line,-1120043
theme_text_header_2_line,-1120043
theme_statuses_color,-16304574
theme_link_color,-14251054
theme_icons_color,-7102047
pref_color_background,-16766154
pref_color_navigation_bar,true
pref_color_status_bar,true
theme_accent,-9670204
theme_text_color,-133405
theme_primary,-16304574
1 base_theme 2
2 author Fedilab
3 name Solarized Dark - Purple
4 theme_boost_header_color -16506327
5 theme_text_header_1_line -1120043
6 theme_text_header_2_line -1120043
7 theme_statuses_color -16304574
8 theme_link_color -14251054
9 theme_icons_color -7102047
10 pref_color_background -16766154
11 pref_color_navigation_bar true
12 pref_color_status_bar true
13 theme_accent -9670204
14 theme_text_color -133405
15 theme_primary -16304574

View file

@ -1,47 +0,0 @@
[
{
"theme_name": "Dark",
"base_theme": "DARK",
"primary": "#FF272727",
"primary_dark": "#FF272727",
"primary_light": "#FFd9e1e8",
"accent": "#FF2b90d9",
"accent_dark": "#FF1b80c9",
"accent_light": "#FF772b90d9",
"background": "#FF121212",
"background_dark": "#FF282c37",
"background_light": "#FF282c37",
"should_tint_statusbar": true,
"should_tint_navbar": true
},
{
"theme_name": "Light",
"base_theme": "LIGHT",
"primary": "#FFFFFF",
"primary_dark": "#FFFFFFFF",
"primary_light": "#FFd9e1e8",
"accent": "#FF2b90d9",
"accent_dark": "#FF1b80c9",
"accent_light": "#FF772b90d9",
"background": "#FFFFFFFF",
"background_dark": "#FFFFFFFF",
"background_light": "#FFFFFFFF",
"should_tint_statusbar": true,
"should_tint_navbar": true
},
{
"theme_name": "Black",
"base_theme": "DARK",
"primary": "#FF000000",
"primary_dark": "#FF000000",
"primary_light": "#FF000000",
"accent": "#FF606984",
"accent_dark": "#FF606984",
"accent_light": "#FF606984",
"background": "#FF000000",
"background_dark": "#FF000000",
"background_light": "#FF000000",
"should_tint_statusbar": true,
"should_tint_navbar": true
}
]

File diff suppressed because it is too large Load diff

View file

@ -15,16 +15,20 @@ package app.fedilab.android;
* see <http://www.gnu.org/licenses>. */
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Build;
import android.os.StrictMode;
import android.webkit.WebView;
import androidx.multidex.MultiDex;
import androidx.multidex.MultiDexApplication;
import androidx.preference.PreferenceManager;
import com.jaredrummler.cyanea.Cyanea;
import com.jaredrummler.cyanea.prefs.CyaneaTheme;
import net.gotev.uploadservice.UploadServiceConfig;
import net.gotev.uploadservice.observer.request.GlobalRequestObserver;
import org.acra.ACRA;
import org.acra.ReportField;
@ -33,49 +37,50 @@ import org.acra.config.DialogConfigurationBuilder;
import org.acra.config.MailSenderConfigurationBuilder;
import org.acra.data.StringFormat;
import java.util.List;
import java.util.Objects;
import app.fedilab.android.mastodon.helper.ThemeHelper;
import app.fedilab.android.peertube.services.GlobalUploadObserver;
import es.dmoral.toasty.Toasty;
public class MainApplication extends MultiDexApplication {
private static MainApplication app;
public static MainApplication getApp() {
return app;
}
public static String UPLOAD_CHANNEL_ID = "upload_info_peertube";
private WebView webView;
@Override
public void onCreate() {
super.onCreate();
app = this;
SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(MainApplication.this);
Cyanea.init(this, super.getResources());
List<CyaneaTheme> list = CyaneaTheme.Companion.from(getAssets(), "themes/cyanea_themes.json");
boolean custom_theme = sharedpreferences.getBoolean("use_custom_theme", false);
boolean no_theme_set = sharedpreferences.getBoolean("no_theme_set", true);
if (no_theme_set && !custom_theme) {
list.get(0).apply(Cyanea.getInstance());
SharedPreferences.Editor editor = sharedpreferences.edit();
editor.putBoolean("no_theme_set", false);
editor.apply();
try {
webView = new WebView(this);
} catch (Exception ignored) {
}
StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
StrictMode.setVmPolicy(builder.build());
Toasty.Config.getInstance().apply();
if (webView != null) {
try {
webView.destroy();
} catch (Exception ignored) {
}
}
createNotificationChannel();
UploadServiceConfig.initialize(MainApplication.this, UPLOAD_CHANNEL_ID, true);
new GlobalRequestObserver(this, new GlobalUploadObserver());
}
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
MultiDex.install(MainApplication.this);
SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(MainApplication.this);
boolean send_crash_reports = sharedpreferences.getBoolean(getString(R.string.SET_SEND_CRASH_REPORTS), true);
boolean send_crash_reports = sharedpreferences.getBoolean(getString(R.string.SET_SEND_CRASH_REPORTS), false);
String currentTheme = sharedpreferences.getString(getString(R.string.SET_THEME_BASE), getString(R.string.SET_DEFAULT_THEME));
ThemeHelper.switchTo(currentTheme);
if (send_crash_reports) {
ACRA.init(this, new CoreConfigurationBuilder()
//core configuration:
@ -92,7 +97,6 @@ public class MainApplication extends MultiDexApplication {
.withResIcon(R.mipmap.ic_launcher)
.withText(getString(R.string.crash_title))
.withCommentPrompt(getString(R.string.crash_message))
.withResTheme(R.style.DialogDark)
.withPositiveButtonText(getString(R.string.send_email))
.withNegativeButtonText(getString(R.string.cancel))
.build()
@ -108,4 +112,15 @@ public class MainApplication extends MultiDexApplication {
);
}
}
private void createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(UPLOAD_CHANNEL_ID,
getString(R.string.notification_channel_name),
NotificationManager.IMPORTANCE_LOW);
channel.setSound(null, null);
((NotificationManager) Objects.requireNonNull(getSystemService(Context.NOTIFICATION_SERVICE))).createNotificationChannel(channel);
}
}
}

View file

@ -18,13 +18,11 @@ package app.fedilab.android.activities;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.view.MenuItem;
import android.view.View;
import androidx.core.app.ActivityOptionsCompat;
import androidx.core.content.ContextCompat;
import androidx.lifecycle.ViewModelProvider;
import java.util.ArrayList;
@ -33,17 +31,18 @@ import java.util.List;
import app.fedilab.android.BaseMainActivity;
import app.fedilab.android.BuildConfig;
import app.fedilab.android.R;
import app.fedilab.android.client.entities.api.Account;
import app.fedilab.android.client.entities.api.Status;
import app.fedilab.android.databinding.ActivityAboutBinding;
import app.fedilab.android.helper.CrossActionHelper;
import app.fedilab.android.helper.Helper;
import app.fedilab.android.helper.MastodonHelper;
import app.fedilab.android.helper.ThemeHelper;
import app.fedilab.android.viewmodel.mastodon.AccountsVM;
import app.fedilab.android.mastodon.activities.BaseBarActivity;
import app.fedilab.android.mastodon.activities.ProfileActivity;
import app.fedilab.android.mastodon.client.entities.api.Account;
import app.fedilab.android.mastodon.client.entities.api.Status;
import app.fedilab.android.mastodon.helper.CrossActionHelper;
import app.fedilab.android.mastodon.helper.Helper;
import app.fedilab.android.mastodon.helper.MastodonHelper;
import app.fedilab.android.mastodon.viewmodel.mastodon.AccountsVM;
public class AboutActivity extends BaseActivity {
public class AboutActivity extends BaseBarActivity {
private ActivityAboutBinding binding;
@ -52,13 +51,12 @@ public class AboutActivity extends BaseActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ThemeHelper.applyThemeBar(this);
binding = ActivityAboutBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setBackgroundDrawable(new ColorDrawable(ContextCompat.getColor(this, R.color.cyanea_primary)));
}
try {
@ -79,13 +77,12 @@ public class AboutActivity extends BaseActivity {
}
binding.aboutSupportPaypal.setOnClickListener(v -> Helper.openBrowser(AboutActivity.this, "https://www.paypal.me/Mastalab"));
binding.accountFollow.setBackgroundTintList(ThemeHelper.getButtonActionColorStateList(AboutActivity.this));
if (BuildConfig.DONATIONS) {
binding.aboutSupportPaypal.setVisibility(View.VISIBLE);
} else {
binding.aboutSupportPaypal.setVisibility(View.GONE);
}
binding.accountFollow.setImageResource(R.drawable.ic_baseline_person_add_24);
binding.accountFollow.setIconResource(R.drawable.ic_baseline_person_add_24);
binding.aboutWebsite.setOnClickListener(v -> Helper.openBrowser(AboutActivity.this, "https://fedilab.app"));
CrossActionHelper.fetchRemoteAccount(AboutActivity.this, "@apps@toot.fedilab.app", new CrossActionHelper.Callback() {
@Override
@ -118,7 +115,7 @@ public class AboutActivity extends BaseActivity {
if (relationShips != null && relationShips.size() > 0) {
if (!relationShips.get(0).following) {
binding.accountFollow.setVisibility(View.VISIBLE);
binding.accountFollow.setOnClickListener(v -> accountsVM.follow(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, account.id, true, false)
binding.accountFollow.setOnClickListener(v -> accountsVM.follow(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, account.id, true, false, null)
.observe(AboutActivity.this, relationShip -> binding.accountFollow.setVisibility(View.GONE)));
}
}

View file

@ -1,177 +0,0 @@
package app.fedilab.android.activities;
/* Copyright 2021 Thomas Schneider
*
* This file is a part of Fedilab
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* Fedilab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see <http://www.gnu.org/licenses>. */
import static app.fedilab.android.BaseMainActivity.currentAccount;
import static app.fedilab.android.ui.drawer.StatusAdapter.sendAction;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.view.Menu;
import android.view.MenuItem;
import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBar;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
import androidx.preference.PreferenceManager;
import app.fedilab.android.BaseMainActivity;
import app.fedilab.android.R;
import app.fedilab.android.client.entities.api.Status;
import app.fedilab.android.client.entities.app.QuickLoad;
import app.fedilab.android.client.entities.app.StatusCache;
import app.fedilab.android.databinding.ActivityConversationBinding;
import app.fedilab.android.exception.DBException;
import app.fedilab.android.helper.Helper;
import app.fedilab.android.helper.MastodonHelper;
import app.fedilab.android.helper.SpannableHelper;
import app.fedilab.android.helper.ThemeHelper;
import app.fedilab.android.ui.fragment.timeline.FragmentMastodonContext;
import app.fedilab.android.viewmodel.mastodon.StatusesVM;
public class ContextActivity extends BaseActivity {
public static boolean expand;
public static boolean displayCW;
public static Resources.Theme theme;
Fragment currentFragment;
private Status focusedStatus;
private ActivityConversationBinding binding;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ThemeHelper.applyTheme(this);
binding = ActivityConversationBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
setSupportActionBar(binding.toolbar);
ActionBar actionBar = getSupportActionBar();
//Remove title
if (actionBar != null) {
actionBar.setDisplayShowTitleEnabled(false);
actionBar.setBackgroundDrawable(new ColorDrawable(ContextCompat.getColor(this, R.color.cyanea_primary)));
}
binding.title.setText(R.string.context_conversation);
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
}
binding.toolbar.setPopupTheme(Helper.popupStyle());
Bundle b = getIntent().getExtras();
final SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(ContextActivity.this);
displayCW = sharedpreferences.getBoolean(getString(R.string.SET_EXPAND_CW), false);
focusedStatus = null; // or other values
if (b != null)
focusedStatus = (Status) b.getSerializable(Helper.ARG_STATUS);
if (focusedStatus == null) {
finish();
return;
}
MastodonHelper.loadPPMastodon(binding.profilePicture, currentAccount.mastodon_account);
Bundle bundle = new Bundle();
new Thread(() -> {
focusedStatus = SpannableHelper.convertStatus(getApplication().getApplicationContext(), focusedStatus);
Handler mainHandler = new Handler(Looper.getMainLooper());
Runnable myRunnable = () -> {
bundle.putSerializable(Helper.ARG_STATUS, focusedStatus);
currentFragment = Helper.addFragment(getSupportFragmentManager(), R.id.nav_host_fragment_content_main, new FragmentMastodonContext(), bundle, null, null);
};
mainHandler.post(myRunnable);
}).start();
StatusesVM timelinesVM = new ViewModelProvider(ContextActivity.this).get(StatusesVM.class);
timelinesVM.getStatus(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, focusedStatus.id).observe(ContextActivity.this, status -> {
if (status != null) {
StatusCache statusCache = new StatusCache();
statusCache.instance = BaseMainActivity.currentInstance;
statusCache.user_id = BaseMainActivity.currentUserID;
statusCache.status = status;
statusCache.status_id = status.id;
//Update cache
new Thread(() -> {
try {
new StatusCache(getApplication()).updateIfExists(statusCache);
new QuickLoad(getApplication().getApplicationContext()).updateStatus(currentAccount, status);
Handler mainHandler = new Handler(Looper.getMainLooper());
//Update UI
Runnable myRunnable = () -> sendAction(ContextActivity.this, Helper.ARG_STATUS_ACTION, status, null);
mainHandler.post(myRunnable);
} catch (DBException e) {
e.printStackTrace();
}
}).start();
}
});
}
@Override
public boolean onCreateOptionsMenu(@NonNull Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_context, menu);
MenuItem itemExpand = menu.findItem(R.id.action_expand);
if (expand) {
itemExpand.setIcon(R.drawable.ic_baseline_expand_less_24);
} else {
itemExpand.setIcon(R.drawable.ic_baseline_expand_more_24);
}
MenuItem itemDisplayCW = menu.findItem(R.id.action_show_cw);
if (displayCW) {
itemDisplayCW.setIcon(R.drawable.ic_baseline_remove_red_eye_24);
} else {
itemDisplayCW.setIcon(R.drawable.ic_outline_remove_red_eye_24);
}
return true;
}
public void setCurrentFragment(FragmentMastodonContext fragmentMastodonContext) {
currentFragment = fragmentMastodonContext;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
finish();
return true;
} else if (item.getItemId() == R.id.action_expand) {
expand = !expand;
if (currentFragment != null && currentFragment instanceof FragmentMastodonContext) {
((FragmentMastodonContext) currentFragment).redraw();
}
invalidateOptionsMenu();
} else if (item.getItemId() == R.id.action_show_cw) {
displayCW = !displayCW;
if (currentFragment != null && currentFragment instanceof FragmentMastodonContext) {
((FragmentMastodonContext) currentFragment).refresh();
}
invalidateOptionsMenu();
}
return true;
}
@Override
protected void onDestroy() {
super.onDestroy();
binding = null;
currentFragment = null;
}
}

View file

@ -1,170 +0,0 @@
package app.fedilab.android.activities;
/* Copyright 2022 Thomas Schneider
*
* This file is a part of Fedilab
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* Fedilab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see <http://www.gnu.org/licenses>. */
import static app.fedilab.android.BaseMainActivity.currentAccount;
import android.content.Intent;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.view.Menu;
import android.view.MenuItem;
import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBar;
import androidx.core.content.ContextCompat;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import java.util.ArrayList;
import java.util.List;
import app.fedilab.android.R;
import app.fedilab.android.client.entities.api.Status;
import app.fedilab.android.client.entities.app.Pinned;
import app.fedilab.android.client.entities.app.PinnedTimeline;
import app.fedilab.android.client.entities.app.StatusDraft;
import app.fedilab.android.client.entities.app.TagTimeline;
import app.fedilab.android.client.entities.app.Timeline;
import app.fedilab.android.databinding.ActivityHashtagBinding;
import app.fedilab.android.exception.DBException;
import app.fedilab.android.helper.Helper;
import app.fedilab.android.helper.ThemeHelper;
import app.fedilab.android.ui.fragment.timeline.FragmentMastodonTimeline;
import es.dmoral.toasty.Toasty;
public class HashTagActivity extends BaseActivity {
public static int position;
private String tag;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ThemeHelper.applyTheme(this);
ActivityHashtagBinding binding = ActivityHashtagBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
Bundle b = getIntent().getExtras();
if (b != null) {
tag = b.getString(Helper.ARG_SEARCH_KEYWORD, null);
}
if (tag == null)
finish();
setSupportActionBar(binding.toolbar);
ActionBar actionBar = getSupportActionBar();
//Remove title
if (actionBar != null) {
actionBar.setDisplayShowTitleEnabled(false);
actionBar.setBackgroundDrawable(new ColorDrawable(ContextCompat.getColor(this, R.color.cyanea_primary)));
}
binding.title.setText(tag);
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
}
Bundle bundle = new Bundle();
bundle.putSerializable(Helper.ARG_TIMELINE_TYPE, Timeline.TimeLineEnum.TAG);
bundle.putString(Helper.ARG_SEARCH_KEYWORD, tag);
Helper.addFragment(getSupportFragmentManager(), R.id.nav_host_fragment_tags, new FragmentMastodonTimeline(), bundle, null, null);
binding.toolbar.setPopupTheme(Helper.popupStyle());
binding.compose.setOnClickListener(v -> {
Intent intentToot = new Intent(HashTagActivity.this, ComposeActivity.class);
StatusDraft statusDraft = new StatusDraft();
Status status = new Status();
status.text = "#" + tag;
List<Status> statuses = new ArrayList<>();
statuses.add(status);
statusDraft.statusDraftList = statuses;
Bundle _b = new Bundle();
_b.putSerializable(Helper.ARG_TAG_TIMELINE, statusDraft);
intentToot.putExtras(_b);
startActivity(intentToot);
});
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
finish();
return true;
} else if (item.getItemId() == R.id.action_add_timeline) {
new Thread(() -> {
try {
Pinned pinned = new Pinned(HashTagActivity.this).getPinned(currentAccount);
boolean canBeAdded = true;
boolean update = true;
if (pinned == null) {
pinned = new Pinned();
pinned.pinnedTimelines = new ArrayList<>();
update = false;
} else {
for (PinnedTimeline pinnedTimeline : pinned.pinnedTimelines) {
if (pinnedTimeline.type == Timeline.TimeLineEnum.TAG) {
if (pinnedTimeline.tagTimeline.name.compareTo(tag.trim()) == 0) {
canBeAdded = false;
}
}
}
}
if (!canBeAdded) {
Handler mainHandler = new Handler(Looper.getMainLooper());
Runnable myRunnable = () -> Toasty.warning(HashTagActivity.this, getString(R.string.tags_already_stored), Toasty.LENGTH_SHORT).show();
mainHandler.post(myRunnable);
return;
}
PinnedTimeline pinnedTimeline = new PinnedTimeline();
pinnedTimeline.type = Timeline.TimeLineEnum.TAG;
pinnedTimeline.position = pinned.pinnedTimelines.size();
pinnedTimeline.displayed = true;
TagTimeline tagTimeline = new TagTimeline();
tagTimeline.name = tag.trim();
tagTimeline.isNSFW = false;
tagTimeline.isART = false;
pinnedTimeline.tagTimeline = tagTimeline;
pinned.pinnedTimelines.add(pinnedTimeline);
if (update) {
new Pinned(HashTagActivity.this).updatePinned(pinned);
} else {
new Pinned(HashTagActivity.this).insertPinned(pinned);
}
Bundle b = new Bundle();
b.putBoolean(Helper.RECEIVE_REDRAW_TOPBAR, true);
Intent intentBD = new Intent(Helper.BROADCAST_DATA);
intentBD.putExtras(b);
LocalBroadcastManager.getInstance(HashTagActivity.this).sendBroadcast(intentBD);
} catch (DBException e) {
e.printStackTrace();
}
}).start();
}
return super.onOptionsItemSelected(item);
}
@Override
public boolean onCreateOptionsMenu(@NonNull Menu menu) {
getMenuInflater().inflate(R.menu.menu_reorder, menu);
return super.onCreateOptionsMenu(menu);
}
}

View file

@ -1,109 +0,0 @@
package app.fedilab.android.activities;
/* Copyright 2022 Thomas Schneider
*
* This file is a part of Fedilab
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* Fedilab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see <http://www.gnu.org/licenses>. */
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.text.Html;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import androidx.lifecycle.ViewModelProvider;
import com.bumptech.glide.Glide;
import app.fedilab.android.BaseMainActivity;
import app.fedilab.android.R;
import app.fedilab.android.client.entities.api.Instance;
import app.fedilab.android.databinding.ActivityInstanceBinding;
import app.fedilab.android.helper.ThemeHelper;
import app.fedilab.android.viewmodel.mastodon.InstancesVM;
import es.dmoral.toasty.Toasty;
public class InstanceActivity extends BaseActivity {
ActivityInstanceBinding binding;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ThemeHelper.applyThemeDialog(this);
binding = ActivityInstanceBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
getWindow().setLayout(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
if (getSupportActionBar() != null)
getSupportActionBar().hide();
binding.close.setOnClickListener(view -> finish());
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
}
InstancesVM instancesVM = new ViewModelProvider(InstanceActivity.this).get(InstancesVM.class);
instancesVM.getInstance(BaseMainActivity.currentInstance).observe(InstanceActivity.this, instanceInfo -> {
binding.instanceContainer.setVisibility(View.VISIBLE);
binding.loader.setVisibility(View.GONE);
if (instanceInfo == null || instanceInfo.info == null) {
Toasty.error(InstanceActivity.this, getString(R.string.toast_error), Toast.LENGTH_LONG).show();
return;
}
Instance instance = instanceInfo.info;
binding.instanceTitle.setText(instance.title);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
binding.instanceDescription.setText(Html.fromHtml(instance.description, Html.FROM_HTML_MODE_LEGACY));
else
binding.instanceDescription.setText(Html.fromHtml(instance.description));
if (instance.description == null || instance.description.trim().length() == 0)
binding.instanceDescription.setText(getString(R.string.instance_no_description));
binding.instanceVersion.setText(instance.version);
binding.instanceUri.setText(instance.uri);
if (instance.email == null) {
binding.instanceContact.hide();
}
Glide.with(InstanceActivity.this)
.asBitmap()
.load(instance.thumbnail)
.into(binding.backGroundImage);
binding.instanceContact.setOnClickListener(v -> {
Intent emailIntent = new Intent(Intent.ACTION_SENDTO, Uri.fromParts("mailto", instance.email, null));
emailIntent.putExtra(Intent.EXTRA_SUBJECT, "[Mastodon] - " + instance.uri);
startActivity(Intent.createChooser(emailIntent, getString(R.string.send_email)));
});
});
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
finish();
return true;
}
return super.onOptionsItemSelected(item);
}
}

View file

@ -1,114 +0,0 @@
package app.fedilab.android.activities;
/* Copyright 2022 Thomas Schneider
*
* This file is a part of Fedilab
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* Fedilab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see <http://www.gnu.org/licenses>. */
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.text.SpannableString;
import android.text.style.UnderlineSpan;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import androidx.core.content.ContextCompat;
import androidx.lifecycle.ViewModelProvider;
import com.bumptech.glide.Glide;
import app.fedilab.android.BaseMainActivity;
import app.fedilab.android.R;
import app.fedilab.android.client.entities.app.InstanceSocial;
import app.fedilab.android.databinding.ActivityInstanceSocialBinding;
import app.fedilab.android.helper.Helper;
import app.fedilab.android.helper.ThemeHelper;
import app.fedilab.android.viewmodel.mastodon.InstanceSocialVM;
public class InstanceHealthActivity extends BaseActivity {
private ActivityInstanceSocialBinding binding;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ThemeHelper.applyThemeDialog(this);
binding = ActivityInstanceSocialBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
getWindow().setLayout(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
if (getSupportActionBar() != null)
getSupportActionBar().hide();
binding.close.setOnClickListener(view -> finish());
SpannableString content = new SpannableString(binding.refInstance.getText().toString());
content.setSpan(new UnderlineSpan(), 0, content.length(), 0);
binding.refInstance.setText(content);
binding.refInstance.setOnClickListener(view -> {
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://instances.social"));
startActivity(browserIntent);
});
checkInstance();
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
finish();
return true;
}
return super.onOptionsItemSelected(item);
}
private void checkInstance() {
InstanceSocialVM instanceSocialVM = new ViewModelProvider(InstanceHealthActivity.this).get(InstanceSocialVM.class);
instanceSocialVM.getInstances(BaseMainActivity.currentInstance.trim()).observe(InstanceHealthActivity.this, instanceSocialList -> {
if (instanceSocialList != null && instanceSocialList.instances.size() > 0) {
InstanceSocial.Instance instanceSocial = instanceSocialList.instances.get(0);
if (instanceSocial.thumbnail != null && !instanceSocial.thumbnail.equals("null"))
Glide.with(InstanceHealthActivity.this)
.asBitmap()
.load(instanceSocial.thumbnail)
.into(binding.backGroundImage);
binding.name.setText(instanceSocial.name);
if (instanceSocial.up) {
binding.up.setText(R.string.is_up);
binding.up.setTextColor(ContextCompat.getColor(InstanceHealthActivity.this, R.color.green_1));
} else {
binding.up.setText(R.string.is_down);
binding.up.setTextColor(ContextCompat.getColor(InstanceHealthActivity.this, R.color.red_1));
}
binding.uptime.setText(getString(R.string.instance_health_uptime, (instanceSocial.uptime * 100)));
if (instanceSocial.checked_at != null)
binding.checkedAt.setText(getString(R.string.instance_health_checkedat, Helper.dateToString(instanceSocial.checked_at)));
binding.values.setText(getString(R.string.instance_health_indication, instanceSocial.version, Helper.withSuffix(instanceSocial.active_users), Helper.withSuffix(instanceSocial.statuses)));
binding.instanceContainer.setVisibility(View.VISIBLE);
} else {
binding.instanceContainer.setVisibility(View.VISIBLE);
binding.mainContainer.setVisibility(View.GONE);
binding.noInstance.setVisibility(View.VISIBLE);
}
binding.loader.setVisibility(View.GONE);
});
}
}

View file

@ -1,127 +0,0 @@
package app.fedilab.android.activities;
/* Copyright 2022 Thomas Schneider
*
* This file is a part of Fedilab
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* Fedilab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see <http://www.gnu.org/licenses>. */
import static androidx.core.text.HtmlCompat.FROM_HTML_MODE_LEGACY;
import android.os.Build;
import android.os.Bundle;
import android.text.Html;
import android.text.SpannableString;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.LinearLayoutManager;
import java.util.ArrayList;
import java.util.List;
import app.fedilab.android.BaseMainActivity;
import app.fedilab.android.R;
import app.fedilab.android.client.entities.api.Account;
import app.fedilab.android.databinding.ActivityInstanceProfileBinding;
import app.fedilab.android.helper.Helper;
import app.fedilab.android.helper.ThemeHelper;
import app.fedilab.android.ui.drawer.AccountAdapter;
import app.fedilab.android.viewmodel.mastodon.NodeInfoVM;
import app.fedilab.android.viewmodel.mastodon.SearchVM;
import es.dmoral.toasty.Toasty;
public class InstanceProfileActivity extends BaseActivity {
private String instance;
private ActivityInstanceProfileBinding binding;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ThemeHelper.applyThemeDialog(this);
binding = ActivityInstanceProfileBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
getWindow().setLayout(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
Bundle b = getIntent().getExtras();
if (getSupportActionBar() != null)
getSupportActionBar().hide();
if (b != null)
instance = b.getString(Helper.ARG_INSTANCE, null);
if (instance == null) {
finish();
}
Button close = findViewById(R.id.close);
close.setOnClickListener(view -> finish());
NodeInfoVM nodeInfoVM = new ViewModelProvider(InstanceProfileActivity.this).get(NodeInfoVM.class);
nodeInfoVM.getNodeInfo(instance).observe(InstanceProfileActivity.this, nodeInfo -> {
if (nodeInfo == null) {
Toasty.error(InstanceProfileActivity.this, getString(R.string.toast_error), Toast.LENGTH_LONG).show();
finish();
return;
}
binding.name.setText(nodeInfo.metadata != null ? nodeInfo.metadata.nodeName : instance);
SpannableString descriptionSpan;
if (nodeInfo.metadata != null && nodeInfo.metadata.nodeDescription != null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
descriptionSpan = new SpannableString(Html.fromHtml(nodeInfo.metadata.nodeDescription, FROM_HTML_MODE_LEGACY));
else
descriptionSpan = new SpannableString(Html.fromHtml(nodeInfo.metadata.nodeDescription));
binding.description.setText(descriptionSpan, TextView.BufferType.SPANNABLE);
}
binding.userCount.setText(Helper.withSuffix((nodeInfo.usage.users.total)));
binding.statusCount.setText(Helper.withSuffix(((nodeInfo.usage.localPosts))));
String softwareStr = nodeInfo.software.name + " - ";
binding.software.setText(softwareStr);
binding.version.setText(nodeInfo.software.version);
if (nodeInfo.metadata != null && nodeInfo.metadata.staffAccounts != null && nodeInfo.metadata.staffAccounts.size() > 0) {
SearchVM searchVM = new ViewModelProvider(InstanceProfileActivity.this).get(SearchVM.class);
List<Account> accounts = new ArrayList<>();
for (String accountURL : nodeInfo.metadata.staffAccounts) {
searchVM.search(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, accountURL, null, "accounts", false, true, false, 0, null, null, 1)
.observe(InstanceProfileActivity.this, results -> {
if (results.accounts != null && results.accounts.size() > 0) {
accounts.add(results.accounts.get(0));
}
if (accounts.size() == nodeInfo.metadata.staffAccounts.size()) {
AccountAdapter accountsListAdapter = new AccountAdapter(accounts);
binding.lvAccounts.setAdapter(accountsListAdapter);
final LinearLayoutManager mLayoutManager;
mLayoutManager = new LinearLayoutManager(InstanceProfileActivity.this);
binding.lvAccounts.setLayoutManager(mLayoutManager);
}
});
}
}
binding.instanceContainer.setVisibility(View.VISIBLE);
binding.loader.setVisibility(View.GONE);
});
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
finish();
return true;
}
return super.onOptionsItemSelected(item);
}
}

View file

@ -15,11 +15,15 @@ package app.fedilab.android.activities;
* see <http://www.gnu.org/licenses>. */
import static app.fedilab.android.helper.MastodonHelper.REDIRECT_CONTENT_WEB;
import static app.fedilab.android.mastodon.helper.Helper.PREF_USER_SOFTWARE;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.FrameLayout;
@ -32,14 +36,18 @@ import org.jetbrains.annotations.NotNull;
import java.util.regex.Matcher;
import app.fedilab.android.BaseMainActivity;
import app.fedilab.android.R;
import app.fedilab.android.client.entities.app.Account;
import app.fedilab.android.helper.Helper;
import app.fedilab.android.helper.ThemeHelper;
import app.fedilab.android.ui.fragment.login.FragmentLoginMain;
import app.fedilab.android.viewmodel.mastodon.AccountsVM;
import app.fedilab.android.viewmodel.mastodon.AdminVM;
import app.fedilab.android.viewmodel.mastodon.OauthVM;
import app.fedilab.android.mastodon.activities.BaseActivity;
import app.fedilab.android.mastodon.activities.ProxyActivity;
import app.fedilab.android.mastodon.client.entities.app.Account;
import app.fedilab.android.mastodon.exception.DBException;
import app.fedilab.android.mastodon.helper.Helper;
import app.fedilab.android.mastodon.helper.MastodonHelper;
import app.fedilab.android.mastodon.viewmodel.mastodon.AccountsVM;
import app.fedilab.android.mastodon.viewmodel.mastodon.AdminVM;
import app.fedilab.android.mastodon.viewmodel.mastodon.OauthVM;
import app.fedilab.android.ui.fragment.FragmentLoginMain;
import es.dmoral.toasty.Toasty;
@ -48,12 +56,40 @@ public class LoginActivity extends BaseActivity {
public static Account.API apiLogin;
public static String currentInstanceLogin, client_idLogin, client_secretLogin, softwareLogin;
private final int PICK_IMPORT = 5557;
private boolean requestedAdmin;
public static boolean requestedAdmin;
@SuppressLint("ApplySharedPref")
public void proceedLogin(Activity activity, Account account) {
new Thread(() -> {
try {
//update the database
new Account(activity).insertOrUpdate(account);
Handler mainHandler = new Handler(Looper.getMainLooper());
BaseMainActivity.currentToken = account.token;
BaseMainActivity.currentUserID = account.user_id;
BaseMainActivity.api = Account.API.MASTODON;
SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(activity);
SharedPreferences.Editor editor = sharedpreferences.edit();
editor.putString(Helper.PREF_USER_TOKEN, account.token);
editor.putString(PREF_USER_SOFTWARE, BaseMainActivity.api.name());
editor.commit();
//The user is now authenticated, it will be redirected to MainActivity
Runnable myRunnable = () -> {
Intent mainActivity = new Intent(activity, MainActivity.class);
startActivity(mainActivity);
finish();
};
mainHandler.post(myRunnable);
} catch (DBException e) {
e.printStackTrace();
}
}).start();
}
private void manageItent(Intent intent) {
if (intent != null && intent.getData() != null && intent.getData().toString().contains(REDIRECT_CONTENT_WEB + "?code=")) {
if (intent != null && intent.getData() != null && intent.getData().toString().contains(MastodonHelper.REDIRECT_CONTENT_WEB + "?code=")) {
String url = intent.getData().toString();
Matcher matcher = Helper.codePattern.matcher(url);
if (!matcher.find()) {
@ -67,34 +103,43 @@ public class LoginActivity extends BaseActivity {
String scope = requestedAdmin ? Helper.OAUTH_SCOPES_ADMIN : Helper.OAUTH_SCOPES;
oauthVM.createToken(currentInstanceLogin, "authorization_code", client_idLogin, client_secretLogin, Helper.REDIRECT_CONTENT_WEB, scope, code)
.observe(LoginActivity.this, tokenObj -> {
Account account = new Account();
account.client_id = client_idLogin;
account.client_secret = client_secretLogin;
account.token = tokenObj.token_type + " " + tokenObj.access_token;
account.api = apiLogin;
account.software = softwareLogin;
account.instance = currentInstanceLogin;
//API call to retrieve account information for the new token
AccountsVM accountsVM = new ViewModelProvider(LoginActivity.this).get(AccountsVM.class);
accountsVM.getConnectedAccount(currentInstanceLogin, account.token).observe(LoginActivity.this, mastodonAccount -> {
account.mastodon_account = mastodonAccount;
account.user_id = mastodonAccount.id;
//We check if user have really moderator rights
if (requestedAdmin) {
AdminVM adminVM = new ViewModelProvider(LoginActivity.this).get(AdminVM.class);
adminVM.getAccount(account.instance, account.token, account.user_id).observe(LoginActivity.this, adminAccount -> {
account.admin = adminAccount != null;
WebviewConnectActivity.proceedLogin(LoginActivity.this, account);
});
} else {
WebviewConnectActivity.proceedLogin(LoginActivity.this, account);
}
});
if (tokenObj != null) {
Account account = new Account();
account.client_id = client_idLogin;
account.client_secret = client_secretLogin;
account.token = tokenObj.token_type + " " + tokenObj.access_token;
account.api = apiLogin;
account.software = softwareLogin;
account.instance = currentInstanceLogin;
//API call to retrieve account information for the new token
AccountsVM accountsVM = new ViewModelProvider(LoginActivity.this).get(AccountsVM.class);
accountsVM.getConnectedAccount(currentInstanceLogin, account.token).observe(LoginActivity.this, mastodonAccount -> {
if (mastodonAccount != null) {
account.mastodon_account = mastodonAccount;
account.user_id = mastodonAccount.id;
//We check if user have really moderator rights
if (requestedAdmin) {
AdminVM adminVM = new ViewModelProvider(LoginActivity.this).get(AdminVM.class);
adminVM.getAccount(account.instance, account.token, account.user_id).observe(LoginActivity.this, adminAccount -> {
account.admin = adminAccount != null;
proceedLogin(LoginActivity.this, account);
});
} else {
proceedLogin(LoginActivity.this, account);
}
} else {
Toasty.error(LoginActivity.this, getString(R.string.toast_token), Toast.LENGTH_LONG).show();
}
});
} else {
Toasty.error(LoginActivity.this, getString(R.string.toast_token), Toast.LENGTH_LONG).show();
}
});
}
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
@ -104,24 +149,18 @@ public class LoginActivity extends BaseActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ThemeHelper.applyTheme(this);
SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(LoginActivity.this);
setContentView(new FrameLayout(this));
FragmentLoginMain fragmentLoginMain = new FragmentLoginMain();
Helper.addFragment(getSupportFragmentManager(), android.R.id.content, fragmentLoginMain, null, null, null);
requestedAdmin = false;
//The activity handles a redirect URI, it will extract token code and will proceed to authentication
//That happens when the user wants to use an external browser
manageItent(getIntent());
}
public boolean requestedAdmin() {
return requestedAdmin;
}
public boolean setAdmin(boolean askAdmin) {
return requestedAdmin = askAdmin;
}
@Override
protected void onResume() {
@ -133,9 +172,6 @@ public class LoginActivity extends BaseActivity {
public boolean onCreateOptionsMenu(@NotNull Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main_login, menu);
SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(LoginActivity.this);
boolean embedded_browser = sharedpreferences.getBoolean(getString(R.string.SET_EMBEDDED_BROWSER), true);
menu.findItem(R.id.action_custom_tabs).setChecked(!embedded_browser);
return true;
}
@ -145,17 +181,8 @@ public class LoginActivity extends BaseActivity {
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_proxy) {
Intent intent = new Intent(LoginActivity.this, ProxyActivity.class);
startActivity(intent);
} else if (id == R.id.action_custom_tabs) {
item.setChecked(!item.isChecked());
SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(LoginActivity.this);
SharedPreferences.Editor editor = sharedpreferences.edit();
editor.putBoolean(getString(R.string.SET_EMBEDDED_BROWSER), !item.isChecked());
editor.apply();
return false;
(new ProxyActivity()).show(getSupportFragmentManager(), null);
} else if (id == R.id.action_request_admin) {
item.setChecked(!item.isChecked());
requestedAdmin = item.isChecked();
@ -164,20 +191,5 @@ public class LoginActivity extends BaseActivity {
return super.onOptionsItemSelected(item);
}
@Override
protected void onActivityResult(int requestCode, int resultCode,
Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == PICK_IMPORT && resultCode == RESULT_OK) {
if (data == null || data.getData() == null) {
Toasty.error(LoginActivity.this, getString(R.string.toot_select_file_error), Toast.LENGTH_LONG).show();
return;
}
// String filename = Helper.getFilePathFromURI(LoginActivity.this, data.getData());
// Sqlite.importDB(LoginActivity.this, filename);
} else {
Toasty.error(LoginActivity.this, getString(R.string.toot_select_file_error), Toast.LENGTH_LONG).show();
}
}
}

View file

@ -1,236 +0,0 @@
package app.fedilab.android.activities;
/* Copyright 2022 Thomas Schneider
*
* This file is a part of Fedilab
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* Fedilab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see <http://www.gnu.org/licenses>. */
import android.app.SearchManager;
import android.content.Context;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.inputmethod.InputMethodManager;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.widget.SearchView;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.viewpager2.adapter.FragmentStateAdapter;
import com.google.android.material.tabs.TabLayout;
import com.google.android.material.tabs.TabLayoutMediator;
import org.jetbrains.annotations.NotNull;
import app.fedilab.android.R;
import app.fedilab.android.databinding.ActivitySearchResultTabsBinding;
import app.fedilab.android.helper.Helper;
import app.fedilab.android.helper.ThemeHelper;
import app.fedilab.android.ui.fragment.timeline.FragmentMastodonAccount;
import app.fedilab.android.ui.fragment.timeline.FragmentMastodonTag;
import app.fedilab.android.ui.fragment.timeline.FragmentMastodonTimeline;
import es.dmoral.toasty.Toasty;
public class SearchResultTabActivity extends BaseActivity {
private String search;
private ActivitySearchResultTabsBinding binding;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ThemeHelper.applyThemeBar(this);
binding = ActivitySearchResultTabsBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
Bundle b = getIntent().getExtras();
if (b != null) {
search = b.getString(Helper.ARG_SEARCH_KEYWORD, null);
}
if (search == null) {
Toasty.error(SearchResultTabActivity.this, getString(R.string.toast_error_search), Toast.LENGTH_LONG).show();
finish();
return;
}
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setBackgroundDrawable(new ColorDrawable(ContextCompat.getColor(this, R.color.cyanea_primary)));
}
setTitle(search);
binding.searchTabLayout.addTab(binding.searchTabLayout.newTab());
binding.searchTabLayout.addTab(binding.searchTabLayout.newTab());
binding.searchTabLayout.addTab(binding.searchTabLayout.newTab());
binding.searchTabLayout.addTab(binding.searchTabLayout.newTab());
binding.searchTabLayout.setTabTextColors(ThemeHelper.getAttColor(SearchResultTabActivity.this, R.attr.mTextColor), ContextCompat.getColor(SearchResultTabActivity.this, R.color.cyanea_accent_dark_reference));
binding.searchTabLayout.setTabIconTint(ThemeHelper.getColorStateList(SearchResultTabActivity.this));
ScreenSlidePagerAdapter mPagerAdapter = new ScreenSlidePagerAdapter(SearchResultTabActivity.this);
binding.searchViewpager.setAdapter(mPagerAdapter);
binding.searchViewpager.setSaveEnabled(false);
binding.searchViewpager.setOffscreenPageLimit(3);
new TabLayoutMediator(binding.searchTabLayout, binding.searchViewpager,
(tab, position) -> {
binding.searchViewpager.setCurrentItem(tab.getPosition(), true);
switch (position) {
case 0:
tab.setText(getString(R.string.tags));
break;
case 1:
tab.setText(getString(R.string.accounts));
break;
case 2:
tab.setText(getString(R.string.toots));
break;
case 3:
tab.setText(getString(R.string.action_cache));
break;
}
}
).attach();
binding.searchTabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
@Override
public void onTabSelected(TabLayout.Tab tab) {
binding.searchViewpager.setCurrentItem(tab.getPosition());
}
@Override
public void onTabUnselected(TabLayout.Tab tab) {
}
@Override
public void onTabReselected(TabLayout.Tab tab) {
Fragment fragment = getSupportFragmentManager().findFragmentByTag("f" + binding.searchViewpager.getCurrentItem());
if (fragment instanceof FragmentMastodonAccount) {
FragmentMastodonAccount fragmentMastodonAccount = ((FragmentMastodonAccount) fragment);
fragmentMastodonAccount.scrollToTop();
} else if (fragment instanceof FragmentMastodonTimeline) {
FragmentMastodonTimeline fragmentMastodonTimeline = ((FragmentMastodonTimeline) fragment);
fragmentMastodonTimeline.scrollToTop();
} else if (fragment instanceof FragmentMastodonTag) {
FragmentMastodonTag fragmentMastodonTag = ((FragmentMastodonTag) fragment);
fragmentMastodonTag.scrollToTop();
}
}
});
}
@Override
public boolean onCreateOptionsMenu(@NonNull Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu_search, menu);
SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
SearchView searchView = (SearchView) menu.findItem(R.id.action_search).getActionView();
searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
searchView.setIconifiedByDefault(false);
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
assert imm != null;
imm.hideSoftInputFromWindow(binding.searchTabLayout.getWindowToken(), 0);
query = query.replaceAll("^#+", "");
search = query.trim();
ScreenSlidePagerAdapter mPagerAdapter = new ScreenSlidePagerAdapter(SearchResultTabActivity.this);
binding.searchViewpager.setAdapter(mPagerAdapter);
searchView.clearFocus();
setTitle(search);
searchView.setIconified(true);
return false;
}
@Override
public boolean onQueryTextChange(String newText) {
return false;
}
});
searchView.setOnCloseListener(() -> {
setTitle(search);
return false;
});
searchView.setOnSearchClickListener(v -> {
searchView.setQuery(search, false);
searchView.setIconified(false);
});
return true;
}
@Override
public boolean onOptionsItemSelected(@NotNull MenuItem item) {
if (item.getItemId() == android.R.id.home) {
finish();
return true;
} else if (item.getItemId() == R.id.action_search) {
return true;
}
return super.onOptionsItemSelected(item);
}
/**
* Pager adapter for the 4 fragments
*/
private class ScreenSlidePagerAdapter extends FragmentStateAdapter {
ScreenSlidePagerAdapter(FragmentActivity fa) {
super(fa);
}
@NonNull
@Override
public Fragment createFragment(int position) {
Bundle bundle = new Bundle();
switch (position) {
case 0:
FragmentMastodonTag fragmentMastodonTag = new FragmentMastodonTag();
bundle.putString(Helper.ARG_SEARCH_KEYWORD, search);
fragmentMastodonTag.setArguments(bundle);
return fragmentMastodonTag;
case 1:
FragmentMastodonAccount fragmentMastodonAccount = new FragmentMastodonAccount();
bundle.putString(Helper.ARG_SEARCH_KEYWORD, search);
fragmentMastodonAccount.setArguments(bundle);
return fragmentMastodonAccount;
case 2:
FragmentMastodonTimeline fragmentMastodonTimeline = new FragmentMastodonTimeline();
bundle.putString(Helper.ARG_SEARCH_KEYWORD, search);
fragmentMastodonTimeline.setArguments(bundle);
return fragmentMastodonTimeline;
default:
fragmentMastodonTimeline = new FragmentMastodonTimeline();
bundle.putString(Helper.ARG_SEARCH_KEYWORD_CACHE, search);
fragmentMastodonTimeline.setArguments(bundle);
return fragmentMastodonTimeline;
}
}
@Override
public int getItemCount() {
return 4;
}
}
}

View file

@ -1,208 +0,0 @@
package app.fedilab.android.activities;
/* Copyright 2022 Thomas Schneider
*
* This file is a part of Fedilab
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* Fedilab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see <http://www.gnu.org/licenses>. */
import static app.fedilab.android.BaseMainActivity.currentAccount;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.view.MenuItem;
import android.view.View;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import com.google.gson.annotations.SerializedName;
import java.util.Locale;
import app.fedilab.android.R;
import app.fedilab.android.databinding.ActivitySettingsBinding;
import app.fedilab.android.helper.ThemeHelper;
import app.fedilab.android.ui.fragment.settings.FragmentComposeSettings;
import app.fedilab.android.ui.fragment.settings.FragmentInterfaceSettings;
import app.fedilab.android.ui.fragment.settings.FragmentLanguageSettings;
import app.fedilab.android.ui.fragment.settings.FragmentNotificationsSettings;
import app.fedilab.android.ui.fragment.settings.FragmentPrivacySettings;
import app.fedilab.android.ui.fragment.settings.FragmentThemingSettings;
import app.fedilab.android.ui.fragment.settings.FragmentTimelinesSettings;
public class SettingsActivity extends BaseActivity {
private ActivitySettingsBinding binding;
private boolean canGoBack;
private Fragment currentFragment;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ThemeHelper.applyThemeBar(this);
binding = ActivitySettingsBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setBackgroundDrawable(new ColorDrawable(ContextCompat.getColor(this, R.color.cyanea_primary)));
}
canGoBack = false;
binding.setTimelines.setOnClickListener(v -> displaySettings(SettingsEnum.TIMELINES));
binding.setNotifications.setOnClickListener(v -> displaySettings(SettingsEnum.NOTIFICATIONS));
binding.setInterface.setOnClickListener(v -> displaySettings(SettingsEnum.INTERFACE));
binding.setCompose.setOnClickListener(v -> displaySettings(SettingsEnum.COMPOSE));
binding.setPrivacy.setOnClickListener(v -> displaySettings(SettingsEnum.PRIVACY));
binding.setTheming.setOnClickListener(v -> displaySettings(SettingsEnum.THEMING));
binding.setAdministration.setOnClickListener(v -> displaySettings(SettingsEnum.ADMINISTRATION));
binding.setLanguage.setOnClickListener(v -> displaySettings(SettingsEnum.LANGUAGE));
if (currentAccount.admin) {
binding.setAdministration.setVisibility(View.VISIBLE);
} else {
binding.setAdministration.setVisibility(View.GONE);
}
}
public void displaySettings(SettingsEnum settingsEnum) {
ThemeHelper.slideViewsToLeft(binding.buttonContainer, binding.fragmentContainer, () -> {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction =
fragmentManager.beginTransaction();
String category = "";
switch (settingsEnum) {
case TIMELINES:
FragmentTimelinesSettings fragmentTimelinesSettings = new FragmentTimelinesSettings();
fragmentTransaction.replace(R.id.fragment_container, fragmentTimelinesSettings);
currentFragment = fragmentTimelinesSettings;
category = getString(R.string.settings_category_label_timelines);
break;
case NOTIFICATIONS:
FragmentNotificationsSettings fragmentNotificationsSettings = new FragmentNotificationsSettings();
fragmentTransaction.replace(R.id.fragment_container, fragmentNotificationsSettings);
currentFragment = fragmentNotificationsSettings;
category = getString(R.string.notifications);
break;
case INTERFACE:
FragmentInterfaceSettings fragmentInterfaceSettings = new FragmentInterfaceSettings();
fragmentTransaction.replace(R.id.fragment_container, fragmentInterfaceSettings);
currentFragment = fragmentInterfaceSettings;
category = getString(R.string.settings_category_label_interface);
break;
case COMPOSE:
FragmentComposeSettings fragmentComposeSettings = new FragmentComposeSettings();
fragmentTransaction.replace(R.id.fragment_container, fragmentComposeSettings);
currentFragment = fragmentComposeSettings;
category = getString(R.string.compose);
break;
case PRIVACY:
FragmentPrivacySettings fragmentPrivacySettings = new FragmentPrivacySettings();
fragmentTransaction.replace(R.id.fragment_container, fragmentPrivacySettings);
currentFragment = fragmentPrivacySettings;
category = getString(R.string.action_privacy);
break;
case THEMING:
FragmentThemingSettings fragmentThemingSettings = new FragmentThemingSettings();
fragmentTransaction.replace(R.id.fragment_container, fragmentThemingSettings);
currentFragment = fragmentThemingSettings;
category = getString(R.string.theming);
break;
case LANGUAGE:
FragmentLanguageSettings fragmentLanguageSettings = new FragmentLanguageSettings();
fragmentTransaction.replace(R.id.fragment_container, fragmentLanguageSettings);
currentFragment = fragmentLanguageSettings;
category = getString(R.string.languages);
break;
}
String title = String.format(Locale.getDefault(), "%s - %s", getString(R.string.settings), category);
setTitle(title);
canGoBack = true;
fragmentTransaction.commit();
});
}
@Override
public void onBackPressed() {
if (canGoBack) {
canGoBack = false;
ThemeHelper.slideViewsToRight(binding.fragmentContainer, binding.buttonContainer, () -> {
if (currentFragment != null) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction =
fragmentManager.beginTransaction();
fragmentTransaction.remove(currentFragment).commit();
}
});
setTitle(R.string.settings);
} else {
super.onBackPressed();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (currentFragment != null) {
currentFragment.onDestroy();
}
binding = null;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
onBackPressed();
return true;
}
return super.onOptionsItemSelected(item);
}
public enum SettingsEnum {
@SerializedName("TIMELINES")
TIMELINES("TIMELINES"),
@SerializedName("NOTIFICATIONS")
NOTIFICATIONS("NOTIFICATIONS"),
@SerializedName("INTERFACE")
INTERFACE("INTERFACE"),
@SerializedName("COMPOSE")
COMPOSE("COMPOSE"),
@SerializedName("PRIVACY")
PRIVACY("PRIVACY"),
@SerializedName("THEMING")
THEMING("THEMING"),
@SerializedName("ADMINISTRATION")
ADMINISTRATION("ADMINISTRATION"),
@SerializedName("LANGUAGE")
LANGUAGE("LANGUAGE");
private final String value;
SettingsEnum(String value) {
this.value = value;
}
public String getValue() {
return value;
}
}
}

View file

@ -1,266 +0,0 @@
/* Copyright 2021 Thomas Schneider
*
* This file is a part of Fedilab
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* Fedilab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see <http://www.gnu.org/licenses>. */
package app.fedilab.android.activities;
import static app.fedilab.android.activities.LoginActivity.apiLogin;
import static app.fedilab.android.activities.LoginActivity.client_idLogin;
import static app.fedilab.android.activities.LoginActivity.client_secretLogin;
import static app.fedilab.android.activities.LoginActivity.currentInstanceLogin;
import static app.fedilab.android.activities.LoginActivity.softwareLogin;
import static app.fedilab.android.helper.Helper.PREF_USER_TOKEN;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.view.View;
import android.webkit.CookieManager;
import android.webkit.CookieSyncManager;
import android.webkit.WebChromeClient;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.ProgressBar;
import androidx.appcompat.app.AlertDialog;
import androidx.lifecycle.ViewModelProvider;
import androidx.preference.PreferenceManager;
import java.util.regex.Matcher;
import app.fedilab.android.BaseMainActivity;
import app.fedilab.android.R;
import app.fedilab.android.client.entities.app.Account;
import app.fedilab.android.databinding.ActivityWebviewConnectBinding;
import app.fedilab.android.exception.DBException;
import app.fedilab.android.helper.Helper;
import app.fedilab.android.helper.ThemeHelper;
import app.fedilab.android.viewmodel.mastodon.AccountsVM;
import app.fedilab.android.viewmodel.mastodon.AdminVM;
import app.fedilab.android.viewmodel.mastodon.OauthVM;
import es.dmoral.toasty.Toasty;
public class WebviewConnectActivity extends BaseActivity {
private ActivityWebviewConnectBinding binding;
private AlertDialog alert;
private String login_url;
private boolean requestedAdmin;
@SuppressWarnings("deprecation")
public static void clearCookies(Context context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
CookieManager.getInstance().removeAllCookies(null);
CookieManager.getInstance().flush();
} else {
CookieSyncManager cookieSyncMngr = CookieSyncManager.createInstance(context);
cookieSyncMngr.startSync();
CookieManager cookieManager = CookieManager.getInstance();
cookieManager.removeAllCookie();
cookieManager.removeSessionCookie();
cookieSyncMngr.stopSync();
cookieSyncMngr.sync();
}
}
@SuppressLint("ApplySharedPref")
public static void proceedLogin(Activity activity, Account account) {
new Thread(() -> {
try {
//update the database
new Account(activity).insertOrUpdate(account);
Handler mainHandler = new Handler(Looper.getMainLooper());
BaseMainActivity.currentToken = account.token;
BaseMainActivity.currentUserID = account.user_id;
BaseMainActivity.api = Account.API.MASTODON;
SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(activity);
SharedPreferences.Editor editor = sharedpreferences.edit();
editor.putString(PREF_USER_TOKEN, account.token);
editor.commit();
//The user is now authenticated, it will be redirected to MainActivity
Runnable myRunnable = () -> {
Intent mainActivity = new Intent(activity, MainActivity.class);
activity.startActivity(mainActivity);
activity.finish();
};
mainHandler.post(myRunnable);
} catch (DBException e) {
e.printStackTrace();
}
}).start();
}
@SuppressLint("SetJavaScriptEnabled")
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ThemeHelper.applyTheme(this);
SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(WebviewConnectActivity.this);
binding = ActivityWebviewConnectBinding.inflate(getLayoutInflater());
View rootView = binding.getRoot();
setContentView(rootView);
Bundle b = getIntent().getExtras();
if (b != null) {
login_url = b.getString("login_url");
requestedAdmin = b.getBoolean("requestedAdmin", false);
}
if (login_url == null)
finish();
clearCookies(WebviewConnectActivity.this);
binding.webviewConnect.getSettings().setJavaScriptEnabled(true);
String user_agent = sharedpreferences.getString(getString(R.string.SET_CUSTOM_USER_AGENT), Helper.USER_AGENT);
binding.webviewConnect.getSettings().setUserAgentString(user_agent);
CookieManager.getInstance().setAcceptThirdPartyCookies(binding.webviewConnect, true);
final ProgressBar pbar = findViewById(R.id.progress_bar);
binding.webviewConnect.setWebChromeClient(new WebChromeClient() {
@Override
public void onProgressChanged(WebView view, int progress) {
if (progress < 100 && pbar.getVisibility() == ProgressBar.GONE) {
pbar.setVisibility(ProgressBar.VISIBLE);
}
pbar.setProgress(progress);
if (progress == 100) {
pbar.setVisibility(ProgressBar.GONE);
}
}
});
binding.webviewConnect.setWebViewClient(new WebViewClient() {
/* @Override
public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
String x_xsrf_token = null;
String x_csrf_token = null;
if (request.getUrl().toString().contains("accounts/verify_credentials")) {
String cookies = CookieManager.getInstance().getCookie(request.getUrl().toString());
Map<String, String> requestHeaders = request.getRequestHeaders();
Iterator<Map.Entry<String, String>> it = requestHeaders.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<String, String> pair = it.next();
if (pair.getKey().compareTo("X-XSRF-TOKEN") == 0) {
x_xsrf_token = pair.getValue();
}
if (pair.getKey().compareTo("X-CSRF-TOKEN") == 0) {
x_csrf_token = pair.getValue();
}
it.remove();
}
if (x_xsrf_token != null && x_csrf_token != null) {
String finalX_xsrf_token = x_xsrf_token;
String finalX_csrf_token = x_csrf_token;
new Handler(Looper.getMainLooper()).post(() -> {
view.stopLoading();
SharedPreferences sharedpreferences1 = getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedpreferences1.edit();
String token = "X-XSRF-TOKEN= " + finalX_xsrf_token + ";X-CSRF-TOKEN= " + finalX_csrf_token + "|" + cookies;
editor.putString(Helper.PREF_KEY_OAUTH_TOKEN, token);
editor.commit();
view.setVisibility(View.GONE);
//Update the account with the token;
new UpdateAccountInfoAsyncTask(WebviewConnectActivity.this, token, clientId, clientSecret, null, instance, social);
});
}
}
return super.shouldInterceptRequest(view, request);
}*/
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
super.shouldOverrideUrlLoading(view, url);
if (url.contains(Helper.REDIRECT_CONTENT_WEB)) {
Matcher matcher = Helper.codePattern.matcher(url);
if (!matcher.find()) {
return false;
}
String code = matcher.group(1);
OauthVM oauthVM = new ViewModelProvider(WebviewConnectActivity.this).get(OauthVM.class);
//API call to get the user token
String scope = requestedAdmin ? Helper.OAUTH_SCOPES_ADMIN : Helper.OAUTH_SCOPES;
oauthVM.createToken(currentInstanceLogin, "authorization_code", client_idLogin, client_secretLogin, Helper.REDIRECT_CONTENT_WEB, scope, code)
.observe(WebviewConnectActivity.this, tokenObj -> {
Account account = new Account();
account.client_id = client_idLogin;
account.client_secret = client_secretLogin;
account.token = tokenObj.token_type + " " + tokenObj.access_token;
account.api = apiLogin;
account.software = softwareLogin;
account.instance = currentInstanceLogin;
//API call to retrieve account information for the new token
AccountsVM accountsVM = new ViewModelProvider(WebviewConnectActivity.this).get(AccountsVM.class);
accountsVM.getConnectedAccount(currentInstanceLogin, account.token).observe(WebviewConnectActivity.this, mastodonAccount -> {
if (mastodonAccount != null) {
account.mastodon_account = mastodonAccount;
account.user_id = mastodonAccount.id;
//We check if user have really moderator rights
if (requestedAdmin) {
AdminVM adminVM = new ViewModelProvider(WebviewConnectActivity.this).get(AdminVM.class);
adminVM.getAccount(account.instance, account.token, account.user_id).observe(WebviewConnectActivity.this, adminAccount -> {
account.admin = adminAccount != null;
proceedLogin(WebviewConnectActivity.this, account);
});
} else {
proceedLogin(WebviewConnectActivity.this, account);
}
} else {
Toasty.error(WebviewConnectActivity.this, getString(R.string.toast_error), Toasty.LENGTH_SHORT).show();
}
});
});
return true;
} else {
return false;
}
}
});
binding.webviewConnect.loadUrl(login_url);
}
@Override
public void onBackPressed() {
if (binding.webviewConnect.canGoBack()) {
binding.webviewConnect.goBack();
} else {
super.onBackPressed();
}
}
@Override
public void onDestroy() {
super.onDestroy();
if (alert != null) {
alert.dismiss();
alert = null;
}
binding.webviewConnect.destroy();
}
}

View file

@ -1,127 +0,0 @@
package app.fedilab.android.client.entities.app;
import android.content.ContentValues;
import android.content.Context;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import androidx.preference.PreferenceManager;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import javax.net.ssl.HttpsURLConnection;
import app.fedilab.android.exception.DBException;
import app.fedilab.android.helper.Helper;
import app.fedilab.android.sqlite.Sqlite;
public class DomainsBlock {
public static final String LAST_DATE_OF_UPDATE = "LAST_DATE_OF_UPDATE";
public static List<String> trackingDomains = null;
private static void getDomains(Context context) {
if (trackingDomains == null) {
try {
SQLiteDatabase db = Sqlite.getInstance(context.getApplicationContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open();
Cursor c = db.query(Sqlite.TABLE_DOMAINS_TRACKING, null, null, null, null, null, null, null);
trackingDomains = cursorToDomain(c);
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static void updateDomains(Context _mContext) {
SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(_mContext);
String last_date = sharedpreferences.getString(LAST_DATE_OF_UPDATE, null);
Date dateUpdate = new Date(System.currentTimeMillis() - TimeUnit.DAYS.toMillis(10));
Date dateLastUpdate = Helper.stringToDate(_mContext, last_date);
SQLiteDatabase db = Sqlite.getInstance(_mContext.getApplicationContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open();
if (last_date == null || dateUpdate.after(dateLastUpdate)) {
new Thread(() -> {
try {
HttpsURLConnection connection = (HttpsURLConnection) new URL("https://hosts.fedilab.app/hosts").openConnection();
if (connection.getResponseCode() > HttpsURLConnection.HTTP_MOVED_TEMP) {
return;
}
BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String line;
List<String> domains = new ArrayList<>();
while ((line = br.readLine()) != null) {
if (line.startsWith("0.0.0.0 ")) {
domains.add(line.replace("0.0.0.0 ", "").trim());
}
}
br.close();
connection.disconnect();
insertDomains(db, domains);
SharedPreferences.Editor editor = sharedpreferences.edit();
editor.putString(LAST_DATE_OF_UPDATE, Helper.dateToString(new Date()));
editor.apply();
} catch (IOException | DBException e) {
e.printStackTrace();
}
}).start();
} else {
getDomains(_mContext);
}
}
/**
* Insert a domains in db
*
* @param domains {@link List<String>}
* @throws DBException exception with database
*/
private static void insertDomains(SQLiteDatabase db, List<String> domains) throws DBException {
if (db == null) {
throw new DBException("db is null. Wrong initialization.");
}
db.delete(Sqlite.TABLE_DOMAINS_TRACKING, null, null);
DomainsBlock.trackingDomains = new ArrayList<>();
for (String domain : domains) {
ContentValues values = new ContentValues();
values.put(Sqlite.COL_DOMAIN, domain);
//Inserts token
try {
db.insertOrThrow(Sqlite.TABLE_DOMAINS_TRACKING, null, values);
} catch (Exception e) {
e.printStackTrace();
}
DomainsBlock.trackingDomains.add(domain);
}
}
/***
* Method to hydrate domain from database
* @param c Cursor
* @return List<String>
*/
private static List<String> cursorToDomain(Cursor c) {
//No element found
if (c.getCount() == 0) {
c.close();
return null;
}
List<String> domains = new ArrayList<>();
while (c.moveToNext()) {
domains.add(c.getString(c.getColumnIndexOrThrow(Sqlite.COL_DOMAIN)));
}
//Close the cursor
c.close();
//domains list is returned
return domains;
}
}

View file

@ -1,649 +0,0 @@
package app.fedilab.android.client.entities.app;
/* Copyright 2022 Thomas Schneider
*
* This file is a part of Fedilab
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* Fedilab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see <http://www.gnu.org/licenses>. */
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import com.google.gson.annotations.SerializedName;
import java.util.ArrayList;
import java.util.List;
import app.fedilab.android.client.entities.api.Notification;
import app.fedilab.android.client.entities.api.Status;
import app.fedilab.android.exception.DBException;
import app.fedilab.android.helper.MastodonHelper;
import app.fedilab.android.helper.SpannableHelper;
import app.fedilab.android.sqlite.Sqlite;
import app.fedilab.android.ui.fragment.timeline.FragmentMastodonNotification;
public class QuickLoad {
private final SQLiteDatabase db;
@SerializedName("id")
public long id;
@SerializedName("user_id")
public String user_id;
@SerializedName("instance")
public String instance;
@SerializedName("slug")
public String slug;
@SerializedName("position")
public int position;
@SerializedName("statuses")
public List<Status> statuses;
@SerializedName("notifications")
public List<Notification> notifications;
private Context _mContext;
private type typeOfFetch;
public QuickLoad() {
db = null;
}
public QuickLoad(Context context) {
//Creation of the DB with tables
this.db = Sqlite.getInstance(context.getApplicationContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open();
_mContext = context;
this.typeOfFetch = type.STATUSES;
}
public QuickLoad(Context context, type type) {
//Creation of the DB with tables
this.db = Sqlite.getInstance(context.getApplicationContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open();
_mContext = context;
this.typeOfFetch = type;
}
/**
* Check if the current timeline can be stored
*
* @param timeLineType - Timeline.TimeLineEnum
* @return boolean
*/
private static boolean cannotBeStored(Timeline.TimeLineEnum timeLineType) {
return timeLineType != Timeline.TimeLineEnum.HOME && timeLineType != Timeline.TimeLineEnum.LOCAL && timeLineType != Timeline.TimeLineEnum.PUBLIC && timeLineType != Timeline.TimeLineEnum.REMOTE && timeLineType != Timeline.TimeLineEnum.LIST && timeLineType != Timeline.TimeLineEnum.TAG;
}
/**
* Update a QuickLoad in db
*
* @param quickLoad {@link QuickLoad}
* @throws DBException exception with database
*/
private void updateStatus(QuickLoad quickLoad) throws DBException {
if (db == null) {
throw new DBException("db is null. Wrong initialization.");
}
ContentValues values = new ContentValues();
values.put(Sqlite.COL_POSITION, quickLoad.position);
if (quickLoad.statuses != null) {
values.put(Sqlite.COL_STATUSES, StatusDraft.mastodonStatusListToStringStorage(quickLoad.statuses));
} else if (quickLoad.notifications != null) {
values.put(Sqlite.COL_STATUSES, Notification.notificationsToStringStorage(quickLoad.notifications));
}
//Inserts token
try {
db.update(Sqlite.TABLE_QUICK_LOAD,
values, Sqlite.COL_USER_ID + " = ? AND " + Sqlite.COL_INSTANCE + " =? AND " + Sqlite.COL_SLUG + "=?",
new String[]{quickLoad.user_id, quickLoad.instance, quickLoad.slug});
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Insert or update a QuickLoad
*
* @param quickLoad {@link QuickLoad}
* @throws DBException exception with database
*/
private void insertOrUpdate(QuickLoad quickLoad) throws DBException {
if (db == null) {
throw new DBException("db is null. Wrong initialization.");
}
boolean exists = quickLoadExist(quickLoad);
if (exists) {
updateStatus(quickLoad);
} else {
insertQuickLoad(quickLoad);
}
}
/**
* Check if a QuickLoad exists in db
*
* @param quickLoad QuickLoad {@link QuickLoad}
* @return boolean - QuickLoad exists
* @throws DBException Exception
*/
public boolean quickLoadExist(QuickLoad quickLoad) throws DBException {
if (db == null) {
throw new DBException("db is null. Wrong initialization.");
}
Cursor mCount = db.rawQuery("select count(*) from " + Sqlite.TABLE_QUICK_LOAD
+ " where " + Sqlite.COL_SLUG + " = '" + quickLoad.slug + "'"
+ " AND " + Sqlite.COL_INSTANCE + " = '" + quickLoad.instance + "'"
+ " AND " + Sqlite.COL_USER_ID + "= '" + quickLoad.user_id + "'", null);
mCount.moveToFirst();
int count = mCount.getInt(0);
mCount.close();
return (count > 0);
}
/**
* Count statuses in cache for an account
*
* @param account Account {@link Account}
* @return int - Number of statuses
* @throws DBException Exception
*/
public int count(BaseAccount account) throws DBException {
if (db == null) {
throw new DBException("db is null. Wrong initialization.");
}
int count = 0;
Cursor c = db.query(Sqlite.TABLE_QUICK_LOAD, null, Sqlite.COL_USER_ID + " = ? AND " + Sqlite.COL_INSTANCE + " =?",
new String[]{account.user_id, account.instance}, null, null, null, null);
List<QuickLoad> quickLoadList = cursorToQuickLoadList(c);
if (quickLoadList != null) {
for (QuickLoad quickLoad : quickLoadList) {
count += quickLoad.statuses.size();
}
}
return count;
}
/**
* @param position - current position in timeline
* @param timeLineType - Timeline.TimeLineEnum
* @param statusList - List<Status> to save
* @param ident - the name for pinned timeline
*/
public void storeTimeline(int position, String user_id, String instance, Timeline.TimeLineEnum timeLineType, List<Status> statusList, String ident) {
if (cannotBeStored(timeLineType)) {
return;
}
String key = timeLineType.getValue();
if (ident != null) {
key += "|" + ident;
}
QuickLoad quickLoad = new QuickLoad();
quickLoad.position = position;
quickLoad.statuses = statusList;
quickLoad.slug = key;
quickLoad.instance = instance;
quickLoad.user_id = user_id;
purge(quickLoad);
try {
insertOrUpdate(quickLoad);
} catch (DBException e) {
e.printStackTrace();
}
}
/**
* @param position - current position in timeline
* @param notificationTypeEnum - Timeline.NotificationTypeEnum
* @param notificationList - List<Notification> to save
*/
public void storeNotifications(int position, String user_id, String instance, FragmentMastodonNotification.NotificationTypeEnum notificationTypeEnum, List<Notification> notificationList) {
String key = notificationTypeEnum.getValue();
QuickLoad quickLoad = new QuickLoad();
quickLoad.position = position;
quickLoad.notifications = notificationList;
quickLoad.slug = key;
quickLoad.instance = instance;
quickLoad.user_id = user_id;
purge(quickLoad);
try {
insertOrUpdate(quickLoad);
} catch (DBException e) {
e.printStackTrace();
}
}
/**
* Insert a QuickLoad in db
*
* @param quickLoad {@link QuickLoad}
* @throws DBException exception with database
*/
private void insertQuickLoad(QuickLoad quickLoad) throws DBException {
if (db == null) {
throw new DBException("db is null. Wrong initialization.");
}
ContentValues values = new ContentValues();
values.put(Sqlite.COL_USER_ID, quickLoad.user_id);
values.put(Sqlite.COL_INSTANCE, quickLoad.instance);
values.put(Sqlite.COL_SLUG, quickLoad.slug);
values.put(Sqlite.COL_POSITION, quickLoad.position);
if (quickLoad.statuses != null) {
values.put(Sqlite.COL_STATUSES, StatusDraft.mastodonStatusListToStringStorage(quickLoad.statuses));
} else if (quickLoad.notifications != null) {
values.put(Sqlite.COL_STATUSES, Notification.notificationsToStringStorage(quickLoad.notifications));
}
//Inserts token
try {
db.insertOrThrow(Sqlite.TABLE_QUICK_LOAD, null, values);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* delete all cache for all accounts
*
* @return long - db id
* @throws DBException exception with database
*/
@SuppressWarnings("UnusedReturnValue")
public long deleteForAllAccount() throws DBException {
if (db == null) {
throw new DBException("db is null. Wrong initialization.");
}
try {
return db.delete(Sqlite.TABLE_QUICK_LOAD, null, null);
} catch (Exception e) {
e.printStackTrace();
return -1;
}
}
/**
* delete all cache for an account
*
* @param account - Account
* @return long - db id
* @throws DBException exception with database
*/
@SuppressWarnings("UnusedReturnValue")
public long deleteForAccount(BaseAccount account) throws DBException {
if (db == null) {
throw new DBException("db is null. Wrong initialization.");
}
try {
return db.delete(Sqlite.TABLE_QUICK_LOAD,
Sqlite.COL_USER_ID + " = ? AND " + Sqlite.COL_INSTANCE + " =?",
new String[]{account.user_id, account.instance});
} catch (Exception e) {
e.printStackTrace();
return -1;
}
}
/**
* Update a status in quickload
*
* @param account {@link BaseAccount}
* @param newStatus - Status
* @throws DBException exception with database
*/
public void updateStatus(BaseAccount account, Status newStatus) throws DBException {
if (db == null) {
throw new DBException("db is null. Wrong initialization.");
}
QuickLoad homeQuickLoad = getSavedValue(account, Timeline.TimeLineEnum.HOME, null);
QuickLoad localQuickLoad = getSavedValue(account, Timeline.TimeLineEnum.LOCAL, null);
QuickLoad publicQuickLoad = getSavedValue(account, Timeline.TimeLineEnum.PUBLIC, null);
if (homeQuickLoad != null && homeQuickLoad.statuses != null) {
for (int i = 0; i < homeQuickLoad.statuses.size(); i++) {
if (homeQuickLoad.statuses.get(i).id.equals(newStatus.id)) {
homeQuickLoad.statuses.set(i, newStatus);
break;
}
}
ContentValues valuesHome = new ContentValues();
valuesHome.put(Sqlite.COL_STATUSES, StatusDraft.mastodonStatusListToStringStorage(homeQuickLoad.statuses));
//Inserts token
try {
db.update(Sqlite.TABLE_QUICK_LOAD,
valuesHome, Sqlite.COL_USER_ID + " = ? AND " + Sqlite.COL_INSTANCE + " =? AND " + Sqlite.COL_SLUG + "=?",
new String[]{homeQuickLoad.user_id, homeQuickLoad.instance, homeQuickLoad.slug});
} catch (Exception e) {
e.printStackTrace();
}
}
if (localQuickLoad != null && localQuickLoad.statuses != null) {
for (int i = 0; i < localQuickLoad.statuses.size(); i++) {
if (localQuickLoad.statuses.get(i).id.equals(newStatus.id)) {
localQuickLoad.statuses.set(i, newStatus);
break;
}
}
ContentValues valuesLocal = new ContentValues();
valuesLocal.put(Sqlite.COL_STATUSES, StatusDraft.mastodonStatusListToStringStorage(localQuickLoad.statuses));
//Inserts token
try {
db.update(Sqlite.TABLE_QUICK_LOAD,
valuesLocal, Sqlite.COL_USER_ID + " = ? AND " + Sqlite.COL_INSTANCE + " =? AND " + Sqlite.COL_SLUG + "=?",
new String[]{localQuickLoad.user_id, localQuickLoad.instance, localQuickLoad.slug});
} catch (Exception e) {
e.printStackTrace();
}
}
if (publicQuickLoad != null && publicQuickLoad.statuses != null) {
for (int i = 0; i < publicQuickLoad.statuses.size(); i++) {
if (publicQuickLoad.statuses.get(i).id.equals(newStatus.id)) {
publicQuickLoad.statuses.set(i, newStatus);
break;
}
}
ContentValues valuesPublic = new ContentValues();
valuesPublic.put(Sqlite.COL_STATUSES, StatusDraft.mastodonStatusListToStringStorage(publicQuickLoad.statuses));
//Inserts token
try {
db.update(Sqlite.TABLE_QUICK_LOAD,
valuesPublic, Sqlite.COL_USER_ID + " = ? AND " + Sqlite.COL_INSTANCE + " =? AND " + Sqlite.COL_SLUG + "=?",
new String[]{publicQuickLoad.user_id, publicQuickLoad.instance, publicQuickLoad.slug});
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* Delete a status in quickload
*
* @param account {@link Account}
* @param id - String id of the status
* @throws DBException exception with database
*/
public void deleteStatus(BaseAccount account, String id) throws DBException {
if (db == null) {
throw new DBException("db is null. Wrong initialization.");
}
QuickLoad homeQuickLoad = getSavedValue(account, Timeline.TimeLineEnum.HOME, null);
QuickLoad localQuickLoad = getSavedValue(account, Timeline.TimeLineEnum.LOCAL, null);
QuickLoad publicQuickLoad = getSavedValue(account, Timeline.TimeLineEnum.PUBLIC, null);
if (homeQuickLoad != null && homeQuickLoad.statuses != null) {
for (Status status : homeQuickLoad.statuses) {
if (status.id.equals(id)) {
homeQuickLoad.statuses.remove(status);
break;
}
}
ContentValues valuesHome = new ContentValues();
valuesHome.put(Sqlite.COL_STATUSES, StatusDraft.mastodonStatusListToStringStorage(homeQuickLoad.statuses));
//Inserts token
try {
db.update(Sqlite.TABLE_QUICK_LOAD,
valuesHome, Sqlite.COL_USER_ID + " = ? AND " + Sqlite.COL_INSTANCE + " =? AND " + Sqlite.COL_SLUG + "=?",
new String[]{homeQuickLoad.user_id, homeQuickLoad.instance, homeQuickLoad.slug});
} catch (Exception e) {
e.printStackTrace();
}
}
if (localQuickLoad != null && localQuickLoad.statuses != null) {
for (Status status : localQuickLoad.statuses) {
if (status.id.equals(id)) {
localQuickLoad.statuses.remove(status);
break;
}
}
ContentValues valuesLocal = new ContentValues();
valuesLocal.put(Sqlite.COL_STATUSES, StatusDraft.mastodonStatusListToStringStorage(localQuickLoad.statuses));
//Inserts token
try {
db.update(Sqlite.TABLE_QUICK_LOAD,
valuesLocal, Sqlite.COL_USER_ID + " = ? AND " + Sqlite.COL_INSTANCE + " =? AND " + Sqlite.COL_SLUG + "=?",
new String[]{localQuickLoad.user_id, localQuickLoad.instance, localQuickLoad.slug});
} catch (Exception e) {
e.printStackTrace();
}
}
if (publicQuickLoad != null && publicQuickLoad.statuses != null) {
for (Status status : publicQuickLoad.statuses) {
if (status.id.equals(id)) {
publicQuickLoad.statuses.remove(status);
break;
}
}
ContentValues valuesPublic = new ContentValues();
valuesPublic.put(Sqlite.COL_STATUSES, StatusDraft.mastodonStatusListToStringStorage(publicQuickLoad.statuses));
//Inserts token
try {
db.update(Sqlite.TABLE_QUICK_LOAD,
valuesPublic, Sqlite.COL_USER_ID + " = ? AND " + Sqlite.COL_INSTANCE + " =? AND " + Sqlite.COL_SLUG + "=?",
new String[]{publicQuickLoad.user_id, publicQuickLoad.instance, publicQuickLoad.slug});
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* Retrieves saved values
*
* @param timeLineType - Timeline.TimeLineEnum
* @param ident - the name for pinned timeline
* @return SavedValues
*/
public QuickLoad getSavedValue(String user_id, String instance, Timeline.TimeLineEnum timeLineType, String ident) {
if (cannotBeStored(timeLineType)) {
return null;
}
String key = timeLineType.getValue();
if (ident != null) {
key += "|" + ident;
}
try {
return get(user_id, instance, key);
} catch (DBException e) {
e.printStackTrace();
}
return null;
}
/**
* Retrieves saved values
*
* @param notificationTypeEnum - FragmentMastodonNotification.NotificationTypeEnum
* @return SavedValues
*/
public QuickLoad getSavedValue(String user_id, String instance, FragmentMastodonNotification.NotificationTypeEnum notificationTypeEnum) {
String key = notificationTypeEnum.getValue();
try {
return get(user_id, instance, key);
} catch (DBException e) {
e.printStackTrace();
}
return null;
}
/**
* Retrieves saved values
*
* @param notificationTypeEnum - FragmentMastodonNotification.NotificationTypeEnum
* @return SavedValues
*/
public QuickLoad getSavedValue(BaseAccount account, FragmentMastodonNotification.NotificationTypeEnum notificationTypeEnum) {
String key = notificationTypeEnum.getValue();
try {
return get(key, account);
} catch (DBException e) {
e.printStackTrace();
}
return null;
}
/**
* Retrieves saved values
*
* @param timeLineType - Timeline.TimeLineEnum
* @param ident - the name for pinned timeline
* @return SavedValues
*/
public QuickLoad getSavedValue(BaseAccount account, Timeline.TimeLineEnum timeLineType, String ident) {
if (cannotBeStored(timeLineType)) {
return null;
}
String key = timeLineType.getValue();
if (ident != null) {
key += "|" + ident;
}
try {
return get(key, account);
} catch (DBException e) {
e.printStackTrace();
}
return null;
}
/**
* Purge the list to avoid long list of Statuses in db
*
* @param quickLoad - QuickLoad to purge
*/
private void purge(QuickLoad quickLoad) {
List<Status> statuses = quickLoad.statuses;
int position = quickLoad.position;
int limit = MastodonHelper.statusesPerCall(_mContext) + 10;
int startAt = Math.max(position - limit, 0);
int endAt = Math.min(position + limit, statuses.size());
quickLoad.position = position - startAt;
quickLoad.statuses = statuses.subList(startAt, endAt);
}
/**
* Restore statusDraft list from db
*
* @param c Cursor
* @return List<Emoji>
*/
private List<QuickLoad> cursorToQuickLoadList(Cursor c) {
//No element found
if (c.getCount() == 0) {
c.close();
return null;
}
List<QuickLoad> quickLoads = new ArrayList<>();
while (c.moveToNext()) {
QuickLoad quickLoad = convertCursorToQuickLoad(c);
quickLoads.add(quickLoad);
}
//Close the cursor
c.close();
return quickLoads;
}
/**
* Convert a cursor to QuickLoad
*
* @param c Cursor
* @return QuickLoad
*/
private QuickLoad convertCursorToQuickLoad(Cursor c) {
QuickLoad quickLoad = new QuickLoad();
quickLoad.id = c.getInt(c.getColumnIndexOrThrow(Sqlite.COL_ID));
quickLoad.instance = c.getString(c.getColumnIndexOrThrow(Sqlite.COL_INSTANCE));
quickLoad.user_id = c.getString(c.getColumnIndexOrThrow(Sqlite.COL_USER_ID));
quickLoad.slug = c.getString(c.getColumnIndexOrThrow(Sqlite.COL_SLUG));
if (typeOfFetch == type.STATUSES) {
quickLoad.statuses = StatusDraft.restoreStatusListFromString(c.getString(c.getColumnIndexOrThrow(Sqlite.COL_STATUSES)));
} else if (typeOfFetch == type.NOTIFICATIONS) {
quickLoad.notifications = Notification.restoreNotificationsFromString(c.getString(c.getColumnIndexOrThrow(Sqlite.COL_STATUSES)));
}
quickLoad.position = c.getInt(c.getColumnIndexOrThrow(Sqlite.COL_POSITION));
//TimelineHelper.filterStatus(_mContext, quickLoad.statuses, TimelineHelper.FilterTimeLineType.PUBLIC);
quickLoad.statuses = SpannableHelper.convertStatus(_mContext, quickLoad.statuses);
return quickLoad;
}
/**
* Convert a cursor to QuickLoad
*
* @param c Cursor
* @return QuickLoad
*/
private QuickLoad cursorToQuickLoad(Cursor c) {
//No element found
if (c.getCount() == 0) {
c.close();
return null;
}
//Take the first element
c.moveToFirst();
QuickLoad quickLoad = convertCursorToQuickLoad(c);
//Close the cursor
c.close();
return quickLoad;
}
/**
* Get paginated statuses from db
*
* @return Statuses
* @throws DBException - throws a db exception
*/
private QuickLoad get(String user_id, String instance, String slug) throws DBException {
if (db == null) {
throw new DBException("db is null. Wrong initialization.");
}
try {
Cursor c = db.query(Sqlite.TABLE_QUICK_LOAD, null, Sqlite.COL_USER_ID + " = ? AND " + Sqlite.COL_INSTANCE + " =? AND " + Sqlite.COL_SLUG + "=?",
new String[]{user_id, instance, slug}, null, null, null, "1");
return cursorToQuickLoad(c);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* Get paginated statuses from db
*
* @return Statuses
* @throws DBException - throws a db exception
*/
private QuickLoad get(String slug, BaseAccount account) throws DBException {
if (db == null) {
throw new DBException("db is null. Wrong initialization.");
}
try {
Cursor c = db.query(Sqlite.TABLE_QUICK_LOAD, null, Sqlite.COL_USER_ID + " = ? AND " + Sqlite.COL_INSTANCE + " =? AND " + Sqlite.COL_SLUG + "=?",
new String[]{account.user_id, account.instance, slug}, null, null, null, "1");
return cursorToQuickLoad(c);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
enum type {
STATUSES,
NOTIFICATIONS
}
}

View file

@ -1,428 +0,0 @@
package app.fedilab.android.client.entities.app;
/* Copyright 2021 Thomas Schneider
*
* This file is a part of Fedilab
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* Fedilab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see <http://www.gnu.org/licenses>. */
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import com.google.gson.Gson;
import com.google.gson.annotations.SerializedName;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import app.fedilab.android.client.entities.api.Pagination;
import app.fedilab.android.client.entities.api.Status;
import app.fedilab.android.client.entities.api.Statuses;
import app.fedilab.android.exception.DBException;
import app.fedilab.android.helper.Helper;
import app.fedilab.android.helper.MastodonHelper;
import app.fedilab.android.sqlite.Sqlite;
public class StatusCache {
private final SQLiteDatabase db;
@SerializedName("id")
public long id;
@SerializedName("user_id")
public String user_id;
@SerializedName("instance")
public String instance;
@SerializedName("type")
public CacheEnum type;
@SerializedName("status_id")
public String status_id;
@SerializedName("status")
public Status status;
@SerializedName("created_at")
public Date created_at;
@SerializedName("updated_at")
public Date updated_at;
private Context context;
public StatusCache() {
db = null;
}
public StatusCache(Context context) {
//Creation of the DB with tables
this.context = context;
this.db = Sqlite.getInstance(context.getApplicationContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open();
}
/**
* Serialized a Status class
*
* @param mastodon_status {@link Status} to serialize
* @return String serialized status
*/
public static String mastodonStatusToStringStorage(Status mastodon_status) {
Gson gson = new Gson();
try {
return gson.toJson(mastodon_status);
} catch (Exception e) {
return null;
}
}
/**
* Unserialized a Mastodon Status
*
* @param serializedStatus String serialized status
* @return {@link Status}
*/
public static Status restoreStatusFromString(String serializedStatus) {
Gson gson = new Gson();
try {
return gson.fromJson(serializedStatus, Status.class);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* Insert or update a status
*
* @param statusCache {@link StatusCache}
* @return long - db id
* @throws DBException exception with database
*/
public long insertOrUpdate(StatusCache statusCache) throws DBException {
if (db == null) {
throw new DBException("db is null. Wrong initialization.");
}
boolean exists = statusExist(statusCache);
long idReturned;
if (exists) {
idReturned = updateStatus(statusCache);
} else {
idReturned = insertStatus(statusCache);
}
return idReturned;
}
/**
* update a status if presents in db
*
* @param statusCache {@link StatusCache}
* @throws DBException exception with database
*/
public void updateIfExists(StatusCache statusCache) throws DBException {
if (db == null) {
throw new DBException("db is null. Wrong initialization.");
}
boolean exists = statusExist(statusCache);
if (exists) {
updateStatus(statusCache);
}
}
/**
* Check if a status exists in db
*
* @param statusCache Status {@link StatusCache}
* @return boolean - StatusCache exists
* @throws DBException Exception
*/
public boolean statusExist(StatusCache statusCache) throws DBException {
if (db == null) {
throw new DBException("db is null. Wrong initialization.");
}
Cursor mCount = db.rawQuery("select count(*) from " + Sqlite.TABLE_STATUS_CACHE
+ " where " + Sqlite.COL_STATUS_ID + " = '" + statusCache.status_id + "'"
+ " AND " + Sqlite.COL_INSTANCE + " = '" + statusCache.instance + "'"
+ " AND " + Sqlite.COL_USER_ID + "= '" + statusCache.user_id + "'", null);
mCount.moveToFirst();
int count = mCount.getInt(0);
mCount.close();
return (count > 0);
}
/**
* Insert a status in db
*
* @param statusCache {@link StatusCache}
* @return long - db id
* @throws DBException exception with database
*/
private long insertStatus(StatusCache statusCache) throws DBException {
if (db == null) {
throw new DBException("db is null. Wrong initialization.");
}
ContentValues values = new ContentValues();
values.put(Sqlite.COL_USER_ID, statusCache.user_id);
values.put(Sqlite.COL_INSTANCE, statusCache.instance);
values.put(Sqlite.COL_TYPE, statusCache.type.getValue());
values.put(Sqlite.COL_STATUS_ID, statusCache.status_id);
values.put(Sqlite.COL_STATUS, mastodonStatusToStringStorage(statusCache.status));
values.put(Sqlite.COL_CREATED_AT, Helper.dateToString(new Date()));
//Inserts token
try {
return db.insertOrThrow(Sqlite.TABLE_STATUS_CACHE, null, values);
} catch (Exception e) {
e.printStackTrace();
return -1;
}
}
/**
* Update a status in db
*
* @param statusCache {@link StatusCache}
* @return long - db id
* @throws DBException exception with database
*/
private long updateStatus(StatusCache statusCache) throws DBException {
if (db == null) {
throw new DBException("db is null. Wrong initialization.");
}
ContentValues values = new ContentValues();
values.put(Sqlite.COL_USER_ID, statusCache.user_id);
if (statusCache.type != null) {
values.put(Sqlite.COL_TYPE, statusCache.type.getValue());
}
values.put(Sqlite.COL_STATUS_ID, statusCache.status_id);
values.put(Sqlite.COL_STATUS, mastodonStatusToStringStorage(statusCache.status));
values.put(Sqlite.COL_UPDATED_AT, Helper.dateToString(new Date()));
//Inserts token
try {
return db.update(Sqlite.TABLE_STATUS_CACHE,
values, Sqlite.COL_STATUS_ID + " = ? AND " + Sqlite.COL_INSTANCE + " =?",
new String[]{statusCache.status_id, statusCache.instance});
} catch (Exception e) {
e.printStackTrace();
return -1;
}
}
/**
* delete all cache for all account
*
* @return long - db id
* @throws DBException exception with database
*/
public long deleteForAllAccount() throws DBException {
if (db == null) {
throw new DBException("db is null. Wrong initialization.");
}
try {
return db.delete(Sqlite.TABLE_STATUS_CACHE, null, null);
} catch (Exception e) {
e.printStackTrace();
return -1;
}
}
/**
* delete all cache for an account
*
* @param account - Account
* @return long - db id
* @throws DBException exception with database
*/
public long deleteForAccount(BaseAccount account) throws DBException {
if (db == null) {
throw new DBException("db is null. Wrong initialization.");
}
try {
return db.delete(Sqlite.TABLE_STATUS_CACHE,
Sqlite.COL_USER_ID + " = ? AND " + Sqlite.COL_INSTANCE + " =?",
new String[]{account.user_id, account.instance});
} catch (Exception e) {
e.printStackTrace();
return -1;
}
}
/**
* delete a status in db
*
* @param instance - String instance
* @param id - String status id
* @return long - db id
* @throws DBException exception with database
*/
public long deleteStatus(String instance, String id) throws DBException {
if (db == null) {
throw new DBException("db is null. Wrong initialization.");
}
try {
return db.delete(Sqlite.TABLE_STATUS_CACHE,
Sqlite.COL_STATUS_ID + " = ? AND " + Sqlite.COL_INSTANCE + " =?",
new String[]{id, instance});
} catch (Exception e) {
e.printStackTrace();
return -1;
}
}
/**
* Get paginated statuses from db
*
* @param type CacheEnum - not used yet but will allow to extend cache to other timelines
* @param instance String - instance
* @param user_id String - us
* @param max_id String - status having max id
* @param min_id String - status having min id
* @return Statuses
* @throws DBException - throws a db exception
*/
public Statuses geStatuses(CacheEnum type, String instance, String user_id, String max_id, String min_id, String since_id) throws DBException {
if (db == null) {
throw new DBException("db is null. Wrong initialization.");
}
String order = " DESC";
String selection = Sqlite.COL_INSTANCE + "='" + instance + "' AND " + Sqlite.COL_USER_ID + "= '" + user_id + "'";
String limit = String.valueOf(MastodonHelper.statusesPerCall(context));
if (min_id != null) {
selection += "AND " + Sqlite.COL_STATUS_ID + " > '" + min_id + "'";
order = " ASC";
} else if (max_id != null) {
selection += "AND " + Sqlite.COL_STATUS_ID + " < '" + max_id + "'";
} else if (since_id != null) {
selection += "AND " + Sqlite.COL_STATUS_ID + " > '" + since_id + "'";
limit = null;
}
try {
Cursor c = db.query(Sqlite.TABLE_STATUS_CACHE, null, selection, null, null, null, Sqlite.COL_STATUS_ID + order, limit);
return createStatusReply(cursorToListOfStatuses(c));
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* @param type CacheEnum - not used yet but will allow to extend cache to other timelines
* @param instance String - instance
* @param user_id String - us
* @param search String search
* @return - List<Status>
* @throws DBException exception
*/
public List<Status> searchStatus(CacheEnum type, String instance, String user_id, String search) throws DBException {
if (db == null) {
throw new DBException("db is null. Wrong initialization.");
}
String selection = Sqlite.COL_INSTANCE + "='" + instance
+ "' AND " + Sqlite.COL_USER_ID + "= '" + user_id + "'";
List<Status> reply = new ArrayList<>();
try {
Cursor c = db.query(Sqlite.TABLE_STATUS_CACHE, null, selection, null, null, null, Sqlite.COL_STATUS_ID + " DESC", "");
List<Status> statuses = cursorToListOfStatuses(c);
if (statuses != null && statuses.size() > 0) {
for (Status status : statuses) {
if (status.content.toLowerCase().contains(search.trim().toLowerCase())) {
reply.add(status);
}
}
}
} catch (Exception e) {
e.printStackTrace();
return null;
}
return reply;
}
public int count(BaseAccount account) throws DBException {
if (db == null) {
throw new DBException("db is null. Wrong initialization.");
}
Cursor mCount = db.rawQuery("select count(*) from " + Sqlite.TABLE_STATUS_CACHE
+ " where " + Sqlite.COL_INSTANCE + " = '" + account.instance + "' AND " + Sqlite.COL_USER_ID + " = '" + account.user_id + "'", null);
mCount.moveToFirst();
int count = mCount.getInt(0);
mCount.close();
return count;
}
/**
* Convert a cursor to list of statuses
*
* @param c Cursor
* @return List<Status>
*/
private List<Status> cursorToListOfStatuses(Cursor c) {
//No element found
if (c.getCount() == 0) {
c.close();
return null;
}
List<Status> statusList = new ArrayList<>();
while (c.moveToNext()) {
Status status = convertCursorToStatus(c);
statusList.add(status);
}
//Close the cursor
c.close();
return statusList;
}
/**
* Create a reply from db in the same way than API call
*
* @param statusList List<Status>
* @return Statuses (with pagination)
*/
private Statuses createStatusReply(List<Status> statusList) {
Statuses statuses = new Statuses();
statuses.statuses = statusList;
Pagination pagination = new Pagination();
if (statusList != null && statusList.size() > 0) {
//Status list is inverted, it happens for min_id due to ASC ordering
if (statusList.get(0).id.compareTo(statusList.get(statusList.size() - 1).id) < 0) {
Collections.reverse(statusList);
statuses.statuses = statusList;
}
pagination.max_id = statusList.get(0).id;
pagination.min_id = statusList.get(statusList.size() - 1).id;
}
statuses.pagination = pagination;
return statuses;
}
/**
* Read cursor and hydrate without closing it
*
* @param c - Cursor
* @return Status
*/
private Status convertCursorToStatus(Cursor c) {
String serializedStatus = c.getString(c.getColumnIndexOrThrow(Sqlite.COL_STATUS));
return restoreStatusFromString(serializedStatus);
}
public enum CacheEnum {
@SerializedName("HOME")
HOME("HOME");
private final String value;
CacheEnum(String value) {
this.value = value;
}
public String getValue() {
return value;
}
}
}

View file

@ -1,123 +0,0 @@
package app.fedilab.android.helper;
/* Copyright 2021 Thomas Schneider
*
* This file is a part of Fedilab
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* Fedilab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see <http://www.gnu.org/licenses>. */
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.DashPathEffect;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.core.content.res.ResourcesCompat;
import androidx.recyclerview.widget.RecyclerView;
import java.util.List;
import app.fedilab.android.R;
import app.fedilab.android.client.entities.api.Status;
import app.fedilab.android.ui.drawer.ComposeAdapter;
public class DividerDecorationSimple extends RecyclerView.ItemDecoration {
private final Context _mContext;
private final List<Status> statusList;
public DividerDecorationSimple(Context context, List<Status> statuses) {
_mContext = context;
statusList = statuses;
}
@Override
public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
int position = ((RecyclerView.LayoutParams) view.getLayoutParams()).getViewAdapterPosition();
ComposeAdapter composeAdapter = ((ComposeAdapter) parent.getAdapter());
if (composeAdapter != null && composeAdapter.getItemCount() > position && position >= 0) {
Status status = composeAdapter.getItem(position);
if (status != null) {
int start = (int) Helper.convertDpToPixel(
4 * CommentDecorationHelper.getIndentation(status.in_reply_to_id, statusList, 15),
_mContext);
if (parent.getLayoutDirection() == View.LAYOUT_DIRECTION_LTR) {
outRect.set(start, 0, 0, 0);
} else {
outRect.set(0, 0, start, 0);
}
}
}
}
@Override
public void onDraw(@NonNull Canvas c, RecyclerView parent, @NonNull RecyclerView.State state) {
for (int i = 0; i < parent.getChildCount(); i++) {
View view = parent.getChildAt(i);
int position = parent.getChildAdapterPosition(view);
ComposeAdapter composeAdapter = ((ComposeAdapter) parent.getAdapter());
if (composeAdapter != null && composeAdapter.getItemCount() > position && position >= 0) {
Status status = composeAdapter.getItem(position);
if (status != null) {
int indentation = CommentDecorationHelper.getIndentation(status.in_reply_to_id, statusList, 15);
if (indentation > 0) {
Paint paint = new Paint();
paint.setDither(false);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(Helper.convertDpToPixel(2F, _mContext));
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setColor(ResourcesCompat.getColor(_mContext.getResources(), R.color.cyanea_accent, _mContext.getTheme()));
if (indentation == 15) {
paint.setPathEffect(new DashPathEffect(
new float[]{Helper.convertDpToPixel(3, _mContext), Helper.convertDpToPixel(3, _mContext)},
0));
}
float startDp = 12 + 4 * (indentation - 1);
if (i > 0) startDp = startDp - 6;
float endDp = startDp + 4;
if (i > 0) endDp = endDp + 4;
float startPx = Helper.convertDpToPixel(startDp, _mContext);
if (parent.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) {
startPx = c.getWidth() - startPx;
}
float topPx = view.getTop() - Helper.convertDpToPixel(12, _mContext);
if (i > 0) {
View aboveView = parent.getChildAt(i - 1);
topPx = topPx - (aboveView.getHeight() / 2F);
}
float bottomPx = view.getBottom() - view.getHeight() / 2F;
float endPx = Helper.convertDpToPixel(endDp, _mContext);
Path path = new Path();
path.moveTo(startPx, topPx);
path.lineTo(startPx, bottomPx);
path.lineTo(endPx, bottomPx);
c.drawPath(path, paint);
}
}
}
}
}
}

View file

@ -1,113 +0,0 @@
package app.fedilab.android.helper
/*
* Copyright 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import android.content.Context
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.View
import android.view.ViewConfiguration
import android.widget.FrameLayout
import androidx.viewpager2.widget.ViewPager2
import androidx.viewpager2.widget.ViewPager2.ORIENTATION_HORIZONTAL
import kotlin.math.absoluteValue
import kotlin.math.sign
/**
* Layout to wrap a scrollable component inside a ViewPager2. Provided as a solution to the problem
* where pages of ViewPager2 have nested scrollable elements that scroll in the same direction as
* ViewPager2. The scrollable element needs to be the immediate and only child of this host layout.
*
* This solution has limitations when using multiple levels of nested scrollable elements
* (e.g. a horizontal RecyclerView in a vertical RecyclerView in a horizontal ViewPager2).
*/
class NestedScrollableHost : FrameLayout {
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
private var touchSlop = 0
private var initialX = 0f
private var initialY = 0f
private val parentViewPager: ViewPager2?
get() {
var v: View? = parent as? View
while (v != null && v !is ViewPager2) {
v = v.parent as? View
}
return v as? ViewPager2
}
private val child: View? get() = if (childCount > 0) getChildAt(0) else null
init {
touchSlop = ViewConfiguration.get(context).scaledTouchSlop
}
private fun canChildScroll(orientation: Int, delta: Float): Boolean {
val direction = -delta.sign.toInt()
return when (orientation) {
0 -> child?.canScrollHorizontally(direction) ?: false
1 -> child?.canScrollVertically(direction) ?: false
else -> throw IllegalArgumentException()
}
}
override fun onInterceptTouchEvent(e: MotionEvent): Boolean {
handleInterceptTouchEvent(e)
return super.onInterceptTouchEvent(e)
}
private fun handleInterceptTouchEvent(e: MotionEvent) {
val orientation = parentViewPager?.orientation ?: return
// Early return if child can't scroll in same direction as parent
if (!canChildScroll(orientation, -1f) && !canChildScroll(orientation, 1f)) {
return
}
if (e.action == MotionEvent.ACTION_DOWN) {
initialX = e.x
initialY = e.y
parent.requestDisallowInterceptTouchEvent(true)
} else if (e.action == MotionEvent.ACTION_MOVE) {
val dx = e.x - initialX
val dy = e.y - initialY
val isVpHorizontal = orientation == ORIENTATION_HORIZONTAL
// assuming ViewPager2 touch-slop is 2x touch-slop of child
val scaledDx = dx.absoluteValue * if (isVpHorizontal) .5f else 1f
val scaledDy = dy.absoluteValue * if (isVpHorizontal) 1f else .5f
if (scaledDx > touchSlop || scaledDy > touchSlop) {
if (isVpHorizontal == (scaledDy > scaledDx)) {
// Gesture is perpendicular, allow all parents to intercept
parent.requestDisallowInterceptTouchEvent(false)
} else {
// Gesture is parallel, query child if movement in that direction is possible
if (canChildScroll(orientation, if (isVpHorizontal) dx else dy)) {
// Child can scroll, disallow all parents to intercept
parent.requestDisallowInterceptTouchEvent(true)
} else {
// Child cannot scroll, allow all parents to intercept
parent.requestDisallowInterceptTouchEvent(false)
}
}
}
}
}
}

View file

@ -1,723 +0,0 @@
package app.fedilab.android.helper;
/* Copyright 2022 Thomas Schneider
*
* This file is a part of Fedilab
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* Fedilab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see <http://www.gnu.org/licenses>. */
import static app.fedilab.android.BaseMainActivity.currentAccount;
import static app.fedilab.android.ui.pageadapter.FedilabPageAdapter.BOTTOM_TIMELINE_COUNT;
import android.os.Bundle;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.widget.PopupMenu;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentTransaction;
import androidx.viewpager2.widget.ViewPager2;
import com.google.android.material.tabs.TabLayout;
import com.google.android.material.tabs.TabLayoutMediator;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import app.fedilab.android.BaseMainActivity;
import app.fedilab.android.R;
import app.fedilab.android.client.entities.api.MastodonList;
import app.fedilab.android.client.entities.app.BottomMenu;
import app.fedilab.android.client.entities.app.Pinned;
import app.fedilab.android.client.entities.app.PinnedTimeline;
import app.fedilab.android.client.entities.app.RemoteInstance;
import app.fedilab.android.client.entities.app.TagTimeline;
import app.fedilab.android.client.entities.app.Timeline;
import app.fedilab.android.databinding.ActivityMainBinding;
import app.fedilab.android.databinding.TabCustomViewBinding;
import app.fedilab.android.exception.DBException;
import app.fedilab.android.ui.fragment.timeline.FragmentMastodonConversation;
import app.fedilab.android.ui.fragment.timeline.FragmentMastodonTimeline;
import app.fedilab.android.ui.pageadapter.FedilabPageAdapter;
public class PinnedTimelineHelper {
public static void sortPositionAsc(List<PinnedTimeline> pinnedTimelineList) {
//noinspection ComparatorCombinators
Collections.sort(pinnedTimelineList, (obj1, obj2) -> Integer.compare(obj1.position, obj2.position));
}
public static void sortMenuItem(List<BottomMenu.MenuItem> menuItemList) {
//noinspection ComparatorCombinators
Collections.sort(menuItemList, (obj1, obj2) -> Integer.compare(obj1.position, obj2.position));
}
public synchronized static void redrawTopBarPinned(BaseMainActivity activity, ActivityMainBinding activityMainBinding, Pinned pinned, BottomMenu bottomMenu, List<MastodonList> mastodonLists) {
//Values must be initialized if there is no records in db
if (pinned == null) {
pinned = new Pinned();
pinned.user_id = BaseMainActivity.currentUserID;
pinned.instance = BaseMainActivity.currentInstance;
}
if (pinned.pinnedTimelines == null) {
pinned.pinnedTimelines = new ArrayList<>();
}
List<PinnedTimeline> pinnedTimelines = pinned.pinnedTimelines;
sortPositionAsc(pinnedTimelines);
//Check if changes occurred, if mastodonLists is null it does need, because it is the first call to draw pinned
boolean needRedraw = mastodonLists == null;
//Lists have been fetched from remote account
if (mastodonLists != null) { //Currently, needRedraw is set to false
List<PinnedTimeline> pinnedToRemove = new ArrayList<>();
for (PinnedTimeline pinnedTimeline : pinned.pinnedTimelines) {
if (pinnedTimeline.type == Timeline.TimeLineEnum.LIST) {
boolean present = false;
for (MastodonList mastodonList : mastodonLists) {
if (mastodonList.id.compareTo(pinnedTimeline.mastodonList.id) == 0) {
present = true;
break;
}
}
//Needs to be removed
if (!present) {
pinnedToRemove.add(pinnedTimeline);
needRedraw = true; //Something changed, redraw must be done
}
}
}
if (pinnedToRemove.size() > 0) {
pinned.pinnedTimelines.removeAll(pinnedToRemove);
try {
new Pinned(activity).updatePinned(pinned);
} catch (DBException e) {
e.printStackTrace();
}
}
for (MastodonList mastodonList : mastodonLists) {
boolean present = false;
for (PinnedTimeline pinnedTimeline : pinned.pinnedTimelines) {
if (pinnedTimeline.mastodonList != null && mastodonList.id.compareTo(pinnedTimeline.mastodonList.id) == 0) {
present = true;
break;
}
}
//Needs to be added
if (!present) {
needRedraw = true; //Something changed, redraw must be done
PinnedTimeline pinnedTimeline = new PinnedTimeline();
pinnedTimeline.type = Timeline.TimeLineEnum.LIST;
pinnedTimeline.position = pinned.pinnedTimelines.size();
pinnedTimeline.mastodonList = mastodonList;
pinned.pinnedTimelines.add(pinnedTimeline);
try {
boolean exist = new Pinned(activity).pinnedExist(pinned);
if (exist) {
new Pinned(activity).updatePinned(pinned);
} else {
new Pinned(activity).insertPinned(pinned);
}
} catch (DBException e) {
e.printStackTrace();
}
}
}
}
if (!needRedraw) { //if there were no changes with list, no need to update tabs
return;
}
//Pinned tab position will start after BOTTOM_TIMELINE_COUNT (ie 5)
activityMainBinding.tabLayout.removeAllTabs();
//Small hack to hide first tabs (they represent the item of the bottom menu)
int toRemove = itemToRemoveInBottomMenu(activity);
List<String> tabTitle = new ArrayList<>();
List<RemoteInstance.InstanceType> tabTypeRemote = new ArrayList<>();
List<Timeline.TimeLineEnum> tabType = new ArrayList<>();
for (int i = 0; i < (BOTTOM_TIMELINE_COUNT - toRemove); i++) {
activityMainBinding.tabLayout.addTab(activityMainBinding.tabLayout.newTab());
tabTitle.add("");
tabType.add(Timeline.TimeLineEnum.HOME);
tabTypeRemote.add(RemoteInstance.InstanceType.MASTODON);
((ViewGroup) activityMainBinding.tabLayout.getChildAt(0)).getChildAt(i).setVisibility(View.GONE);
}
List<PinnedTimeline> pinnedTimelineVisibleList = new ArrayList<>();
for (PinnedTimeline pinnedTimeline : pinned.pinnedTimelines) {
if (pinnedTimeline.displayed) {
TabLayout.Tab tab = activityMainBinding.tabLayout.newTab();
String name = "";
switch (pinnedTimeline.type) {
case LIST:
name = pinnedTimeline.mastodonList.title;
break;
case TAG:
name = pinnedTimeline.tagTimeline.name;
break;
case REMOTE:
name = pinnedTimeline.remoteInstance.host;
break;
}
TextView tv = (TextView) LayoutInflater.from(activity).inflate(R.layout.custom_tab_instance, new LinearLayout(activity), false);
tv.setText(name);
tabTitle.add(name);
tabType.add(pinnedTimeline.type);
if (pinnedTimeline.type == Timeline.TimeLineEnum.REMOTE) {
tabTypeRemote.add(pinnedTimeline.remoteInstance.type);
} else {
tabTypeRemote.add(null);
}
tab.setCustomView(tv);
activityMainBinding.tabLayout.addTab(tab);
pinnedTimelineVisibleList.add(pinnedTimeline);
}
}
LinearLayout tabStrip = (LinearLayout) activityMainBinding.tabLayout.getChildAt(0);
for (int i = 0; i < tabStrip.getChildCount(); i++) {
// Set LongClick listener to each Tab
int finalI = i;
Pinned finalPinned = pinned;
tabStrip.getChildAt(i).setOnLongClickListener(v -> {
switch (pinnedTimelineVisibleList.get(finalI - (BOTTOM_TIMELINE_COUNT - toRemove)).type) {
case LIST:
break;
case TAG:
tagClick(activity, finalPinned, v, activityMainBinding, finalI);
break;
case REMOTE:
instanceClick(activity, finalPinned, v, activityMainBinding, finalI);
break;
}
return true;
});
}
activityMainBinding.viewPager.setAdapter(null);
activityMainBinding.tabLayout.clearOnTabSelectedListeners();
FedilabPageAdapter fedilabPageAdapter = new FedilabPageAdapter(activity, activity, pinned, bottomMenu);
activityMainBinding.viewPager.setAdapter(fedilabPageAdapter);
activityMainBinding.viewPager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
@Override
public void onPageSelected(int position) {
if (position < BOTTOM_TIMELINE_COUNT - toRemove) {
activityMainBinding.bottomNavView.getMenu().getItem(position).setChecked(true);
} else {
activityMainBinding.bottomNavView.getMenu().setGroupCheckable(0, true, false);
for (int i = 0; i < activityMainBinding.bottomNavView.getMenu().size(); i++) {
activityMainBinding.bottomNavView.getMenu().getItem(i).setChecked(false);
}
activityMainBinding.bottomNavView.getMenu().setGroupCheckable(0, true, true);
}
}
});
new TabLayoutMediator(activityMainBinding.tabLayout, activityMainBinding.viewPager,
(tab, position) -> {
TabCustomViewBinding tabCustomViewBinding = TabCustomViewBinding.inflate(activity.getLayoutInflater());
tabCustomViewBinding.title.setText(tabTitle.get(position));
switch (tabType.get(position)) {
case LIST:
tabCustomViewBinding.icon.setImageResource(R.drawable.ic_tl_list);
break;
case TAG:
tabCustomViewBinding.icon.setImageResource(R.drawable.ic_tl_tag);
break;
case REMOTE:
switch (tabTypeRemote.get(position)) {
case PIXELFED:
tabCustomViewBinding.icon.setImageResource(R.drawable.pixelfed);
break;
case MASTODON:
tabCustomViewBinding.icon.setImageResource(R.drawable.mastodon_icon_item);
break;
case MISSKEY:
tabCustomViewBinding.icon.setImageResource(R.drawable.misskey);
break;
case NITTER:
tabCustomViewBinding.icon.setImageResource(R.drawable.nitter);
break;
case GNU:
tabCustomViewBinding.icon.setImageResource(R.drawable.ic_gnu_social);
break;
case PEERTUBE:
tabCustomViewBinding.icon.setImageResource(R.drawable.peertube_icon);
break;
}
break;
}
tab.setCustomView(tabCustomViewBinding.getRoot());
}
).attach();
activityMainBinding.tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
@Override
public void onTabSelected(TabLayout.Tab tab) {
}
@Override
public void onTabUnselected(TabLayout.Tab tab) {
}
@Override
public void onTabReselected(TabLayout.Tab tab) {
Fragment fragment = activity.getSupportFragmentManager().findFragmentByTag("f" + activityMainBinding.viewPager.getCurrentItem());
if (fragment instanceof FragmentMastodonTimeline) {
((FragmentMastodonTimeline) fragment).scrollToTop();
} else if (fragment instanceof FragmentMastodonConversation) {
((FragmentMastodonConversation) fragment).scrollToTop();
}
}
});
}
public static int itemToRemoveInBottomMenu(BaseMainActivity activity) {
//Small hack to hide first tabs (they represent the item of the bottom menu)
BottomMenu bottomMenuDb;
int toRemove = 0;
try {
//If some menu items have been hidden we should not create tab for them
bottomMenuDb = new BottomMenu(activity).getAllBottomMenu(currentAccount);
if (bottomMenuDb != null) {
List<BottomMenu.MenuItem> menuItemList = bottomMenuDb.bottom_menu;
if (menuItemList != null) {
for (BottomMenu.MenuItem menuItem : menuItemList) {
if (!menuItem.visible) {
toRemove++;
}
}
}
}
} catch (DBException e) {
e.printStackTrace();
}
return toRemove;
}
/**
* Manage long clicks on Tag timelines
*
* @param activity - BaseMainActivity activity
* @param pinned - {@link Pinned}
* @param view - View
* @param position - int position of the tab
*/
public static void tagClick(BaseMainActivity activity, Pinned pinned, View view, ActivityMainBinding activityMainBinding, int position) {
int toRemove = itemToRemoveInBottomMenu(activity);
PopupMenu popup = new PopupMenu(new ContextThemeWrapper(activity, Helper.popupStyle()), view);
int offSetPosition = position - (BOTTOM_TIMELINE_COUNT - toRemove);
String tag;
TagTimeline tagTimeline = pinned.pinnedTimelines.get(offSetPosition).tagTimeline;
if (tagTimeline == null)
return;
if (tagTimeline.displayName != null)
tag = tagTimeline.displayName;
else
tag = tagTimeline.name;
popup.getMenuInflater()
.inflate(R.menu.option_tag_timeline, popup.getMenu());
Menu menu = popup.getMenu();
final MenuItem itemMediaOnly = menu.findItem(R.id.action_show_media_only);
final MenuItem itemShowNSFW = menu.findItem(R.id.action_show_nsfw);
final boolean[] changes = {false};
final boolean[] mediaOnly = {false};
final boolean[] showNSFW = {false};
mediaOnly[0] = tagTimeline.isART;
showNSFW[0] = tagTimeline.isNSFW;
itemMediaOnly.setChecked(mediaOnly[0]);
itemShowNSFW.setChecked(showNSFW[0]);
popup.setOnDismissListener(menu1 -> {
if (changes[0]) {
FragmentMastodonTimeline fragmentMastodonTimeline;
Fragment fragment = activity.getSupportFragmentManager().findFragmentByTag("f" + activityMainBinding.viewPager.getCurrentItem());
if (fragment instanceof FragmentMastodonTimeline && fragment.isVisible()) {
fragmentMastodonTimeline = ((FragmentMastodonTimeline) fragment);
FragmentTransaction fragTransaction = activity.getSupportFragmentManager().beginTransaction();
fragTransaction.detach(fragmentMastodonTimeline).commit();
Bundle bundle = new Bundle();
bundle.putSerializable(Helper.ARG_TIMELINE_TYPE, Timeline.TimeLineEnum.TAG);
bundle.putSerializable(Helper.ARG_TAG_TIMELINE, tagTimeline);
fragmentMastodonTimeline.setArguments(bundle);
FragmentTransaction fragTransaction2 = activity.getSupportFragmentManager().beginTransaction();
fragTransaction2.attach(fragmentMastodonTimeline);
fragTransaction2.commit();
}
}
});
popup.setOnMenuItemClickListener(item -> {
item.setShowAsAction(MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW);
item.setActionView(new View(activity));
item.setOnActionExpandListener(new MenuItem.OnActionExpandListener() {
@Override
public boolean onMenuItemActionExpand(MenuItem item) {
return false;
}
@Override
public boolean onMenuItemActionCollapse(MenuItem item) {
return false;
}
});
changes[0] = true;
int itemId = item.getItemId();
if (itemId == R.id.action_show_media_only) {
mediaOnly[0] = !mediaOnly[0];
tagTimeline.isART = mediaOnly[0];
pinned.pinnedTimelines.get(offSetPosition).tagTimeline = tagTimeline;
itemMediaOnly.setChecked(mediaOnly[0]);
try {
new Pinned(activity).updatePinned(pinned);
} catch (DBException e) {
e.printStackTrace();
}
} else if (itemId == R.id.action_show_nsfw) {
showNSFW[0] = !showNSFW[0];
tagTimeline.isNSFW = showNSFW[0];
pinned.pinnedTimelines.get(offSetPosition).tagTimeline = tagTimeline;
itemShowNSFW.setChecked(showNSFW[0]);
try {
new Pinned(activity).updatePinned(pinned);
} catch (DBException e) {
e.printStackTrace();
}
} else if (itemId == R.id.action_any) {
AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(activity, Helper.dialogStyle());
LayoutInflater inflater = activity.getLayoutInflater();
View dialogView = inflater.inflate(R.layout.tags_any, new LinearLayout(activity), false);
dialogBuilder.setView(dialogView);
final EditText editText = dialogView.findViewById(R.id.filter_any);
if (tagTimeline.any != null) {
StringBuilder valuesTag = new StringBuilder();
for (String val : tagTimeline.any)
valuesTag.append(val).append(" ");
editText.setText(valuesTag.toString());
editText.setSelection(editText.getText().toString().length());
}
dialogBuilder.setPositiveButton(R.string.validate, (dialog, id) -> {
String[] values = editText.getText().toString().trim().split("\\s+");
tagTimeline.any = new ArrayList<>(Arrays.asList(values));
pinned.pinnedTimelines.get(offSetPosition).tagTimeline = tagTimeline;
try {
new Pinned(activity).updatePinned(pinned);
} catch (DBException e) {
e.printStackTrace();
}
});
AlertDialog alertDialog = dialogBuilder.create();
alertDialog.show();
} else if (itemId == R.id.action_all) {
AlertDialog.Builder dialogBuilder;
LayoutInflater inflater;
View dialogView;
AlertDialog alertDialog;
dialogBuilder = new AlertDialog.Builder(activity, Helper.dialogStyle());
inflater = activity.getLayoutInflater();
dialogView = inflater.inflate(R.layout.tags_all, new LinearLayout(activity), false);
dialogBuilder.setView(dialogView);
final EditText editTextAll = dialogView.findViewById(R.id.filter_all);
if (tagTimeline.all != null) {
StringBuilder valuesTag = new StringBuilder();
for (String val : tagTimeline.all)
valuesTag.append(val).append(" ");
editTextAll.setText(valuesTag.toString());
editTextAll.setSelection(editTextAll.getText().toString().length());
}
dialogBuilder.setPositiveButton(R.string.validate, (dialog, id) -> {
String[] values = editTextAll.getText().toString().trim().split("\\s+");
tagTimeline.all = new ArrayList<>(Arrays.asList(values));
pinned.pinnedTimelines.get(offSetPosition).tagTimeline = tagTimeline;
try {
new Pinned(activity).updatePinned(pinned);
} catch (DBException e) {
e.printStackTrace();
}
});
alertDialog = dialogBuilder.create();
alertDialog.show();
} else if (itemId == R.id.action_none) {
AlertDialog.Builder dialogBuilder;
LayoutInflater inflater;
View dialogView;
AlertDialog alertDialog;
dialogBuilder = new AlertDialog.Builder(activity, Helper.dialogStyle());
inflater = activity.getLayoutInflater();
dialogView = inflater.inflate(R.layout.tags_all, new LinearLayout(activity), false);
dialogBuilder.setView(dialogView);
final EditText editTextNone = dialogView.findViewById(R.id.filter_all);
if (tagTimeline.none != null) {
StringBuilder valuesTag = new StringBuilder();
for (String val : tagTimeline.none)
valuesTag.append(val).append(" ");
editTextNone.setText(valuesTag.toString());
editTextNone.setSelection(editTextNone.getText().toString().length());
}
dialogBuilder.setPositiveButton(R.string.validate, (dialog, id) -> {
String[] values = editTextNone.getText().toString().trim().split("\\s+");
tagTimeline.none = new ArrayList<>(Arrays.asList(values));
pinned.pinnedTimelines.get(offSetPosition).tagTimeline = tagTimeline;
try {
new Pinned(activity).updatePinned(pinned);
} catch (DBException e) {
e.printStackTrace();
}
});
alertDialog = dialogBuilder.create();
alertDialog.show();
} else if (itemId == R.id.action_displayname) {
AlertDialog.Builder dialogBuilder;
LayoutInflater inflater;
View dialogView;
AlertDialog alertDialog;
dialogBuilder = new AlertDialog.Builder(activity, Helper.dialogStyle());
inflater = activity.getLayoutInflater();
dialogView = inflater.inflate(R.layout.tags_name, new LinearLayout(activity), false);
dialogBuilder.setView(dialogView);
final EditText editTextName = dialogView.findViewById(R.id.column_name);
if (tagTimeline.displayName != null) {
editTextName.setText(tagTimeline.displayName);
editTextName.setSelection(editTextName.getText().toString().length());
}
dialogBuilder.setPositiveButton(R.string.validate, (dialog, id) -> {
String values = editTextName.getText().toString();
if (values.trim().length() == 0)
values = tag;
tagTimeline.displayName = values;
pinned.pinnedTimelines.get(offSetPosition).tagTimeline = tagTimeline;
try {
new Pinned(activity).updatePinned(pinned);
} catch (DBException e) {
e.printStackTrace();
}
});
alertDialog = dialogBuilder.create();
alertDialog.show();
}
return false;
});
popup.show();
}
/**
* Manage long clicks on followed instances
*
* @param activity - BaseMainActivity activity
* @param pinned - {@link Pinned}
* @param view - View
* @param position - int position of the tab
*/
public static void instanceClick(BaseMainActivity activity, Pinned pinned, View view, ActivityMainBinding activityMainBinding, int position) {
PopupMenu popup = new PopupMenu(new ContextThemeWrapper(activity, Helper.popupStyle()), view);
int toRemove = itemToRemoveInBottomMenu(activity);
int offSetPosition = position - (BOTTOM_TIMELINE_COUNT - toRemove);
RemoteInstance remoteInstance = pinned.pinnedTimelines.get(offSetPosition).remoteInstance;
if (remoteInstance == null)
return;
final String[] currentFilter = {remoteInstance.filteredWith};
final boolean[] changes = {false};
String title;
if (currentFilter[0] == null) {
title = "" + activity.getString(R.string.all);
} else {
title = activity.getString(R.string.all);
}
MenuItem itemAll = popup.getMenu().add(0, 0, Menu.NONE, title);
itemAll.setOnMenuItemClickListener(item -> {
item.setShowAsAction(MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW);
item.setActionView(new View(activity));
item.setOnActionExpandListener(new MenuItem.OnActionExpandListener() {
@Override
public boolean onMenuItemActionExpand(MenuItem item) {
return false;
}
@Override
public boolean onMenuItemActionCollapse(MenuItem item) {
return false;
}
});
changes[0] = true;
FragmentMastodonTimeline fragmentMastodonTimeline = null;
Fragment fragment = activity.getSupportFragmentManager().findFragmentByTag("f" + activityMainBinding.viewPager.getCurrentItem());
if (fragment instanceof FragmentMastodonTimeline && fragment.isVisible()) {
fragmentMastodonTimeline = ((FragmentMastodonTimeline) fragment);
}
if (fragmentMastodonTimeline == null)
return false;
FragmentTransaction fragTransaction1 = activity.getSupportFragmentManager().beginTransaction();
pinned.pinnedTimelines.get(offSetPosition).remoteInstance.filteredWith = null;
remoteInstance.filteredWith = null;
currentFilter[0] = null;
pinned.pinnedTimelines.get(offSetPosition).remoteInstance = remoteInstance;
try {
new Pinned(activity).updatePinned(pinned);
} catch (DBException e) {
e.printStackTrace();
}
fragTransaction1.detach(fragmentMastodonTimeline).commit();
Bundle bundle = new Bundle();
bundle.putString(Helper.ARG_REMOTE_INSTANCE, remoteInstance.host != null ? remoteInstance.host : "");
bundle.putString("instanceType", remoteInstance.type.getValue());
bundle.putString("timelineId", remoteInstance.id);
bundle.putSerializable(Helper.ARG_TIMELINE_TYPE, Timeline.TimeLineEnum.REMOTE);
fragmentMastodonTimeline.setArguments(bundle);
FragmentTransaction fragTransaction2 = activity.getSupportFragmentManager().beginTransaction();
fragTransaction2.attach(fragmentMastodonTimeline);
fragTransaction2.commit();
popup.getMenu().close();
return false;
});
java.util.List<String> tags = remoteInstance.tags;
if (tags != null && tags.size() > 0) {
java.util.Collections.sort(tags);
for (String tag : tags) {
if (tag == null || tag.length() == 0)
continue;
if (currentFilter[0] != null && currentFilter[0].equals(tag)) {
title = "" + tag;
} else {
title = tag;
}
MenuItem item = popup.getMenu().add(0, 0, Menu.NONE, title);
item.setOnMenuItemClickListener(item1 -> {
FragmentMastodonTimeline fragmentMastodonTimeline = null;
Fragment fragment = activity.getSupportFragmentManager().findFragmentByTag("f" + activityMainBinding.viewPager.getCurrentItem());
if (fragment instanceof FragmentMastodonTimeline && fragment.isVisible()) {
fragmentMastodonTimeline = ((FragmentMastodonTimeline) fragment);
fragmentMastodonTimeline.refreshAllAdapters();
}
FragmentTransaction fragTransaction1 = activity.getSupportFragmentManager().beginTransaction();
if (fragmentMastodonTimeline == null)
return false;
pinned.pinnedTimelines.get(offSetPosition).remoteInstance.filteredWith = tag;
remoteInstance.filteredWith = tag;
try {
new Pinned(activity).updatePinned(pinned);
} catch (DBException e) {
e.printStackTrace();
}
currentFilter[0] = remoteInstance.filteredWith;
fragTransaction1.detach(fragmentMastodonTimeline).commit();
Bundle bundle = new Bundle();
bundle.putString(Helper.ARG_REMOTE_INSTANCE, remoteInstance.host != null ? remoteInstance.host : "");
bundle.putString("instanceType", remoteInstance.type.getValue());
bundle.putString("timelineId", remoteInstance.id);
bundle.putString("currentfilter", remoteInstance.filteredWith);
bundle.putSerializable(Helper.ARG_TIMELINE_TYPE, Timeline.TimeLineEnum.REMOTE);
fragmentMastodonTimeline.setArguments(bundle);
FragmentTransaction fragTransaction2 = activity.getSupportFragmentManager().beginTransaction();
fragTransaction2.attach(fragmentMastodonTimeline);
fragTransaction2.commit();
return false;
});
}
}
MenuItem itemadd = popup.getMenu().add(0, 0, Menu.NONE, activity.getString(R.string.add_tags));
itemadd.setOnMenuItemClickListener(item -> {
item.setShowAsAction(MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW);
item.setActionView(new View(activity));
item.setOnActionExpandListener(new MenuItem.OnActionExpandListener() {
@Override
public boolean onMenuItemActionExpand(MenuItem item) {
return false;
}
@Override
public boolean onMenuItemActionCollapse(MenuItem item) {
return false;
}
});
changes[0] = true;
AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(activity, Helper.dialogStyle());
LayoutInflater inflater = activity.getLayoutInflater();
View dialogView = inflater.inflate(R.layout.tags_instance, new LinearLayout(activity), false);
dialogBuilder.setView(dialogView);
final EditText editText = dialogView.findViewById(R.id.filter_words);
if (remoteInstance.tags != null) {
StringBuilder valuesTag = new StringBuilder();
for (String val : remoteInstance.tags)
valuesTag.append(val).append(" ");
editText.setText(valuesTag.toString());
editText.setSelection(editText.getText().toString().length());
}
dialogBuilder.setPositiveButton(R.string.validate, (dialog, id) -> {
String[] values = editText.getText().toString().trim().split("\\s+");
remoteInstance.tags = new ArrayList<>(Arrays.asList(values));
try {
new Pinned(activity).updatePinned(pinned);
} catch (DBException e) {
e.printStackTrace();
}
popup.getMenu().clear();
popup.getMenu().close();
instanceClick(activity, pinned, view, activityMainBinding, position);
});
AlertDialog alertDialog = dialogBuilder.create();
alertDialog.show();
return false;
});
popup.setOnDismissListener(menu -> {
if (changes[0]) {
FragmentMastodonTimeline fragmentMastodonTimeline = null;
Fragment fragment = activity.getSupportFragmentManager().findFragmentByTag("f" + activityMainBinding.viewPager.getCurrentItem());
if (fragment instanceof FragmentMastodonTimeline && fragment.isVisible()) {
fragmentMastodonTimeline = ((FragmentMastodonTimeline) fragment);
fragmentMastodonTimeline.refreshAllAdapters();
}
FragmentTransaction fragTransaction1 = activity.getSupportFragmentManager().beginTransaction();
if (fragmentMastodonTimeline == null)
return;
fragTransaction1.detach(fragmentMastodonTimeline).commit();
Bundle bundle = new Bundle();
bundle.putString(Helper.ARG_REMOTE_INSTANCE, remoteInstance.host != null ? remoteInstance.host : "");
bundle.putString("instanceType", remoteInstance.type.getValue());
bundle.putString("timelineId", remoteInstance.id);
if (currentFilter[0] != null) {
bundle.putString("currentfilter", remoteInstance.filteredWith);
}
bundle.putSerializable(Helper.ARG_TIMELINE_TYPE, Timeline.TimeLineEnum.REMOTE);
fragmentMastodonTimeline.setArguments(bundle);
FragmentTransaction fragTransaction2 = activity.getSupportFragmentManager().beginTransaction();
fragTransaction2.attach(fragmentMastodonTimeline);
fragTransaction2.commit();
}
});
popup.show();
}
}

View file

@ -1,217 +0,0 @@
package app.fedilab.android.helper;
/* Copyright 2022 Thomas Schneider
*
* This file is a part of Fedilab
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* Fedilab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see <http://www.gnu.org/licenses>. */
import android.content.Context;
import android.os.Build;
import android.text.Html;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.ViewModelProvider;
import androidx.lifecycle.ViewModelStoreOwner;
import com.google.gson.annotations.SerializedName;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import app.fedilab.android.BaseMainActivity;
import app.fedilab.android.client.endpoints.MastodonAccountsService;
import app.fedilab.android.client.entities.api.Filter;
import app.fedilab.android.client.entities.api.Notification;
import app.fedilab.android.client.entities.api.Status;
import app.fedilab.android.viewmodel.mastodon.AccountsVM;
import okhttp3.OkHttpClient;
import retrofit2.Call;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
public class TimelineHelper {
private static MastodonAccountsService init(Context context) {
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.readTimeout(60, TimeUnit.SECONDS)
.connectTimeout(60, TimeUnit.SECONDS)
.proxy(Helper.getProxy(context))
.build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://" + BaseMainActivity.currentInstance + "/api/v1/")
.addConverterFactory(GsonConverterFactory.create())
.client(okHttpClient)
.build();
return retrofit.create(MastodonAccountsService.class);
}
/**
* Allows to filter statuses, should be called in API calls (background)
*
* @param context - Context
* @param statuses - List of {@link Status}
* @param filterTimeLineType - {@link FilterTimeLineType}
* @return filtered List<Status>
*/
public static List<Status> filterStatus(Context context, List<Status> statuses, FilterTimeLineType filterTimeLineType) {
//A security to make sure filters have been fetched before displaying messages
List<Status> statusesToRemove = new ArrayList<>();
if (!BaseMainActivity.filterFetched) {
MastodonAccountsService mastodonAccountsService = init(context);
List<Filter> filterList;
Call<List<Filter>> getFiltersCall = mastodonAccountsService.getFilters(BaseMainActivity.currentToken);
if (getFiltersCall != null) {
try {
Response<List<Filter>> getFiltersResponse = getFiltersCall.execute();
if (getFiltersResponse.isSuccessful()) {
BaseMainActivity.filterFetched = true;
filterList = getFiltersResponse.body();
BaseMainActivity.mainFilters = filterList;
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
//If there are filters:
if (BaseMainActivity.mainFilters != null && BaseMainActivity.mainFilters.size() > 0 && statuses != null && statuses.size() > 0) {
for (Filter filter : BaseMainActivity.mainFilters) {
if (filter.irreversible) { //Dealt by the server
continue;
}
for (String filterContext : filter.context) {
if (filterTimeLineType.value.equalsIgnoreCase(filterContext)) {
if (filter.whole_word) {
Pattern p = Pattern.compile("(^" + Pattern.quote(filter.phrase) + "\\b|\\b" + Pattern.quote(filter.phrase) + "$)");
for (Status status : statuses) {
String content;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
content = Html.fromHtml(status.content, Html.FROM_HTML_MODE_LEGACY).toString();
else
content = Html.fromHtml(status.content).toString();
Matcher m = p.matcher(content);
if (m.find()) {
statusesToRemove.add(status);
}
}
} else {
for (Status status : statuses) {
String content;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
content = Html.fromHtml(status.content, Html.FROM_HTML_MODE_LEGACY).toString();
else
content = Html.fromHtml(status.content).toString();
if (content.contains(filter.phrase)) {
statusesToRemove.add(status);
}
}
}
}
}
}
}
if (statuses != null) {
statuses.removeAll(statusesToRemove);
}
return statuses;
}
/**
* Allows to filter notifications, should be called in API calls (background)
*
* @param context - Context
* @param notifications - List of {@link Notification}
* @return filtered List<Status>
*/
public static List<Notification> filterNotification(Context context, List<Notification> notifications) {
//A security to make sure filters have been fetched before displaying messages
List<Notification> notificationToRemove = new ArrayList<>();
if (!BaseMainActivity.filterFetched) {
try {
AccountsVM accountsVM = new ViewModelProvider((ViewModelStoreOwner) context).get(AccountsVM.class);
accountsVM.getFilters(BaseMainActivity.currentInstance, BaseMainActivity.currentToken).observe((LifecycleOwner) context, filters -> {
BaseMainActivity.filterFetched = true;
BaseMainActivity.mainFilters = filters;
});
} catch (Exception e) {
return notifications;
}
}
//If there are filters:
if (BaseMainActivity.mainFilters != null && BaseMainActivity.mainFilters.size() > 0) {
for (Filter filter : BaseMainActivity.mainFilters) {
if (filter.irreversible) { //Dealt by the server
continue;
}
for (String filterContext : filter.context) {
if (FilterTimeLineType.NOTIFICATION.value.equalsIgnoreCase(filterContext)) {
if (filter.whole_word) {
Pattern p = Pattern.compile("(^" + Pattern.quote(filter.phrase) + "\\b|\\b" + Pattern.quote(filter.phrase) + "$)");
for (Notification notification : notifications) {
if (notification.status != null) {
String content;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
content = Html.fromHtml(notification.status.content, Html.FROM_HTML_MODE_LEGACY).toString();
else
content = Html.fromHtml(notification.status.content).toString();
Matcher m = p.matcher(content);
if (m.find()) {
notificationToRemove.add(notification);
}
}
}
} else {
for (Notification notification : notifications) {
String content;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
content = Html.fromHtml(notification.status.content, Html.FROM_HTML_MODE_LEGACY).toString();
else
content = Html.fromHtml(notification.status.content).toString();
if (content.contains(filter.phrase)) {
notificationToRemove.add(notification);
}
}
}
}
}
}
}
notifications.removeAll(notificationToRemove);
return notifications;
}
public enum FilterTimeLineType {
@SerializedName("HOME")
HOME("HOME"),
@SerializedName("PUBLIC")
PUBLIC("PUBLIC"),
@SerializedName("CONTEXT")
CONTEXT("CONTEXT"),
@SerializedName("NOTIFICATION")
NOTIFICATION("NOTIFICATION");
private final String value;
FilterTimeLineType(String value) {
this.value = value;
}
public String getValue() {
return value;
}
}
}

View file

@ -1,44 +0,0 @@
package app.fedilab.android.helper;
import android.view.View;
import androidx.viewpager2.widget.ViewPager2;
public class ZoomOutPageTransformer implements ViewPager2.PageTransformer {
private static final float MIN_SCALE = 0.85f;
private static final float MIN_ALPHA = 0.5f;
public void transformPage(View view, float position) {
int pageWidth = view.getWidth();
int pageHeight = view.getHeight();
if (position < -1) { // [-Infinity,-1)
// This page is way off-screen to the left.
view.setAlpha(0f);
} else if (position <= 1) { // [-1,1]
// Modify the default slide transition to shrink the page as well
float scaleFactor = Math.max(MIN_SCALE, 1 - Math.abs(position));
float vertMargin = pageHeight * (1 - scaleFactor) / 2;
float horzMargin = pageWidth * (1 - scaleFactor) / 2;
if (position < 0) {
view.setTranslationX(horzMargin - vertMargin / 2);
} else {
view.setTranslationX(-horzMargin + vertMargin / 2);
}
// Scale the page down (between MIN_SCALE and 1)
view.setScaleX(scaleFactor);
view.setScaleY(scaleFactor);
// Fade the page relative to its size.
view.setAlpha(MIN_ALPHA +
(scaleFactor - MIN_SCALE) /
(1 - MIN_SCALE) * (1 - MIN_ALPHA));
} else { // (1,+Infinity]
// This page is way off-screen to the right.
view.setAlpha(0f);
}
}
}

View file

@ -0,0 +1,353 @@
package app.fedilab.android.mastodon.activities;
/* Copyright 2022 Thomas Schneider
*
* This file is a part of Fedilab
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* Fedilab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see <http://www.gnu.org/licenses>. */
import android.app.Activity;
import android.graphics.PorterDuff;
import android.os.Bundle;
import android.view.MenuItem;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.Toast;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.LinearLayoutManager;
import java.util.ArrayList;
import app.fedilab.android.R;
import app.fedilab.android.activities.MainActivity;
import app.fedilab.android.databinding.ActivityAdminReportBinding;
import app.fedilab.android.mastodon.client.entities.api.Status;
import app.fedilab.android.mastodon.client.entities.api.admin.AdminAccount;
import app.fedilab.android.mastodon.client.entities.api.admin.AdminReport;
import app.fedilab.android.mastodon.helper.Helper;
import app.fedilab.android.mastodon.helper.ThemeHelper;
import app.fedilab.android.mastodon.ui.drawer.StatusReportAdapter;
import app.fedilab.android.mastodon.viewmodel.mastodon.AdminVM;
import es.dmoral.toasty.Toasty;
public class AccountReportActivity extends BaseBarActivity {
private String account_id;
private AdminReport report;
private ActivityAdminReportBinding binding;
private AdminVM adminVM;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityAdminReportBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
report = null;
AdminAccount targeted_account = null;
Bundle b = getIntent().getExtras();
if (b != null) {
account_id = b.getString(Helper.ARG_ACCOUNT_ID, null);
targeted_account = (AdminAccount) b.getSerializable(Helper.ARG_ACCOUNT);
report = (AdminReport) b.getSerializable(Helper.ARG_REPORT);
}
binding.allow.getBackground().setColorFilter(ThemeHelper.getAttColor(this, R.attr.colorPrimary), PorterDuff.Mode.MULTIPLY);
binding.reject.getBackground().setColorFilter(ThemeHelper.getAttColor(this, R.attr.colorError), PorterDuff.Mode.MULTIPLY);
if (account_id == null && report == null && targeted_account == null) {
Toasty.error(AccountReportActivity.this, getString(R.string.toast_error), Toast.LENGTH_LONG).show();
finish();
}
binding.assign.setVisibility(View.GONE);
binding.status.setVisibility(View.GONE);
adminVM = new ViewModelProvider(this).get(AdminVM.class);
if (account_id != null) {
adminVM.getAccount(MainActivity.currentInstance, MainActivity.currentToken, account_id).observe(this, account -> fillReport(account, null));
return;
}
if (report != null) {
ArrayList<String> contents = new ArrayList<>();
for (Status status : report.statuses) {
contents.add(status.content);
}
binding.lvStatuses.setLayoutManager(new LinearLayoutManager(this));
StatusReportAdapter adapter = new StatusReportAdapter(contents);
binding.lvStatuses.setAdapter(adapter);
binding.statusesGroup.setVisibility(View.VISIBLE);
targeted_account = report.target_account;
}
if (targeted_account != null) {
account_id = targeted_account.id;
fillReport(targeted_account, null);
account_id = targeted_account.username;
}
}
private void fillReport(AdminAccount accountAdmin, actionType type) {
if (accountAdmin == null) {
Toasty.error(AccountReportActivity.this, getString(R.string.toast_error), Toast.LENGTH_LONG).show();
return;
}
if (!accountAdmin.approved && (accountAdmin.domain == null || accountAdmin.domain.equals("null"))) {
binding.allowRejectGroup.setVisibility(View.VISIBLE);
}
if (!accountAdmin.silenced) {
binding.silence.setText(getString(R.string.silence));
} else {
binding.silence.setText(getString(R.string.unsilence));
}
if (!accountAdmin.disabled) {
binding.disable.setText(getString(R.string.disable));
} else {
binding.disable.setText(getString(R.string.undisable));
}
if (!accountAdmin.suspended) {
binding.suspend.setText(getString(R.string.suspend));
} else {
binding.suspend.setText(getString(R.string.unsuspend));
}
binding.reject.setOnClickListener(view -> adminVM.reject(MainActivity.currentInstance, MainActivity.currentToken, account_id).observe(this, account -> fillReport(account, actionType.REJECT)));
binding.allow.setOnClickListener(view -> adminVM.approve(MainActivity.currentInstance, MainActivity.currentToken, account_id).observe(this, account -> fillReport(account, actionType.APPROVE)));
binding.warn.setOnClickListener(view -> {
adminVM.performAction(MainActivity.currentInstance, MainActivity.currentToken, account_id, "none", null, null, binding.comment.getText().toString().trim(), binding.emailUser.isChecked());
fillReport(accountAdmin, actionType.NONE);
});
binding.silence.setOnClickListener(view -> {
if (!accountAdmin.silenced) {
adminVM.performAction(MainActivity.currentInstance, MainActivity.currentToken, account_id, "silence", null, null, binding.comment.getText().toString().trim(), binding.emailUser.isChecked());
accountAdmin.silenced = true;
fillReport(accountAdmin, actionType.SILENCE);
} else {
adminVM.unsilence(MainActivity.currentInstance, MainActivity.currentToken, account_id).observe(this, account -> fillReport(account, actionType.UNSILENCE));
}
});
binding.disable.setOnClickListener(view -> {
if (!accountAdmin.disabled) {
adminVM.performAction(MainActivity.currentInstance, MainActivity.currentToken, account_id, "disable", null, null, binding.comment.getText().toString().trim(), binding.emailUser.isChecked());
accountAdmin.disabled = true;
fillReport(accountAdmin, actionType.DISABLE);
} else {
adminVM.enable(MainActivity.currentInstance, MainActivity.currentToken, account_id).observe(this, account -> fillReport(account, actionType.ENABLE));
}
});
binding.suspend.setOnClickListener(view -> {
if (!accountAdmin.suspended) {
adminVM.performAction(MainActivity.currentInstance, MainActivity.currentToken, account_id, "suspend", null, null, binding.comment.getText().toString().trim(), binding.emailUser.isChecked());
accountAdmin.suspended = true;
fillReport(accountAdmin, actionType.SUSPEND);
} else {
adminVM.unsuspend(MainActivity.currentInstance, MainActivity.currentToken, account_id).observe(this, account -> fillReport(account, actionType.UNSUSPEND));
}
});
if (type != null) {
String message = null;
switch (type) {
case SILENCE:
message = getString(R.string.account_silenced);
break;
case UNSILENCE:
message = getString(R.string.account_unsilenced);
break;
case DISABLE:
message = getString(R.string.account_disabled);
break;
case ENABLE:
message = getString(R.string.account_undisabled);
break;
case SUSPEND:
message = getString(R.string.account_suspended);
break;
case UNSUSPEND:
message = getString(R.string.account_unsuspended);
break;
case NONE:
message = getString(R.string.account_warned);
break;
case APPROVE:
binding.allowRejectGroup.setVisibility(View.GONE);
message = getString(R.string.account_approved);
break;
case REJECT:
binding.allowRejectGroup.setVisibility(View.GONE);
message = getString(R.string.account_rejected);
break;
}
if (message != null) {
Toasty.success(AccountReportActivity.this, message, Toast.LENGTH_LONG).show();
}
binding.comment.setText("");
InputMethodManager imm = (InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE);
assert imm != null;
imm.hideSoftInputFromWindow(binding.comment.getWindowToken(), 0);
}
if (accountAdmin.account != null) {
binding.username.setText(String.format("@%s", accountAdmin.account.acct));
}
binding.email.setText(accountAdmin.email);
if (accountAdmin.email == null || accountAdmin.email.trim().equals("")) {
binding.email.setVisibility(View.GONE);
binding.emailLabel.setVisibility(View.GONE);
}
if (accountAdmin.ip == null || accountAdmin.ip.trim().equals("")) {
binding.recentIp.setVisibility(View.GONE);
binding.recentIpLabel.setVisibility(View.GONE);
}
if (accountAdmin.created_at == null) {
binding.joined.setVisibility(View.GONE);
binding.joinedLabel.setVisibility(View.GONE);
}
if (accountAdmin.disabled) {
binding.loginStatus.setText(getString(R.string.disabled));
} else if (accountAdmin.silenced) {
binding.loginStatus.setText(getString(R.string.silenced));
} else if (accountAdmin.suspended) {
binding.loginStatus.setText(getString(R.string.suspended));
} else {
binding.loginStatus.setText(getString(R.string.active));
}
if (accountAdmin.domain == null || accountAdmin.domain.trim().equalsIgnoreCase("null")) {
binding.warn.setVisibility(View.VISIBLE);
binding.emailUser.setVisibility(View.VISIBLE);
binding.commentLabel.setVisibility(View.VISIBLE);
binding.comment.setVisibility(View.VISIBLE);
binding.recentIp.setText(accountAdmin.ip != null ? accountAdmin.ip : "");
binding.disable.setVisibility(View.VISIBLE);
binding.suspend.setVisibility(View.VISIBLE);
} else {
binding.warn.setVisibility(View.GONE);
binding.emailUser.setVisibility(View.GONE);
binding.emailUser.setChecked(false);
binding.comment.setVisibility(View.GONE);
binding.recentIp.setText("-");
binding.permissions.setText("-");
binding.email.setText("-");
binding.disable.setVisibility(View.GONE);
binding.suspend.setVisibility(View.VISIBLE);
binding.commentLabel.setVisibility(View.GONE);
}
if (accountAdmin.role != null) {
binding.permissions.setText(AdminAccount.permissions.get(accountAdmin.role.permissions));
binding.permissions.setText(getString(R.string.user));
if (accountAdmin.role.permissions == 1 || accountAdmin.role.permissions == 400) {
binding.warn.setVisibility(View.GONE);
binding.suspend.setVisibility(View.GONE);
binding.silence.setVisibility(View.GONE);
binding.disable.setVisibility(View.GONE);
binding.emailUser.setVisibility(View.GONE);
binding.emailUser.setChecked(false);
binding.comment.setVisibility(View.GONE);
binding.commentLabel.setVisibility(View.GONE);
}
binding.emailStatus.setText(accountAdmin.confirmed ? getString(R.string.confirmed) : getString(R.string.unconfirmed));
}
binding.joined.setText(Helper.dateToString(accountAdmin.created_at));
if (report != null) {
binding.assign.setVisibility(View.VISIBLE);
binding.status.setVisibility(View.VISIBLE);
if (report.assigned_account == null) {
binding.assign.setText(getString(R.string.assign_to_me));
} else {
binding.assign.setText(getString(R.string.unassign));
}
binding.assign.setOnClickListener(view -> {
if (report.assigned_account == null) {
adminVM.assignToSelf(MainActivity.currentInstance, MainActivity.currentToken, report.id).observe(this, adminReport -> {
report = adminReport;
fillReport(accountAdmin, null);
});
} else {
adminVM.unassign(MainActivity.currentInstance, MainActivity.currentToken, report.id).observe(this, adminReport -> {
report = adminReport;
fillReport(accountAdmin, null);
});
}
});
if (report.action_taken) {
binding.status.setText(getString(R.string.mark_unresolved));
} else {
binding.status.setText(getString(R.string.mark_resolved));
}
binding.status.setOnClickListener(view -> {
if (report.action_taken) {
adminVM.reopen(MainActivity.currentInstance, MainActivity.currentToken, report.id).observe(this, adminReport -> {
report = adminReport;
fillReport(accountAdmin, null);
});
} else {
adminVM.resolved(MainActivity.currentInstance, MainActivity.currentToken, report.id).observe(this, adminReport -> {
report = adminReport;
fillReport(accountAdmin, null);
});
}
});
} else {
binding.assign.setVisibility(View.GONE);
binding.status.setVisibility(View.GONE);
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
finish();
return true;
}
return super.onOptionsItemSelected(item);
}
public enum actionType {
ENABLE,
APPROVE,
REJECT,
NONE,
SILENCE,
DISABLE,
UNSILENCE,
SUSPEND,
UNSUSPEND,
ASSIGN_TO_SELF,
UNASSIGN,
REOPEN,
RESOLVE,
GET_ACCOUNTS,
GET_ONE_ACCOUNT,
GET_REPORTS,
GET_ONE_REPORT
}
}

View file

@ -1,4 +1,4 @@
package app.fedilab.android.activities;
package app.fedilab.android.mastodon.activities;
/* Copyright 2022 Thomas Schneider
*
* This file is a part of Fedilab
@ -14,51 +14,52 @@ package app.fedilab.android.activities;
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see <http://www.gnu.org/licenses>. */
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.view.MenuItem;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import app.fedilab.android.R;
import app.fedilab.android.client.entities.app.Timeline;
import app.fedilab.android.databinding.ActivityActionsBinding;
import app.fedilab.android.helper.Helper;
import app.fedilab.android.helper.ThemeHelper;
import app.fedilab.android.ui.fragment.timeline.FragmentMastodonAccount;
import app.fedilab.android.ui.fragment.timeline.FragmentMastodonTimeline;
import app.fedilab.android.mastodon.client.entities.app.Timeline;
import app.fedilab.android.mastodon.helper.Helper;
import app.fedilab.android.mastodon.helper.ThemeHelper;
import app.fedilab.android.mastodon.ui.fragment.timeline.FragmentMastodonAccount;
import app.fedilab.android.mastodon.ui.fragment.timeline.FragmentMastodonDomainBlock;
import app.fedilab.android.mastodon.ui.fragment.timeline.FragmentMastodonTimeline;
public class ActionActivity extends BaseActivity {
public class ActionActivity extends BaseBarActivity {
private ActivityActionsBinding binding;
private boolean canGoBack;
private FragmentMastodonTimeline fragmentMastodonTimeline;
private FragmentMastodonAccount fragmentMastodonAccount;
private FragmentMastodonDomainBlock fragmentMastodonDomainBlock;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ThemeHelper.applyThemeBar(this);
binding = ActivityActionsBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setBackgroundDrawable(new ColorDrawable(ContextCompat.getColor(this, R.color.cyanea_primary)));
}
canGoBack = false;
binding.favourites.setOnClickListener(v -> displayTimeline(Timeline.TimeLineEnum.FAVOURITE_TIMELINE));
binding.bookmarks.setOnClickListener(v -> displayTimeline(Timeline.TimeLineEnum.BOOKMARK_TIMELINE));
binding.muted.setOnClickListener(v -> displayTimeline(Timeline.TimeLineEnum.MUTED_TIMELINE));
binding.blocked.setOnClickListener(v -> displayTimeline(Timeline.TimeLineEnum.BLOCKED_TIMELINE));
binding.domainBlock.setOnClickListener(v -> displayTimeline(Timeline.TimeLineEnum.BLOCKED_DOMAIN_TIMELINE));
binding.mutedHome.setOnClickListener(v -> displayTimeline(Timeline.TimeLineEnum.MUTED_TIMELINE_HOME));
}
private void displayTimeline(Timeline.TimeLineEnum type) {
canGoBack = true;
if (type == Timeline.TimeLineEnum.MUTED_TIMELINE || type == Timeline.TimeLineEnum.BLOCKED_TIMELINE) {
if (type == Timeline.TimeLineEnum.MUTED_TIMELINE || type == Timeline.TimeLineEnum.BLOCKED_TIMELINE || type == Timeline.TimeLineEnum.MUTED_TIMELINE_HOME) {
ThemeHelper.slideViewsToLeft(binding.buttonContainer, binding.fragmentContainer, () -> {
fragmentMastodonAccount = new FragmentMastodonAccount();
@ -73,6 +74,15 @@ public class ActionActivity extends BaseActivity {
fragmentTransaction.commit();
});
} else if (type == Timeline.TimeLineEnum.BLOCKED_DOMAIN_TIMELINE) {
ThemeHelper.slideViewsToLeft(binding.buttonContainer, binding.fragmentContainer, () -> {
fragmentMastodonDomainBlock = new FragmentMastodonDomainBlock();
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction =
fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, fragmentMastodonDomainBlock);
fragmentTransaction.commit();
});
} else {
ThemeHelper.slideViewsToLeft(binding.buttonContainer, binding.fragmentContainer, () -> {
@ -102,6 +112,12 @@ public class ActionActivity extends BaseActivity {
case BOOKMARK_TIMELINE:
setTitle(R.string.bookmarks);
break;
case BLOCKED_DOMAIN_TIMELINE:
setTitle(R.string.blocked_domains);
break;
case MUTED_TIMELINE_HOME:
setTitle(R.string.muted_menu_home);
break;
}
}
@ -116,6 +132,9 @@ public class ActionActivity extends BaseActivity {
if (fragmentMastodonAccount != null) {
fragmentMastodonAccount.onDestroyView();
}
if (fragmentMastodonDomainBlock != null) {
fragmentMastodonDomainBlock.onDestroyView();
}
});
setTitle(R.string.interactions);
} else {

View file

@ -1,4 +1,4 @@
package app.fedilab.android.activities;
package app.fedilab.android.mastodon.activities;
/* Copyright 2022 Thomas Schneider
*
* This file is a part of Fedilab
@ -18,20 +18,20 @@ package app.fedilab.android.activities;
import static app.fedilab.android.BaseMainActivity.currentInstance;
import static app.fedilab.android.BaseMainActivity.emojis;
import android.graphics.drawable.ColorDrawable;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.util.TypedValue;
import android.view.MenuItem;
import androidx.appcompat.app.ActionBar;
import androidx.core.content.ContextCompat;
import androidx.preference.PreferenceManager;
import app.fedilab.android.R;
import app.fedilab.android.client.entities.api.EmojiInstance;
import app.fedilab.android.databinding.ActivityAnnouncementBinding;
import app.fedilab.android.exception.DBException;
import app.fedilab.android.helper.Helper;
import app.fedilab.android.helper.ThemeHelper;
import app.fedilab.android.ui.fragment.timeline.FragmentMastodonAnnouncement;
import app.fedilab.android.mastodon.client.entities.api.EmojiInstance;
import app.fedilab.android.mastodon.exception.DBException;
import app.fedilab.android.mastodon.helper.Helper;
import app.fedilab.android.mastodon.ui.fragment.timeline.FragmentMastodonAnnouncement;
public class AnnouncementActivity extends BaseActivity {
@ -40,7 +40,7 @@ public class AnnouncementActivity extends BaseActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ThemeHelper.applyTheme(this);
ActivityAnnouncementBinding binding = ActivityAnnouncementBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
@ -50,14 +50,15 @@ public class AnnouncementActivity extends BaseActivity {
//Remove title
if (actionBar != null) {
actionBar.setDisplayShowTitleEnabled(false);
actionBar.setBackgroundDrawable(new ColorDrawable(ContextCompat.getColor(this, R.color.cyanea_primary)));
}
binding.title.setText(R.string.action_announcements);
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
}
SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(this);
float scale = sharedpreferences.getFloat(getString(R.string.SET_FONT_SCALE), 1.1f);
binding.title.setTextSize(TypedValue.COMPLEX_UNIT_SP, 18 * 1.1f / scale);
Helper.addFragment(getSupportFragmentManager(), R.id.nav_host_fragment_tags, new FragmentMastodonAnnouncement(), null, null, null);
if (emojis == null || !emojis.containsKey(currentInstance)) {
new Thread(() -> {

View file

@ -0,0 +1,173 @@
package app.fedilab.android.mastodon.activities;
/* Copyright 2021 Thomas Schneider
*
* This file is a part of Fedilab
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* Fedilab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see <http://www.gnu.org/licenses>. */
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.view.Window;
import android.view.WindowManager;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.preference.PreferenceManager;
import com.google.android.material.color.DynamicColors;
import com.vanniktech.emoji.EmojiManager;
import com.vanniktech.emoji.one.EmojiOneProvider;
import org.conscrypt.Conscrypt;
import java.security.Security;
import app.fedilab.android.R;
import app.fedilab.android.mastodon.helper.Helper;
import app.fedilab.android.mastodon.helper.ThemeHelper;
@SuppressLint("Registered")
public class BaseActivity extends AppCompatActivity {
public static int currentThemeId;
static {
EmojiManager.install(new EmojiOneProvider());
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
boolean patch_provider = true;
final SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(this);
try {
patch_provider = sharedpreferences.getBoolean(Helper.SET_SECURITY_PROVIDER, true);
} catch (Exception ignored) {
}
if (patch_provider) {
try {
Security.insertProviderAt(Conscrypt.newProvider(), 1);
} catch (Exception ignored) {
}
}
String currentTheme = sharedpreferences.getString(getString(R.string.SET_THEME_BASE), getString(R.string.SET_DEFAULT_THEME));
//Default automatic switch
if (currentTheme.equals(getString(R.string.SET_DEFAULT_THEME))) {
int currentNightMode = getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
switch (currentNightMode) {
case Configuration.UI_MODE_NIGHT_NO:
String defaultLight = sharedpreferences.getString(getString(R.string.SET_THEME_DEFAULT_LIGHT), "LIGHT");
switch (defaultLight) {
case "LIGHT":
setTheme(R.style.AppTheme);
currentThemeId = R.style.AppTheme;
break;
case "SOLARIZED_LIGHT":
setTheme(R.style.SolarizedAppTheme);
currentThemeId = R.style.SolarizedAppTheme;
break;
}
break;
case Configuration.UI_MODE_NIGHT_YES:
String defaultDark = sharedpreferences.getString(getString(R.string.SET_THEME_DEFAULT_DARK), "DARK");
switch (defaultDark) {
case "DARK":
setTheme(R.style.AppTheme);
currentThemeId = R.style.AppTheme;
break;
case "SOLARIZED_DARK":
setTheme(R.style.SolarizedAppTheme);
currentThemeId = R.style.SolarizedAppTheme;
break;
case "BLACK":
setTheme(R.style.BlackAppTheme);
currentThemeId = R.style.BlackAppTheme;
break;
case "DRACULA":
setTheme(R.style.DraculaAppTheme);
currentThemeId = R.style.DraculaAppTheme;
break;
}
break;
}
} else {
switch (currentTheme) {
case "LIGHT":
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
setTheme(R.style.AppTheme);
currentThemeId = R.style.AppTheme;
break;
case "DARK":
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
setTheme(R.style.AppTheme);
currentThemeId = R.style.AppTheme;
break;
case "SOLARIZED_LIGHT":
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
setTheme(R.style.SolarizedAppTheme);
currentThemeId = R.style.SolarizedAppTheme;
break;
case "SOLARIZED_DARK":
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
setTheme(R.style.SolarizedAppTheme);
currentThemeId = R.style.SolarizedAppTheme;
break;
case "BLACK":
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
setTheme(R.style.BlackAppTheme);
currentThemeId = R.style.BlackAppTheme;
break;
case "DRACULA":
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
setTheme(R.style.DraculaAppTheme);
currentThemeId = R.style.DraculaAppTheme;
break;
}
}
super.onCreate(savedInstanceState);
boolean dynamicColor = sharedpreferences.getBoolean(getString(R.string.SET_DYNAMICCOLOR), false);
if (dynamicColor) {
DynamicColors.applyToActivityIfAvailable(this);
}
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.N) {
ThemeHelper.adjustFontScale(this, getResources().getConfiguration());
}
if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
Window window = getWindow();
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
window.setStatusBarColor(Color.BLACK);
window.setNavigationBarColor(Color.BLACK);
}
Helper.setLocale(this);
}
@Override
protected void attachBaseContext(Context newBase) {
if (android.os.Build.VERSION.SDK_INT > Build.VERSION_CODES.N) {
final Configuration override = new Configuration(newBase.getResources().getConfiguration());
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(newBase);
override.fontScale = prefs.getFloat(newBase.getString(R.string.SET_FONT_SCALE), 1.1f);
applyOverrideConfiguration(override);
}
super.attachBaseContext(newBase);
}
}

View file

@ -0,0 +1,161 @@
package app.fedilab.android.mastodon.activities;
/* Copyright 2022 Thomas Schneider
*
* This file is a part of Fedilab
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* Fedilab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see <http://www.gnu.org/licenses>. */
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.view.Window;
import android.view.WindowManager;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.preference.PreferenceManager;
import com.google.android.material.color.DynamicColors;
import com.vanniktech.emoji.EmojiManager;
import com.vanniktech.emoji.one.EmojiOneProvider;
import org.conscrypt.Conscrypt;
import java.security.Security;
import app.fedilab.android.R;
import app.fedilab.android.mastodon.helper.Helper;
import app.fedilab.android.mastodon.helper.ThemeHelper;
@SuppressLint("Registered")
public class BaseBarActivity extends AppCompatActivity {
static {
EmojiManager.install(new EmojiOneProvider());
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
final SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(this);
boolean patch_provider = true;
try {
patch_provider = sharedpreferences.getBoolean(Helper.SET_SECURITY_PROVIDER, true);
} catch (Exception ignored) {
}
if (patch_provider) {
try {
Security.insertProviderAt(Conscrypt.newProvider(), 1);
} catch (Exception ignored) {
}
}
String currentTheme = sharedpreferences.getString(getString(R.string.SET_THEME_BASE), getString(R.string.SET_DEFAULT_THEME));
//Default automatic switch
if (currentTheme.equals(getString(R.string.SET_DEFAULT_THEME))) {
int currentNightMode = getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
switch (currentNightMode) {
case Configuration.UI_MODE_NIGHT_NO:
String defaultLight = sharedpreferences.getString(getString(R.string.SET_THEME_DEFAULT_LIGHT), "LIGHT");
switch (defaultLight) {
case "LIGHT":
setTheme(R.style.AppThemeBar);
break;
case "SOLARIZED_LIGHT":
setTheme(R.style.SolarizedAppThemeBar);
break;
}
break;
case Configuration.UI_MODE_NIGHT_YES:
String defaultDark = sharedpreferences.getString(getString(R.string.SET_THEME_DEFAULT_DARK), "DARK");
switch (defaultDark) {
case "DARK":
setTheme(R.style.AppThemeBar);
break;
case "SOLARIZED_DARK":
setTheme(R.style.SolarizedAppThemeBar);
break;
case "BLACK":
setTheme(R.style.BlackAppThemeBar);
break;
case "DRACULA":
setTheme(R.style.DraculaAppThemeBar);
break;
}
break;
}
} else {
switch (currentTheme) {
case "LIGHT":
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
setTheme(R.style.AppThemeBar);
break;
case "DARK":
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
setTheme(R.style.AppThemeBar);
break;
case "SOLARIZED_LIGHT":
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
setTheme(R.style.SolarizedAppThemeBar);
break;
case "SOLARIZED_DARK":
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
setTheme(R.style.SolarizedAppThemeBar);
break;
case "BLACK":
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
setTheme(R.style.BlackAppThemeBar);
break;
case "DRACULA":
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
setTheme(R.style.DraculaAppThemeBar);
break;
}
}
super.onCreate(savedInstanceState);
boolean dynamicColor = sharedpreferences.getBoolean(getString(R.string.SET_DYNAMICCOLOR), false);
if (dynamicColor) {
DynamicColors.applyToActivityIfAvailable(this);
}
if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
Window window = getWindow();
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
window.setStatusBarColor(Color.BLACK);
window.setNavigationBarColor(Color.BLACK);
}
if (android.os.Build.VERSION.SDK_INT <= Build.VERSION_CODES.N) {
ThemeHelper.adjustFontScale(this, getResources().getConfiguration());
}
Helper.setLocale(this);
}
@Override
protected void attachBaseContext(Context newBase) {
if (android.os.Build.VERSION.SDK_INT > Build.VERSION_CODES.N) {
final Configuration override = new Configuration(newBase.getResources().getConfiguration());
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(newBase);
override.fontScale = prefs.getFloat(newBase.getString(R.string.SET_FONT_SCALE), 1.1f);
applyOverrideConfiguration(override);
}
super.attachBaseContext(newBase);
}
}

View file

@ -0,0 +1,161 @@
package app.fedilab.android.mastodon.activities;
/* Copyright 2022 Thomas Schneider
*
* This file is a part of Fedilab
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* Fedilab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see <http://www.gnu.org/licenses>. */
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.view.Window;
import android.view.WindowManager;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.preference.PreferenceManager;
import com.google.android.material.color.DynamicColors;
import com.vanniktech.emoji.EmojiManager;
import com.vanniktech.emoji.one.EmojiOneProvider;
import org.conscrypt.Conscrypt;
import java.security.Security;
import app.fedilab.android.R;
import app.fedilab.android.mastodon.helper.Helper;
import app.fedilab.android.mastodon.helper.ThemeHelper;
@SuppressLint("Registered")
public class BaseTransparentActivity extends AppCompatActivity {
static {
EmojiManager.install(new EmojiOneProvider());
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
final SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(this);
boolean patch_provider = true;
try {
patch_provider = sharedpreferences.getBoolean(Helper.SET_SECURITY_PROVIDER, true);
} catch (Exception ignored) {
}
if (patch_provider) {
try {
Security.insertProviderAt(Conscrypt.newProvider(), 1);
} catch (Exception ignored) {
}
}
String currentTheme = sharedpreferences.getString(getString(R.string.SET_THEME_BASE), getString(R.string.SET_DEFAULT_THEME));
//Default automatic switch
if (currentTheme.equals(getString(R.string.SET_DEFAULT_THEME))) {
int currentNightMode = getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
switch (currentNightMode) {
case Configuration.UI_MODE_NIGHT_NO:
String defaultLight = sharedpreferences.getString(getString(R.string.SET_THEME_DEFAULT_LIGHT), "LIGHT");
switch (defaultLight) {
case "LIGHT":
setTheme(R.style.Transparent);
break;
case "SOLARIZED_LIGHT":
setTheme(R.style.TransparentSolarized);
break;
}
break;
case Configuration.UI_MODE_NIGHT_YES:
String defaultDark = sharedpreferences.getString(getString(R.string.SET_THEME_DEFAULT_DARK), "DARK");
switch (defaultDark) {
case "DARK":
setTheme(R.style.Transparent);
break;
case "SOLARIZED_DARK":
setTheme(R.style.TransparentSolarized);
break;
case "BLACK":
setTheme(R.style.TransparentBlack);
break;
case "DRACULA":
setTheme(R.style.TransparentDracula);
break;
}
break;
}
} else {
switch (currentTheme) {
case "LIGHT":
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
setTheme(R.style.Transparent);
break;
case "DARK":
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
setTheme(R.style.Transparent);
break;
case "SOLARIZED_LIGHT":
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
setTheme(R.style.TransparentSolarized);
break;
case "SOLARIZED_DARK":
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
setTheme(R.style.TransparentSolarized);
break;
case "BLACK":
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
setTheme(R.style.TransparentBlack);
break;
case "DRACULA":
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
setTheme(R.style.TransparentDracula);
break;
}
}
super.onCreate(savedInstanceState);
boolean dynamicColor = sharedpreferences.getBoolean(getString(R.string.SET_DYNAMICCOLOR), false);
if (dynamicColor) {
DynamicColors.applyToActivityIfAvailable(this);
}
if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
Window window = getWindow();
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
window.setStatusBarColor(Color.BLACK);
window.setNavigationBarColor(Color.BLACK);
}
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.N) {
ThemeHelper.adjustFontScale(this, getResources().getConfiguration());
}
Helper.setLocale(this);
}
@Override
protected void attachBaseContext(Context newBase) {
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N) {
final Configuration override = new Configuration(newBase.getResources().getConfiguration());
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(newBase);
override.fontScale = prefs.getFloat(newBase.getString(R.string.SET_FONT_SCALE), 1.1f);
applyOverrideConfiguration(override);
}
super.attachBaseContext(newBase);
}
}

View file

@ -1,4 +1,4 @@
package app.fedilab.android.activities;
package app.fedilab.android.mastodon.activities;
/* Copyright 2022 Thomas Schneider
*
* This file is a part of Fedilab
@ -15,7 +15,6 @@ package app.fedilab.android.activities;
* see <http://www.gnu.org/licenses>. */
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
@ -25,24 +24,27 @@ import android.view.MenuItem;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.LinearLayoutManager;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import app.fedilab.android.R;
import app.fedilab.android.client.entities.app.Account;
import app.fedilab.android.client.entities.app.BaseAccount;
import app.fedilab.android.client.entities.app.CacheAccount;
import app.fedilab.android.databinding.ActivityCacheBinding;
import app.fedilab.android.helper.CacheHelper;
import app.fedilab.android.helper.Helper;
import app.fedilab.android.helper.ThemeHelper;
import app.fedilab.android.ui.drawer.CacheAdapter;
import app.fedilab.android.mastodon.client.entities.app.Account;
import app.fedilab.android.mastodon.client.entities.app.BaseAccount;
import app.fedilab.android.mastodon.client.entities.app.CacheAccount;
import app.fedilab.android.mastodon.client.entities.app.StatusCache;
import app.fedilab.android.mastodon.client.entities.app.StatusDraft;
import app.fedilab.android.mastodon.exception.DBException;
import app.fedilab.android.mastodon.helper.CacheHelper;
import app.fedilab.android.mastodon.helper.Helper;
import app.fedilab.android.mastodon.ui.drawer.CacheAdapter;
public class CacheActivity extends BaseActivity {
public class CacheActivity extends BaseBarActivity {
private ActivityCacheBinding binding;
private List<CacheAccount> cacheAccounts;
@ -51,12 +53,11 @@ public class CacheActivity extends BaseActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ThemeHelper.applyThemeBar(this);
binding = ActivityCacheBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setBackgroundDrawable(new ColorDrawable(ContextCompat.getColor(this, R.color.cyanea_primary)));
}
CacheHelper.getCacheValues(CacheActivity.this, size -> {
if (size > 0) {
@ -67,13 +68,35 @@ public class CacheActivity extends BaseActivity {
new Thread(() -> {
List<BaseAccount> accounts = new Account(CacheActivity.this).getPushNotificationAccounts();
List<BaseAccount> accounts;
cacheAccounts = new ArrayList<>();
for (BaseAccount baseAccount : accounts) {
CacheAccount cacheAccount = new CacheAccount();
cacheAccount.account = baseAccount;
cacheAccounts.add(cacheAccount);
try {
accounts = new Account(CacheActivity.this).getAll();
for (BaseAccount baseAccount : accounts) {
CacheAccount cacheAccount = new CacheAccount();
cacheAccount.account = baseAccount;
try {
cacheAccount.home_cache_count = new StatusCache(CacheActivity.this).countHome(baseAccount);
} catch (DBException e) {
e.printStackTrace();
}
try {
cacheAccount.other_cache_count = new StatusCache(CacheActivity.this).countOther(baseAccount);
} catch (DBException e) {
e.printStackTrace();
}
try {
cacheAccount.draft_count = new StatusDraft(CacheActivity.this).count(baseAccount);
} catch (DBException e) {
e.printStackTrace();
}
cacheAccounts.add(cacheAccount);
}
} catch (DBException e) {
e.printStackTrace();
}
Handler mainHandler = new Handler(Looper.getMainLooper());
Runnable myRunnable = () -> {
cacheAdapter = new CacheAdapter(cacheAccounts);
@ -98,7 +121,7 @@ public class CacheActivity extends BaseActivity {
finish();
return true;
} else if (item.getItemId() == R.id.action_clear) {
AlertDialog.Builder deleteConfirm = new AlertDialog.Builder(CacheActivity.this, Helper.dialogStyle());
AlertDialog.Builder deleteConfirm = new MaterialAlertDialogBuilder(CacheActivity.this);
deleteConfirm.setTitle(getString(R.string.delete_cache));
deleteConfirm.setMessage(getString(R.string.delete_cache_message));
deleteConfirm.setNegativeButton(R.string.cancel, (dialog, which) -> dialog.dismiss());
@ -108,7 +131,21 @@ public class CacheActivity extends BaseActivity {
size = size / 1000000.0f;
}
binding.fileCacheSize.setText(String.format("%s %s", String.format(Locale.getDefault(), "%.2f", size), getString(R.string.cache_units)));
cacheAdapter.notifyDataSetChanged();
AlertDialog.Builder restartBuilder = new MaterialAlertDialogBuilder(CacheActivity.this);
restartBuilder.setMessage(getString(R.string.restart_the_app));
restartBuilder.setNegativeButton(R.string.no, (dialogRestart, whichRestart) -> {
recreate();
dialogRestart.dismiss();
});
restartBuilder.setPositiveButton(R.string.restart, (dialogRestart, whichRestart) -> {
dialogRestart.dismiss();
Helper.restart(CacheActivity.this);
});
AlertDialog alertDialog = restartBuilder.create();
if (!isFinishing()) {
alertDialog.show();
}
}));
dialog.dismiss();
});

View file

@ -1,4 +1,4 @@
package app.fedilab.android.activities;
package app.fedilab.android.mastodon.activities;
/* Copyright 2021 Thomas Schneider
*
* This file is a part of Fedilab
@ -18,7 +18,6 @@ package app.fedilab.android.activities;
import static app.fedilab.android.BaseMainActivity.currentAccount;
import static app.fedilab.android.BaseMainActivity.currentInstance;
import static app.fedilab.android.BaseMainActivity.emojis;
import static app.fedilab.android.ui.drawer.ComposeAdapter.prepareDraft;
import android.Manifest;
import android.annotation.SuppressLint;
@ -26,8 +25,8 @@ import android.content.BroadcastReceiver;
import android.content.ClipData;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.graphics.drawable.ColorDrawable;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
@ -35,6 +34,7 @@ import android.os.Handler;
import android.os.Looper;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.TypedValue;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
@ -48,11 +48,15 @@ import androidx.appcompat.app.AlertDialog;
import androidx.core.content.ContextCompat;
import androidx.lifecycle.ViewModelProvider;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import androidx.preference.PreferenceManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.work.Data;
import androidx.work.OneTimeWorkRequest;
import androidx.work.OutOfQuotaPolicy;
import androidx.work.WorkManager;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import java.io.File;
import java.text.ParseException;
import java.text.SimpleDateFormat;
@ -60,59 +64,69 @@ import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.TimeUnit;
import app.fedilab.android.BaseMainActivity;
import app.fedilab.android.R;
import app.fedilab.android.client.entities.api.Attachment;
import app.fedilab.android.client.entities.api.Context;
import app.fedilab.android.client.entities.api.EmojiInstance;
import app.fedilab.android.client.entities.api.Mention;
import app.fedilab.android.client.entities.api.ScheduledStatus;
import app.fedilab.android.client.entities.api.Status;
import app.fedilab.android.client.entities.app.Account;
import app.fedilab.android.client.entities.app.BaseAccount;
import app.fedilab.android.client.entities.app.StatusDraft;
import app.fedilab.android.activities.MainActivity;
import app.fedilab.android.databinding.ActivityPaginationBinding;
import app.fedilab.android.databinding.PopupContactBinding;
import app.fedilab.android.exception.DBException;
import app.fedilab.android.helper.DividerDecorationSimple;
import app.fedilab.android.helper.Helper;
import app.fedilab.android.helper.MastodonHelper;
import app.fedilab.android.helper.MediaHelper;
import app.fedilab.android.helper.SpannableHelper;
import app.fedilab.android.helper.ThemeHelper;
import app.fedilab.android.jobs.ScheduleThreadWorker;
import app.fedilab.android.services.PostMessageService;
import app.fedilab.android.services.ThreadMessageService;
import app.fedilab.android.ui.drawer.AccountsReplyAdapter;
import app.fedilab.android.ui.drawer.ComposeAdapter;
import app.fedilab.android.viewmodel.mastodon.AccountsVM;
import app.fedilab.android.viewmodel.mastodon.StatusesVM;
import app.fedilab.android.mastodon.client.entities.api.Account;
import app.fedilab.android.mastodon.client.entities.api.Attachment;
import app.fedilab.android.mastodon.client.entities.api.Context;
import app.fedilab.android.mastodon.client.entities.api.EmojiInstance;
import app.fedilab.android.mastodon.client.entities.api.Instance;
import app.fedilab.android.mastodon.client.entities.api.Mention;
import app.fedilab.android.mastodon.client.entities.api.ScheduledStatus;
import app.fedilab.android.mastodon.client.entities.api.Status;
import app.fedilab.android.mastodon.client.entities.app.BaseAccount;
import app.fedilab.android.mastodon.client.entities.app.StatusDraft;
import app.fedilab.android.mastodon.exception.DBException;
import app.fedilab.android.mastodon.helper.DividerDecorationSimple;
import app.fedilab.android.mastodon.helper.Helper;
import app.fedilab.android.mastodon.helper.MastodonHelper;
import app.fedilab.android.mastodon.helper.MediaHelper;
import app.fedilab.android.mastodon.interfaces.OnDownloadInterface;
import app.fedilab.android.mastodon.jobs.ComposeWorker;
import app.fedilab.android.mastodon.jobs.ScheduleThreadWorker;
import app.fedilab.android.mastodon.services.ThreadMessageService;
import app.fedilab.android.mastodon.ui.drawer.AccountsReplyAdapter;
import app.fedilab.android.mastodon.ui.drawer.ComposeAdapter;
import app.fedilab.android.mastodon.viewmodel.mastodon.AccountsVM;
import app.fedilab.android.mastodon.viewmodel.mastodon.StatusesVM;
import es.dmoral.toasty.Toasty;
public class ComposeActivity extends BaseActivity implements ComposeAdapter.ManageDrafts, AccountsReplyAdapter.ActionDone {
public class ComposeActivity extends BaseActivity implements ComposeAdapter.ManageDrafts, AccountsReplyAdapter.ActionDone, ComposeAdapter.promptDraftListener {
public static final int MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE = 754;
public static final int REQUEST_AUDIO_PERMISSION_RESULT = 1653;
public static final int PICK_MEDIA = 5700;
public static final int TAKE_PHOTO = 5600;
private final Timer timer = new Timer();
private List<Status> statusList;
private Status statusReply, statusMention;
private Status statusReply, statusMention, statusQuoted;
private StatusDraft statusDraft;
private ComposeAdapter composeAdapter;
private final BroadcastReceiver imageReceiver = new BroadcastReceiver() {
@Override
public void onReceive(android.content.Context context, Intent intent) {
String imgpath = intent.getStringExtra("imgpath");
float focusX = intent.getFloatExtra("focusX", -2);
float focusY = intent.getFloatExtra("focusY", -2);
if (imgpath != null) {
int position = 0;
for (Status status : statusList) {
if (status.media_attachments != null && status.media_attachments.size() > 0) {
for (Attachment attachment : status.media_attachments) {
if (attachment.local_path.equalsIgnoreCase(imgpath)) {
if (attachment.local_path != null && attachment.local_path.equalsIgnoreCase(imgpath)) {
if (focusX != -2) {
attachment.focus = focusX + "," + focusY;
}
composeAdapter.notifyItemChanged(position);
break;
}
@ -123,224 +137,71 @@ public class ComposeActivity extends BaseActivity implements ComposeAdapter.Mana
}
}
};
private boolean promptSaveDraft;
private boolean restoredDraft;
private List<Attachment> sharedAttachments;
private ActivityPaginationBinding binding;
private BaseAccount account;
private String instance, token;
private Uri photoFileUri;
private ScheduledStatus scheduledStatus;
private String visibility;
private app.fedilab.android.client.entities.api.Account accountMention;
private Account accountMention;
private String statusReplyId;
private app.fedilab.android.client.entities.api.Account mentionBooster;
private Account mentionBooster;
private String sharedSubject, sharedContent, sharedTitle, sharedDescription, shareURL, sharedUrlMedia;
private String editMessageId;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ThemeHelper.applyTheme(this);
binding = ActivityPaginationBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
setSupportActionBar(binding.toolbar);
ActionBar actionBar = getSupportActionBar();
//Remove title
if (actionBar != null) {
actionBar.setDisplayShowTitleEnabled(false);
actionBar.setBackgroundDrawable(new ColorDrawable(ContextCompat.getColor(this, R.color.cyanea_primary)));
private static int visibilityToNumber(String visibility) {
switch (visibility) {
case "public":
return 3;
case "unlisted":
return 2;
case "private":
return 1;
case "direct":
return 0;
}
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
}
statusList = new ArrayList<>();
Bundle b = getIntent().getExtras();
if (b != null) {
statusReply = (Status) b.getSerializable(Helper.ARG_STATUS_REPLY);
statusDraft = (StatusDraft) b.getSerializable(Helper.ARG_STATUS_DRAFT);
scheduledStatus = (ScheduledStatus) b.getSerializable(Helper.ARG_STATUS_SCHEDULED);
statusReplyId = b.getString(Helper.ARG_STATUS_REPLY_ID);
statusMention = (Status) b.getSerializable(Helper.ARG_STATUS_MENTION);
account = (Account) b.getSerializable(Helper.ARG_ACCOUNT);
instance = b.getString(Helper.ARG_INSTANCE, null);
token = b.getString(Helper.ARG_TOKEN, null);
visibility = b.getString(Helper.ARG_VISIBILITY, null);
mentionBooster = (app.fedilab.android.client.entities.api.Account) b.getSerializable(Helper.ARG_MENTION_BOOSTER);
accountMention = (app.fedilab.android.client.entities.api.Account) b.getSerializable(Helper.ARG_ACCOUNT_MENTION);
}
binding.toolbar.setPopupTheme(Helper.popupStyle());
//Edit a scheduled status from server
if (scheduledStatus != null) {
statusDraft = new StatusDraft();
List<Status> statuses = new ArrayList<>();
Status status = new Status();
status.text = scheduledStatus.params.text;
status.in_reply_to_id = scheduledStatus.params.in_reply_to_id;
status.poll = scheduledStatus.params.poll;
return 3;
}
if (scheduledStatus.params.media_ids != null && scheduledStatus.params.media_ids.size() > 0) {
status.media_attachments = new ArrayList<>();
new Thread(() -> {
StatusesVM statusesVM = new ViewModelProvider(ComposeActivity.this).get(StatusesVM.class);
for (String attachmentId : scheduledStatus.params.media_ids) {
statusesVM.getAttachment(instance, token, attachmentId)
.observe(ComposeActivity.this, attachment -> status.media_attachments.add(attachment));
}
}).start();
private static String visibilityToString(int visibility) {
switch (visibility) {
case 3:
return "public";
case 2:
return "unlisted";
case 1:
return "private";
case 0:
return "direct";
}
return "public";
}
public static String getVisibility(String defaultVisibility) {
int tootVisibility = visibilityToNumber(defaultVisibility);
if (currentAccount != null && currentAccount.mastodon_account != null && currentAccount.mastodon_account.source != null) {
int userVisibility = visibilityToNumber(currentAccount.mastodon_account.source.privacy);
if (tootVisibility > userVisibility) {
return visibilityToString(userVisibility);
} else {
return visibilityToString(tootVisibility);
}
status.sensitive = scheduledStatus.params.sensitive;
status.spoiler_text = scheduledStatus.params.spoiler_text;
status.visibility = scheduledStatus.params.visibility;
statusDraft.statusDraftList = statuses;
}
if (account == null) {
account = currentAccount;
}
if (account == null) {
Toasty.error(ComposeActivity.this, getString(R.string.toast_error), Toasty.LENGTH_SHORT).show();
finish();
return;
}
if (instance == null) {
instance = account.instance;
}
if (token == null) {
token = account.token;
}
if (emojis == null || !emojis.containsKey(currentInstance)) {
new Thread(() -> {
try {
emojis.put(currentInstance, new EmojiInstance(ComposeActivity.this).getEmojiList(currentInstance));
} catch (DBException e) {
e.printStackTrace();
}
}).start();
}
StatusesVM statusesVM = new ViewModelProvider(ComposeActivity.this).get(StatusesVM.class);
//Empty compose
List<Status> statusDraftList = new ArrayList<>();
Status status = new Status();
statusDraftList.add(status);
if (statusReplyId != null && statusDraft != null) {//Delete and redraft
statusesVM.getStatus(currentInstance, BaseMainActivity.currentToken, statusReplyId)
.observe(ComposeActivity.this, status1 -> {
if (status1 != null) {
statusesVM.getContext(currentInstance, BaseMainActivity.currentToken, statusReplyId)
.observe(ComposeActivity.this, statusContext -> {
if (statusContext != null) {
initializeContextRedraftView(statusContext, status1);
} else {
Helper.sendToastMessage(getApplication(), Helper.RECEIVE_TOAST_TYPE_ERROR, getString(R.string.toast_error));
}
});
} else {
Helper.sendToastMessage(getApplication(), Helper.RECEIVE_TOAST_TYPE_ERROR, getString(R.string.toast_error));
}
});
} else if (statusDraft != null) {//Restore a draft with all messages
new Thread(() -> {
if (statusDraft.statusReplyList != null) {
statusDraft.statusReplyList = SpannableHelper.convertStatus(getApplication().getApplicationContext(), statusDraft.statusReplyList);
}
Handler mainHandler = new Handler(Looper.getMainLooper());
Runnable myRunnable = () -> {
if (statusDraft.statusReplyList != null) {
statusList.addAll(statusDraft.statusReplyList);
binding.recyclerView.addItemDecoration(new DividerDecorationSimple(ComposeActivity.this, statusList));
}
int statusCount = statusList.size();
statusList.addAll(statusDraft.statusDraftList);
composeAdapter = new ComposeAdapter(statusList, statusCount, account, accountMention, visibility);
composeAdapter.manageDrafts = this;
LinearLayoutManager mLayoutManager = new LinearLayoutManager(ComposeActivity.this);
binding.recyclerView.setLayoutManager(mLayoutManager);
binding.recyclerView.setAdapter(composeAdapter);
binding.recyclerView.scrollToPosition(composeAdapter.getItemCount() - 1);
};
mainHandler.post(myRunnable);
}).start();
} else if (statusReply != null) {
new Thread(() -> {
statusReply = SpannableHelper.convertStatus(getApplication().getApplicationContext(), statusReply);
Handler mainHandler = new Handler(Looper.getMainLooper());
Runnable myRunnable = () -> {
statusList.add(statusReply);
int statusCount = statusList.size();
statusDraftList.get(0).in_reply_to_id = statusReply.id;
//We change order for mentions
//At first place the account that has been mentioned if it's not our
statusDraftList.get(0).mentions = new ArrayList<>();
if (!statusReply.account.acct.equalsIgnoreCase(currentAccount.mastodon_account.acct)) {
Mention mention = new Mention();
mention.acct = "@" + statusReply.account.acct;
mention.url = statusReply.account.url;
mention.username = statusReply.account.username;
statusDraftList.get(0).mentions.add(mention);
}
//There are other mentions to
if (statusReply.mentions != null && statusReply.mentions.size() > 0) {
for (Mention mentionTmp : statusReply.mentions) {
if (!mentionTmp.acct.equalsIgnoreCase(statusReply.account.acct) && !mentionTmp.acct.equalsIgnoreCase(currentAccount.mastodon_account.acct)) {
statusDraftList.get(0).mentions.add(mentionTmp);
}
}
}
if (mentionBooster != null) {
Mention mention = new Mention();
mention.acct = mentionBooster.acct;
mention.url = mentionBooster.url;
mention.username = mentionBooster.username;
boolean present = false;
for (Mention mentionTmp : statusDraftList.get(0).mentions) {
if (mentionTmp.acct.equalsIgnoreCase(mentionBooster.acct)) {
present = true;
break;
}
}
if (!present) {
statusDraftList.get(0).mentions.add(mention);
}
}
if (statusReply.spoiler_text != null) {
statusDraftList.get(0).spoiler_text = statusReply.spoiler_text;
}
//StatusDraftList at this point should only have one element
statusList.addAll(statusDraftList);
composeAdapter = new ComposeAdapter(statusList, statusCount, account, accountMention, visibility);
composeAdapter.manageDrafts = this;
LinearLayoutManager mLayoutManager = new LinearLayoutManager(ComposeActivity.this);
binding.recyclerView.setLayoutManager(mLayoutManager);
binding.recyclerView.setAdapter(composeAdapter);
statusesVM.getContext(currentInstance, BaseMainActivity.currentToken, statusReply.id)
.observe(ComposeActivity.this, this::initializeContextView);
};
mainHandler.post(myRunnable);
}).start();
} else {
//Compose without replying
statusList.addAll(statusDraftList);
composeAdapter = new ComposeAdapter(statusList, 0, account, accountMention, visibility);
composeAdapter.manageDrafts = this;
LinearLayoutManager mLayoutManager = new LinearLayoutManager(ComposeActivity.this);
binding.recyclerView.setLayoutManager(mLayoutManager);
binding.recyclerView.setAdapter(composeAdapter);
if (statusMention != null) {
composeAdapter.loadMentions(statusMention);
}
}
MastodonHelper.loadPPMastodon(binding.profilePicture, account.mastodon_account);
LocalBroadcastManager.getInstance(this)
.registerReceiver(imageReceiver,
new IntentFilter(Helper.INTENT_SEND_MODIFIED_IMAGE));
return defaultVisibility;
}
@Override
protected void onDestroy() {
super.onDestroy();
if (timer != null) {
timer.cancel();
}
LocalBroadcastManager.getInstance(this)
.unregisterReceiver(imageReceiver);
}
@Override
@ -350,23 +211,39 @@ public class ComposeActivity extends BaseActivity implements ComposeAdapter.Mana
private void storeDraftWarning() {
if (statusDraft == null) {
statusDraft = prepareDraft(statusList, composeAdapter, account.instance, account.user_id);
statusDraft = ComposeAdapter.prepareDraft(statusList, composeAdapter, account.instance, account.user_id);
}
if (canBeSent(statusDraft)) {
AlertDialog.Builder alt_bld = new AlertDialog.Builder(ComposeActivity.this, Helper.dialogStyle());
alt_bld.setMessage(R.string.save_draft);
alt_bld.setPositiveButton(R.string.save, (dialog, id) -> {
dialog.dismiss();
storeDraft(false);
finish();
if (promptSaveDraft) {
AlertDialog.Builder alt_bld = new MaterialAlertDialogBuilder(ComposeActivity.this);
alt_bld.setMessage(R.string.save_draft);
alt_bld.setPositiveButton(R.string.save, (dialog, id) -> {
dialog.dismiss();
storeDraft(false);
finish();
});
alt_bld.setNegativeButton(R.string.no, (dialog, id) -> {
dialog.dismiss();
});
alt_bld.setNegativeButton(R.string.no, (dialog, id) -> {
try {
new StatusDraft(ComposeActivity.this).removeDraft(statusDraft);
} catch (DBException e) {
e.printStackTrace();
}
dialog.dismiss();
finish();
});
AlertDialog alert = alt_bld.create();
alert.show();
} else {
if (!restoredDraft) {
try {
new StatusDraft(ComposeActivity.this).removeDraft(statusDraft);
} catch (DBException e) {
e.printStackTrace();
}
}
finish();
});
AlertDialog alert = alt_bld.create();
alert.show();
}
} else {
finish();
}
@ -386,7 +263,8 @@ public class ComposeActivity extends BaseActivity implements ComposeAdapter.Mana
statusList.addAll(0, context.ancestors);
composeAdapter.setStatusCount(context.ancestors.size() + 1);
composeAdapter.notifyItemRangeInserted(0, context.ancestors.size());
composeAdapter.notifyItemChanged(context.ancestors.size() + 1);
composeAdapter.notifyItemRangeChanged(0, statusList.size());
if (binding.recyclerView.getItemDecorationCount() > 0) {
for (int i = 0; i < binding.recyclerView.getItemDecorationCount(); i++) {
binding.recyclerView.removeItemDecorationAt(i);
@ -396,7 +274,6 @@ public class ComposeActivity extends BaseActivity implements ComposeAdapter.Mana
binding.recyclerView.scrollToPosition(composeAdapter.getItemCount() - 1);
}
/**
* Intialize the common view for the context
*
@ -412,7 +289,8 @@ public class ComposeActivity extends BaseActivity implements ComposeAdapter.Mana
statusList.addAll(0, context.ancestors);
statusList.add(initialStatus);
statusList.add(statusDraft.statusDraftList.get(0));
composeAdapter = new ComposeAdapter(statusList, context.ancestors.size(), account, accountMention, visibility);
composeAdapter = new ComposeAdapter(statusList, context.ancestors.size(), account, accountMention, visibility, editMessageId);
composeAdapter.promptDraftListener = this;
composeAdapter.manageDrafts = this;
LinearLayoutManager mLayoutManager = new LinearLayoutManager(ComposeActivity.this);
binding.recyclerView.setLayoutManager(mLayoutManager);
@ -422,7 +300,6 @@ public class ComposeActivity extends BaseActivity implements ComposeAdapter.Mana
binding.recyclerView.scrollToPosition(composeAdapter.getItemCount() - 1);
}
@Override
public boolean onCreateOptionsMenu(@NonNull Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
@ -430,7 +307,6 @@ public class ComposeActivity extends BaseActivity implements ComposeAdapter.Mana
return true;
}
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onOptionsItemSelected(MenuItem item) {
@ -440,7 +316,7 @@ public class ComposeActivity extends BaseActivity implements ComposeAdapter.Mana
} else if (item.getItemId() == R.id.action_photo_camera) {
photoFileUri = MediaHelper.dispatchTakePictureIntent(ComposeActivity.this);
} else if (item.getItemId() == R.id.action_contacts) {
AlertDialog.Builder builderSingle = new AlertDialog.Builder(ComposeActivity.this, Helper.dialogStyle());
AlertDialog.Builder builderSingle = new MaterialAlertDialogBuilder(ComposeActivity.this);
builderSingle.setTitle(getString(R.string.select_accounts));
PopupContactBinding popupContactBinding = PopupContactBinding.inflate(getLayoutInflater(), new LinearLayout(ComposeActivity.this), false);
@ -516,7 +392,7 @@ public class ComposeActivity extends BaseActivity implements ComposeAdapter.Mana
}
} else if (item.getItemId() == R.id.action_schedule) {
if (statusDraft == null) {
statusDraft = prepareDraft(statusList, composeAdapter, account.instance, account.user_id);
statusDraft = ComposeAdapter.prepareDraft(statusList, composeAdapter, account.instance, account.user_id);
}
if (canBeSent(statusDraft)) {
MediaHelper.scheduleMessage(ComposeActivity.this, date -> storeDraft(true, date));
@ -527,23 +403,22 @@ public class ComposeActivity extends BaseActivity implements ComposeAdapter.Mana
return true;
}
private void onRetrieveContact(PopupContactBinding binding, List<app.fedilab.android.client.entities.api.Account> accounts) {
binding.loader.setVisibility(View.GONE);
private void onRetrieveContact(PopupContactBinding popupContactBinding, List<Account> accounts) {
popupContactBinding.loader.setVisibility(View.GONE);
if (accounts == null) {
accounts = new ArrayList<>();
}
List<Boolean> checkedValues = new ArrayList<>();
List<app.fedilab.android.client.entities.api.Account> contacts = new ArrayList<>(accounts);
for (app.fedilab.android.client.entities.api.Account account : contacts) {
List<Account> contacts = new ArrayList<>(accounts);
for (Account account : contacts) {
checkedValues.add(composeAdapter.getLastComposeContent().contains("@" + account.acct));
}
AccountsReplyAdapter contactAdapter = new AccountsReplyAdapter(contacts, checkedValues);
binding.lvAccountsSearch.setAdapter(contactAdapter);
binding.lvAccountsSearch.setLayoutManager(new LinearLayoutManager(ComposeActivity.this));
contactAdapter.actionDone = ComposeActivity.this;
popupContactBinding.lvAccountsSearch.setAdapter(contactAdapter);
popupContactBinding.lvAccountsSearch.setLayoutManager(new LinearLayoutManager(ComposeActivity.this));
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
@ -566,16 +441,327 @@ public class ComposeActivity extends BaseActivity implements ComposeAdapter.Mana
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityPaginationBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
setSupportActionBar(binding.toolbar);
promptSaveDraft = false;
restoredDraft = false;
ActionBar actionBar = getSupportActionBar();
//Remove title
if (actionBar != null) {
actionBar.setDisplayShowTitleEnabled(false);
}
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
}
SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(this);
float scale = sharedpreferences.getFloat(getString(R.string.SET_FONT_SCALE), 1.1f);
binding.title.setTextSize(TypedValue.COMPLEX_UNIT_SP, 18 * 1.1f / scale);
statusList = new ArrayList<>();
Bundle b = getIntent().getExtras();
if (b != null) {
statusReply = (Status) b.getSerializable(Helper.ARG_STATUS_REPLY);
statusQuoted = (Status) b.getSerializable(Helper.ARG_QUOTED_MESSAGE);
statusDraft = (StatusDraft) b.getSerializable(Helper.ARG_STATUS_DRAFT);
scheduledStatus = (ScheduledStatus) b.getSerializable(Helper.ARG_STATUS_SCHEDULED);
statusReplyId = b.getString(Helper.ARG_STATUS_REPLY_ID);
statusMention = (Status) b.getSerializable(Helper.ARG_STATUS_MENTION);
account = (BaseAccount) b.getSerializable(Helper.ARG_ACCOUNT);
editMessageId = b.getString(Helper.ARG_EDIT_STATUS_ID, null);
instance = b.getString(Helper.ARG_INSTANCE, null);
token = b.getString(Helper.ARG_TOKEN, null);
visibility = b.getString(Helper.ARG_VISIBILITY, null);
if (visibility == null && statusReply != null) {
visibility = getVisibility(statusReply.visibility);
} else if (visibility == null && currentAccount != null && currentAccount.mastodon_account != null && currentAccount.mastodon_account.source != null) {
visibility = currentAccount.mastodon_account.source.privacy;
}
mentionBooster = (Account) b.getSerializable(Helper.ARG_MENTION_BOOSTER);
accountMention = (Account) b.getSerializable(Helper.ARG_ACCOUNT_MENTION);
//Shared elements
sharedAttachments = (ArrayList<Attachment>) b.getSerializable(Helper.ARG_MEDIA_ATTACHMENTS);
sharedUrlMedia = b.getString(Helper.ARG_SHARE_URL_MEDIA);
sharedSubject = b.getString(Helper.ARG_SHARE_SUBJECT, null);
sharedContent = b.getString(Helper.ARG_SHARE_CONTENT, null);
sharedTitle = b.getString(Helper.ARG_SHARE_TITLE, null);
sharedDescription = b.getString(Helper.ARG_SHARE_DESCRIPTION, null);
shareURL = b.getString(Helper.ARG_SHARE_URL, null);
}
if (sharedContent != null && shareURL != null && sharedContent.compareTo(shareURL) == 0) {
sharedContent = "";
}
if (sharedTitle != null && sharedSubject != null && sharedSubject.length() > sharedTitle.length()) {
sharedTitle = sharedSubject;
}
//Edit a scheduled status from server
if (scheduledStatus != null) {
statusDraft = new StatusDraft();
List<Status> statuses = new ArrayList<>();
Status status = new Status();
status.id = Helper.generateIdString();
status.text = scheduledStatus.params.text;
status.in_reply_to_id = scheduledStatus.params.in_reply_to_id;
status.poll = scheduledStatus.params.poll;
if (scheduledStatus.params.media_ids != null && scheduledStatus.params.media_ids.size() > 0) {
status.media_attachments = new ArrayList<>();
new Thread(() -> {
StatusesVM statusesVM = new ViewModelProvider(ComposeActivity.this).get(StatusesVM.class);
for (String attachmentId : scheduledStatus.params.media_ids) {
statusesVM.getAttachment(instance, token, attachmentId)
.observe(ComposeActivity.this, attachment -> status.media_attachments.add(attachment));
}
}).start();
}
status.sensitive = scheduledStatus.params.sensitive;
status.spoiler_text = scheduledStatus.params.spoiler_text;
status.visibility = scheduledStatus.params.visibility;
statusDraft.statusDraftList = statuses;
}
if (account == null) {
account = currentAccount;
}
if (account == null) {
Toasty.error(ComposeActivity.this, getString(R.string.toast_error), Toasty.LENGTH_SHORT).show();
finish();
return;
}
if (instance == null) {
instance = account.instance;
}
if (token == null) {
token = account.token;
}
if (emojis == null || !emojis.containsKey(instance)) {
new Thread(() -> {
try {
emojis.put(instance, new EmojiInstance(ComposeActivity.this).getEmojiList(instance));
} catch (DBException e) {
e.printStackTrace();
}
}).start();
}
if (MainActivity.instanceInfo == null) {
String instanceInfo = sharedpreferences.getString(getString(R.string.INSTANCE_INFO) + instance, null);
if (instanceInfo != null) {
MainActivity.instanceInfo = Instance.restore(instanceInfo);
}
}
StatusesVM statusesVM = new ViewModelProvider(ComposeActivity.this).get(StatusesVM.class);
//Empty compose
List<Status> statusDraftList = new ArrayList<>();
Status status = new Status();
status.id = Helper.generateIdString();
if (statusQuoted != null) {
status.quote_id = statusQuoted.id;
}
statusDraftList.add(status);
if (statusReplyId != null && statusDraft != null) {//Delete and redraft
statusesVM.getStatus(currentInstance, BaseMainActivity.currentToken, statusReplyId)
.observe(ComposeActivity.this, status1 -> {
if (status1 != null) {
statusesVM.getContext(currentInstance, BaseMainActivity.currentToken, statusReplyId)
.observe(ComposeActivity.this, statusContext -> {
if (statusContext != null) {
initializeContextRedraftView(statusContext, status1);
} else {
Helper.sendToastMessage(getApplication(), Helper.RECEIVE_TOAST_TYPE_ERROR, getString(R.string.toast_error));
}
});
} else {
Helper.sendToastMessage(getApplication(), Helper.RECEIVE_TOAST_TYPE_ERROR, getString(R.string.toast_error));
}
});
} else if (statusDraft != null) {//Restore a draft with all messages
restoredDraft = true;
if (statusDraft.statusReplyList != null) {
statusList.addAll(statusDraft.statusReplyList);
binding.recyclerView.addItemDecoration(new DividerDecorationSimple(ComposeActivity.this, statusList));
}
int statusCount = statusList.size();
statusList.addAll(statusDraft.statusDraftList);
composeAdapter = new ComposeAdapter(statusList, statusCount, account, accountMention, visibility, editMessageId);
composeAdapter.manageDrafts = this;
composeAdapter.promptDraftListener = this;
LinearLayoutManager mLayoutManager = new LinearLayoutManager(ComposeActivity.this);
binding.recyclerView.setLayoutManager(mLayoutManager);
binding.recyclerView.setAdapter(composeAdapter);
binding.recyclerView.scrollToPosition(composeAdapter.getItemCount() - 1);
} else if (statusReply != null) {
statusList.add(statusReply);
int statusCount = statusList.size();
statusDraftList.get(0).in_reply_to_id = statusReply.id;
//We change order for mentions
//At first place the account that has been mentioned if it's not our
statusDraftList.get(0).mentions = new ArrayList<>();
if (statusReply.account.acct != null && currentAccount.mastodon_account != null && !statusReply.account.acct.equalsIgnoreCase(currentAccount.mastodon_account.acct)) {
Mention mention = new Mention();
mention.acct = "@" + statusReply.account.acct;
mention.url = statusReply.account.url;
mention.username = statusReply.account.username;
statusDraftList.get(0).mentions.add(mention);
}
//There are other mentions to
if (statusReply.mentions != null && statusReply.mentions.size() > 0) {
for (Mention mentionTmp : statusReply.mentions) {
if (statusReply.account.acct != null && !mentionTmp.acct.equalsIgnoreCase(statusReply.account.acct) && currentAccount.mastodon_account != null && !mentionTmp.acct.equalsIgnoreCase(currentAccount.mastodon_account.acct)) {
statusDraftList.get(0).mentions.add(mentionTmp);
}
}
}
if (mentionBooster != null) {
Mention mention = new Mention();
mention.acct = mentionBooster.acct;
mention.url = mentionBooster.url;
mention.username = mentionBooster.username;
boolean present = false;
for (Mention mentionTmp : statusDraftList.get(0).mentions) {
if (mentionTmp.acct.equalsIgnoreCase(mentionBooster.acct)) {
present = true;
break;
}
}
if (!present) {
statusDraftList.get(0).mentions.add(mention);
}
}
if (statusReply.spoiler_text != null) {
statusDraftList.get(0).spoiler_text = statusReply.spoiler_text;
if (statusReply.spoiler_text.trim().length() > 0) {
statusDraftList.get(0).spoilerChecked = true;
}
}
if (statusReply.language != null && !statusReply.language.isEmpty()) {
Set<String> storedLanguages = sharedpreferences.getStringSet(getString(R.string.SET_SELECTED_LANGUAGE), null);
if (storedLanguages == null || storedLanguages.size() == 0) {
statusDraftList.get(0).language = statusReply.language;
} else {
if (storedLanguages.contains(statusReply.language)) {
statusDraftList.get(0).language = statusReply.language;
} else {
String currentCode = sharedpreferences.getString(getString(R.string.SET_COMPOSE_LANGUAGE) + account.user_id + account.instance, Locale.getDefault().getLanguage());
if (currentCode.isEmpty()) {
currentCode = "EN";
}
statusDraftList.get(0).language = currentCode;
}
}
}
//StatusDraftList at this point should only have one element
statusList.addAll(statusDraftList);
composeAdapter = new ComposeAdapter(statusList, statusCount, account, accountMention, visibility, editMessageId);
composeAdapter.manageDrafts = this;
composeAdapter.promptDraftListener = this;
LinearLayoutManager mLayoutManager = new LinearLayoutManager(ComposeActivity.this);
binding.recyclerView.setLayoutManager(mLayoutManager);
binding.recyclerView.setAdapter(composeAdapter);
statusesVM.getContext(currentInstance, BaseMainActivity.currentToken, statusReply.id)
.observe(ComposeActivity.this, this::initializeContextView);
} else if (statusQuoted != null) {
statusList.add(statusQuoted);
int statusCount = statusList.size();
statusDraftList.get(0).quote_id = statusQuoted.id;
//StatusDraftList at this point should only have one element
statusList.addAll(statusDraftList);
composeAdapter = new ComposeAdapter(statusList, statusCount, account, accountMention, visibility, editMessageId);
composeAdapter.manageDrafts = this;
composeAdapter.promptDraftListener = this;
LinearLayoutManager mLayoutManager = new LinearLayoutManager(ComposeActivity.this);
binding.recyclerView.setLayoutManager(mLayoutManager);
binding.recyclerView.setAdapter(composeAdapter);
} else {
//Compose without replying
statusList.addAll(statusDraftList);
composeAdapter = new ComposeAdapter(statusList, 0, account, accountMention, visibility, editMessageId);
composeAdapter.manageDrafts = this;
composeAdapter.promptDraftListener = this;
LinearLayoutManager mLayoutManager = new LinearLayoutManager(ComposeActivity.this);
binding.recyclerView.setLayoutManager(mLayoutManager);
binding.recyclerView.setAdapter(composeAdapter);
if (statusMention != null) {
composeAdapter.loadMentions(statusMention);
}
}
MastodonHelper.loadPPMastodon(binding.profilePicture, account.mastodon_account);
LocalBroadcastManager.getInstance(this)
.registerReceiver(imageReceiver,
new IntentFilter(Helper.INTENT_SEND_MODIFIED_IMAGE));
if (timer != null) {
timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
if (promptSaveDraft) {
storeDraft(false);
}
}
}, 0, 10000);
}
if (sharedAttachments != null && sharedAttachments.size() > 0) {
for (Attachment attachment : sharedAttachments) {
composeAdapter.addAttachment(-1, attachment);
}
} /*else if (sharedUri != null && !sharedUri.toString().startsWith("http")) {
List<Uri> uris = new ArrayList<>();
uris.add(sharedUri);
Helper.createAttachmentFromUri(ComposeActivity.this, uris, attachments -> {
for(Attachment attachment: attachments) {
composeAdapter.addAttachment(-1, attachment);
}
});
} */ else if (shareURL != null) {
Helper.download(ComposeActivity.this, sharedUrlMedia, new OnDownloadInterface() {
@Override
public void onDownloaded(String saveFilePath, String downloadUrl, Error error) {
composeAdapter.addSharing(shareURL, sharedTitle, sharedDescription, sharedSubject, sharedContent, saveFilePath);
}
@Override
public void onUpdateProgress(int progress) {
}
});
} else {
if (composeAdapter != null) {
composeAdapter.addSharing(null, null, sharedDescription, null, sharedContent, null);
}
}
}
@Override
public void onItemDraftAdded(int position) {
Status status = new Status();
status.mentions = statusList.get(position).mentions;
status.visibility = statusList.get(position).visibility;
status.spoiler_text = statusList.get(position).spoiler_text;
status.sensitive = statusList.get(position).sensitive;
status.id = Helper.generateIdString();
status.mentions = statusList.get(position - 1).mentions;
status.visibility = statusList.get(position - 1).visibility;
final SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(ComposeActivity.this);
boolean unlistedReplies = sharedpreferences.getBoolean(getString(R.string.SET_UNLISTED_REPLIES), true);
if (status.visibility.equalsIgnoreCase("public") && unlistedReplies) {
status.visibility = "unlisted";
}
status.spoiler_text = statusList.get(position - 1).spoiler_text;
status.sensitive = statusList.get(position - 1).sensitive;
statusList.add(status);
composeAdapter.notifyItemInserted(position + 1);
binding.recyclerView.smoothScrollToPosition(position + 1);
composeAdapter.notifyItemInserted(position);
composeAdapter.notifyItemRangeChanged(0, statusList.size());
binding.recyclerView.smoothScrollToPosition(statusList.size());
}
@Override
@ -602,15 +788,17 @@ public class ComposeActivity extends BaseActivity implements ComposeAdapter.Mana
private void storeDraft(boolean sendMessage, String scheduledDate) {
new Thread(() -> {
//Collect all statusCompose
List<Status> statusDrafts = new ArrayList<>();
List<Status> statusReplies = new ArrayList<>();
for (Status status : statusList) {
if (status.id == null) {
if (status.id == null || status.id.startsWith("@fedilab_compose_")) {
statusDrafts.add(status);
} else {
statusReplies.add(status);
}
}
if (statusDraft == null) {
statusDraft = new StatusDraft(ComposeActivity.this);
@ -620,10 +808,20 @@ public class ComposeActivity extends BaseActivity implements ComposeAdapter.Mana
WorkManager.getInstance(ComposeActivity.this).cancelWorkById(statusDraft.workerUuid);
}
}
statusDraft.statusReplyList = statusReplies;
statusDraft.statusDraftList = statusDrafts;
statusDraft.instance = account.instance;
statusDraft.user_id = account.user_id;
if (statusReplies.size() > 0) {
statusDraft.statusReplyList = new ArrayList<>();
statusDraft.statusReplyList.addAll(statusReplies);
}
if (statusDrafts.size() > 0) {
statusDraft.statusDraftList = new ArrayList<>();
statusDraft.statusDraftList.addAll(statusDrafts);
}
if (statusDraft.instance == null) {
statusDraft.instance = account.instance;
}
if (statusDraft.user_id == null) {
statusDraft.user_id = account.user_id;
}
if (!canBeSent(statusDraft)) {
return;
@ -664,8 +862,14 @@ public class ComposeActivity extends BaseActivity implements ComposeAdapter.Mana
.addTag(Helper.WORKER_SCHEDULED_STATUSES)
.setInitialDelay(delayToPass, TimeUnit.MILLISECONDS)
.build();
WorkManager.getInstance(ComposeActivity.this).enqueue(oneTimeWorkRequest);
statusDraft.workerUuid = oneTimeWorkRequest.getId();
statusDraft.scheduled_at = date;
try {
new StatusDraft(ComposeActivity.this).updateStatusDraft(statusDraft);
} catch (DBException e) {
e.printStackTrace();
}
Handler mainHandler = new Handler(Looper.getMainLooper());
Runnable myRunnable = () -> {
Toasty.info(ComposeActivity.this, getString(R.string.toot_scheduled), Toasty.LENGTH_LONG).show();
@ -682,18 +886,21 @@ public class ComposeActivity extends BaseActivity implements ComposeAdapter.Mana
mediaCount += status.media_attachments != null ? status.media_attachments.size() : 0;
}
if (mediaCount > 0) {
Intent intent = new Intent(ComposeActivity.this, PostMessageService.class);
intent.putExtra(Helper.ARG_STATUS_DRAFT, statusDraft);
intent.putExtra(Helper.ARG_INSTANCE, instance);
intent.putExtra(Helper.ARG_TOKEN, token);
intent.putExtra(Helper.ARG_SCHEDULED_DATE, scheduledDate);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(intent);
} else {
startService(intent);
}
Data inputData = new Data.Builder()
.putString(Helper.ARG_STATUS_DRAFT_ID, String.valueOf(statusDraft.id))
.putString(Helper.ARG_INSTANCE, instance)
.putString(Helper.ARG_TOKEN, token)
.putString(Helper.ARG_EDIT_STATUS_ID, editMessageId)
.putString(Helper.ARG_USER_ID, account.user_id)
.putString(Helper.ARG_SCHEDULED_DATE, scheduledDate).build();
OneTimeWorkRequest request = new OneTimeWorkRequest.Builder(ComposeWorker.class)
.setInputData(inputData)
.setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)
.build();
WorkManager.getInstance(ComposeActivity.this).enqueue(request);
} else {
new ThreadMessageService(ComposeActivity.this, instance, token, statusDraft, scheduledDate);
new ThreadMessageService(ComposeActivity.this, instance, account.user_id, token, statusDraft, scheduledDate, editMessageId);
}
finish();
}
@ -703,10 +910,14 @@ public class ComposeActivity extends BaseActivity implements ComposeAdapter.Mana
private boolean canBeSent(StatusDraft statusDraft) {
if (statusDraft == null || statusDraft.statusDraftList == null || statusDraft.statusDraftList.size() == 0) {
if (statusDraft == null) {
return false;
}
Status statusCheck = statusDraft.statusDraftList.get(0);
List<Status> statuses = statusDraft.statusDraftList;
if (statuses == null || statuses.size() == 0) {
return false;
}
Status statusCheck = statuses.get(0);
if (statusCheck == null) {
return false;
}
@ -722,6 +933,11 @@ public class ComposeActivity extends BaseActivity implements ComposeAdapter.Mana
composeAdapter.updateContent(isChecked, acct);
}
@Override
public void promptDraft() {
promptSaveDraft = true;
}
public enum mediaType {
PHOTO,

View file

@ -0,0 +1,240 @@
package app.fedilab.android.mastodon.activities;
/* Copyright 2021 Thomas Schneider
*
* This file is a part of Fedilab
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* Fedilab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see <http://www.gnu.org/licenses>. */
import static app.fedilab.android.BaseMainActivity.currentAccount;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.util.TypedValue;
import android.view.Menu;
import android.view.MenuItem;
import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBar;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
import androidx.preference.PreferenceManager;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import app.fedilab.android.BaseMainActivity;
import app.fedilab.android.R;
import app.fedilab.android.activities.MainActivity;
import app.fedilab.android.databinding.ActivityConversationBinding;
import app.fedilab.android.mastodon.client.entities.api.Status;
import app.fedilab.android.mastodon.client.entities.app.StatusCache;
import app.fedilab.android.mastodon.exception.DBException;
import app.fedilab.android.mastodon.helper.Helper;
import app.fedilab.android.mastodon.helper.MastodonHelper;
import app.fedilab.android.mastodon.ui.drawer.StatusAdapter;
import app.fedilab.android.mastodon.ui.fragment.timeline.FragmentMastodonContext;
import app.fedilab.android.mastodon.viewmodel.mastodon.StatusesVM;
import es.dmoral.toasty.Toasty;
public class ContextActivity extends BaseActivity implements FragmentMastodonContext.FirstMessage {
public static boolean expand;
public static boolean displayCW;
public static Resources.Theme theme;
Fragment currentFragment;
private Status firstMessage;
private String remote_instance;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityConversationBinding binding = ActivityConversationBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
setSupportActionBar(binding.toolbar);
ActionBar actionBar = getSupportActionBar();
//Remove title
if (actionBar != null) {
actionBar.setDisplayShowTitleEnabled(false);
}
binding.title.setText(R.string.context_conversation);
SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(this);
float scale = sharedpreferences.getFloat(getString(R.string.SET_FONT_SCALE), 1.1f);
binding.title.setTextSize(TypedValue.COMPLEX_UNIT_SP, 18 * 1.1f / scale);
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
}
Bundle b = getIntent().getExtras();
displayCW = sharedpreferences.getBoolean(getString(R.string.SET_EXPAND_CW), false);
Status focusedStatus = null; // or other values
if (b != null) {
focusedStatus = (Status) b.getSerializable(Helper.ARG_STATUS);
remote_instance = b.getString(Helper.ARG_REMOTE_INSTANCE, null);
}
if (focusedStatus == null || currentAccount == null || currentAccount.mastodon_account == null) {
finish();
return;
}
MastodonHelper.loadPPMastodon(binding.profilePicture, currentAccount.mastodon_account);
Bundle bundle = new Bundle();
bundle.putSerializable(Helper.ARG_STATUS, focusedStatus);
bundle.putString(Helper.ARG_REMOTE_INSTANCE, remote_instance);
FragmentMastodonContext fragmentMastodonContext = new FragmentMastodonContext();
fragmentMastodonContext.firstMessage = this;
currentFragment = Helper.addFragment(getSupportFragmentManager(), R.id.nav_host_fragment_content_main, fragmentMastodonContext, bundle, null, null);
if (remote_instance == null) {
StatusesVM timelinesVM = new ViewModelProvider(ContextActivity.this).get(StatusesVM.class);
timelinesVM.getStatus(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, focusedStatus.id).observe(ContextActivity.this, status -> {
if (status != null) {
StatusCache statusCache = new StatusCache();
statusCache.instance = BaseMainActivity.currentInstance;
statusCache.user_id = BaseMainActivity.currentUserID;
statusCache.status = status;
statusCache.status_id = status.id;
//Update cache
new Thread(() -> {
try {
new StatusCache(getApplication()).updateIfExists(statusCache);
Handler mainHandler = new Handler(Looper.getMainLooper());
//Update UI
Runnable myRunnable = () -> StatusAdapter.sendAction(ContextActivity.this, Helper.ARG_STATUS_ACTION, status, null);
mainHandler.post(myRunnable);
} catch (DBException e) {
e.printStackTrace();
}
}).start();
}
});
}
}
@Override
public boolean onCreateOptionsMenu(@NonNull Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_context, menu);
MenuItem itemExpand = menu.findItem(R.id.action_expand);
if (expand) {
itemExpand.setIcon(R.drawable.ic_baseline_expand_less_24);
} else {
itemExpand.setIcon(R.drawable.ic_baseline_expand_more_24);
}
MenuItem itemDisplayCW = menu.findItem(R.id.action_show_cw);
if (displayCW) {
itemDisplayCW.setIcon(R.drawable.ic_baseline_remove_red_eye_24);
} else {
itemDisplayCW.setIcon(R.drawable.ic_outline_remove_red_eye_24);
}
MenuItem action_remote = menu.findItem(R.id.action_remote);
if (remote_instance != null) {
action_remote.setVisible(false);
} else {
if (firstMessage != null && !firstMessage.visibility.equalsIgnoreCase("direct") && !firstMessage.visibility.equalsIgnoreCase("private")) {
Pattern pattern = Helper.statusIdInUrl;
Matcher matcher = pattern.matcher(firstMessage.uri);
action_remote.setVisible(matcher.find());
} else {
action_remote.setVisible(false);
}
}
return true;
}
public void setCurrentFragment(FragmentMastodonContext fragmentMastodonContext) {
currentFragment = fragmentMastodonContext;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
finish();
return true;
} else if (item.getItemId() == R.id.action_expand) {
expand = !expand;
if (currentFragment != null && currentFragment instanceof FragmentMastodonContext) {
((FragmentMastodonContext) currentFragment).redraw();
}
invalidateOptionsMenu();
} else if (item.getItemId() == R.id.action_show_cw) {
displayCW = !displayCW;
if (currentFragment != null && currentFragment instanceof FragmentMastodonContext) {
((FragmentMastodonContext) currentFragment).refresh();
}
invalidateOptionsMenu();
} else if (item.getItemId() == R.id.action_remote) {
if (firstMessage == null) {
Toasty.warning(ContextActivity.this, getString(R.string.toast_try_later), Toasty.LENGTH_SHORT).show();
return true;
}
if (firstMessage.account.acct != null) {
String instance = null;
try {
URL url = new URL(firstMessage.uri);
instance = url.getHost();
} catch (MalformedURLException e) {
e.printStackTrace();
}
if (instance == null) {
Toasty.info(ContextActivity.this, getString(R.string.toast_error_fetch_message), Toasty.LENGTH_SHORT).show();
return true;
}
if (instance.equalsIgnoreCase(MainActivity.currentInstance)) {
Toasty.info(ContextActivity.this, getString(R.string.toast_on_your_instance), Toasty.LENGTH_SHORT).show();
return true;
}
Pattern pattern = Helper.statusIdInUrl;
Matcher matcher = pattern.matcher(firstMessage.uri);
String remoteId = null;
if (matcher.find()) {
remoteId = matcher.group(1);
}
if (remoteId != null) {
StatusesVM statusesVM = new ViewModelProvider(ContextActivity.this).get(StatusesVM.class);
String finalInstance = instance;
statusesVM.getStatus(instance, null, remoteId).observe(ContextActivity.this, status -> {
if (status != null) {
Intent intentContext = new Intent(ContextActivity.this, ContextActivity.class);
intentContext.putExtra(Helper.ARG_STATUS, status);
intentContext.putExtra(Helper.ARG_REMOTE_INSTANCE, finalInstance);
intentContext.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intentContext);
} else {
Toasty.warning(ContextActivity.this, getString(R.string.toast_error_fetch_message), Toasty.LENGTH_SHORT).show();
}
});
} else {
Toasty.warning(ContextActivity.this, getString(R.string.toast_error_fetch_message), Toasty.LENGTH_SHORT).show();
}
} else {
Toasty.warning(ContextActivity.this, getString(R.string.toast_error_fetch_message), Toasty.LENGTH_SHORT).show();
}
}
return true;
}
@Override
public void get(Status status) {
firstMessage = status;
invalidateOptionsMenu();
}
}

View file

@ -1,4 +1,4 @@
package app.fedilab.android.activities;
package app.fedilab.android.mastodon.activities;
/* Copyright 2022 Thomas Schneider
*
* This file is a part of Fedilab
@ -17,7 +17,6 @@ package app.fedilab.android.activities;
import static app.fedilab.android.BaseMainActivity.currentAccount;
import android.content.SharedPreferences;
import android.graphics.drawable.ColorDrawable;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
@ -26,23 +25,21 @@ import android.text.TextUtils;
import android.view.MenuItem;
import android.widget.Toast;
import androidx.core.content.ContextCompat;
import androidx.preference.PreferenceManager;
import java.util.List;
import java.util.Set;
import app.fedilab.android.R;
import app.fedilab.android.client.entities.api.Attachment;
import app.fedilab.android.client.entities.api.Emoji;
import app.fedilab.android.client.entities.api.Status;
import app.fedilab.android.client.entities.api.Tag;
import app.fedilab.android.databinding.ActivityCustomSharingBinding;
import app.fedilab.android.helper.Helper;
import app.fedilab.android.helper.ThemeHelper;
import app.fedilab.android.helper.customsharing.CustomSharingAsyncTask;
import app.fedilab.android.helper.customsharing.CustomSharingResponse;
import app.fedilab.android.helper.customsharing.OnCustomSharingInterface;
import app.fedilab.android.mastodon.client.entities.api.Attachment;
import app.fedilab.android.mastodon.client.entities.api.Emoji;
import app.fedilab.android.mastodon.client.entities.api.Status;
import app.fedilab.android.mastodon.client.entities.api.Tag;
import app.fedilab.android.mastodon.helper.Helper;
import app.fedilab.android.mastodon.helper.customsharing.CustomSharingAsyncTask;
import app.fedilab.android.mastodon.helper.customsharing.CustomSharingResponse;
import app.fedilab.android.mastodon.helper.customsharing.OnCustomSharingInterface;
import es.dmoral.toasty.Toasty;
@ -51,7 +48,7 @@ import es.dmoral.toasty.Toasty;
* Share status metadata to remote content aggregators
*/
public class CustomSharingActivity extends BaseActivity implements OnCustomSharingInterface {
public class CustomSharingActivity extends BaseBarActivity implements OnCustomSharingInterface {
private String title, keywords, custom_sharing_url, encodedCustomSharingURL;
private String bundle_url;
@ -66,14 +63,13 @@ public class CustomSharingActivity extends BaseActivity implements OnCustomShari
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ThemeHelper.applyThemeBar(this);
SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(CustomSharingActivity.this);
binding = ActivityCustomSharingBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
getSupportActionBar().setBackgroundDrawable(new ColorDrawable(ContextCompat.getColor(this, R.color.cyanea_primary)));
}
Bundle b = getIntent().getExtras();
status = null;

View file

@ -0,0 +1,81 @@
package app.fedilab.android.mastodon.activities;
/* Copyright 2022 Thomas Schneider
*
* This file is a part of Fedilab
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* Fedilab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see <http://www.gnu.org/licenses>. */
import static app.fedilab.android.mastodon.client.entities.app.Timeline.TimeLineEnum.ACCOUNT_DIRECTORY;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import org.jetbrains.annotations.NotNull;
import app.fedilab.android.R;
import app.fedilab.android.databinding.ActivityDirectoryBinding;
import app.fedilab.android.mastodon.helper.Helper;
import app.fedilab.android.mastodon.ui.fragment.timeline.FragmentMastodonAccount;
public class DirectoryActivity extends BaseBarActivity {
private static boolean local = false;
private static String order = "active";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityDirectoryBinding binding = ActivityDirectoryBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
Bundle bundle = new Bundle();
bundle.putBoolean(Helper.ARG_DIRECTORY_LOCAL, local);
bundle.putString(Helper.ARG_DIRECTORY_ORDER, order);
bundle.putSerializable(Helper.ARG_TIMELINE_TYPE, ACCOUNT_DIRECTORY);
Helper.addFragment(getSupportFragmentManager(), R.id.nav_host_fragment_directory, new FragmentMastodonAccount(), bundle, null, null);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_directory, menu);
if (order.equals("active")) {
menu.findItem(R.id.order_active).setChecked(true);
} else {
menu.findItem(R.id.order_new).setChecked(true);
}
menu.findItem(R.id.action_local).setChecked(local);
return true;
}
@Override
public boolean onOptionsItemSelected(@NotNull MenuItem item) {
if (item.getItemId() == android.R.id.home) {
finish();
return true;
} else if (item.getItemId() == R.id.action_local) {
item.setChecked(!item.isChecked());
local = item.isChecked();
} else if (item.getItemId() == R.id.order_active) {
order = "active";
} else if (item.getItemId() == R.id.order_new) {
order = "new";
}
recreate();
return super.onOptionsItemSelected(item);
}
}

View file

@ -1,4 +1,4 @@
package app.fedilab.android.activities;
package app.fedilab.android.mastodon.activities;
/* Copyright 2022 Thomas Schneider
*
* This file is a part of Fedilab
@ -16,10 +16,11 @@ package app.fedilab.android.activities;
import static app.fedilab.android.BaseMainActivity.currentAccount;
import android.graphics.drawable.ColorDrawable;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.util.TypedValue;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
@ -28,24 +29,24 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AlertDialog;
import androidx.core.content.ContextCompat;
import androidx.lifecycle.ViewModelProvider;
import androidx.preference.PreferenceManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import app.fedilab.android.R;
import app.fedilab.android.client.entities.api.Attachment;
import app.fedilab.android.client.entities.api.Status;
import app.fedilab.android.client.entities.app.StatusDraft;
import app.fedilab.android.databinding.ActivityDraftsBinding;
import app.fedilab.android.exception.DBException;
import app.fedilab.android.helper.Helper;
import app.fedilab.android.helper.ThemeHelper;
import app.fedilab.android.ui.drawer.StatusDraftAdapter;
import app.fedilab.android.viewmodel.mastodon.TimelinesVM;
import app.fedilab.android.mastodon.client.entities.api.Attachment;
import app.fedilab.android.mastodon.client.entities.api.Status;
import app.fedilab.android.mastodon.client.entities.app.StatusDraft;
import app.fedilab.android.mastodon.exception.DBException;
import app.fedilab.android.mastodon.ui.drawer.StatusDraftAdapter;
import app.fedilab.android.mastodon.viewmodel.mastodon.TimelinesVM;
public class DraftActivity extends BaseActivity implements StatusDraftAdapter.DraftActions {
@ -59,21 +60,20 @@ public class DraftActivity extends BaseActivity implements StatusDraftAdapter.Dr
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ThemeHelper.applyTheme(this);
binding = ActivityDraftsBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
setSupportActionBar(binding.toolbar);
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setBackgroundDrawable(new ColorDrawable(ContextCompat.getColor(this, R.color.cyanea_primary)));
}
//Remove title
if (actionBar != null) {
actionBar.setDisplayShowTitleEnabled(false);
}
binding.toolbar.setPopupTheme(Helper.popupStyle());
binding.title.setText(R.string.drafts);
SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(this);
float scale = sharedpreferences.getFloat(getString(R.string.SET_FONT_SCALE), 1.1f);
binding.title.setTextSize(TypedValue.COMPLEX_UNIT_SP, 18 * 1.1f / scale);
binding.loader.setVisibility(View.VISIBLE);
binding.lvStatus.setVisibility(View.GONE);
binding.noAction.setVisibility(View.GONE);
@ -99,7 +99,7 @@ public class DraftActivity extends BaseActivity implements StatusDraftAdapter.Dr
finish();
return true;
} else if (item.getItemId() == R.id.action_delete) {
AlertDialog.Builder unfollowConfirm = new AlertDialog.Builder(DraftActivity.this, Helper.dialogStyle());
AlertDialog.Builder unfollowConfirm = new MaterialAlertDialogBuilder(DraftActivity.this);
unfollowConfirm.setTitle(getString(R.string.delete_all));
unfollowConfirm.setMessage(getString(R.string.remove_draft));
unfollowConfirm.setNegativeButton(R.string.cancel, (dialog, which) -> dialog.dismiss());
@ -205,12 +205,6 @@ public class DraftActivity extends BaseActivity implements StatusDraftAdapter.Dr
}
}
@Override
public void onDestroy() {
super.onDestroy();
binding.lvStatus.setAdapter(null);
binding = null;
}
@Override
public void onAllDeleted() {

View file

@ -1,4 +1,4 @@
package app.fedilab.android.activities;
package app.fedilab.android.mastodon.activities;
/* Copyright 2022 Thomas Schneider
*
* This file is a part of Fedilab
@ -18,7 +18,7 @@ import static app.fedilab.android.BaseMainActivity.currentAccount;
import static app.fedilab.android.BaseMainActivity.instanceInfo;
import android.content.Intent;
import android.graphics.drawable.ColorDrawable;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.provider.MediaStore;
@ -30,11 +30,11 @@ import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.core.content.ContextCompat;
import androidx.lifecycle.ViewModelProvider;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import com.bumptech.glide.Glide;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.textfield.TextInputEditText;
import java.util.LinkedHashMap;
@ -43,18 +43,17 @@ import java.util.Locale;
import app.fedilab.android.BaseMainActivity;
import app.fedilab.android.R;
import app.fedilab.android.client.entities.api.Account;
import app.fedilab.android.client.entities.api.Field;
import app.fedilab.android.databinding.AccountFieldItemBinding;
import app.fedilab.android.databinding.ActivityEditProfileBinding;
import app.fedilab.android.exception.DBException;
import app.fedilab.android.helper.Helper;
import app.fedilab.android.helper.MastodonHelper;
import app.fedilab.android.helper.ThemeHelper;
import app.fedilab.android.viewmodel.mastodon.AccountsVM;
import app.fedilab.android.mastodon.client.entities.api.Account;
import app.fedilab.android.mastodon.client.entities.api.Field;
import app.fedilab.android.mastodon.exception.DBException;
import app.fedilab.android.mastodon.helper.Helper;
import app.fedilab.android.mastodon.helper.MastodonHelper;
import app.fedilab.android.mastodon.viewmodel.mastodon.AccountsVM;
import es.dmoral.toasty.Toasty;
public class EditProfileActivity extends BaseActivity {
public class EditProfileActivity extends BaseBarActivity {
public static final int PICK_MEDIA_AVATAR = 5705;
public static final int PICK_MEDIA_HEADER = 5706;
@ -64,12 +63,11 @@ public class EditProfileActivity extends BaseActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ThemeHelper.applyThemeBar(this);
binding = ActivityEditProfileBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setBackgroundDrawable(new ColorDrawable(ContextCompat.getColor(this, R.color.cyanea_primary)));
}
new ViewModelProvider(EditProfileActivity.this).get(AccountsVM.class).getConnectedAccount(BaseMainActivity.currentInstance, BaseMainActivity.currentToken)
@ -87,7 +85,7 @@ public class EditProfileActivity extends BaseActivity {
@SuppressWarnings("deprecation")
private void initializeView() {
//Hydrate values
MastodonHelper.loadProfileMediaMastodon(binding.bannerPp, currentAccount.mastodon_account, MastodonHelper.MediaAccountType.HEADER);
MastodonHelper.loadProfileMediaMastodon(EditProfileActivity.this, binding.bannerPp, currentAccount.mastodon_account, MastodonHelper.MediaAccountType.HEADER);
MastodonHelper.loadPPMastodon(binding.accountPp, currentAccount.mastodon_account);
binding.displayName.setText(currentAccount.mastodon_account.display_name);
binding.acct.setText(String.format(Locale.getDefault(), "%s@%s", currentAccount.mastodon_account.acct, BaseMainActivity.currentInstance));
@ -138,7 +136,7 @@ public class EditProfileActivity extends BaseActivity {
value = Html.fromHtml(field.value).toString();
fieldItemBinding.value.setText(value);
fieldItemBinding.remove.setOnClickListener(v -> {
AlertDialog.Builder deleteConfirm = new AlertDialog.Builder(EditProfileActivity.this, Helper.dialogStyle());
AlertDialog.Builder deleteConfirm = new MaterialAlertDialogBuilder(EditProfileActivity.this);
deleteConfirm.setTitle(getString(R.string.delete_field));
deleteConfirm.setMessage(getString(R.string.delete_field_confirm));
deleteConfirm.setNegativeButton(R.string.cancel, (dialog, which) -> dialog.dismiss());
@ -160,7 +158,7 @@ public class EditProfileActivity extends BaseActivity {
binding.addField.setOnClickListener(view -> {
AccountFieldItemBinding fieldItemBinding = AccountFieldItemBinding.inflate(getLayoutInflater());
fieldItemBinding.remove.setOnClickListener(v -> {
AlertDialog.Builder deleteConfirm = new AlertDialog.Builder(EditProfileActivity.this, Helper.dialogStyle());
AlertDialog.Builder deleteConfirm = new MaterialAlertDialogBuilder(EditProfileActivity.this);
deleteConfirm.setTitle(getString(R.string.delete_field));
deleteConfirm.setMessage(getString(R.string.delete_field_confirm));
deleteConfirm.setNegativeButton(R.string.cancel, (dialog, which) -> dialog.dismiss());
@ -180,6 +178,8 @@ public class EditProfileActivity extends BaseActivity {
binding.addField.setVisibility(View.GONE);
}
});
//Actions with the activity
accountsVM = new ViewModelProvider(EditProfileActivity.this).get(AccountsVM.class);
binding.headerSelect.setOnClickListener(view -> startActivityForResult(prepareIntent(), EditProfileActivity.PICK_MEDIA_HEADER));
@ -191,30 +191,35 @@ public class EditProfileActivity extends BaseActivity {
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == PICK_MEDIA_AVATAR && resultCode == RESULT_OK) {
binding.avatarProgress.setVisibility(View.VISIBLE);
Glide.with(EditProfileActivity.this)
.asDrawable()
.load(data.getData())
.thumbnail(0.1f)
.into(binding.accountPp);
accountsVM.updateProfilePicture(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, data.getData(), AccountsVM.UpdateMediaType.AVATAR)
.observe(EditProfileActivity.this, account -> {
if (account != null) {
sendBroadCast(account);
binding.avatarProgress.setVisibility(View.GONE);
currentAccount.mastodon_account = account;
Helper.recreateMainActivity(EditProfileActivity.this);
new Thread(() -> {
try {
new app.fedilab.android.client.entities.app.Account(EditProfileActivity.this).insertOrUpdate(currentAccount);
} catch (DBException e) {
e.printStackTrace();
}
}).start();
} else {
Helper.sendToastMessage(getApplication(), Helper.RECEIVE_TOAST_TYPE_ERROR, getString(R.string.toast_error));
}
});
Uri uri = data.getData();
if (uri != null) {
binding.avatarProgress.setVisibility(View.VISIBLE);
Glide.with(EditProfileActivity.this)
.asDrawable()
.load(uri)
.thumbnail(0.1f)
.into(binding.accountPp);
accountsVM.updateProfilePicture(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, uri, AccountsVM.UpdateMediaType.AVATAR)
.observe(EditProfileActivity.this, account -> {
if (account != null) {
sendBroadCast(account);
binding.avatarProgress.setVisibility(View.GONE);
currentAccount.mastodon_account = account;
Helper.recreateMainActivity(EditProfileActivity.this);
new Thread(() -> {
try {
new app.fedilab.android.mastodon.client.entities.app.Account(EditProfileActivity.this).insertOrUpdate(currentAccount);
} catch (DBException e) {
e.printStackTrace();
}
}).start();
} else {
Helper.sendToastMessage(getApplication(), Helper.RECEIVE_TOAST_TYPE_ERROR, getString(R.string.toast_error));
}
});
} else {
Toasty.error(EditProfileActivity.this, getString(R.string.toast_error), Toasty.LENGTH_LONG).show();
}
} else if (requestCode == PICK_MEDIA_HEADER && resultCode == RESULT_OK) {
Glide.with(EditProfileActivity.this)
.asDrawable()
@ -230,7 +235,7 @@ public class EditProfileActivity extends BaseActivity {
currentAccount.mastodon_account = account;
new Thread(() -> {
try {
new app.fedilab.android.client.entities.app.Account(EditProfileActivity.this).insertOrUpdate(currentAccount);
new app.fedilab.android.mastodon.client.entities.app.Account(EditProfileActivity.this).insertOrUpdate(currentAccount);
} catch (DBException e) {
e.printStackTrace();
}
@ -309,22 +314,22 @@ public class EditProfileActivity extends BaseActivity {
return true;
} else if (item.getItemId() == R.id.action_save) {
accountsVM.updateCredentials(BaseMainActivity.currentInstance, BaseMainActivity.currentToken,
binding.discoverable.isChecked(),
binding.bot.isChecked(),
binding.displayName.getText().toString().trim(),
binding.bio.getText().toString(),
binding.locked.isChecked(),
getPrivacy(),
binding.sensitive.isChecked(),
null,
getFields()
)
binding.discoverable.isChecked(),
binding.bot.isChecked(),
binding.displayName.getText().toString().trim(),
binding.bio.getText().toString(),
binding.locked.isChecked(),
getPrivacy(),
binding.sensitive.isChecked(),
null,
getFields()
)
.observe(EditProfileActivity.this, account -> {
if (account != null) {
currentAccount.mastodon_account = account;
new Thread(() -> {
try {
new app.fedilab.android.client.entities.app.Account(EditProfileActivity.this).insertOrUpdate(currentAccount);
new app.fedilab.android.mastodon.client.entities.app.Account(EditProfileActivity.this).insertOrUpdate(currentAccount);
sendBroadCast(account);
} catch (DBException e) {
e.printStackTrace();

View file

@ -1,4 +1,4 @@
package app.fedilab.android.activities;
package app.fedilab.android.mastodon.activities;
/* Copyright 2022 Thomas Schneider
*
* This file is a part of Fedilab
@ -15,7 +15,6 @@ package app.fedilab.android.activities;
* see <http://www.gnu.org/licenses>. */
import android.content.Context;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.MenuItem;
@ -28,27 +27,28 @@ import android.widget.Button;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.core.content.ContextCompat;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.ViewModelProvider;
import androidx.lifecycle.ViewModelStoreOwner;
import androidx.recyclerview.widget.LinearLayoutManager;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import app.fedilab.android.BaseMainActivity;
import app.fedilab.android.R;
import app.fedilab.android.client.entities.api.Filter;
import app.fedilab.android.activities.MainActivity;
import app.fedilab.android.databinding.ActivityFiltersBinding;
import app.fedilab.android.databinding.PopupAddFilterBinding;
import app.fedilab.android.helper.Helper;
import app.fedilab.android.helper.ThemeHelper;
import app.fedilab.android.ui.drawer.FilterAdapter;
import app.fedilab.android.viewmodel.mastodon.AccountsVM;
import app.fedilab.android.mastodon.client.entities.api.Filter;
import app.fedilab.android.mastodon.ui.drawer.FilterAdapter;
import app.fedilab.android.mastodon.ui.drawer.KeywordAdapter;
import app.fedilab.android.mastodon.viewmodel.mastodon.FiltersVM;
public class FilterActivity extends BaseActivity implements FilterAdapter.Delete {
public class FilterActivity extends BaseBarActivity implements FilterAdapter.Delete {
private ActivityFiltersBinding binding;
private List<Filter> filterList;
@ -62,14 +62,15 @@ public class FilterActivity extends BaseActivity implements FilterAdapter.Delete
* @param listener - {@link FilterAdapter.FilterAction}
*/
public static void addEditFilter(Context context, Filter filter, FilterAdapter.FilterAction listener) {
AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(context, Helper.dialogStyle());
AlertDialog.Builder dialogBuilder = new MaterialAlertDialogBuilder(context);
PopupAddFilterBinding popupAddFilterBinding = PopupAddFilterBinding.inflate(LayoutInflater.from(context));
AccountsVM accountsVM = new ViewModelProvider((ViewModelStoreOwner) context).get(AccountsVM.class);
FiltersVM filtersVM = new ViewModelProvider((ViewModelStoreOwner) context).get(FiltersVM.class);
dialogBuilder.setView(popupAddFilterBinding.getRoot());
ArrayAdapter<CharSequence> adapterResize = ArrayAdapter.createFromResource(Objects.requireNonNull(context),
R.array.filter_expire, android.R.layout.simple_spinner_dropdown_item);
popupAddFilterBinding.filterExpire.setAdapter(adapterResize);
final int[] expire = {-1};
Filter.FilterParams filterParams = new Filter.FilterParams();
popupAddFilterBinding.filterExpire.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent1, View view, int position1, long id) {
@ -78,18 +79,21 @@ public class FilterActivity extends BaseActivity implements FilterAdapter.Delete
expire[0] = -1;
break;
case 1:
expire[0] = 3600;
expire[0] = 1800;
break;
case 2:
expire[0] = 21600;
expire[0] = 3600;
break;
case 3:
expire[0] = 43200;
expire[0] = 21600;
break;
case 4:
expire[0] = 86400;
expire[0] = 43200;
break;
case 5:
expire[0] = 86400;
break;
case 6:
expire[0] = 604800;
break;
}
@ -99,9 +103,29 @@ public class FilterActivity extends BaseActivity implements FilterAdapter.Delete
public void onNothingSelected(AdapterView<?> parent1) {
}
});
if (filter != null) {
popupAddFilterBinding.addPhrase.setText(filter.phrase);
if (filter.context != null)
filterParams.filter_action = filter.filter_action;
filterParams.title = filter.title;
// filterParams.expires_in = filter.expires_at;
filterParams.context = filter.context;
filterParams.id = filter.id;
if (filter.keywords != null && filter.keywords.size() > 0) {
filterParams.keywords = new ArrayList<>();
for (Filter.KeywordsAttributes keywordsAttributes : filter.keywords) {
Filter.KeywordsParams keywordsParams = new Filter.KeywordsParams();
keywordsParams._destroy = null;
keywordsParams.id = keywordsAttributes.id;
keywordsParams.keyword = keywordsAttributes.keyword;
keywordsParams.whole_word = keywordsAttributes.whole_word;
filterParams.keywords.add(keywordsParams);
}
}
popupAddFilterBinding.addTitle.setText(filter.title);
if (filter.context != null) {
for (String val : filter.context) {
switch (val) {
case "home":
@ -116,48 +140,91 @@ public class FilterActivity extends BaseActivity implements FilterAdapter.Delete
case "thread":
popupAddFilterBinding.contextConversation.setChecked(true);
break;
case "account":
popupAddFilterBinding.contextProfiles.setChecked(true);
break;
}
}
popupAddFilterBinding.contextWholeWord.setChecked(filter.whole_word);
popupAddFilterBinding.contextDrop.setChecked(filter.irreversible);
}
if (filter.filter_action.equalsIgnoreCase("warn")) {
popupAddFilterBinding.actionHide.setChecked(true);
popupAddFilterBinding.actionRemove.setChecked(false);
} else {
popupAddFilterBinding.actionHide.setChecked(false);
popupAddFilterBinding.actionRemove.setChecked(true);
}
}
if (filterParams.keywords == null) {
filterParams.keywords = new ArrayList<>();
}
KeywordAdapter keywordAdapter = new KeywordAdapter(filterParams.keywords);
popupAddFilterBinding.lvKeywords.setAdapter(keywordAdapter);
popupAddFilterBinding.lvKeywords.setNestedScrollingEnabled(false);
popupAddFilterBinding.lvKeywords.setLayoutManager(new LinearLayoutManager(context));
popupAddFilterBinding.addKeyword.setOnClickListener(v -> {
Filter.KeywordsParams keywordsParams = new Filter.KeywordsParams();
keywordsParams.whole_word = true;
filterParams.keywords.add(keywordsParams);
keywordAdapter.notifyItemInserted(filterParams.keywords.size() - 1);
});
popupAddFilterBinding.actionRemove.setOnClickListener(v -> {
popupAddFilterBinding.actionHide.setChecked(false);
popupAddFilterBinding.actionRemove.setChecked(true);
});
popupAddFilterBinding.actionHide.setOnClickListener(v -> {
popupAddFilterBinding.actionRemove.setChecked(false);
popupAddFilterBinding.actionHide.setChecked(true);
});
AlertDialog alertDialog = dialogBuilder.setPositiveButton(R.string.validate, null)
.setNegativeButton(R.string.cancel, null).create();
alertDialog.setOnShowListener(dialogInterface -> {
Button button = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE);
button.setOnClickListener(view -> {
if (popupAddFilterBinding.addPhrase.getText() == null || popupAddFilterBinding.addPhrase.getText().toString().trim().length() == 0) {
popupAddFilterBinding.addPhrase.setError(context.getString(R.string.cannot_be_empty));
return;
boolean canBeSent = true;
for (int i = 0; i < filterParams.keywords.size(); i++) {
if (filterParams.keywords.get(i).keyword == null || (filterParams.keywords.get(i).keyword.trim().isEmpty() && filterParams.keywords.get(i)._destroy != null && !filterParams.keywords.get(i)._destroy)) {
canBeSent = false;
}
}
if (!popupAddFilterBinding.contextConversation.isChecked() && !popupAddFilterBinding.contextHome.isChecked() && !popupAddFilterBinding.contextPublic.isChecked() && !popupAddFilterBinding.contextNotification.isChecked()) {
if (popupAddFilterBinding.addTitle.getText().toString().trim().isEmpty()) {
popupAddFilterBinding.addTitle.setError(context.getString(R.string.cannot_be_empty));
canBeSent = false;
}
if (!popupAddFilterBinding.contextConversation.isChecked() && !popupAddFilterBinding.contextHome.isChecked() && !popupAddFilterBinding.contextPublic.isChecked() && !popupAddFilterBinding.contextNotification.isChecked() && !popupAddFilterBinding.contextProfiles.isChecked()) {
popupAddFilterBinding.contextDescription.setError(context.getString(R.string.cannot_be_empty));
return;
canBeSent = false;
}
if (popupAddFilterBinding.addPhrase.getText() != null && popupAddFilterBinding.addPhrase.getText().toString().trim().length() > 0) {
Filter filterSent = new Filter();
ArrayList<String> contextFilter = new ArrayList<>();
if (canBeSent) {
filterParams.context = new ArrayList<>();
if (popupAddFilterBinding.contextHome.isChecked())
contextFilter.add("home");
filterParams.context.add("home");
if (popupAddFilterBinding.contextPublic.isChecked())
contextFilter.add("public");
filterParams.context.add("public");
if (popupAddFilterBinding.contextNotification.isChecked())
contextFilter.add("notifications");
filterParams.context.add("notifications");
if (popupAddFilterBinding.contextConversation.isChecked())
contextFilter.add("thread");
filterSent.context = contextFilter;
filterSent.expires_at_sent = expire[0];
filterSent.phrase = popupAddFilterBinding.addPhrase.getText().toString();
filterSent.whole_word = popupAddFilterBinding.contextWholeWord.isChecked();
filterSent.irreversible = popupAddFilterBinding.contextDrop.isChecked();
if (filter != null) {
accountsVM.editFilter(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, filter.id, filterSent.phrase, filterSent.context, filterSent.irreversible, filterSent.whole_word, filterSent.expires_at_sent)
filterParams.context.add("thread");
if (popupAddFilterBinding.contextProfiles.isChecked())
filterParams.context.add("account");
if (expire[0] != -1) {
filterParams.expires_in = (long) expire[0];
} else {
filterParams.expires_in = null;
}
filterParams.title = popupAddFilterBinding.addTitle.getText().toString().trim();
filterParams.filter_action = popupAddFilterBinding.actionRemove.isChecked() ? "hide" : "warn";
if (filterParams.id != null) {
filtersVM.editFilter(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, filterParams)
.observe((LifecycleOwner) context, listener::callback);
} else {
accountsVM.addFilter(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, filterSent.phrase, filterSent.context, filterSent.irreversible, filterSent.whole_word, filterSent.expires_at_sent)
filtersVM.addFilter(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, filterParams)
.observe((LifecycleOwner) context, listener::callback);
}
alertDialog.dismiss();
@ -169,8 +236,8 @@ public class FilterActivity extends BaseActivity implements FilterAdapter.Delete
alertDialog.setTitle(context.getString(R.string.action_update_filter));
alertDialog.setOnDismissListener(dialogInterface -> {
//Hide keyboard
InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(popupAddFilterBinding.addPhrase.getWindowToken(), 0);
InputMethodManager imm = (InputMethodManager) context.getSystemService(INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(popupAddFilterBinding.addTitle.getWindowToken(), 0);
});
if (alertDialog.getWindow() != null) {
alertDialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
@ -182,17 +249,16 @@ public class FilterActivity extends BaseActivity implements FilterAdapter.Delete
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ThemeHelper.applyThemeBar(this);
binding = ActivityFiltersBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
filterList = new ArrayList<>();
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setBackgroundDrawable(new ColorDrawable(ContextCompat.getColor(this, R.color.cyanea_primary)));
}
AccountsVM accountsVM = new ViewModelProvider(FilterActivity.this).get(AccountsVM.class);
accountsVM.getFilters(BaseMainActivity.currentInstance, BaseMainActivity.currentToken)
FiltersVM filtersVM = new ViewModelProvider(FilterActivity.this).get(FiltersVM.class);
filtersVM.getFilters(BaseMainActivity.currentInstance, BaseMainActivity.currentToken)
.observe(FilterActivity.this, filters -> {
BaseMainActivity.mainFilters = filters;
if (filters != null && filters.size() > 0) {
@ -209,7 +275,11 @@ public class FilterActivity extends BaseActivity implements FilterAdapter.Delete
binding.addFilter.setOnClickListener(v -> addEditFilter(FilterActivity.this, null, filter -> {
if (filter != null) {
if (MainActivity.mainFilters == null) {
MainActivity.mainFilters = new ArrayList<>();
}
filterList.add(0, filter);
MainActivity.mainFilters.add(filter);
if (filterAdapter != null) {
filterAdapter.notifyItemInserted(0);
} else {

View file

@ -1,4 +1,4 @@
package app.fedilab.android.activities;
package app.fedilab.android.mastodon.activities;
/* Copyright 2022 Thomas Schneider
*
* This file is a part of Fedilab
@ -15,13 +15,11 @@ package app.fedilab.android.activities;
* see <http://www.gnu.org/licenses>. */
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.view.MenuItem;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
@ -31,13 +29,12 @@ import java.util.List;
import app.fedilab.android.BaseMainActivity;
import app.fedilab.android.R;
import app.fedilab.android.client.entities.api.Account;
import app.fedilab.android.client.entities.api.Accounts;
import app.fedilab.android.databinding.ActivityStatusInfoBinding;
import app.fedilab.android.helper.MastodonHelper;
import app.fedilab.android.helper.ThemeHelper;
import app.fedilab.android.ui.drawer.AccountFollowRequestAdapter;
import app.fedilab.android.viewmodel.mastodon.AccountsVM;
import app.fedilab.android.mastodon.client.entities.api.Account;
import app.fedilab.android.mastodon.client.entities.api.Accounts;
import app.fedilab.android.mastodon.helper.MastodonHelper;
import app.fedilab.android.mastodon.ui.drawer.AccountFollowRequestAdapter;
import app.fedilab.android.mastodon.viewmodel.mastodon.AccountsVM;
public class FollowRequestActivity extends BaseActivity {
@ -51,14 +48,13 @@ public class FollowRequestActivity extends BaseActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ThemeHelper.applyTheme(this);
binding = ActivityStatusInfoBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
setSupportActionBar(binding.toolbar);
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
getSupportActionBar().setBackgroundDrawable(new ColorDrawable(ContextCompat.getColor(this, R.color.cyanea_primary)));
}
accountList = new ArrayList<>();
flagLoading = false;

View file

@ -0,0 +1,208 @@
package app.fedilab.android.mastodon.activities;
/* Copyright 2022 Thomas Schneider
*
* This file is a part of Fedilab
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* Fedilab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see <http://www.gnu.org/licenses>. */
import android.os.Bundle;
import android.text.InputFilter;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.LinearLayoutManager;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import java.util.ArrayList;
import app.fedilab.android.BaseMainActivity;
import app.fedilab.android.R;
import app.fedilab.android.databinding.ActivityFollowedTagsBinding;
import app.fedilab.android.databinding.PopupAddFollowedTagtBinding;
import app.fedilab.android.mastodon.client.entities.api.Tag;
import app.fedilab.android.mastodon.client.entities.app.Timeline;
import app.fedilab.android.mastodon.helper.Helper;
import app.fedilab.android.mastodon.helper.ThemeHelper;
import app.fedilab.android.mastodon.ui.drawer.FollowedTagAdapter;
import app.fedilab.android.mastodon.ui.fragment.timeline.FragmentMastodonTimeline;
import app.fedilab.android.mastodon.viewmodel.mastodon.TagVM;
import es.dmoral.toasty.Toasty;
public class FollowedTagActivity extends BaseBarActivity implements FollowedTagAdapter.ActionOnTag {
private ActivityFollowedTagsBinding binding;
private boolean canGoBack;
private TagVM tagVM;
private Tag tag;
private ArrayList<Tag> tagList;
private FollowedTagAdapter followedTagAdapter;
private FragmentMastodonTimeline fragmentMastodonTimeline;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityFollowedTagsBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
canGoBack = false;
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
}
tagVM = new ViewModelProvider(FollowedTagActivity.this).get(TagVM.class);
tagVM.followedTags(BaseMainActivity.currentInstance, BaseMainActivity.currentToken)
.observe(FollowedTagActivity.this, tags -> {
if (tags != null && tags.tags != null && tags.tags.size() > 0) {
tagList = new ArrayList<>(tags.tags);
followedTagAdapter = new FollowedTagAdapter(tagList);
followedTagAdapter.actionOnTag = this;
binding.notContent.setVisibility(View.GONE);
binding.recyclerView.setAdapter(followedTagAdapter);
binding.recyclerView.setLayoutManager(new LinearLayoutManager(FollowedTagActivity.this));
} else {
binding.notContent.setVisibility(View.VISIBLE);
}
});
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
onBackPressed();
return true;
} else if (item.getItemId() == R.id.action_unfollow && tag != null) {
AlertDialog.Builder alt_bld = new MaterialAlertDialogBuilder(FollowedTagActivity.this);
alt_bld.setTitle(R.string.action_unfollow_tag);
alt_bld.setMessage(R.string.action_unfollow_tag_confirm);
alt_bld.setPositiveButton(R.string.unfollow, (dialog, id) -> {
tagVM.unfollow(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, tag.name);
int position = 0;
for (Tag tagTmp : tagList) {
if (tagTmp.name.equalsIgnoreCase(tag.name)) {
break;
}
position++;
}
tagList.remove(position);
followedTagAdapter.notifyItemRemoved(position);
ThemeHelper.slideViewsToRight(binding.fragmentContainer, binding.recyclerView, () -> {
canGoBack = false;
if (fragmentMastodonTimeline != null) {
fragmentMastodonTimeline.onDestroyView();
}
invalidateOptionsMenu();
setTitle(R.string.followed_tags);
});
if (tagList.size() == 0) {
binding.notContent.setVisibility(View.VISIBLE);
} else {
binding.notContent.setVisibility(View.GONE);
}
});
alt_bld.setNegativeButton(R.string.cancel, (dialog, id) -> dialog.dismiss());
AlertDialog alert = alt_bld.create();
alert.show();
} else if (item.getItemId() == R.id.action_follow_tag) {
AlertDialog.Builder dialogBuilder = new MaterialAlertDialogBuilder(FollowedTagActivity.this);
PopupAddFollowedTagtBinding popupAddFollowedTagtBinding = PopupAddFollowedTagtBinding.inflate(getLayoutInflater());
dialogBuilder.setView(popupAddFollowedTagtBinding.getRoot());
popupAddFollowedTagtBinding.addTag.setFilters(new InputFilter[]{new InputFilter.LengthFilter(255)});
dialogBuilder.setPositiveButton(R.string.validate, (dialog, id) -> {
if (popupAddFollowedTagtBinding.addTag.getText() != null && popupAddFollowedTagtBinding.addTag.getText().toString().trim().length() > 0) {
tagVM.follow(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, popupAddFollowedTagtBinding.addTag.getText().toString().trim())
.observe(FollowedTagActivity.this, newTag -> {
if (tagList == null) {
tagList = new ArrayList<>();
}
if (followedTagAdapter == null) {
followedTagAdapter = new FollowedTagAdapter(tagList);
followedTagAdapter.actionOnTag = this;
binding.notContent.setVisibility(View.GONE);
binding.recyclerView.setAdapter(followedTagAdapter);
binding.recyclerView.setLayoutManager(new LinearLayoutManager(FollowedTagActivity.this));
}
if (newTag != null) {
tagList.add(0, newTag);
followedTagAdapter.notifyItemInserted(0);
} else {
Toasty.error(FollowedTagActivity.this, getString(R.string.toast_feature_not_supported), Toasty.LENGTH_LONG).show();
}
});
dialog.dismiss();
} else {
popupAddFollowedTagtBinding.addTag.setError(getString(R.string.not_valid_tag_name));
}
});
dialogBuilder.setNegativeButton(R.string.cancel, (dialog, id) -> dialog.dismiss());
dialogBuilder.create().show();
}
return super.onOptionsItemSelected(item);
}
@Override
public boolean onCreateOptionsMenu(@NonNull Menu menu) {
if (!canGoBack) {
getMenuInflater().inflate(R.menu.menu_main_followed_tag, menu);
} else {
getMenuInflater().inflate(R.menu.menu_followed_tag, menu);
}
return true;
}
@Override
public void onBackPressed() {
if (canGoBack) {
canGoBack = false;
ThemeHelper.slideViewsToRight(binding.fragmentContainer, binding.recyclerView, () -> {
if (fragmentMastodonTimeline != null) {
fragmentMastodonTimeline.onDestroyView();
}
});
setTitle(R.string.followed_tags);
invalidateOptionsMenu();
} else {
super.onBackPressed();
}
}
@Override
public void click(Tag tag) {
this.tag = tag;
canGoBack = true;
ThemeHelper.slideViewsToLeft(binding.recyclerView, binding.fragmentContainer, () -> {
fragmentMastodonTimeline = new FragmentMastodonTimeline();
Bundle bundle = new Bundle();
bundle.putSerializable(Helper.ARG_SEARCH_KEYWORD, tag.name);
bundle.putSerializable(Helper.ARG_TIMELINE_TYPE, Timeline.TimeLineEnum.TAG);
setTitle(tag.name);
fragmentMastodonTimeline.setArguments(bundle);
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction =
fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, fragmentMastodonTimeline);
fragmentTransaction.commit();
invalidateOptionsMenu();
});
}
}

View file

@ -0,0 +1,391 @@
package app.fedilab.android.mastodon.activities;
/* Copyright 2022 Thomas Schneider
*
* This file is a part of Fedilab
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* Fedilab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see <http://www.gnu.org/licenses>. */
import static app.fedilab.android.BaseMainActivity.currentAccount;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.view.Menu;
import android.view.MenuItem;
import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AlertDialog;
import androidx.lifecycle.ViewModelProvider;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import java.util.ArrayList;
import java.util.List;
import app.fedilab.android.BaseMainActivity;
import app.fedilab.android.R;
import app.fedilab.android.activities.MainActivity;
import app.fedilab.android.databinding.ActivityHashtagBinding;
import app.fedilab.android.mastodon.client.entities.api.Filter;
import app.fedilab.android.mastodon.client.entities.api.Status;
import app.fedilab.android.mastodon.client.entities.app.Pinned;
import app.fedilab.android.mastodon.client.entities.app.PinnedTimeline;
import app.fedilab.android.mastodon.client.entities.app.StatusDraft;
import app.fedilab.android.mastodon.client.entities.app.TagTimeline;
import app.fedilab.android.mastodon.client.entities.app.Timeline;
import app.fedilab.android.mastodon.exception.DBException;
import app.fedilab.android.mastodon.helper.Helper;
import app.fedilab.android.mastodon.ui.fragment.timeline.FragmentMastodonTimeline;
import app.fedilab.android.mastodon.viewmodel.mastodon.FiltersVM;
import app.fedilab.android.mastodon.viewmodel.mastodon.ReorderVM;
import app.fedilab.android.mastodon.viewmodel.mastodon.TagVM;
import es.dmoral.toasty.Toasty;
public class HashTagActivity extends BaseActivity {
public static int position;
private String tag;
private String stripTag;
private Boolean pinnedTag;
private Boolean followedTag;
private Boolean mutedTag;
private TagVM tagVM;
private Filter fedilabFilter;
private Filter.KeywordsAttributes keyword;
private PinnedTimeline pinnedTimeline;
private Pinned pinned;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityHashtagBinding binding = ActivityHashtagBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
Bundle b = getIntent().getExtras();
if (b != null) {
tag = b.getString(Helper.ARG_SEARCH_KEYWORD, null);
}
if (tag == null)
finish();
pinnedTag = null;
followedTag = null;
mutedTag = null;
stripTag = tag.replaceAll("#", "");
setSupportActionBar(binding.toolbar);
ActionBar actionBar = getSupportActionBar();
//Remove title
if (actionBar != null) {
actionBar.setDisplayShowTitleEnabled(false);
}
binding.title.setText(tag);
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
}
tagVM = new ViewModelProvider(HashTagActivity.this).get(TagVM.class);
tagVM.getTag(MainActivity.currentInstance, MainActivity.currentToken, stripTag).observe(this, returnedTag -> {
if (returnedTag != null) {
followedTag = returnedTag.following;
invalidateOptionsMenu();
}
});
ReorderVM reorderVM = new ViewModelProvider(HashTagActivity.this).get(ReorderVM.class);
reorderVM.getAllPinned().observe(HashTagActivity.this, pinned -> {
if (pinned == null) {
pinned = new Pinned();
pinned.pinnedTimelines = new ArrayList<>();
}
this.pinned = pinned;
pinnedTag = false;
if (pinned.pinnedTimelines != null) {
for (PinnedTimeline pinnedTimeline : pinned.pinnedTimelines) {
if (pinnedTimeline.tagTimeline != null) {
if (pinnedTimeline.tagTimeline.name.equalsIgnoreCase(stripTag)) {
this.pinnedTimeline = pinnedTimeline;
pinnedTag = true;
break;
}
}
}
invalidateOptionsMenu();
}
});
if (MainActivity.filterFetched && MainActivity.mainFilters != null) {
mutedTag = false;
for (Filter filter : MainActivity.mainFilters) {
if (filter.title.equalsIgnoreCase(Helper.FEDILAB_MUTED_HASHTAGS)) {
fedilabFilter = filter;
String fetch = tag.startsWith("#") ? tag : "#" + tag;
for (Filter.KeywordsAttributes keywordsAttributes : filter.keywords) {
if (fetch.equalsIgnoreCase(keywordsAttributes.keyword)) {
mutedTag = true;
keyword = keywordsAttributes;
invalidateOptionsMenu();
break;
}
}
}
}
invalidateOptionsMenu();
}
Bundle bundle = new Bundle();
bundle.putSerializable(Helper.ARG_TIMELINE_TYPE, Timeline.TimeLineEnum.TAG);
bundle.putString(Helper.ARG_SEARCH_KEYWORD, tag);
Helper.addFragment(getSupportFragmentManager(), R.id.nav_host_fragment_tags, new FragmentMastodonTimeline(), bundle, null, null);
binding.compose.setOnClickListener(v -> {
Intent intentToot = new Intent(HashTagActivity.this, ComposeActivity.class);
StatusDraft statusDraft = new StatusDraft();
Status status = new Status();
status.text = "#" + stripTag;
List<Status> statuses = new ArrayList<>();
statuses.add(status);
statusDraft.statusDraftList = statuses;
Bundle _b = new Bundle();
_b.putSerializable(Helper.ARG_STATUS_DRAFT, statusDraft);
intentToot.putExtras(_b);
startActivity(intentToot);
});
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
finish();
return true;
} else if (item.getItemId() == R.id.action_add_timeline) {
if (pinnedTag) {
AlertDialog.Builder unpinConfirm = new MaterialAlertDialogBuilder(HashTagActivity.this);
unpinConfirm.setMessage(getString(R.string.unpin_timeline_description));
unpinConfirm.setNegativeButton(R.string.cancel, (dialog, which) -> dialog.dismiss());
unpinConfirm.setPositiveButton(R.string.yes, (dialog, which) -> {
if (pinned == null || pinned.pinnedTimelines == null) {
return;
}
pinned.pinnedTimelines.remove(pinnedTimeline);
try {
new Pinned(HashTagActivity.this).updatePinned(pinned);
} catch (DBException e) {
e.printStackTrace();
}
pinnedTag = false;
invalidateOptionsMenu();
Bundle b = new Bundle();
b.putBoolean(Helper.RECEIVE_REDRAW_TOPBAR, true);
Intent intentBD = new Intent(Helper.BROADCAST_DATA);
intentBD.putExtras(b);
LocalBroadcastManager.getInstance(HashTagActivity.this).sendBroadcast(intentBD);
dialog.dismiss();
});
unpinConfirm.show();
} else {
new Thread(() -> {
try {
Pinned pinned = new Pinned(HashTagActivity.this).getPinned(currentAccount);
boolean canBeAdded = true;
boolean update = true;
if (pinned == null) {
pinned = new Pinned();
pinned.pinnedTimelines = new ArrayList<>();
update = false;
} else {
for (PinnedTimeline pinnedTimeline : pinned.pinnedTimelines) {
if (pinnedTimeline.type == Timeline.TimeLineEnum.TAG) {
if (pinnedTimeline.tagTimeline.name.compareTo(stripTag.trim()) == 0) {
canBeAdded = false;
}
}
}
}
if (!canBeAdded) {
Handler mainHandler = new Handler(Looper.getMainLooper());
Runnable myRunnable = () -> Toasty.warning(HashTagActivity.this, getString(R.string.tags_already_stored), Toasty.LENGTH_SHORT).show();
mainHandler.post(myRunnable);
return;
}
pinnedTimeline = new PinnedTimeline();
pinnedTimeline.type = Timeline.TimeLineEnum.TAG;
pinnedTimeline.position = pinned.pinnedTimelines.size();
pinnedTimeline.displayed = true;
TagTimeline tagTimeline = new TagTimeline();
tagTimeline.name = stripTag.trim();
tagTimeline.isNSFW = false;
tagTimeline.isART = false;
tagTimeline.any = new ArrayList<>();
tagTimeline.any.add(stripTag.trim());
pinnedTimeline.tagTimeline = tagTimeline;
pinned.pinnedTimelines.add(pinnedTimeline);
if (pinned.instance == null || pinned.user_id == null) {
pinned.instance = MainActivity.currentInstance;
pinned.user_id = MainActivity.currentUserID;
}
if (update) {
new Pinned(HashTagActivity.this).updatePinned(pinned);
} else {
new Pinned(HashTagActivity.this).insertPinned(pinned);
}
Bundle b = new Bundle();
b.putBoolean(Helper.RECEIVE_REDRAW_TOPBAR, true);
Intent intentBD = new Intent(Helper.BROADCAST_DATA);
intentBD.putExtras(b);
LocalBroadcastManager.getInstance(HashTagActivity.this).sendBroadcast(intentBD);
pinnedTag = true;
invalidateOptionsMenu();
} catch (DBException e) {
e.printStackTrace();
}
}).start();
}
} else if (item.getItemId() == R.id.action_follow_tag) {
if (!followedTag) {
tagVM.follow(MainActivity.currentInstance, MainActivity.currentToken, stripTag).observe(this, returnedTag -> {
if (returnedTag != null) {
followedTag = returnedTag.following;
invalidateOptionsMenu();
}
});
} else {
tagVM.unfollow(MainActivity.currentInstance, MainActivity.currentToken, stripTag).observe(this, returnedTag -> {
if (returnedTag != null) {
followedTag = returnedTag.following;
invalidateOptionsMenu();
}
});
}
} else if (item.getItemId() == R.id.action_mute) {
if (!mutedTag) {
if (MainActivity.mainFilters == null || fedilabFilter == null) {
MainActivity.mainFilters = new ArrayList<>();
Filter.FilterParams filterParams = new Filter.FilterParams();
filterParams.title = Helper.FEDILAB_MUTED_HASHTAGS;
filterParams.filter_action = "hide";
filterParams.context = new ArrayList<>();
filterParams.context.add("home");
filterParams.context.add("public");
filterParams.context.add("thread");
filterParams.context.add("account");
FiltersVM filtersVM = new ViewModelProvider(HashTagActivity.this).get(FiltersVM.class);
filtersVM.addFilter(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, filterParams)
.observe(HashTagActivity.this, filter -> {
if (filter != null) {
MainActivity.mainFilters.add(filter);
mutedTag = false;
fedilabFilter = filter;
muteTags();
invalidateOptionsMenu();
}
});
} else {
muteTags();
}
} else {
unmuteTags();
}
}
return super.onOptionsItemSelected(item);
}
private void unmuteTags() {
String search = tag.startsWith("#") ? tag : "#" + tag;
for (Filter.KeywordsAttributes keywordsAttributes : fedilabFilter.keywords) {
if (search.equalsIgnoreCase(keywordsAttributes.keyword)) {
keyword = keywordsAttributes;
break;
}
}
if (keyword != null && keyword.id != null) {
FiltersVM filtersVM = new ViewModelProvider(HashTagActivity.this).get(FiltersVM.class);
filtersVM.removeKeyword(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, keyword.id);
fedilabFilter.keywords.remove(keyword);
mutedTag = false;
invalidateOptionsMenu();
}
}
private void muteTags() {
Filter.FilterParams filterParams = new Filter.FilterParams();
filterParams.id = fedilabFilter.id;
filterParams.keywords = new ArrayList<>();
Filter.KeywordsParams keywordsParams = new Filter.KeywordsParams();
keywordsParams.whole_word = true;
keywordsParams.keyword = tag.startsWith("#") ? tag : "#" + tag;
filterParams.keywords.add(keywordsParams);
filterParams.context = fedilabFilter.context;
FiltersVM filtersVM = new ViewModelProvider(HashTagActivity.this).get(FiltersVM.class);
filtersVM.editFilter(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, filterParams)
.observe(HashTagActivity.this, filter -> {
fedilabFilter = filter;
mutedTag = true;
invalidateOptionsMenu();
});
}
@Override
public boolean onCreateOptionsMenu(@NonNull Menu menu) {
getMenuInflater().inflate(R.menu.menu_hashtag, menu);
MenuItem pin = menu.findItem(R.id.action_add_timeline);
MenuItem follow = menu.findItem(R.id.action_follow_tag);
MenuItem mute = menu.findItem(R.id.action_mute);
if (pinnedTag != null) {
pin.setVisible(true);
if (pinnedTag) {
pin.setIcon(R.drawable.tag_pin_off);
pin.setTitle(getString(R.string.unpin_tag));
} else {
pin.setTitle(getString(R.string.unpin_tag));
pin.setIcon(R.drawable.tag_pin);
}
} else {
pin.setVisible(false);
}
if (followedTag != null) {
follow.setVisible(true);
if (followedTag) {
follow.setTitle(getString(R.string.unfollow_tag));
follow.setIcon(R.drawable.tag_unfollow);
} else {
follow.setTitle(getString(R.string.follow_tag));
follow.setIcon(R.drawable.tag_follow);
}
} else {
follow.setVisible(false);
}
if (mutedTag != null) {
mute.setVisible(true);
if (mutedTag) {
mute.setTitle(getString(R.string.unmute_tag_action));
mute.setIcon(R.drawable.tag_unmuted);
} else {
mute.setTitle(getString(R.string.mute_tag_action));
mute.setIcon(R.drawable.tag_muted);
}
} else {
mute.setVisible(false);
}
return super.onCreateOptionsMenu(menu);
}
}

View file

@ -0,0 +1,158 @@
package app.fedilab.android.mastodon.activities;
/* Copyright 2022 Thomas Schneider
*
* This file is a part of Fedilab
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* Fedilab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see <http://www.gnu.org/licenses>. */
import android.app.Dialog;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.text.Html;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.style.ForegroundColorSpan;
import android.text.style.UnderlineSpan;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.DialogFragment;
import androidx.lifecycle.ViewModelProvider;
import androidx.preference.PreferenceManager;
import com.bumptech.glide.Glide;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import app.fedilab.android.BaseMainActivity;
import app.fedilab.android.R;
import app.fedilab.android.activities.MainActivity;
import app.fedilab.android.databinding.ActivityInstanceBinding;
import app.fedilab.android.mastodon.client.entities.api.Instance;
import app.fedilab.android.mastodon.helper.Helper;
import app.fedilab.android.mastodon.helper.ThemeHelper;
import app.fedilab.android.mastodon.viewmodel.mastodon.InstancesVM;
public class InstanceActivity extends DialogFragment {
ActivityInstanceBinding binding;
private boolean applyMaxChar = false;
@NonNull
@Override
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
binding = ActivityInstanceBinding.inflate(getLayoutInflater());
MaterialAlertDialogBuilder materialAlertDialogBuilder = new MaterialAlertDialogBuilder(requireContext());
materialAlertDialogBuilder.setView(binding.getRoot());
Dialog dialog = materialAlertDialogBuilder.create();
SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(requireActivity());
final SpannableString contentAbout = new SpannableString(getString(R.string.action_about_instance));
contentAbout.setSpan(new UnderlineSpan(), 0, contentAbout.length(), 0);
contentAbout.setSpan(new ForegroundColorSpan(ThemeHelper.getAttColor(requireContext(), R.attr.colorPrimary)), 0, contentAbout.length(),
Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
binding.about.setText(contentAbout);
final SpannableString contentPrivacy = new SpannableString(getString(R.string.action_privacy_policy));
contentPrivacy.setSpan(new UnderlineSpan(), 0, contentPrivacy.length(), 0);
contentPrivacy.setSpan(new ForegroundColorSpan(ThemeHelper.getAttColor(requireContext(), R.attr.colorPrimary)), 0, contentPrivacy.length(),
Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
binding.privacy.setText(contentPrivacy);
binding.about.setOnClickListener(v -> Helper.openBrowser(requireActivity(), "https://" + MainActivity.currentInstance + "/about"));
binding.privacy.setOnClickListener(v -> Helper.openBrowser(requireActivity(), "https://" + MainActivity.currentInstance + "/privacy-policy"));
binding.close.setOnClickListener(view -> {
if (applyMaxChar) {
String max_char = binding.maxChar.getText().toString();
SharedPreferences.Editor editor = sharedpreferences.edit();
if (!max_char.isEmpty()) {
try {
editor.putInt(getString(R.string.SET_MAX_INSTANCE_CHAR) + MainActivity.currentInstance, Integer.parseInt(max_char));
editor.apply();
} catch (Exception ignored) {
}
}
}
requireDialog().dismiss();
}
);
InstancesVM instancesVM = new ViewModelProvider(InstanceActivity.this).get(InstancesVM.class);
instancesVM.getInstance(BaseMainActivity.currentInstance).observe(InstanceActivity.this, instanceInfo -> {
binding.loader.setVisibility(View.GONE);
if (instanceInfo == null || instanceInfo.info == null || instanceInfo.info.description == null) {
binding.instanceData.setVisibility(View.GONE);
binding.contact.setVisibility(View.GONE);
int val = sharedpreferences.getInt(getString(R.string.SET_MAX_INSTANCE_CHAR) + MainActivity.currentInstance, -1);
if (val != -1) {
binding.maxChar.setText(String.valueOf(val));
}
applyMaxChar = true;
} else {
Instance instance = instanceInfo.info;
Glide.with(InstanceActivity.this)
.asDrawable()
.placeholder(R.drawable.default_banner)
.load(instance.thumbnail)
.into(binding.backgroundImage);
binding.name.setText(instance.title);
if (instance.description == null || instance.description.trim().length() == 0)
binding.description.setText(getString(R.string.instance_no_description));
else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
binding.description.setText(Html.fromHtml(instance.description, Html.FROM_HTML_MODE_LEGACY));
else
binding.description.setText(Html.fromHtml(instance.description));
binding.version.setText(instance.version);
binding.uri.setText(instance.uri);
if (instance.email == null) {
binding.contact.setVisibility(View.GONE);
} else {
binding.contact.setVisibility(View.VISIBLE);
}
binding.contact.setOnClickListener(v -> {
Intent emailIntent = new Intent(Intent.ACTION_SENDTO, Uri.fromParts("mailto", instance.email, null));
emailIntent.putExtra(Intent.EXTRA_SUBJECT, "[Mastodon] - " + instance.uri);
startActivity(Intent.createChooser(emailIntent, getString(R.string.send_email)));
});
binding.instanceData.setVisibility(View.VISIBLE);
}
});
return dialog;
}
@Override
public void onDestroyView() {
super.onDestroyView();
binding = null;
}
}

View file

@ -0,0 +1,126 @@
package app.fedilab.android.mastodon.activities
import android.app.Dialog
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.text.SpannableString
import android.text.style.UnderlineSpan
import android.view.Window
import androidx.core.view.isVisible
import androidx.fragment.app.DialogFragment
import androidx.lifecycle.ViewModelProvider
import app.fedilab.android.BaseMainActivity
import app.fedilab.android.R
import app.fedilab.android.databinding.ActivityInstanceSocialBinding
import app.fedilab.android.mastodon.client.entities.app.InstanceSocial
import app.fedilab.android.mastodon.helper.Helper
import app.fedilab.android.mastodon.helper.ThemeHelper
import app.fedilab.android.mastodon.viewmodel.mastodon.InstanceSocialVM
import com.bumptech.glide.Glide
import com.google.android.material.dialog.MaterialAlertDialogBuilder
/* Copyright 2022 Thomas Schneider
*
* This file is a part of Fedilab
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* Fedilab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see <http://www.gnu.org/licenses>. */
class InstanceHealthActivity : DialogFragment() {
private var _binding: ActivityInstanceSocialBinding? = null
private val binding: ActivityInstanceSocialBinding get() = _binding!!
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
_binding = ActivityInstanceSocialBinding.inflate(layoutInflater)
binding.close.setOnClickListener { dialog?.dismiss() }
val content = SpannableString(binding.refInstance.text.toString())
content.setSpan(UnderlineSpan(), 0, content.length, 0)
binding.refInstance.text = content
binding.refInstance.setOnClickListener {
startActivity(Intent(Intent.ACTION_VIEW, Uri.parse("https://instances.social")))
}
val materialAlertDialogBuilder = MaterialAlertDialogBuilder(requireContext())
materialAlertDialogBuilder.setView(binding.root)
val dialog = materialAlertDialogBuilder.create()
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE)
dialog.setOnShowListener { checkInstance() }
return dialog
}
private fun checkInstance() {
val instanceSocialVM =
ViewModelProvider(this@InstanceHealthActivity)[InstanceSocialVM::class.java]
instanceSocialVM.getInstances(BaseMainActivity.currentInstance.trim { it <= ' ' })
.observe(this@InstanceHealthActivity) { instanceSocialList: InstanceSocial? ->
val instance = instanceSocialList?.instances?.firstOrNull { instance ->
instance.name.equals(
BaseMainActivity.currentInstance.trim { it <= ' ' },
ignoreCase = true
)
}
if (instance != null) {
instance.thumbnail?.takeIf { it != "null" }?.let { thumbnail ->
Glide.with(this@InstanceHealthActivity)
.asBitmap()
.placeholder(R.drawable.default_banner)
.load(thumbnail)
.into(binding.backgroundImage)
}
binding.name.text = instance.name
if (instance.up) {
binding.up.setText(app.fedilab.android.R.string.is_up)
binding.up.setTextColor(
ThemeHelper.getAttColor(
requireContext(),
app.fedilab.android.R.attr.colorPrimary
)
)
} else {
binding.up.setText(app.fedilab.android.R.string.is_down)
binding.up.setTextColor(
ThemeHelper.getAttColor(
requireContext(),
app.fedilab.android.R.attr.colorError
)
)
}
binding.uptime.text = getString(
app.fedilab.android.R.string.instance_health_uptime,
instance.uptime * 100
)
if (instance.checked_at != null)
binding.checkedAt.text =
getString(
app.fedilab.android.R.string.instance_health_checkedat,
Helper.dateToString(instance.checked_at)
)
binding.values.text = getString(
app.fedilab.android.R.string.instance_health_indication,
instance.version,
Helper.withSuffix(instance.active_users.toLong()),
Helper.withSuffix(instance.statuses.toLong())
)
} else {
binding.instanceData.isVisible = false
binding.noInstance.isVisible = true
}
binding.loader.isVisible = false
}
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}

View file

@ -0,0 +1,78 @@
package app.fedilab.android.mastodon.activities;
/* Copyright 2022 Thomas Schneider
*
* This file is a part of Fedilab
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* Fedilab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see <http://www.gnu.org/licenses>. */
import android.app.Dialog;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.DialogFragment;
import androidx.lifecycle.ViewModelProvider;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import app.fedilab.android.R;
import app.fedilab.android.databinding.ActivityInstanceProfileBinding;
import app.fedilab.android.mastodon.helper.Helper;
import app.fedilab.android.mastodon.viewmodel.mastodon.NodeInfoVM;
import es.dmoral.toasty.Toasty;
public class InstanceProfileActivity extends DialogFragment {
private String instance;
private ActivityInstanceProfileBinding binding;
@NonNull
@Override
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
binding = ActivityInstanceProfileBinding.inflate(getLayoutInflater());
MaterialAlertDialogBuilder materialAlertDialogBuilder = new MaterialAlertDialogBuilder(requireContext());
materialAlertDialogBuilder.setView(binding.getRoot());
Dialog dialog = materialAlertDialogBuilder.create();
Bundle b = getArguments();
if (b != null)
instance = b.getString(Helper.ARG_INSTANCE, null);
if (instance == null) {
requireDialog().dismiss();
}
binding.close.setOnClickListener(v -> requireDialog().dismiss());
NodeInfoVM nodeInfoVM = new ViewModelProvider(InstanceProfileActivity.this).get(NodeInfoVM.class);
nodeInfoVM.getNodeInfo(instance).observe(InstanceProfileActivity.this, nodeInfo -> {
if (nodeInfo == null) {
Toasty.error(requireContext(), getString(R.string.toast_error), Toast.LENGTH_LONG).show();
requireDialog().dismiss();
return;
}
binding.name.setText(instance);
binding.userCount.setText(Helper.withSuffix((nodeInfo.usage.users.total)));
binding.statusCount.setText(Helper.withSuffix(((nodeInfo.usage.localPosts))));
String softwareStr = nodeInfo.software.name + " - ";
binding.software.setText(softwareStr);
binding.version.setText(nodeInfo.software.version);
binding.loader.setVisibility(View.GONE);
});
return dialog;
}
}

View file

@ -1,4 +1,4 @@
package app.fedilab.android.activities;
package app.fedilab.android.mastodon.activities;
/* Copyright 2022 Thomas Schneider
*
* This file is a part of Fedilab
@ -16,7 +16,6 @@ package app.fedilab.android.activities;
import android.content.Intent;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.text.Editable;
import android.text.InputFilter;
@ -28,7 +27,6 @@ import android.view.View;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import androidx.lifecycle.ViewModelProvider;
@ -36,28 +34,36 @@ import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import app.fedilab.android.BaseMainActivity;
import app.fedilab.android.R;
import app.fedilab.android.client.entities.api.Account;
import app.fedilab.android.client.entities.api.MastodonList;
import app.fedilab.android.client.entities.app.Timeline;
import app.fedilab.android.activities.MainActivity;
import app.fedilab.android.databinding.ActivityListBinding;
import app.fedilab.android.databinding.PopupAddListBinding;
import app.fedilab.android.databinding.PopupManageAccountsListBinding;
import app.fedilab.android.helper.Helper;
import app.fedilab.android.helper.ThemeHelper;
import app.fedilab.android.ui.drawer.AccountListAdapter;
import app.fedilab.android.ui.drawer.MastodonListAdapter;
import app.fedilab.android.ui.fragment.timeline.FragmentMastodonTimeline;
import app.fedilab.android.viewmodel.mastodon.AccountsVM;
import app.fedilab.android.viewmodel.mastodon.TimelinesVM;
import app.fedilab.android.mastodon.client.entities.api.Account;
import app.fedilab.android.mastodon.client.entities.api.MastodonList;
import app.fedilab.android.mastodon.client.entities.app.Pinned;
import app.fedilab.android.mastodon.client.entities.app.PinnedTimeline;
import app.fedilab.android.mastodon.client.entities.app.Timeline;
import app.fedilab.android.mastodon.exception.DBException;
import app.fedilab.android.mastodon.helper.Helper;
import app.fedilab.android.mastodon.helper.ThemeHelper;
import app.fedilab.android.mastodon.ui.drawer.AccountListAdapter;
import app.fedilab.android.mastodon.ui.drawer.MastodonListAdapter;
import app.fedilab.android.mastodon.ui.fragment.timeline.FragmentMastodonTimeline;
import app.fedilab.android.mastodon.viewmodel.mastodon.AccountsVM;
import app.fedilab.android.mastodon.viewmodel.mastodon.ReorderVM;
import app.fedilab.android.mastodon.viewmodel.mastodon.TimelinesVM;
import es.dmoral.toasty.Toasty;
public class MastodonListActivity extends BaseActivity implements MastodonListAdapter.ActionOnList {
public class MastodonListActivity extends BaseBarActivity implements MastodonListAdapter.ActionOnList {
AccountListAdapter accountsInListAdapter;
@ -72,45 +78,90 @@ public class MastodonListActivity extends BaseActivity implements MastodonListAd
private boolean flagLoading;
private String max_id;
private FragmentMastodonTimeline fragmentMastodonTimeline;
private boolean orderASC;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ThemeHelper.applyThemeBar(this);
binding = ActivityListBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
canGoBack = false;
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
getSupportActionBar().setBackgroundDrawable(new ColorDrawable(ContextCompat.getColor(this, R.color.cyanea_primary)));
}
flagLoading = false;
orderASC = true;
max_id = null;
accountsVM = new ViewModelProvider(MastodonListActivity.this).get(AccountsVM.class);
timelinesVM = new ViewModelProvider(MastodonListActivity.this).get(TimelinesVM.class);
timelinesVM.getLists(BaseMainActivity.currentInstance, BaseMainActivity.currentToken)
.observe(MastodonListActivity.this, mastodonLists -> {
if (mastodonLists != null && mastodonLists.size() > 0) {
mastodonListList = new ArrayList<>(mastodonLists);
mastodonListAdapter = new MastodonListAdapter(mastodonListList);
mastodonListAdapter.actionOnList = this;
binding.notContent.setVisibility(View.GONE);
binding.recyclerView.setAdapter(mastodonListAdapter);
binding.recyclerView.setLayoutManager(new LinearLayoutManager(MastodonListActivity.this));
} else {
binding.notContent.setVisibility(View.VISIBLE);
}
ReorderVM reorderVM = new ViewModelProvider(MastodonListActivity.this).get(ReorderVM.class);
reorderVM.getPinned().observe(MastodonListActivity.this, pinned -> {
if (mastodonLists != null && mastodonLists.size() > 0) {
mastodonListList = new ArrayList<>(mastodonLists);
if (pinned != null) {
if (pinned.pinnedTimelines != null && pinned.pinnedTimelines.size() > 0) {
for (PinnedTimeline pinnedTimeline : pinned.pinnedTimelines) {
if (pinnedTimeline.type == Timeline.TimeLineEnum.LIST) {
for (MastodonList mastodonList : mastodonLists) {
if (mastodonList.id.equalsIgnoreCase(pinnedTimeline.mastodonList.id)) {
mastodonList.position = pinnedTimeline.position;
}
}
}
}
}
}
sortAsc(mastodonListList);
mastodonListAdapter = new MastodonListAdapter(mastodonListList);
mastodonListAdapter.actionOnList = this;
binding.notContent.setVisibility(View.GONE);
binding.recyclerView.setAdapter(mastodonListAdapter);
binding.recyclerView.setLayoutManager(new LinearLayoutManager(MastodonListActivity.this));
} else {
binding.notContent.setVisibility(View.VISIBLE);
}
});
});
}
private void sortAsc(List<MastodonList> mastodonLists) {
Collections.sort(mastodonLists, (obj1, obj2) -> obj1.title.compareToIgnoreCase(obj2.title));
orderASC = true;
invalidateOptionsMenu();
}
private void sortDesc(List<MastodonList> mastodonLists) {
Collections.sort(mastodonLists, (obj1, obj2) -> obj2.title.compareToIgnoreCase(obj1.title));
orderASC = false;
invalidateOptionsMenu();
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
onBackPressed();
return true;
} else if (item.getItemId() == R.id.action_user_mute_home) {
AlertDialog.Builder dialogBuilder = new MaterialAlertDialogBuilder(MastodonListActivity.this);
dialogBuilder.setTitle(R.string.put_all_accounts_in_home_muted);
dialogBuilder.setPositiveButton(R.string.mute_them_all, (dialog, id) -> {
timelinesVM.getAccountsInList(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, mastodonList.id, null, null, 0)
.observe(MastodonListActivity.this, accounts -> {
if (accounts != null && accounts.size() > 0) {
accountsVM.muteAccountsHome(MainActivity.currentAccount, accounts);
}
});
dialog.dismiss();
});
dialogBuilder.setNegativeButton(R.string.cancel, (dialog, id) -> dialog.dismiss());
dialogBuilder.show();
} else if (item.getItemId() == R.id.action_manage_users) {
AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(MastodonListActivity.this, Helper.dialogStyle());
AlertDialog.Builder dialogBuilder = new MaterialAlertDialogBuilder(MastodonListActivity.this);
PopupManageAccountsListBinding popupManageAccountsListBinding = PopupManageAccountsListBinding.inflate(getLayoutInflater());
dialogBuilder.setView(popupManageAccountsListBinding.getRoot());
popupManageAccountsListBinding.loader.setVisibility(View.VISIBLE);
@ -207,7 +258,7 @@ public class MastodonListActivity extends BaseActivity implements MastodonListAd
dialogBuilder.setPositiveButton(R.string.close, (dialog, id) -> dialog.dismiss());
dialogBuilder.create().show();
} else if (item.getItemId() == R.id.action_delete && mastodonList != null) {
AlertDialog.Builder alt_bld = new AlertDialog.Builder(MastodonListActivity.this, Helper.dialogStyle());
AlertDialog.Builder alt_bld = new MaterialAlertDialogBuilder(MastodonListActivity.this);
alt_bld.setTitle(R.string.action_lists_delete);
alt_bld.setMessage(R.string.action_lists_confirm_delete);
alt_bld.setPositiveButton(R.string.delete, (dialog, id) -> {
@ -245,7 +296,7 @@ public class MastodonListActivity extends BaseActivity implements MastodonListAd
AlertDialog alert = alt_bld.create();
alert.show();
} else if (item.getItemId() == R.id.action_add_list) {
AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(MastodonListActivity.this, Helper.dialogStyle());
AlertDialog.Builder dialogBuilder = new MaterialAlertDialogBuilder(MastodonListActivity.this);
PopupAddListBinding popupAddListBinding = PopupAddListBinding.inflate(getLayoutInflater());
dialogBuilder.setView(popupAddListBinding.getRoot());
popupAddListBinding.addList.setFilters(new InputFilter[]{new InputFilter.LengthFilter(255)});
@ -258,6 +309,13 @@ public class MastodonListActivity extends BaseActivity implements MastodonListAd
}
if (newMastodonList != null) {
mastodonListList.add(0, newMastodonList);
if (mastodonListAdapter == null) {
mastodonListAdapter = new MastodonListAdapter(mastodonListList);
mastodonListAdapter.actionOnList = MastodonListActivity.this;
binding.notContent.setVisibility(View.GONE);
binding.recyclerView.setAdapter(mastodonListAdapter);
binding.recyclerView.setLayoutManager(new LinearLayoutManager(MastodonListActivity.this));
}
mastodonListAdapter.notifyItemInserted(0);
} else {
Toasty.error(MastodonListActivity.this, getString(R.string.toast_error), Toasty.LENGTH_LONG).show();
@ -277,6 +335,83 @@ public class MastodonListActivity extends BaseActivity implements MastodonListAd
});
dialogBuilder.setNegativeButton(R.string.cancel, (dialog, id) -> dialog.dismiss());
dialogBuilder.create().show();
} else if (item.getItemId() == R.id.action_edit) {
AlertDialog.Builder dialogBuilder = new MaterialAlertDialogBuilder(MastodonListActivity.this);
PopupAddListBinding popupAddListBinding = PopupAddListBinding.inflate(getLayoutInflater());
dialogBuilder.setView(popupAddListBinding.getRoot());
popupAddListBinding.addList.setFilters(new InputFilter[]{new InputFilter.LengthFilter(255)});
popupAddListBinding.addList.setText(mastodonList.title);
popupAddListBinding.addList.setSelection(popupAddListBinding.addList.getText().length());
dialogBuilder.setPositiveButton(R.string.validate, (dialog, id) -> {
if (popupAddListBinding.addList.getText() != null && popupAddListBinding.addList.getText().toString().trim().length() > 0) {
timelinesVM.updateList(
BaseMainActivity.currentInstance, BaseMainActivity.currentToken, mastodonList.id,
popupAddListBinding.addList.getText().toString().trim(), null)
.observe(MastodonListActivity.this, newMastodonList -> {
if (mastodonListList != null && newMastodonList != null) {
int position = 0;
for (MastodonList mastodonList : mastodonListList) {
if (newMastodonList.id.equalsIgnoreCase(mastodonList.id)) {
ReorderVM reorderVM = new ViewModelProvider(MastodonListActivity.this).get(ReorderVM.class);
int finalPosition = position;
reorderVM.getAllPinned().observe(MastodonListActivity.this, pinned -> {
if (pinned != null) {
if (pinned.pinnedTimelines != null) {
for (PinnedTimeline pinnedTimeline : pinned.pinnedTimelines) {
if (pinnedTimeline.mastodonList != null) {
if (pinnedTimeline.mastodonList.id.equalsIgnoreCase(newMastodonList.id)) {
if (!newMastodonList.title.equalsIgnoreCase(pinnedTimeline.mastodonList.title)) {
pinnedTimeline.mastodonList.title = newMastodonList.title;
setTitle(newMastodonList.title);
mastodonListList.get(finalPosition).title = newMastodonList.title;
mastodonListAdapter.notifyItemChanged(finalPosition);
new Thread(() -> {
try {
new Pinned(MastodonListActivity.this).updatePinned(pinned);
Bundle b = new Bundle();
b.putBoolean(Helper.RECEIVE_REDRAW_TOPBAR, true);
Intent intentBD = new Intent(Helper.BROADCAST_DATA);
intentBD.putExtras(b);
LocalBroadcastManager.getInstance(MastodonListActivity.this).sendBroadcast(intentBD);
} catch (DBException e) {
e.printStackTrace();
}
}).start();
}
break;
}
}
}
}
}
});
}
position++;
}
} else {
Toasty.error(MastodonListActivity.this, getString(R.string.toast_error), Toasty.LENGTH_LONG).show();
}
});
dialog.dismiss();
} else {
popupAddListBinding.addList.setError(getString(R.string.not_valid_list_name));
}
});
dialogBuilder.setNegativeButton(R.string.cancel, (dialog, id) -> dialog.dismiss());
dialogBuilder.create().show();
} else if (item.getItemId() == R.id.action_order) {
if (mastodonListList != null && mastodonListList.size() > 0 && mastodonListAdapter != null) {
if (orderASC) {
sortDesc(mastodonListList);
} else {
sortAsc(mastodonListList);
}
invalidateOptionsMenu();
mastodonListAdapter.notifyItemRangeChanged(0, mastodonListList.size());
}
}
return super.onOptionsItemSelected(item);
}
@ -306,6 +441,14 @@ public class MastodonListActivity extends BaseActivity implements MastodonListAd
public boolean onCreateOptionsMenu(@NonNull Menu menu) {
if (!canGoBack) {
getMenuInflater().inflate(R.menu.menu_main_list, menu);
MenuItem order = menu.findItem(R.id.action_order);
if (order != null) {
if (orderASC) {
order.setIcon(R.drawable.ic_baseline_filter_asc_24);
} else {
order.setIcon(R.drawable.ic_baseline_filter_desc_24);
}
}
} else {
getMenuInflater().inflate(R.menu.menu_list, menu);
}

View file

@ -1,4 +1,4 @@
package app.fedilab.android.activities;
package app.fedilab.android.mastodon.activities;
/* Copyright 2022 Thomas Schneider
*
* This file is a part of Fedilab
@ -22,41 +22,44 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.graphics.Point;
import android.graphics.drawable.ColorDrawable;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.view.Display;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.viewpager2.adapter.FragmentStateAdapter;
import androidx.viewpager2.widget.ViewPager2;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentStatePagerAdapter;
import androidx.viewpager.widget.ViewPager;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import app.fedilab.android.R;
import app.fedilab.android.client.entities.api.Attachment;
import app.fedilab.android.databinding.ActivityMediaPagerBinding;
import app.fedilab.android.helper.Helper;
import app.fedilab.android.helper.MediaHelper;
import app.fedilab.android.helper.ThemeHelper;
import app.fedilab.android.interfaces.OnDownloadInterface;
import app.fedilab.android.ui.fragment.media.FragmentMedia;
import app.fedilab.android.mastodon.client.entities.api.Attachment;
import app.fedilab.android.mastodon.client.entities.api.Status;
import app.fedilab.android.mastodon.helper.Helper;
import app.fedilab.android.mastodon.helper.MediaHelper;
import app.fedilab.android.mastodon.helper.TranslateHelper;
import app.fedilab.android.mastodon.interfaces.OnDownloadInterface;
import app.fedilab.android.mastodon.ui.fragment.media.FragmentMedia;
import app.fedilab.android.mastodon.ui.fragment.media.FragmentMediaProfile;
import es.dmoral.toasty.Toasty;
public class MediaActivity extends BaseActivity implements OnDownloadInterface {
public class MediaActivity extends BaseTransparentActivity implements OnDownloadInterface {
int flags;
private ArrayList<Attachment> attachments;
@ -68,7 +71,7 @@ public class MediaActivity extends BaseActivity implements OnDownloadInterface {
public void onReceive(Context context, Intent intent) {
long id = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1);
if (downloadID == id) {
DownloadManager manager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
DownloadManager manager = (DownloadManager) context.getSystemService(DOWNLOAD_SERVICE);
assert manager != null;
Uri uri = manager.getUriForDownloadedFile(downloadID);
Intent shareIntent = new Intent(Intent.ACTION_SEND);
@ -90,15 +93,15 @@ public class MediaActivity extends BaseActivity implements OnDownloadInterface {
};
private boolean fullscreen;
private Handler handler;
private int minTouch, maxTouch;
private float startX;
private float startY;
private ActivityMediaPagerBinding binding;
private FragmentMedia mCurrentFragment;
private Status status;
private boolean mediaFromProfile;
@Override
protected void onCreate(Bundle savedInstanceState) {
getWindow().requestFeature(Window.FEATURE_ACTION_BAR_OVERLAY);
ThemeHelper.applyThemeBar(this);
super.onCreate(savedInstanceState);
ActivityCompat.postponeEnterTransition(MediaActivity.this);
binding = ActivityMediaPagerBinding.inflate(getLayoutInflater());
@ -111,11 +114,16 @@ public class MediaActivity extends BaseActivity implements OnDownloadInterface {
if (b != null) {
mediaPosition = b.getInt(Helper.ARG_MEDIA_POSITION, 1);
attachments = (ArrayList<Attachment>) b.getSerializable(Helper.ARG_MEDIA_ARRAY);
mediaFromProfile = b.getBoolean(Helper.ARG_MEDIA_ARRAY_PROFILE, false);
status = (Status) b.getSerializable(Helper.ARG_STATUS);
}
if (mediaFromProfile && FragmentMediaProfile.mediaAttachmentProfile != null) {
attachments = new ArrayList<>();
attachments.addAll(FragmentMediaProfile.mediaAttachmentProfile);
}
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
getSupportActionBar().setBackgroundDrawable(new ColorDrawable(ContextCompat.getColor(this, R.color.cyanea_primary)));
}
if (attachments == null || attachments.size() == 0)
@ -123,27 +131,55 @@ public class MediaActivity extends BaseActivity implements OnDownloadInterface {
setTitle("");
ScreenSlidePagerAdapter mPagerAdapter = new ScreenSlidePagerAdapter(MediaActivity.this);
ScreenSlidePagerAdapter mPagerAdapter = new ScreenSlidePagerAdapter(getSupportFragmentManager());
binding.mediaViewpager.setAdapter(mPagerAdapter);
binding.mediaViewpager.setSaveEnabled(false);
binding.mediaViewpager.setCurrentItem(mediaPosition - 1);
binding.haulerView.setOnDragDismissedListener(dragDirection -> ActivityCompat.finishAfterTransition(MediaActivity.this));
registerReceiver(onDownloadComplete, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
String description = attachments.get(mediaPosition - 1).description;
handler = new Handler();
if (attachments.get(mediaPosition - 1).status != null) {
binding.originalMessage.setOnClickListener(v -> {
Intent intentContext = new Intent(MediaActivity.this, ContextActivity.class);
intentContext.putExtra(Helper.ARG_STATUS, attachments.get(mediaPosition - 1).status);
intentContext.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intentContext);
});
}
if (description != null && description.trim().length() > 0 && description.trim().compareTo("null") != 0) {
binding.mediaDescription.setText(description);
binding.translate.setOnClickListener(v -> {
String descriptionToTranslate = attachments.get(mediaPosition - 1).description;
TranslateHelper.translate(MediaActivity.this, descriptionToTranslate, translated -> {
if (translated != null) {
attachments.get(mediaPosition - 1).translation = translated;
binding.mediaDescriptionTranslated.setText(translated);
binding.mediaDescriptionTranslated.setVisibility(View.VISIBLE);
binding.mediaDescription.setVisibility(View.GONE);
} else {
Toasty.error(MediaActivity.this, getString(R.string.toast_error_translate), Toast.LENGTH_LONG).show();
}
});
});
if (attachments.get(mediaPosition - 1).translation != null) {
binding.mediaDescription.setVisibility(View.GONE);
binding.mediaDescriptionTranslated.setText(attachments.get(mediaPosition - 1).translation);
binding.mediaDescriptionTranslated.setVisibility(View.VISIBLE);
} else {
binding.mediaDescription.setVisibility(View.VISIBLE);
binding.mediaDescriptionTranslated.setVisibility(View.GONE);
}
}
binding.mediaViewpager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
super.onPageScrolled(position, positionOffset, positionOffsetPixels);
binding.mediaViewpager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
public void onPageScrollStateChanged(int state) {
}
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
super.onPageSelected(position);
mediaPosition = position;
String description = attachments.get(position).description;
if (handler != null) {
handler.removeCallbacksAndMessages(null);
@ -152,24 +188,51 @@ public class MediaActivity extends BaseActivity implements OnDownloadInterface {
if (description != null && description.trim().length() > 0 && description.trim().compareTo("null") != 0) {
binding.mediaDescription.setText(description);
}
}
@Override
public void onPageScrollStateChanged(int state) {
super.onPageScrollStateChanged(state);
binding.translate.setOnClickListener(v -> {
String descriptionToTranslate = attachments.get(position).description;
TranslateHelper.translate(MediaActivity.this, descriptionToTranslate, translated -> {
if (translated != null) {
attachments.get(position).translation = translated;
binding.mediaDescriptionTranslated.setText(translated);
binding.mediaDescriptionTranslated.setVisibility(View.VISIBLE);
binding.mediaDescription.setVisibility(View.GONE);
} else {
Toasty.error(MediaActivity.this, getString(R.string.toast_error_translate), Toast.LENGTH_LONG).show();
}
});
});
if (!fullscreen) {
if (attachments.get(position).translation != null) {
binding.mediaDescription.setVisibility(View.GONE);
binding.mediaDescriptionTranslated.setText(attachments.get(position).translation);
binding.mediaDescriptionTranslated.setVisibility(View.VISIBLE);
} else {
binding.mediaDescription.setVisibility(View.VISIBLE);
binding.mediaDescriptionTranslated.setVisibility(View.GONE);
}
} else {
binding.mediaDescription.setVisibility(View.GONE);
binding.mediaDescriptionTranslated.setVisibility(View.GONE);
}
}
});
setFullscreen(true);
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
int screenHeight = size.y;
minTouch = (int) (screenHeight * 0.1);
maxTouch = (int) (screenHeight * 0.9);
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
try {
return super.dispatchTouchEvent(event);
} catch (IllegalArgumentException ex) {
ex.printStackTrace();
}
return false;
}
public void toogleFullScreen() {
fullscreen = !fullscreen;
setFullscreen(fullscreen);
}
@Override
public boolean onCreateOptionsMenu(@NonNull Menu menu) {
@ -187,8 +250,17 @@ public class MediaActivity extends BaseActivity implements OnDownloadInterface {
int position = binding.mediaViewpager.getCurrentItem();
Attachment attachment = attachments.get(position);
if (Build.VERSION.SDK_INT >= 23) {
if (ContextCompat.checkSelfPermission(MediaActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(MediaActivity.this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(MediaActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, Helper.EXTERNAL_STORAGE_REQUEST_CODE_MEDIA_SAVE);
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.Q) {
if (ContextCompat.checkSelfPermission(MediaActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(MediaActivity.this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(MediaActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, Helper.EXTERNAL_STORAGE_REQUEST_CODE_MEDIA_SAVE);
} else {
if (attachment.type.compareTo("image") == 0) {
MediaHelper.manageMove(MediaActivity.this, attachment.url, false);
} else {
MediaHelper.manageDownloadsNoPopup(MediaActivity.this, attachment.url);
downloadID = -1;
}
}
} else {
if (attachment.type.compareTo("image") == 0) {
MediaHelper.manageMove(MediaActivity.this, attachment.url, false);
@ -250,52 +322,40 @@ public class MediaActivity extends BaseActivity implements OnDownloadInterface {
}
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
startX = event.getX();
startY = event.getY();
break;
case MotionEvent.ACTION_UP:
float endX = event.getX();
float endY = event.getY();
if (endY > minTouch && endY < maxTouch && isAClick(startX, endX, startY, endY)) {
setFullscreen(!fullscreen);
if (!fullscreen) {
String description = attachments.get(binding.mediaViewpager.getCurrentItem()).description;
if (handler != null) {
handler.removeCallbacksAndMessages(null);
}
handler = new Handler();
if (description != null && description.trim().length() > 0 && description.trim().compareTo("null") != 0) {
binding.mediaDescription.setText(description);
}
}
private void toggleScreenContain(boolean fullscreen) {
if (!fullscreen) {
String description = attachments.get(binding.mediaViewpager.getCurrentItem()).description;
if (description != null && description.trim().length() > 0 && description.trim().compareTo("null") != 0) {
binding.mediaDescription.setText(description);
if (attachments.get(binding.mediaViewpager.getCurrentItem()).translation != null) {
binding.mediaDescription.setVisibility(View.GONE);
binding.mediaDescriptionTranslated.setText(attachments.get(binding.mediaViewpager.getCurrentItem()).translation);
binding.mediaDescriptionTranslated.setVisibility(View.VISIBLE);
} else {
binding.mediaDescription.setVisibility(View.VISIBLE);
binding.mediaDescriptionTranslated.setVisibility(View.GONE);
}
break;
} else {
binding.translate.setVisibility(View.GONE);
if (status != null) {
binding.originalMessage.setVisibility(View.VISIBLE);
} else {
binding.originalMessage.setVisibility(View.INVISIBLE);
}
binding.mediaDescriptionTranslated.setVisibility(View.GONE);
binding.mediaDescription.setVisibility(View.GONE);
}
} else {
binding.originalMessage.setVisibility(View.INVISIBLE);
binding.translate.setVisibility(View.GONE);
binding.mediaDescriptionTranslated.setVisibility(View.GONE);
binding.mediaDescription.setVisibility(View.GONE);
}
try {
return super.dispatchTouchEvent(event);
} catch (IllegalArgumentException ex) {
ex.printStackTrace();
}
return false;
}
private boolean isAClick(float startX, float endX, float startY, float endY) {
float differenceX = Math.abs(startX - endX);
float differenceY = Math.abs(startY - endY);
int CLICK_ACTION_THRESHOLD = 200;
return !(differenceX > CLICK_ACTION_THRESHOLD/* =5 */ || differenceY > CLICK_ACTION_THRESHOLD);
}
@Override
public void onDestroy() {
binding = null;
unregisterReceiver(onDownloadComplete);
super.onDestroy();
}
@ -315,6 +375,15 @@ public class MediaActivity extends BaseActivity implements OnDownloadInterface {
super.onPostResume();
}
// Shows the system bars by removing all the flags
// except for the ones that make the content appear under the system bars.
private void showSystemUI() {
View decorView = getWindow().getDecorView();
decorView.setSystemUiVisibility(flags |
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
}
public boolean getFullScreen() {
return this.fullscreen;
@ -325,10 +394,17 @@ public class MediaActivity extends BaseActivity implements OnDownloadInterface {
if (!fullscreen) {
showSystemUI();
binding.mediaDescription.setVisibility(View.VISIBLE);
binding.translate.setVisibility(View.VISIBLE);
if (mediaFromProfile) {
binding.originalMessage.setVisibility(View.VISIBLE);
}
} else {
binding.mediaDescription.setVisibility(View.GONE);
hideSystemUI();
binding.mediaDescription.setVisibility(View.GONE);
binding.translate.setVisibility(View.GONE);
binding.originalMessage.setVisibility(View.INVISIBLE);
}
toggleScreenContain(fullscreen);
}
private void hideSystemUI() {
@ -348,28 +424,22 @@ public class MediaActivity extends BaseActivity implements OnDownloadInterface {
| View.SYSTEM_UI_FLAG_FULLSCREEN);
}
// Shows the system bars by removing all the flags
// except for the ones that make the content appear under the system bars.
private void showSystemUI() {
View decorView = getWindow().getDecorView();
decorView.setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
public FragmentMedia getCurrentFragment() {
return mCurrentFragment;
}
/**
* Media Pager
*/
private class ScreenSlidePagerAdapter extends FragmentStateAdapter {
ScreenSlidePagerAdapter(FragmentActivity fa) {
super(fa);
@SuppressWarnings("deprecation")
private class ScreenSlidePagerAdapter extends FragmentStatePagerAdapter {
ScreenSlidePagerAdapter(FragmentManager fm) {
super(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
}
@NonNull
@NotNull
@Override
public Fragment createFragment(int position) {
public Fragment getItem(int position) {
Bundle bundle = new Bundle();
FragmentMedia mediaSliderFragment = new FragmentMedia();
bundle.putInt(Helper.ARG_MEDIA_POSITION, position);
@ -379,7 +449,15 @@ public class MediaActivity extends BaseActivity implements OnDownloadInterface {
}
@Override
public int getItemCount() {
public void setPrimaryItem(@NotNull ViewGroup container, int position, @NotNull Object object) {
if (getCurrentFragment() != object) {
mCurrentFragment = ((FragmentMedia) object);
}
super.setPrimaryItem(container, position, object);
}
@Override
public int getCount() {
return attachments.size();
}
}

View file

@ -1,4 +1,4 @@
package app.fedilab.android.activities;
package app.fedilab.android.mastodon.activities;
/* Copyright 2022 Thomas Schneider
*
* This file is a part of Fedilab
@ -16,7 +16,6 @@ package app.fedilab.android.activities;
import android.content.Intent;
import android.graphics.drawable.ColorDrawable;
import android.net.Uri;
import android.os.Bundle;
import android.text.method.LinkMovementMethod;
@ -25,7 +24,6 @@ import android.view.View;
import android.widget.TextView;
import androidx.core.app.ActivityOptionsCompat;
import androidx.core.content.ContextCompat;
import androidx.lifecycle.ViewModelProvider;
import java.util.ArrayList;
@ -33,29 +31,27 @@ import java.util.List;
import app.fedilab.android.BaseMainActivity;
import app.fedilab.android.R;
import app.fedilab.android.client.entities.api.Account;
import app.fedilab.android.client.entities.api.Status;
import app.fedilab.android.databinding.ActivityPartnershipBinding;
import app.fedilab.android.helper.CrossActionHelper;
import app.fedilab.android.helper.Helper;
import app.fedilab.android.helper.MastodonHelper;
import app.fedilab.android.helper.ThemeHelper;
import app.fedilab.android.viewmodel.mastodon.AccountsVM;
import app.fedilab.android.mastodon.client.entities.api.Account;
import app.fedilab.android.mastodon.client.entities.api.Status;
import app.fedilab.android.mastodon.helper.CrossActionHelper;
import app.fedilab.android.mastodon.helper.Helper;
import app.fedilab.android.mastodon.helper.MastodonHelper;
import app.fedilab.android.mastodon.viewmodel.mastodon.AccountsVM;
public class PartnerShipActivity extends BaseActivity {
public class PartnerShipActivity extends BaseBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ThemeHelper.applyThemeBar(this);
ActivityPartnershipBinding binding = ActivityPartnershipBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setBackgroundDrawable(new ColorDrawable(ContextCompat.getColor(this, R.color.cyanea_primary)));
}
TextView about_partnership = findViewById(R.id.about_partnership);
@ -65,9 +61,8 @@ public class PartnerShipActivity extends BaseActivity {
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://masto.host"));
startActivity(browserIntent);
});
binding.accountFollow.setBackgroundTintList(ThemeHelper.getButtonActionColorStateList(PartnerShipActivity.this));
setTitle(R.string.action_partnership);
binding.accountFollow.setImageResource(R.drawable.ic_baseline_person_add_24);
binding.accountFollow.setIconResource(R.drawable.ic_baseline_person_add_24);
CrossActionHelper.fetchRemoteAccount(PartnerShipActivity.this, "@mastohost@mastodon.social", new CrossActionHelper.Callback() {
@Override
public void federatedStatus(Status status) {
@ -98,7 +93,7 @@ public class PartnerShipActivity extends BaseActivity {
if (relationShips != null && relationShips.size() > 0) {
if (!relationShips.get(0).following) {
binding.accountFollow.setVisibility(View.VISIBLE);
binding.accountFollow.setOnClickListener(v -> accountsVM.follow(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, account.id, true, false)
binding.accountFollow.setOnClickListener(v -> accountsVM.follow(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, account.id, true, false, null)
.observe(PartnerShipActivity.this, relationShip -> binding.accountFollow.setVisibility(View.GONE)));
}
}

View file

@ -1,4 +1,4 @@
package app.fedilab.android.activities;
package app.fedilab.android.mastodon.activities;
/* Copyright 2022 Thomas Schneider
*
* This file is a part of Fedilab
@ -15,39 +15,44 @@ package app.fedilab.android.activities;
* see <http://www.gnu.org/licenses>. */
import android.app.Dialog;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.view.MenuItem;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.view.Window;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.DialogFragment;
import androidx.preference.PreferenceManager;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import app.fedilab.android.R;
import app.fedilab.android.databinding.ActivityProxyBinding;
public class ProxyActivity extends BaseActivity {
public class ProxyActivity extends DialogFragment {
private ActivityProxyBinding binding;
private int position;
@NonNull
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(ProxyActivity.this);
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
binding = ActivityProxyBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
getWindow().setLayout(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
if (getSupportActionBar() != null)
getSupportActionBar().hide();
MaterialAlertDialogBuilder materialAlertDialogBuilder = new MaterialAlertDialogBuilder(requireContext());
materialAlertDialogBuilder.setView(binding.getRoot());
SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(requireActivity());
//Enable proxy
boolean enable_proxy = sharedpreferences.getBoolean(getString(R.string.SET_PROXY_ENABLED), false);
binding.enableProxy.setChecked(enable_proxy);
position = 0;
position = sharedpreferences.getInt(getString(R.string.SET_PROXY_TYPE), 0);
String hostVal = sharedpreferences.getString(getString(R.string.SET_PROXY_HOST), "127.0.0.1");
int portVal = sharedpreferences.getInt(getString(R.string.SET_PROXY_PORT), 8118);
final String login = sharedpreferences.getString(getString(R.string.SET_PROXY_LOGIN), null);
@ -62,22 +67,17 @@ public class ProxyActivity extends BaseActivity {
if (pwd != null && binding.proxyPassword.length() > 0) {
binding.proxyPassword.setText(pwd);
}
ArrayAdapter<CharSequence> adapterTrans = ArrayAdapter.createFromResource(ProxyActivity.this,
R.array.proxy_type_choice, android.R.layout.simple_spinner_dropdown_item);
binding.type.setAdapter(adapterTrans);
binding.type.setSelection(sharedpreferences.getInt(getString(R.string.SET_PROXY_TYPE), 0), false);
binding.type.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int p, long id) {
position = p;
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
if (position == 1) binding.protocol.check(R.id.protocol_socks);
binding.protocol.addOnButtonCheckedListener((group, checkedId, isChecked) -> {
if (isChecked) {
if (checkedId == R.id.protocol_http)
position = 0;
else
position = 1;
}
});
binding.setProxySave.setOnClickListener(view -> {
materialAlertDialogBuilder.setPositiveButton(R.string.save, (dialog1, which) -> {
String hostVal1 = binding.host.getText().toString().trim();
String portVal1 = binding.port.getText().toString().trim();
String proxy_loginVal = binding.proxyLogin.getText().toString().trim();
@ -91,18 +91,24 @@ public class ProxyActivity extends BaseActivity {
editor.putString(getString(R.string.SET_PROXY_LOGIN), proxy_loginVal);
editor.putString(getString(R.string.SET_PROXY_PASSWORD), proxy_passwordVal);
editor.apply();
finish();
});
materialAlertDialogBuilder.setNeutralButton(R.string.cancel, (dialog, which) -> dialog.dismiss());
Dialog dialog = materialAlertDialogBuilder.create();
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
return dialog;
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return super.onCreateView(inflater, container, savedInstanceState);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
finish();
return true;
}
return super.onOptionsItemSelected(item);
public void onDestroyView() {
super.onDestroyView();
binding = null;
}
}

View file

@ -1,4 +1,4 @@
package app.fedilab.android.activities;
package app.fedilab.android.mastodon.activities;
/* Copyright 2022 Thomas Schneider
*
* This file is a part of Fedilab
@ -15,19 +15,14 @@ package app.fedilab.android.activities;
* see <http://www.gnu.org/licenses>. */
import static app.fedilab.android.helper.PinnedTimelineHelper.sortMenuItem;
import static app.fedilab.android.helper.PinnedTimelineHelper.sortPositionAsc;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.os.Handler;
import android.text.Editable;
import android.text.InputFilter;
import android.text.TextWatcher;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import android.widget.ArrayAdapter;
@ -35,7 +30,6 @@ import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.core.content.ContextCompat;
import androidx.lifecycle.ViewModelProvider;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import androidx.preference.PreferenceManager;
@ -43,31 +37,31 @@ import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.google.android.material.snackbar.Snackbar;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import java.io.IOException;
import java.util.ArrayList;
import java.util.concurrent.TimeUnit;
import app.fedilab.android.R;
import app.fedilab.android.client.entities.app.BottomMenu;
import app.fedilab.android.client.entities.app.InstanceSocial;
import app.fedilab.android.client.entities.app.Pinned;
import app.fedilab.android.client.entities.app.PinnedTimeline;
import app.fedilab.android.client.entities.app.RemoteInstance;
import app.fedilab.android.client.entities.app.Timeline;
import app.fedilab.android.activities.MainActivity;
import app.fedilab.android.databinding.ActivityReorderTabsBinding;
import app.fedilab.android.databinding.PopupSearchInstanceBinding;
import app.fedilab.android.exception.DBException;
import app.fedilab.android.helper.Helper;
import app.fedilab.android.helper.ThemeHelper;
import app.fedilab.android.helper.itemtouchhelper.OnStartDragListener;
import app.fedilab.android.helper.itemtouchhelper.OnUndoListener;
import app.fedilab.android.helper.itemtouchhelper.SimpleItemTouchHelperCallback;
import app.fedilab.android.ui.drawer.ReorderBottomMenuAdapter;
import app.fedilab.android.ui.drawer.ReorderTabAdapter;
import app.fedilab.android.viewmodel.mastodon.InstanceSocialVM;
import app.fedilab.android.viewmodel.mastodon.ReorderVM;
import app.fedilab.android.mastodon.client.entities.app.BottomMenu;
import app.fedilab.android.mastodon.client.entities.app.InstanceSocial;
import app.fedilab.android.mastodon.client.entities.app.Pinned;
import app.fedilab.android.mastodon.client.entities.app.PinnedTimeline;
import app.fedilab.android.mastodon.client.entities.app.RemoteInstance;
import app.fedilab.android.mastodon.client.entities.app.Timeline;
import app.fedilab.android.mastodon.exception.DBException;
import app.fedilab.android.mastodon.helper.Helper;
import app.fedilab.android.mastodon.helper.PinnedTimelineHelper;
import app.fedilab.android.mastodon.helper.itemtouchhelper.OnStartDragListener;
import app.fedilab.android.mastodon.helper.itemtouchhelper.SimpleItemTouchHelperCallback;
import app.fedilab.android.mastodon.ui.drawer.ReorderBottomMenuAdapter;
import app.fedilab.android.mastodon.ui.drawer.ReorderTabAdapter;
import app.fedilab.android.mastodon.viewmodel.mastodon.InstanceSocialVM;
import app.fedilab.android.mastodon.viewmodel.mastodon.ReorderVM;
import es.dmoral.toasty.Toasty;
import okhttp3.Call;
import okhttp3.Callback;
@ -78,7 +72,7 @@ import okhttp3.RequestBody;
import okhttp3.Response;
public class ReorderTimelinesActivity extends BaseActivity implements OnStartDragListener, OnUndoListener {
public class ReorderTimelinesActivity extends BaseBarActivity implements OnStartDragListener {
private ItemTouchHelper touchHelper;
@ -92,6 +86,7 @@ public class ReorderTimelinesActivity extends BaseActivity implements OnStartDra
private boolean changes;
private boolean bottomChanges;
private boolean update;
public void setChanges(boolean changes) {
this.changes = changes;
}
@ -103,15 +98,21 @@ public class ReorderTimelinesActivity extends BaseActivity implements OnStartDra
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ThemeHelper.applyThemeBar(this);
binding = ActivityReorderTabsBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
searchInstanceRunning = false;
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setBackgroundDrawable(new ColorDrawable(ContextCompat.getColor(this, R.color.cyanea_primary)));
}
SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(ReorderTimelinesActivity.this);
boolean singleBar = sharedpreferences.getBoolean(getString(R.string.SET_USE_SINGLE_TOPBAR), false);
if (singleBar) {
binding.titleBottom.setVisibility(View.GONE);
binding.lvReorderBottom.setVisibility(View.GONE);
binding.titleTop.setVisibility(View.GONE);
}
changes = false;
bottomChanges = false;
ReorderVM reorderVM = new ViewModelProvider(ReorderTimelinesActivity.this).get(ReorderVM.class);
@ -123,8 +124,8 @@ public class ReorderTimelinesActivity extends BaseActivity implements OnStartDra
this.pinned.pinnedTimelines = new ArrayList<>();
update = false;
}
sortPositionAsc(this.pinned.pinnedTimelines);
reorderTabAdapter = new ReorderTabAdapter(this.pinned, ReorderTimelinesActivity.this, ReorderTimelinesActivity.this);
PinnedTimelineHelper.sortPositionAsc(this.pinned.pinnedTimelines);
reorderTabAdapter = new ReorderTabAdapter(this.pinned, ReorderTimelinesActivity.this);
ItemTouchHelper.Callback callback =
new SimpleItemTouchHelperCallback(reorderTabAdapter);
touchHelper = new ItemTouchHelper(callback);
@ -139,7 +140,7 @@ public class ReorderTimelinesActivity extends BaseActivity implements OnStartDra
this.bottomMenu = new BottomMenu(getApplicationContext()).defaultBottomMenu();
this.bottomMenu.bottom_menu = new ArrayList<>();
}
sortMenuItem(this.bottomMenu.bottom_menu);
PinnedTimelineHelper.sortMenuItem(this.bottomMenu.bottom_menu);
reorderBottomMenuAdapter = new ReorderBottomMenuAdapter(this.bottomMenu, ReorderTimelinesActivity.this);
ItemTouchHelper.Callback callback =
new SimpleItemTouchHelperCallback(reorderBottomMenuAdapter);
@ -170,7 +171,7 @@ public class ReorderTimelinesActivity extends BaseActivity implements OnStartDra
}
private void addInstance() {
AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(ReorderTimelinesActivity.this, Helper.dialogStyle());
AlertDialog.Builder dialogBuilder = new MaterialAlertDialogBuilder(ReorderTimelinesActivity.this);
PopupSearchInstanceBinding popupSearchInstanceBinding = PopupSearchInstanceBinding.inflate(getLayoutInflater());
dialogBuilder.setView(popupSearchInstanceBinding.getRoot());
TextWatcher textWatcher = autoComplete(popupSearchInstanceBinding);
@ -186,7 +187,6 @@ public class ReorderTimelinesActivity extends BaseActivity implements OnStartDra
popupSearchInstanceBinding.searchInstance.addTextChangedListener(textWatcher);
}
});
popupSearchInstanceBinding.searchInstance.setFilters(new InputFilter[]{new InputFilter.LengthFilter(60)});
dialogBuilder.setPositiveButton(R.string.validate, (dialog, id) -> {
String instanceName = popupSearchInstanceBinding.searchInstance.getText().toString().trim().replace("@", "");
new Thread(() -> {
@ -208,7 +208,7 @@ public class ReorderTimelinesActivity extends BaseActivity implements OnStartDra
} else if (popupSearchInstanceBinding.setAttachmentGroup.getCheckedRadioButtonId() == R.id.twitter_accounts) {
SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(ReorderTimelinesActivity.this);
String nitterHost = sharedpreferences.getString(getString(R.string.SET_NITTER_HOST), getString(R.string.DEFAULT_NITTER_HOST)).toLowerCase();
url = "https://" + nitterHost + "/" + instanceName.replaceAll("\\s", "") + "/rss";
url = "https://" + nitterHost + "/" + instanceName.replaceAll("[ ]+", ",").replaceAll("\\s", "") + "/rss";
}
OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(10, TimeUnit.SECONDS)
@ -262,7 +262,10 @@ public class ReorderTimelinesActivity extends BaseActivity implements OnStartDra
pinnedTimeline.type = Timeline.TimeLineEnum.REMOTE;
pinnedTimeline.position = pinned.pinnedTimelines.size();
pinned.pinnedTimelines.add(pinnedTimeline);
if (pinned.user_id == null || pinned.instance == null) {
pinned.user_id = MainActivity.currentUserID;
pinned.instance = MainActivity.currentInstance;
}
if (update) {
try {
new Pinned(ReorderTimelinesActivity.this).updatePinned(pinned);
@ -386,51 +389,6 @@ public class ReorderTimelinesActivity extends BaseActivity implements OnStartDra
}
@Override
public void onUndo(PinnedTimeline pinnedTimeline, int position) {
String text = "";
switch (pinnedTimeline.type) {
case TAG:
text = getString(R.string.reorder_tag_removed);
break;
case REMOTE:
text = getString(R.string.reorder_instance_removed);
break;
case LIST:
text = getString(R.string.reorder_list_deleted);
break;
}
Runnable runnable = () -> {
//change position of pinned that are after the removed item
for (int i = pinnedTimeline.position + 1; i < pinned.pinnedTimelines.size(); i++) {
pinned.pinnedTimelines.get(i).position -= 1;
}
pinned.pinnedTimelines.remove(pinnedTimeline);
reorderTabAdapter.notifyItemRemoved(position);
try {
new Pinned(ReorderTimelinesActivity.this).updatePinned(pinned);
changes = true;
} catch (DBException e) {
e.printStackTrace();
}
};
Handler handler = new Handler();
handler.postDelayed(runnable, 4000);
Snackbar.make(binding.getRoot(), text, 4000)
.setAction(getString(R.string.undo), view -> {
pinned.pinnedTimelines.add(position, pinnedTimeline);
reorderTabAdapter.notifyItemInserted(position);
handler.removeCallbacks(runnable);
})
.setTextColor(ThemeHelper.getAttColor(ReorderTimelinesActivity.this, R.attr.mTextColor))
.setActionTextColor(ContextCompat.getColor(ReorderTimelinesActivity.this, R.color.cyanea_accent_reference))
.setBackgroundTint(ContextCompat.getColor(ReorderTimelinesActivity.this, R.color.cyanea_primary_dark_reference))
.show();
}
@Override
public void onStop() {
super.onStop();

View file

@ -1,4 +1,4 @@
package app.fedilab.android.activities;
package app.fedilab.android.mastodon.activities;
/* Copyright 2022 Thomas Schneider
*
* This file is a part of Fedilab
@ -14,7 +14,6 @@ package app.fedilab.android.activities;
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see <http://www.gnu.org/licenses>. */
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.view.MenuItem;
import android.view.View;
@ -22,7 +21,6 @@ import android.widget.RadioButton;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.LinearLayoutCompat;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import androidx.lifecycle.ViewModelProvider;
@ -33,20 +31,19 @@ import java.util.List;
import app.fedilab.android.BaseMainActivity;
import app.fedilab.android.R;
import app.fedilab.android.client.entities.api.Account;
import app.fedilab.android.client.entities.api.RelationShip;
import app.fedilab.android.client.entities.api.Status;
import app.fedilab.android.client.entities.app.Timeline;
import app.fedilab.android.databinding.ActivityReportBinding;
import app.fedilab.android.helper.Helper;
import app.fedilab.android.helper.ThemeHelper;
import app.fedilab.android.ui.drawer.RulesAdapter;
import app.fedilab.android.ui.fragment.timeline.FragmentMastodonTimeline;
import app.fedilab.android.viewmodel.mastodon.AccountsVM;
import app.fedilab.android.mastodon.client.entities.api.Account;
import app.fedilab.android.mastodon.client.entities.api.RelationShip;
import app.fedilab.android.mastodon.client.entities.api.Status;
import app.fedilab.android.mastodon.client.entities.app.Timeline;
import app.fedilab.android.mastodon.helper.Helper;
import app.fedilab.android.mastodon.ui.drawer.RulesAdapter;
import app.fedilab.android.mastodon.ui.fragment.timeline.FragmentMastodonTimeline;
import app.fedilab.android.mastodon.viewmodel.mastodon.AccountsVM;
import es.dmoral.toasty.Toasty;
public class ReportActivity extends BaseActivity {
public class ReportActivity extends BaseBarActivity {
private ActivityReportBinding binding;
private Status status;
@ -64,14 +61,13 @@ public class ReportActivity extends BaseActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ThemeHelper.applyThemeBar(this);
binding = ActivityReportBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setBackgroundDrawable(new ColorDrawable(ContextCompat.getColor(this, R.color.cyanea_primary)));
}
Bundle b = getIntent().getExtras();

View file

@ -1,4 +1,4 @@
package app.fedilab.android.activities;
package app.fedilab.android.mastodon.activities;
/* Copyright 2022 Thomas Schneider
*
* This file is a part of Fedilab
@ -16,21 +16,21 @@ package app.fedilab.android.activities;
import static app.fedilab.android.BaseMainActivity.currentAccount;
import android.graphics.drawable.ColorDrawable;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.util.TypedValue;
import android.view.MenuItem;
import androidx.annotation.Nullable;
import androidx.appcompat.app.ActionBar;
import androidx.core.content.ContextCompat;
import androidx.preference.PreferenceManager;
import com.google.android.material.tabs.TabLayoutMediator;
import com.google.android.material.tabs.TabLayout;
import app.fedilab.android.R;
import app.fedilab.android.databinding.ActivityScheduledBinding;
import app.fedilab.android.helper.MastodonHelper;
import app.fedilab.android.helper.ThemeHelper;
import app.fedilab.android.ui.pageadapter.FedilabScheduledPageAdapter;
import app.fedilab.android.mastodon.helper.MastodonHelper;
import app.fedilab.android.mastodon.ui.pageadapter.FedilabScheduledPageAdapter;
public class ScheduledActivity extends BaseActivity {
@ -39,7 +39,7 @@ public class ScheduledActivity extends BaseActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ThemeHelper.applyTheme(this);
binding = ActivityScheduledBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
setSupportActionBar(binding.toolbar);
@ -47,40 +47,39 @@ public class ScheduledActivity extends BaseActivity {
//Remove title
if (actionBar != null) {
actionBar.setDisplayShowTitleEnabled(false);
actionBar.setBackgroundDrawable(new ColorDrawable(ContextCompat.getColor(this, R.color.cyanea_primary)));
}
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
}
SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(this);
float scale = sharedpreferences.getFloat(getString(R.string.SET_FONT_SCALE), 1.1f);
binding.title.setTextSize(TypedValue.COMPLEX_UNIT_SP, 18 * 1.1f / scale);
MastodonHelper.loadPPMastodon(binding.profilePicture, currentAccount.mastodon_account);
binding.title.setText(R.string.scheduled);
binding.scheduleTablayout.addTab(binding.scheduleTablayout.newTab());
binding.scheduleTablayout.addTab(binding.scheduleTablayout.newTab());
binding.scheduleTablayout.addTab(binding.scheduleTablayout.newTab());
binding.scheduleTablayout.addTab(binding.scheduleTablayout.newTab().setText(getString(R.string.toots_server)));
binding.scheduleTablayout.addTab(binding.scheduleTablayout.newTab().setText(getString(R.string.toots_client)));
binding.scheduleTablayout.addTab(binding.scheduleTablayout.newTab().setText(getString(R.string.reblog)));
binding.scheduleViewpager.setAdapter(new FedilabScheduledPageAdapter(ScheduledActivity.this));
binding.scheduleViewpager.setAdapter(new FedilabScheduledPageAdapter(getSupportFragmentManager()));
binding.scheduleViewpager.setOffscreenPageLimit(3);
binding.scheduleTablayout.setTabTextColors(ThemeHelper.getAttColor(ScheduledActivity.this, R.attr.mTextColor), ContextCompat.getColor(ScheduledActivity.this, R.color.cyanea_accent_dark_reference));
binding.scheduleTablayout.setTabIconTint(ThemeHelper.getColorStateList(ScheduledActivity.this));
binding.scheduleViewpager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(binding.scheduleTablayout));
new TabLayoutMediator(binding.scheduleTablayout, binding.scheduleViewpager,
(tab, position) -> {
binding.scheduleViewpager.setCurrentItem(tab.getPosition(), true);
switch (position) {
case 0:
tab.setText(getString(R.string.toots_server));
break;
case 1:
tab.setText(getString(R.string.toots_client));
break;
case 2:
tab.setText(getString(R.string.reblog));
break;
}
}
).attach();
binding.scheduleTablayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
@Override
public void onTabSelected(TabLayout.Tab tab) {
binding.scheduleViewpager.setCurrentItem(tab.getPosition());
}
@Override
public void onTabUnselected(TabLayout.Tab tab) {
}
@Override
public void onTabReselected(TabLayout.Tab tab) {
}
});
}
@Override

View file

@ -0,0 +1,338 @@
package app.fedilab.android.mastodon.activities;
/* Copyright 2022 Thomas Schneider
*
* This file is a part of Fedilab
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* Fedilab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see <http://www.gnu.org/licenses>. */
import android.app.SearchManager;
import android.content.Context;
import android.database.MatrixCursor;
import android.os.Bundle;
import android.provider.BaseColumns;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.ViewGroup;
import android.view.inputmethod.InputMethodManager;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.widget.SearchView;
import androidx.cursoradapter.widget.CursorAdapter;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentStatePagerAdapter;
import androidx.lifecycle.ViewModelProvider;
import androidx.viewpager.widget.PagerAdapter;
import androidx.viewpager.widget.ViewPager;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.FutureTarget;
import com.bumptech.glide.request.target.Target;
import com.google.android.material.tabs.TabLayout;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.util.concurrent.ExecutionException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import app.fedilab.android.BaseMainActivity;
import app.fedilab.android.R;
import app.fedilab.android.databinding.ActivitySearchResultTabsBinding;
import app.fedilab.android.mastodon.client.entities.api.Account;
import app.fedilab.android.mastodon.client.entities.api.Tag;
import app.fedilab.android.mastodon.helper.Helper;
import app.fedilab.android.mastodon.ui.drawer.AccountsSearchTopBarAdapter;
import app.fedilab.android.mastodon.ui.drawer.TagSearchTopBarAdapter;
import app.fedilab.android.mastodon.ui.fragment.timeline.FragmentMastodonAccount;
import app.fedilab.android.mastodon.ui.fragment.timeline.FragmentMastodonTag;
import app.fedilab.android.mastodon.ui.fragment.timeline.FragmentMastodonTimeline;
import app.fedilab.android.mastodon.viewmodel.mastodon.AccountsVM;
import app.fedilab.android.mastodon.viewmodel.mastodon.SearchVM;
import es.dmoral.toasty.Toasty;
public class SearchResultTabActivity extends BaseBarActivity {
private String search;
private ActivitySearchResultTabsBinding binding;
private TabLayout.Tab initial;
public Boolean tagEmpty, accountEmpty;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivitySearchResultTabsBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
Bundle b = getIntent().getExtras();
if (b != null) {
search = b.getString(Helper.ARG_SEARCH_KEYWORD, null);
}
if (search == null) {
Toasty.error(SearchResultTabActivity.this, getString(R.string.toast_error_search), Toast.LENGTH_LONG).show();
finish();
return;
}
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
setTitle(search);
initial = binding.searchTabLayout.newTab();
binding.searchTabLayout.addTab(initial.setText(getString(R.string.tags)));
binding.searchTabLayout.addTab(binding.searchTabLayout.newTab().setText(getString(R.string.accounts)));
binding.searchTabLayout.addTab(binding.searchTabLayout.newTab().setText(getString(R.string.toots)));
binding.searchTabLayout.addTab(binding.searchTabLayout.newTab().setText(getString(R.string.action_cache)));
binding.searchTabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
@Override
public void onTabSelected(TabLayout.Tab tab) {
binding.searchViewpager.setCurrentItem(tab.getPosition());
}
@Override
public void onTabUnselected(TabLayout.Tab tab) {
}
@Override
public void onTabReselected(TabLayout.Tab tab) {
Fragment fragment;
if (binding.searchViewpager.getAdapter() != null) {
fragment = (Fragment) binding.searchViewpager.getAdapter().instantiateItem(binding.searchViewpager, tab.getPosition());
if (fragment instanceof FragmentMastodonAccount) {
FragmentMastodonAccount fragmentMastodonAccount = ((FragmentMastodonAccount) fragment);
fragmentMastodonAccount.scrollToTop();
} else if (fragment instanceof FragmentMastodonTimeline) {
FragmentMastodonTimeline fragmentMastodonTimeline = ((FragmentMastodonTimeline) fragment);
fragmentMastodonTimeline.scrollToTop();
} else if (fragment instanceof FragmentMastodonTag) {
FragmentMastodonTag fragmentMastodonTag = ((FragmentMastodonTag) fragment);
fragmentMastodonTag.scrollToTop();
}
}
}
});
}
@Override
public boolean onCreateOptionsMenu(@NonNull Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu_search, menu);
SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
SearchView searchView = (SearchView) menu.findItem(R.id.action_search).getActionView();
if (search != null) {
searchView.setQuery(search, false);
}
searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
searchView.setIconifiedByDefault(false);
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(binding.searchTabLayout.getWindowToken(), 0);
query = query.replaceAll("^#+", "");
search = query.trim();
ScreenSlidePagerAdapter mPagerAdapter = new ScreenSlidePagerAdapter(getSupportFragmentManager());
binding.searchViewpager.setAdapter(mPagerAdapter);
setTitle(search);
searchView.setIconified(true);
searchView.setQuery(search, false);
searchView.clearFocus();
binding.searchTabLayout.selectTab(initial);
return false;
}
@Override
public boolean onQueryTextChange(String newText) {
String pattern = "^(@[\\w_-]+@[a-z0-9.\\-]+|@[\\w_-]+)";
final Pattern mentionPattern = Pattern.compile(pattern);
String patternTag = "^#([\\w-]{2,})$";
final Pattern tagPattern = Pattern.compile(patternTag);
Matcher matcherMention, matcherTag;
matcherMention = mentionPattern.matcher(newText);
matcherTag = tagPattern.matcher(newText);
if (newText.trim().isEmpty()) {
searchView.setSuggestionsAdapter(null);
}
if (matcherMention.matches()) {
String[] from = new String[]{SearchManager.SUGGEST_COLUMN_ICON_1, SearchManager.SUGGEST_COLUMN_TEXT_1};
int[] to = new int[]{R.id.account_pp, R.id.account_un};
String searchGroup = matcherMention.group();
AccountsVM accountsVM = new ViewModelProvider(SearchResultTabActivity.this).get(AccountsVM.class);
MatrixCursor cursor = new MatrixCursor(new String[]{BaseColumns._ID,
SearchManager.SUGGEST_COLUMN_ICON_1,
SearchManager.SUGGEST_COLUMN_TEXT_1});
accountsVM.searchAccounts(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, searchGroup, 5, false, false)
.observe(SearchResultTabActivity.this, accounts -> {
if (accounts == null) {
return;
}
AccountsSearchTopBarAdapter cursorAdapter = new AccountsSearchTopBarAdapter(SearchResultTabActivity.this, accounts, R.layout.drawer_account_search, null, from, to, CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
searchView.setSuggestionsAdapter(cursorAdapter);
new Thread(() -> {
int i = 0;
for (Account account : accounts) {
FutureTarget<File> futureTarget = Glide
.with(SearchResultTabActivity.this.getApplicationContext())
.load(account.avatar_static)
.downloadOnly(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL);
File cacheFile;
try {
cacheFile = futureTarget.get();
cursor.addRow(new String[]{String.valueOf(i), cacheFile.getAbsolutePath(), "@" + account.acct});
i++;
} catch (ExecutionException | InterruptedException e) {
e.printStackTrace();
}
}
runOnUiThread(() -> cursorAdapter.changeCursor(cursor));
}).start();
});
} else if (matcherTag.matches()) {
SearchVM searchVM = new ViewModelProvider(SearchResultTabActivity.this).get(SearchVM.class);
String[] from = new String[]{SearchManager.SUGGEST_COLUMN_TEXT_1};
int[] to = new int[]{R.id.tag_name};
String searchGroup = matcherTag.group();
MatrixCursor cursor = new MatrixCursor(new String[]{BaseColumns._ID,
SearchManager.SUGGEST_COLUMN_TEXT_1});
searchVM.search(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, searchGroup, null,
"hashtags", false, true, false, 0,
null, null, 10).observe(SearchResultTabActivity.this,
results -> {
if (results == null || results.hashtags == null) {
return;
}
TagSearchTopBarAdapter cursorAdapter = new TagSearchTopBarAdapter(SearchResultTabActivity.this, results.hashtags, R.layout.drawer_tag_search, null, from, to, CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
searchView.setSuggestionsAdapter(cursorAdapter);
int i = 0;
for (Tag tag : results.hashtags) {
cursor.addRow(new String[]{String.valueOf(i), "#" + tag.name});
i++;
}
runOnUiThread(() -> cursorAdapter.changeCursor(cursor));
});
}
return false;
}
});
searchView.setOnCloseListener(() -> {
setTitle(search);
return false;
});
searchView.setOnSearchClickListener(v -> {
searchView.setQuery(search, false);
searchView.setIconified(false);
});
PagerAdapter mPagerAdapter = new ScreenSlidePagerAdapter(getSupportFragmentManager());
binding.searchViewpager.setAdapter(mPagerAdapter);
binding.searchViewpager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
TabLayout.Tab tab = binding.searchTabLayout.getTabAt(position);
if (tab != null)
tab.select();
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
return true;
}
@Override
public boolean onOptionsItemSelected(@NotNull MenuItem item) {
if (item.getItemId() == android.R.id.home) {
finish();
return true;
} else if (item.getItemId() == R.id.action_search) {
return true;
}
return super.onOptionsItemSelected(item);
}
public void moveToAccount() {
tagEmpty = null;
accountEmpty = null;
binding.searchViewpager.setCurrentItem(1);
}
public void moveToMessage() {
tagEmpty = null;
accountEmpty = null;
binding.searchViewpager.setCurrentItem(2);
}
/**
* Pager adapter for the 4 fragments
*/
@SuppressWarnings("deprecation")
private class ScreenSlidePagerAdapter extends FragmentStatePagerAdapter {
ScreenSlidePagerAdapter(FragmentManager fm) {
super(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
}
@NotNull
@Override
public Fragment getItem(int position) {
Bundle bundle = new Bundle();
switch (position) {
case 0:
FragmentMastodonTag fragmentMastodonTag = new FragmentMastodonTag();
bundle.putString(Helper.ARG_SEARCH_KEYWORD, search);
fragmentMastodonTag.setArguments(bundle);
return fragmentMastodonTag;
case 1:
FragmentMastodonAccount fragmentMastodonAccount = new FragmentMastodonAccount();
bundle.putString(Helper.ARG_SEARCH_KEYWORD, search);
fragmentMastodonAccount.setArguments(bundle);
return fragmentMastodonAccount;
case 2:
FragmentMastodonTimeline fragmentMastodonTimeline = new FragmentMastodonTimeline();
bundle.putString(Helper.ARG_SEARCH_KEYWORD, search);
fragmentMastodonTimeline.setArguments(bundle);
return fragmentMastodonTimeline;
default:
fragmentMastodonTimeline = new FragmentMastodonTimeline();
bundle.putString(Helper.ARG_SEARCH_KEYWORD_CACHE, search);
fragmentMastodonTimeline.setArguments(bundle);
return fragmentMastodonTimeline;
}
}
@Override
public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
}
@Override
public int getCount() {
return 4;
}
}
}

View file

@ -0,0 +1,57 @@
package app.fedilab.android.mastodon.activities;
/* Copyright 2022 Thomas Schneider
*
* This file is a part of Fedilab
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* Fedilab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see <http://www.gnu.org/licenses>. */
import static androidx.navigation.ui.NavigationUI.setupActionBarWithNavController;
import android.os.Bundle;
import android.view.MenuItem;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.navigation.NavController;
import androidx.navigation.Navigation;
import androidx.navigation.ui.AppBarConfiguration;
import app.fedilab.android.R;
import app.fedilab.android.databinding.ActivitySettingsBinding;
public class SettingsActivity extends BaseBarActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
app.fedilab.android.databinding.ActivitySettingsBinding binding = ActivitySettingsBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
NavController navController = Navigation.findNavController(this, R.id.fragment_container);
AppBarConfiguration appBarConfiguration = new AppBarConfiguration.Builder().build();
setupActionBarWithNavController(this, navController, appBarConfiguration);
}
@Override
public boolean onSupportNavigateUp() {
NavController navController = Navigation.findNavController(this, R.id.fragment_container);
return navController.navigateUp() || super.onSupportNavigateUp();
}
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
NavController navController = Navigation.findNavController(this, R.id.fragment_container);
if (item.getItemId() == android.R.id.home && navController.getCurrentDestination() != null && navController.getCurrentDestination().getId() == R.id.FragmentSettingsCategories) {
finish();
}
return super.onOptionsItemSelected(item);
}
}

View file

@ -0,0 +1,82 @@
package app.fedilab.android.mastodon.activities;
/* Copyright 2022 Thomas Schneider
*
* This file is a part of Fedilab
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* Fedilab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see <http://www.gnu.org/licenses>. */
import android.content.res.Resources;
import android.os.Bundle;
import android.view.MenuItem;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.LinearLayoutManager;
import app.fedilab.android.R;
import app.fedilab.android.activities.MainActivity;
import app.fedilab.android.databinding.ActivityStatusHistoryBinding;
import app.fedilab.android.mastodon.helper.Helper;
import app.fedilab.android.mastodon.ui.drawer.StatusHistoryAdapter;
import app.fedilab.android.mastodon.viewmodel.mastodon.StatusesVM;
import es.dmoral.toasty.Toasty;
public class StatusHistoryActivity extends BaseBarActivity {
public static Resources.Theme theme;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityStatusHistoryBinding binding = ActivityStatusHistoryBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
Bundle b = getIntent().getExtras();
String statusId;
if (b != null) {
statusId = b.getString(Helper.ARG_STATUS_ID);
} else {
finish();
return;
}
StatusesVM statusesVM = new ViewModelProvider(StatusHistoryActivity.this).get(StatusesVM.class);
statusesVM.getStatusHistory(MainActivity.currentInstance, MainActivity.currentToken, statusId).observe(this, statuses -> {
if (statuses != null && statuses.size() > 0) {
StatusHistoryAdapter statusHistoryAdapter = new StatusHistoryAdapter(statuses);
binding.recyclerView.setAdapter(statusHistoryAdapter);
binding.recyclerView.setLayoutManager(new LinearLayoutManager(this));
} else {
Toasty.error(this, getString(R.string.toast_error), Toasty.LENGTH_LONG).show();
finish();
}
});
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
finish();
return true;
}
return true;
}
}

View file

@ -1,4 +1,4 @@
package app.fedilab.android.activities;
package app.fedilab.android.mastodon.activities;
/* Copyright 2021 Thomas Schneider
*
* This file is a part of Fedilab
@ -15,13 +15,11 @@ package app.fedilab.android.activities;
* see <http://www.gnu.org/licenses>. */
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.view.MenuItem;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
@ -31,14 +29,15 @@ import java.util.List;
import app.fedilab.android.BaseMainActivity;
import app.fedilab.android.R;
import app.fedilab.android.client.entities.api.Account;
import app.fedilab.android.client.entities.api.Accounts;
import app.fedilab.android.client.entities.api.Status;
import app.fedilab.android.databinding.ActivityStatusInfoBinding;
import app.fedilab.android.helper.Helper;
import app.fedilab.android.helper.ThemeHelper;
import app.fedilab.android.ui.drawer.AccountAdapter;
import app.fedilab.android.viewmodel.mastodon.StatusesVM;
import app.fedilab.android.mastodon.client.entities.api.Account;
import app.fedilab.android.mastodon.client.entities.api.Accounts;
import app.fedilab.android.mastodon.client.entities.api.RelationShip;
import app.fedilab.android.mastodon.client.entities.api.Status;
import app.fedilab.android.mastodon.helper.Helper;
import app.fedilab.android.mastodon.ui.drawer.AccountAdapter;
import app.fedilab.android.mastodon.viewmodel.mastodon.AccountsVM;
import app.fedilab.android.mastodon.viewmodel.mastodon.StatusesVM;
public class StatusInfoActivity extends BaseActivity {
@ -54,14 +53,13 @@ public class StatusInfoActivity extends BaseActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ThemeHelper.applyTheme(this);
binding = ActivityStatusInfoBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
setSupportActionBar(binding.toolbar);
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
getSupportActionBar().setBackgroundDrawable(new ColorDrawable(ContextCompat.getColor(this, R.color.cyanea_primary)));
}
accountList = new ArrayList<>();
Bundle b = getIntent().getExtras();
@ -115,6 +113,8 @@ public class StatusInfoActivity extends BaseActivity {
private void manageView(Accounts accounts) {
binding.loadingNextAccounts.setVisibility(View.GONE);
if (accountList != null && accounts != null && accounts.accounts != null) {
int position = this.accountList.size();
fetchRelationShip(accounts.accounts, position);
int startId = 0;
//There are some statuses present in the timeline
if (accountList.size() > 0) {
@ -127,6 +127,27 @@ public class StatusInfoActivity extends BaseActivity {
}
}
private void fetchRelationShip(List<Account> accounts, int position) {
List<String> ids = new ArrayList<>();
for (Account account : accounts) {
ids.add(account.id);
}
AccountsVM accountsVM = new ViewModelProvider(StatusInfoActivity.this).get(AccountsVM.class);
accountsVM.getRelationships(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, ids)
.observe(StatusInfoActivity.this, relationShips -> {
if (relationShips != null) {
for (RelationShip relationShip : relationShips) {
for (Account account : accounts) {
if (account.id.compareToIgnoreCase(relationShip.id) == 0) {
account.relationShip = relationShip;
}
}
}
accountAdapter.notifyItemRangeChanged(position, accounts.size());
}
});
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {

View file

@ -0,0 +1,56 @@
package app.fedilab.android.mastodon.activities;
/* Copyright 2022 Thomas Schneider
*
* This file is a part of Fedilab
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* Fedilab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see <http://www.gnu.org/licenses>. */
import android.os.Bundle;
import android.view.MenuItem;
import org.jetbrains.annotations.NotNull;
import app.fedilab.android.R;
import app.fedilab.android.databinding.ActivitySuggestionsBinding;
import app.fedilab.android.mastodon.helper.Helper;
import app.fedilab.android.mastodon.ui.fragment.timeline.FragmentMastodonSuggestion;
public class SuggestionActivity extends BaseBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivitySuggestionsBinding binding = ActivitySuggestionsBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
Helper.addFragment(getSupportFragmentManager(), R.id.nav_host_fragment_suggestions, new FragmentMastodonSuggestion(), null, null, null);
}
@Override
public boolean onOptionsItemSelected(@NotNull MenuItem item) {
if (item.getItemId() == android.R.id.home) {
finish();
return true;
}
return super.onOptionsItemSelected(item);
}
}

View file

@ -0,0 +1,150 @@
package app.fedilab.android.mastodon.activities;
/* Copyright 2022 Thomas Schneider
*
* This file is a part of Fedilab
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* Fedilab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see <http://www.gnu.org/licenses>. */
import android.os.Bundle;
import android.view.MenuItem;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentStatePagerAdapter;
import androidx.viewpager.widget.PagerAdapter;
import androidx.viewpager.widget.ViewPager;
import com.google.android.material.tabs.TabLayout;
import org.jetbrains.annotations.NotNull;
import app.fedilab.android.R;
import app.fedilab.android.databinding.ActivityTrendsBinding;
import app.fedilab.android.mastodon.client.entities.app.Timeline;
import app.fedilab.android.mastodon.helper.Helper;
import app.fedilab.android.mastodon.ui.fragment.timeline.FragmentMastodonTag;
import app.fedilab.android.mastodon.ui.fragment.timeline.FragmentMastodonTimeline;
public class TrendsActivity extends BaseBarActivity {
private ActivityTrendsBinding binding;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityTrendsBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
binding.searchTabLayout.addTab(binding.searchTabLayout.newTab().setText(getString(R.string.tags)));
binding.searchTabLayout.addTab(binding.searchTabLayout.newTab().setText(getString(R.string.toots)));
binding.searchTabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
@Override
public void onTabSelected(TabLayout.Tab tab) {
binding.trendsViewpager.setCurrentItem(tab.getPosition());
}
@Override
public void onTabUnselected(TabLayout.Tab tab) {
}
@Override
public void onTabReselected(TabLayout.Tab tab) {
Fragment fragment;
if (binding.trendsViewpager.getAdapter() != null) {
fragment = (Fragment) binding.trendsViewpager.getAdapter().instantiateItem(binding.trendsViewpager, tab.getPosition());
if (fragment instanceof FragmentMastodonTimeline) {
FragmentMastodonTimeline fragmentMastodonTimeline = ((FragmentMastodonTimeline) fragment);
fragmentMastodonTimeline.scrollToTop();
} else if (fragment instanceof FragmentMastodonTag) {
FragmentMastodonTag fragmentMastodonTag = ((FragmentMastodonTag) fragment);
fragmentMastodonTag.scrollToTop();
}
}
}
});
PagerAdapter mPagerAdapter = new ScreenSlidePagerAdapter(getSupportFragmentManager());
binding.trendsViewpager.setAdapter(mPagerAdapter);
binding.trendsViewpager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
TabLayout.Tab tab = binding.searchTabLayout.getTabAt(position);
if (tab != null)
tab.select();
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
}
@Override
public boolean onOptionsItemSelected(@NotNull MenuItem item) {
if (item.getItemId() == android.R.id.home) {
finish();
return true;
}
return super.onOptionsItemSelected(item);
}
/**
* Pager adapter for the 4 fragments
*/
@SuppressWarnings("deprecation")
private static class ScreenSlidePagerAdapter extends FragmentStatePagerAdapter {
ScreenSlidePagerAdapter(FragmentManager fm) {
super(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
}
@NotNull
@Override
public Fragment getItem(int position) {
Bundle bundle = new Bundle();
if (position == 0) {
FragmentMastodonTag fragmentMastodonTag = new FragmentMastodonTag();
bundle.putSerializable(Helper.ARG_TIMELINE_TYPE, Timeline.TimeLineEnum.TREND_TAG);
fragmentMastodonTag.setArguments(bundle);
return fragmentMastodonTag;
}
FragmentMastodonTimeline fragmentMastodonTimeline = new FragmentMastodonTimeline();
bundle.putSerializable(Helper.ARG_TIMELINE_TYPE, Timeline.TimeLineEnum.TREND_MESSAGE);
fragmentMastodonTimeline.setArguments(bundle);
return fragmentMastodonTimeline;
}
@Override
public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
}
@Override
public int getCount() {
return 2;
}
}
}

View file

@ -1,4 +1,4 @@
package app.fedilab.android.activities;
package app.fedilab.android.mastodon.activities.admin;
/* Copyright 2022 Thomas Schneider
*
* This file is a part of Fedilab
@ -19,16 +19,14 @@ import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.method.LinkMovementMethod;
import android.text.style.ForegroundColorSpan;
import android.text.style.UnderlineSpan;
import android.util.TypedValue;
import android.view.MenuItem;
import android.view.View;
import android.widget.TextView;
@ -46,8 +44,8 @@ import com.bumptech.glide.Glide;
import com.bumptech.glide.request.target.CustomTarget;
import com.bumptech.glide.request.transition.Transition;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
@ -55,78 +53,140 @@ import java.util.concurrent.TimeUnit;
import app.fedilab.android.BaseMainActivity;
import app.fedilab.android.R;
import app.fedilab.android.client.entities.api.Account;
import app.fedilab.android.client.entities.api.AdminAccount;
import app.fedilab.android.client.entities.api.Attachment;
import app.fedilab.android.activities.MainActivity;
import app.fedilab.android.databinding.ActivityAdminAccountBinding;
import app.fedilab.android.helper.Helper;
import app.fedilab.android.helper.MastodonHelper;
import app.fedilab.android.helper.SpannableHelper;
import app.fedilab.android.helper.ThemeHelper;
import app.fedilab.android.viewmodel.mastodon.AdminVM;
import app.fedilab.android.viewmodel.mastodon.NodeInfoVM;
import app.fedilab.android.mastodon.activities.BaseActivity;
import app.fedilab.android.mastodon.activities.InstanceProfileActivity;
import app.fedilab.android.mastodon.activities.MediaActivity;
import app.fedilab.android.mastodon.client.entities.api.Attachment;
import app.fedilab.android.mastodon.client.entities.api.admin.AdminAccount;
import app.fedilab.android.mastodon.client.entities.api.admin.AdminIp;
import app.fedilab.android.mastodon.helper.Helper;
import app.fedilab.android.mastodon.helper.MastodonHelper;
import app.fedilab.android.mastodon.helper.SpannableHelper;
import app.fedilab.android.mastodon.helper.ThemeHelper;
import app.fedilab.android.mastodon.viewmodel.mastodon.AdminVM;
import app.fedilab.android.mastodon.viewmodel.mastodon.NodeInfoVM;
import es.dmoral.toasty.Toasty;
public class AdminAccountActivity extends BaseActivity {
private AdminAccount adminAccount;
private Account account;
private ScheduledExecutorService scheduledExecutorService;
private ActivityAdminAccountBinding binding;
private String account_id;
private AdminVM adminVM;
private AdminAccount adminAccount;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ThemeHelper.applyTheme(this);
binding = ActivityAdminAccountBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
setSupportActionBar(binding.toolbar);
ActionBar actionBar = getSupportActionBar();
Bundle b = getIntent().getExtras();
adminAccount = null;
if (b != null) {
adminAccount = (AdminAccount) b.getSerializable(Helper.ARG_ACCOUNT);
if (adminAccount != null) {
account = adminAccount.account;
}
account_id = b.getString(Helper.ARG_ACCOUNT_ID, null);
}
postponeEnterTransition();
//Remove title
if (actionBar != null) {
actionBar.setDisplayShowTitleEnabled(false);
actionBar.setBackgroundDrawable(new ColorDrawable(ContextCompat.getColor(this, R.color.cyanea_primary)));
}
SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(this);
float scale = sharedpreferences.getFloat(getString(R.string.SET_FONT_SCALE), 1.1f);
binding.title.setTextSize(TypedValue.COMPLEX_UNIT_SP, 18 * 1.1f / scale);
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
}
binding.toolbar.setPopupTheme(Helper.popupStyle());
if (account != null) {
new Thread(() -> {
account = SpannableHelper.convertAccount(AdminAccountActivity.this, account);
Handler mainHandler = new Handler(Looper.getMainLooper());
Runnable myRunnable = () -> initializeView(account);
mainHandler.post(myRunnable);
}).start();
adminVM = new ViewModelProvider(AdminAccountActivity.this).get(AdminVM.class);
if (account_id != null) {
adminVM.getAccount(MainActivity.currentInstance, MainActivity.currentToken, account_id).observe(this, this::initializeView);
return;
}
if (adminAccount != null && adminAccount.account != null) {
initializeView(adminAccount);
} else {
Toasty.error(AdminAccountActivity.this, getString(R.string.toast_error_loading_account), Toast.LENGTH_LONG).show();
Toasty.error(AdminAccountActivity.this, getString(R.string.toast_error), Toast.LENGTH_LONG).show();
finish();
}
binding.disableAction.setOnClickListener(v -> {
if (adminAccount.disabled) {
adminVM.enable(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, adminAccount.id)
.observe(AdminAccountActivity.this, adminAccountResult -> {
adminAccount.disabled = false;
binding.disableAction.setText(R.string.disable);
binding.disabled.setText(R.string.no);
});
} else {
adminVM.performAction(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, adminAccount.id, "disable ", null, null, null, null);
adminAccount.disabled = true;
binding.disableAction.setText(R.string.undisable);
binding.disabled.setText(R.string.yes);
}
});
binding.approveAction.setOnClickListener(v -> {
if (adminAccount.approved) {
adminVM.reject(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, adminAccount.id)
.observe(AdminAccountActivity.this, adminAccountResult -> {
adminAccount = adminAccountResult;
initializeView(adminAccount);
});
} else {
adminVM.approve(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, adminAccount.id);
adminAccount.approved = true;
initializeView(adminAccount);
}
});
binding.silenceAction.setOnClickListener(v -> {
if (adminAccount.silenced) {
adminVM.unsilence(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, adminAccount.id)
.observe(AdminAccountActivity.this, adminAccountResult -> {
adminAccount = adminAccountResult;
initializeView(adminAccount);
});
} else {
adminVM.performAction(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, adminAccount.id, "silence", null, null, null, null);
adminAccount.silenced = true;
initializeView(adminAccount);
}
});
binding.suspendAction.setOnClickListener(v -> {
if (adminAccount.suspended) {
adminVM.unsuspend(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, adminAccount.id)
.observe(AdminAccountActivity.this, adminAccountResult -> {
adminAccount = adminAccountResult;
initializeView(adminAccount);
});
} else {
adminVM.performAction(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, adminAccount.id, "suspend", null, null, null, null);
adminAccount.suspended = true;
initializeView(adminAccount);
}
});
}
private void initializeView(Account account) {
private void initializeView(AdminAccount adminAccount) {
SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(AdminAccountActivity.this);
if (account == null) {
Toasty.error(AdminAccountActivity.this, getString(R.string.toast_error_loading_account), Toast.LENGTH_LONG).show();
if (adminAccount == null) {
Toasty.error(AdminAccountActivity.this, getString(R.string.toast_error), Toast.LENGTH_LONG).show();
finish();
return;
}
binding.title.setText(String.format(Locale.getDefault(), "@%s", account.acct));
binding.title.setText(String.format(Locale.getDefault(), "@%s", adminAccount.account.acct));
// MastodonHelper.loadPPMastodon(binding.profilePicture, account);
binding.appBar.addOnOffsetChangedListener((appBarLayout, verticalOffset) -> {
@ -140,14 +200,18 @@ public class AdminAccountActivity extends BaseActivity {
}
});
binding.username.setText(String.format(Locale.getDefault(), "@%s", adminAccount.username));
binding.domain.setText(adminAccount.domain);
binding.email.setText(adminAccount.email);
StringBuilder lastActive = new StringBuilder();
if (adminAccount.ips != null) {
for (AdminAccount.IP ip : adminAccount.ips) {
int count = 0;
for (AdminIp ip : adminAccount.ips) {
lastActive.append(Helper.shortDateToString(ip.used_at)).append(" - ").append(ip.ip).append("\r\n");
count++;
if (count > 4) {
break;
}
}
}
if (lastActive.toString().trim().length() == 0) {
@ -167,78 +231,9 @@ public class AdminAccountActivity extends BaseActivity {
binding.silenceAction.setText(adminAccount.silenced ? R.string.unsilence : R.string.silence);
binding.suspendAction.setText(adminAccount.suspended ? R.string.unsuspend : R.string.suspend);
AdminVM adminVM = new ViewModelProvider(AdminAccountActivity.this).get(AdminVM.class);
binding.disableAction.setOnClickListener(v -> {
if (adminAccount.disabled) {
adminVM.enable(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, account.id)
.observe(AdminAccountActivity.this, adminAccountResult -> {
adminAccount.disabled = false;
binding.disableAction.setText(R.string.disable);
binding.disabled.setText(R.string.no);
});
} else {
adminVM.performAction(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, account.id, "disable ", null, null, null, null);
adminAccount.disabled = true;
binding.disableAction.setText(R.string.undisable);
binding.disabled.setText(R.string.yes);
}
});
binding.approveAction.setOnClickListener(v -> {
if (adminAccount.approved) {
adminVM.reject(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, account.id)
.observe(AdminAccountActivity.this, adminAccountResult -> {
adminAccount.approved = false;
binding.approveAction.setText(R.string.approve);
binding.approved.setText(R.string.no);
});
} else {
adminVM.approve(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, account.id);
adminAccount.approved = true;
binding.approveAction.setText(R.string.reject);
binding.approved.setText(R.string.yes);
}
});
binding.silenceAction.setOnClickListener(v -> {
if (adminAccount.disabled) {
adminVM.unsilence(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, account.id)
.observe(AdminAccountActivity.this, adminAccountResult -> {
adminAccount.silenced = false;
binding.silenceAction.setText(R.string.silence);
binding.disabled.setText(R.string.no);
});
} else {
adminVM.performAction(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, account.id, "silence", null, null, null, null);
adminAccount.silenced = true;
binding.disableAction.setText(R.string.unsilence);
binding.disabled.setText(R.string.yes);
}
});
binding.suspendAction.setOnClickListener(v -> {
if (adminAccount.disabled) {
adminVM.unsuspend(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, account.id)
.observe(AdminAccountActivity.this, adminAccountResult -> {
adminAccount.suspended = false;
binding.suspendAction.setText(R.string.suspend);
binding.suspended.setText(R.string.no);
});
} else {
adminVM.performAction(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, account.id, "suspend", null, null, null, null);
adminAccount.suspended = true;
binding.disableAction.setText(R.string.unsuspend);
binding.suspended.setText(R.string.yes);
}
});
//Retrieve relationship with the connected account
List<String> accountListToCheck = new ArrayList<>();
accountListToCheck.add(account.id);
//Animate emojis
if (account.emojis != null && account.emojis.size() > 0) {
if (adminAccount.account.emojis != null && adminAccount.account.emojis.size() > 0) {
boolean disableAnimatedEmoji = sharedpreferences.getBoolean(getString(R.string.SET_DISABLE_ANIMATED_EMOJI), false);
if (!disableAnimatedEmoji) {
scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
@ -249,35 +244,35 @@ public class AdminAccountActivity extends BaseActivity {
//Tablayout for timelines/following/followers
boolean disableGif = sharedpreferences.getBoolean(getString(R.string.SET_DISABLE_GIF), false);
String targetedUrl = disableGif ? account.avatar_static : account.avatar;
String targetedUrl = disableGif ? adminAccount.account.avatar_static : adminAccount.account.avatar;
Glide.with(AdminAccountActivity.this)
.asDrawable()
.dontTransform()
.load(targetedUrl).into(
new CustomTarget<Drawable>() {
@Override
public void onResourceReady(@NonNull final Drawable resource, Transition<? super Drawable> transition) {
binding.profilePicture.setImageDrawable(resource);
startPostponedEnterTransition();
}
new CustomTarget<Drawable>() {
@Override
public void onResourceReady(@NonNull final Drawable resource, Transition<? super Drawable> transition) {
binding.profilePicture.setImageDrawable(resource);
startPostponedEnterTransition();
}
@Override
public void onLoadFailed(@Nullable Drawable errorDrawable) {
binding.profilePicture.setImageResource(R.drawable.ic_person);
startPostponedEnterTransition();
}
@Override
public void onLoadFailed(@Nullable Drawable errorDrawable) {
binding.profilePicture.setImageResource(R.drawable.ic_person);
startPostponedEnterTransition();
}
@Override
public void onLoadCleared(@Nullable Drawable placeholder) {
@Override
public void onLoadCleared(@Nullable Drawable placeholder) {
}
}
);
}
}
);
//Load header
MastodonHelper.loadProfileMediaMastodon(binding.bannerPp, account, MastodonHelper.MediaAccountType.HEADER);
MastodonHelper.loadProfileMediaMastodon(AdminAccountActivity.this, binding.bannerPp, adminAccount.account, MastodonHelper.MediaAccountType.HEADER);
//Redraws icon for locked accounts
final float scale = getResources().getDisplayMetrics().density;
if (account.locked) {
if (adminAccount.account.locked) {
Drawable img = ContextCompat.getDrawable(AdminAccountActivity.this, R.drawable.ic_baseline_lock_24);
assert img != null;
img.setBounds(0, 0, (int) (16 * scale + 0.5f), (int) (16 * scale + 0.5f));
@ -287,38 +282,41 @@ public class AdminAccountActivity extends BaseActivity {
}
//Peertube account watched by a Mastodon account
//Bot account
if (account.bot) {
if (adminAccount.account.bot) {
binding.accountBot.setVisibility(View.VISIBLE);
}
if (account.acct != null) {
setTitle(account.acct);
if (adminAccount.account.acct != null) {
setTitle(adminAccount.account.acct);
}
final SpannableString content = new SpannableString(getString(R.string.disclaimer_full));
content.setSpan(new UnderlineSpan(), 0, content.length(), 0);
content.setSpan(new ForegroundColorSpan(ContextCompat.getColor(AdminAccountActivity.this, R.color.cyanea_accent_reference)), 0, content.length(),
content.setSpan(new ForegroundColorSpan(ThemeHelper.getAttColor(this, R.attr.colorPrimary)), 0, content.length(),
Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
//This account was moved to another one
if (account.moved != null) {
if (adminAccount.account.moved != null) {
binding.accountMoved.setVisibility(View.VISIBLE);
Drawable imgTravel = ContextCompat.getDrawable(AdminAccountActivity.this, R.drawable.ic_baseline_card_travel_24);
assert imgTravel != null;
imgTravel.setBounds(0, 0, (int) (20 * scale + 0.5f), (int) (20 * scale + 0.5f));
binding.accountMoved.setCompoundDrawables(imgTravel, null, null, null);
//Retrieves content and make account names clickable
SpannableString spannableString = SpannableHelper.moveToText(AdminAccountActivity.this, account);
SpannableString spannableString = SpannableHelper.moveToText(AdminAccountActivity.this, adminAccount.account);
binding.accountMoved.setText(spannableString, TextView.BufferType.SPANNABLE);
binding.accountMoved.setMovementMethod(LinkMovementMethod.getInstance());
}
binding.accountDn.setText(account.span_display_name != null ? account.span_display_name : account.display_name, TextView.BufferType.SPANNABLE);
binding.accountUn.setText(String.format("@%s", account.acct));
binding.accountDn.setText(
adminAccount.account.getSpanDisplayName(AdminAccountActivity.this,
new WeakReference<>(binding.accountDn)),
TextView.BufferType.SPANNABLE);
binding.accountUn.setText(String.format("@%s", adminAccount.account.acct));
binding.accountUn.setOnLongClickListener(v -> {
ClipboardManager clipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
String account_id = account.acct;
String account_id = adminAccount.account.acct;
if (account_id.split("@").length == 1)
account_id += "@" + BaseMainActivity.currentInstance;
ClipData clip = ClipData.newPlainText("mastodon_account_id", "@" + account_id);
@ -328,15 +326,15 @@ public class AdminAccountActivity extends BaseActivity {
return false;
});
MastodonHelper.loadPPMastodon(binding.accountPp, account);
MastodonHelper.loadPPMastodon(binding.accountPp, adminAccount.account);
binding.accountPp.setOnClickListener(v -> {
Intent intent = new Intent(AdminAccountActivity.this, MediaActivity.class);
Bundle b = new Bundle();
Attachment attachment = new Attachment();
attachment.description = account.acct;
attachment.preview_url = account.avatar;
attachment.url = account.avatar;
attachment.remote_url = account.avatar;
attachment.description = adminAccount.account.acct;
attachment.preview_url = adminAccount.account.avatar;
attachment.url = adminAccount.account.avatar;
attachment.remote_url = adminAccount.account.avatar;
attachment.type = "image";
ArrayList<Attachment> attachments = new ArrayList<>();
attachments.add(attachment);
@ -350,10 +348,10 @@ public class AdminAccountActivity extends BaseActivity {
});
binding.accountDate.setText(Helper.shortDateToString(account.created_at));
binding.accountDate.setText(Helper.shortDateToString(adminAccount.created_at));
binding.accountDate.setVisibility(View.VISIBLE);
String[] accountInstanceArray = account.acct.split("@");
String[] accountInstanceArray = adminAccount.account.acct.split("@");
String accountInstance = BaseMainActivity.currentInstance;
if (accountInstanceArray.length > 1) {
accountInstance = accountInstanceArray[1];
@ -367,12 +365,11 @@ public class AdminAccountActivity extends BaseActivity {
binding.instanceInfo.setVisibility(View.VISIBLE);
binding.instanceInfo.setOnClickListener(v -> {
Intent intent = new Intent(AdminAccountActivity.this, InstanceProfileActivity.class);
InstanceProfileActivity instanceProfileActivity = new InstanceProfileActivity();
Bundle b = new Bundle();
b.putString(Helper.ARG_INSTANCE, finalAccountInstance);
intent.putExtras(b);
startActivity(intent);
instanceProfileActivity.setArguments(b);
instanceProfileActivity.show(getSupportFragmentManager(), null);
});
}
});

View file

@ -1,4 +1,4 @@
package app.fedilab.android.activities;
package app.fedilab.android.mastodon.activities.admin;
/* Copyright 2022 Thomas Schneider
*
* This file is a part of Fedilab
@ -14,9 +14,14 @@ package app.fedilab.android.activities;
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see <http://www.gnu.org/licenses>. */
import static app.fedilab.android.activities.AdminActionActivity.AdminEnum.REPORT;
import static app.fedilab.android.mastodon.activities.admin.AdminActionActivity.AdminEnum.ACCOUNT;
import static app.fedilab.android.mastodon.activities.admin.AdminActionActivity.AdminEnum.DOMAIN;
import static app.fedilab.android.mastodon.activities.admin.AdminActionActivity.AdminEnum.REPORT;
import android.graphics.drawable.ColorDrawable;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
@ -24,50 +29,74 @@ import android.view.MenuItem;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.gson.annotations.SerializedName;
import app.fedilab.android.R;
import app.fedilab.android.databinding.ActivityAdminActionsBinding;
import app.fedilab.android.databinding.PopupAdminFilterAccountsBinding;
import app.fedilab.android.databinding.PopupAdminFilterReportsBinding;
import app.fedilab.android.helper.Helper;
import app.fedilab.android.helper.ThemeHelper;
import app.fedilab.android.ui.fragment.admin.FragmentAdminAccount;
import app.fedilab.android.ui.fragment.admin.FragmentAdminReport;
import app.fedilab.android.mastodon.activities.BaseBarActivity;
import app.fedilab.android.mastodon.client.entities.api.admin.AdminDomainBlock;
import app.fedilab.android.mastodon.helper.Helper;
import app.fedilab.android.mastodon.helper.ThemeHelper;
import app.fedilab.android.mastodon.ui.fragment.admin.FragmentAdminAccount;
import app.fedilab.android.mastodon.ui.fragment.admin.FragmentAdminDomain;
import app.fedilab.android.mastodon.ui.fragment.admin.FragmentAdminReport;
public class AdminActionActivity extends BaseActivity {
public class AdminActionActivity extends BaseBarActivity {
public static Boolean local = true, remote = true, active = true, pending = true, disabled = true, silenced = true, suspended = true, staff = null, orderByMostRecent = true;
public static Boolean resolved = false, reportLocal = true, reportRemote = true;
public static Boolean resolved = null, reportLocal = true, reportRemote = true;
private ActivityAdminActionsBinding binding;
private boolean canGoBack;
private FragmentAdminReport fragmentAdminReport;
private FragmentAdminAccount fragmentAdminAccount;
private FragmentAdminDomain fragmentAdminDomain;
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Bundle b = intent.getExtras();
if (b != null) {
AdminDomainBlock adminDomainBlock = (AdminDomainBlock) b.getSerializable(Helper.ARG_ADMIN_DOMAINBLOCK);
AdminDomainBlock adminDomainBlockDelete = (AdminDomainBlock) b.getSerializable(Helper.ARG_ADMIN_DOMAINBLOCK_DELETE);
if (adminDomainBlock != null && adminDomainBlock.domain != null && fragmentAdminDomain != null) {
fragmentAdminDomain.update(adminDomainBlock);
}
if (adminDomainBlockDelete != null && fragmentAdminDomain != null) {
fragmentAdminDomain.delete(adminDomainBlockDelete);
}
}
}
};
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ThemeHelper.applyThemeBar(this);
binding = ActivityAdminActionsBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
LocalBroadcastManager.getInstance(this).registerReceiver(mReceiver, new IntentFilter(Helper.BROADCAST_DATA));
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setBackgroundDrawable(new ColorDrawable(ContextCompat.getColor(this, R.color.cyanea_primary)));
}
canGoBack = false;
binding.reports.setOnClickListener(v -> displayTimeline(REPORT));
binding.accounts.setOnClickListener(v -> displayTimeline(AdminEnum.ACCOUNT));
binding.accounts.setOnClickListener(v -> displayTimeline(ACCOUNT));
binding.domains.setOnClickListener(v -> displayTimeline(DOMAIN));
}
private void displayTimeline(AdminEnum type) {
canGoBack = true;
if (type == REPORT) {
ThemeHelper.slideViewsToLeft(binding.buttonContainer, binding.fragmentContainer, () -> {
fragmentAdminReport = new FragmentAdminReport();
Bundle bundle = new Bundle();
@ -80,9 +109,7 @@ public class AdminActionActivity extends BaseActivity {
fragmentTransaction.replace(R.id.fragment_container, fragmentAdminReport);
fragmentTransaction.commit();
});
} else {
} else if (type == ACCOUNT) {
ThemeHelper.slideViewsToLeft(binding.buttonContainer, binding.fragmentContainer, () -> {
fragmentAdminAccount = new FragmentAdminAccount();
Bundle bundle = new Bundle();
@ -95,7 +122,19 @@ public class AdminActionActivity extends BaseActivity {
fragmentTransaction.replace(R.id.fragment_container, fragmentAdminAccount);
fragmentTransaction.commit();
});
} else if (type == DOMAIN) {
ThemeHelper.slideViewsToLeft(binding.buttonContainer, binding.fragmentContainer, () -> {
fragmentAdminDomain = new FragmentAdminDomain();
Bundle bundle = new Bundle();
bundle.putSerializable(Helper.ARG_TIMELINE_TYPE, type);
bundle.putString(Helper.ARG_VIEW_MODEL_KEY, "FEDILAB_" + type.getValue());
fragmentAdminDomain.setArguments(bundle);
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction =
fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, fragmentAdminDomain);
fragmentTransaction.commit();
});
}
switch (type) {
case REPORT:
@ -104,13 +143,16 @@ public class AdminActionActivity extends BaseActivity {
case ACCOUNT:
setTitle(R.string.accounts);
break;
case DOMAIN:
setTitle(R.string.domains);
break;
}
invalidateOptionsMenu();
}
@Override
public boolean onCreateOptionsMenu(@NonNull Menu menu) {
if (canGoBack) {
if (canGoBack && fragmentAdminAccount != null) {
getMenuInflater().inflate(R.menu.menu_admin_account, menu);
}
return super.onCreateOptionsMenu(menu);
@ -123,7 +165,7 @@ public class AdminActionActivity extends BaseActivity {
return true;
} else if (item.getItemId() == R.id.action_filter) {
if (getTitle().toString().equalsIgnoreCase(getString(R.string.accounts))) {
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(AdminActionActivity.this, Helper.dialogStyle());
AlertDialog.Builder alertDialogBuilder = new MaterialAlertDialogBuilder(AdminActionActivity.this);
PopupAdminFilterAccountsBinding binding = PopupAdminFilterAccountsBinding.inflate(getLayoutInflater());
alertDialogBuilder.setView(binding.getRoot());
if (local != null && remote == null) {
@ -155,6 +197,8 @@ public class AdminActionActivity extends BaseActivity {
binding.moderationAll.setChecked(true);
}
binding.moderation.setOnCheckedChangeListener((group, checkedId) -> {
disabled = null;
silenced = null;
if (checkedId == R.id.moderation_all) {
active = true;
suspended = true;
@ -215,7 +259,7 @@ public class AdminActionActivity extends BaseActivity {
AlertDialog alert = alertDialogBuilder.create();
alert.show();
} else {
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(AdminActionActivity.this, Helper.dialogStyle());
AlertDialog.Builder alertDialogBuilder = new MaterialAlertDialogBuilder(AdminActionActivity.this);
PopupAdminFilterReportsBinding binding = PopupAdminFilterReportsBinding.inflate(getLayoutInflater());
alertDialogBuilder.setView(binding.getRoot());
if (resolved == null) {
@ -227,7 +271,7 @@ public class AdminActionActivity extends BaseActivity {
if (checkedId == R.id.status_resolved) {
resolved = true;
} else if (checkedId == R.id.status_unresolved) {
resolved = false;
resolved = null;
}
});
if (reportLocal != null && reportRemote == null) {
@ -270,6 +314,14 @@ public class AdminActionActivity extends BaseActivity {
return super.onOptionsItemSelected(item);
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mReceiver != null) {
LocalBroadcastManager.getInstance(this).unregisterReceiver(mReceiver);
}
}
@Override
public void onBackPressed() {
if (canGoBack) {
@ -277,9 +329,15 @@ public class AdminActionActivity extends BaseActivity {
ThemeHelper.slideViewsToRight(binding.fragmentContainer, binding.buttonContainer, () -> {
if (fragmentAdminReport != null) {
fragmentAdminReport.onDestroyView();
fragmentAdminReport = null;
}
if (fragmentAdminAccount != null) {
fragmentAdminAccount.onDestroyView();
fragmentAdminAccount = null;
}
if (fragmentAdminDomain != null) {
fragmentAdminDomain.onDestroyView();
fragmentAdminDomain = null;
}
setTitle(R.string.administration);
invalidateOptionsMenu();
@ -294,8 +352,9 @@ public class AdminActionActivity extends BaseActivity {
@SerializedName("REPORT")
REPORT("REPORT"),
@SerializedName("ACCOUNT")
ACCOUNT("ACCOUNT");
ACCOUNT("ACCOUNT"),
@SerializedName("DOMAIN")
DOMAIN("DOMAIN");
private final String value;
AdminEnum(String value) {

View file

@ -0,0 +1,155 @@
package app.fedilab.android.mastodon.activities.admin;
/* Copyright 2022 Thomas Schneider
*
* This file is a part of Fedilab
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* Fedilab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see <http://www.gnu.org/licenses>. */
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.lifecycle.ViewModelProvider;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import app.fedilab.android.R;
import app.fedilab.android.activities.MainActivity;
import app.fedilab.android.databinding.ActivityAdminDomainblockBinding;
import app.fedilab.android.mastodon.activities.BaseBarActivity;
import app.fedilab.android.mastodon.client.entities.api.admin.AdminDomainBlock;
import app.fedilab.android.mastodon.helper.Helper;
import app.fedilab.android.mastodon.viewmodel.mastodon.AdminVM;
import es.dmoral.toasty.Toasty;
public class AdminDomainBlockActivity extends BaseBarActivity {
private final String[] severityChoices = {"silence", "suspend", "noop"};
private AdminVM adminVM;
private AdminDomainBlock adminDomainBlock;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityAdminDomainblockBinding binding = ActivityAdminDomainblockBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
Bundle b = getIntent().getExtras();
if (b != null) {
adminDomainBlock = (AdminDomainBlock) b.getSerializable(Helper.ARG_ADMIN_DOMAINBLOCK);
}
ArrayAdapter<CharSequence> adapterResize = ArrayAdapter.createFromResource(this,
R.array.admin_block_severity, android.R.layout.simple_spinner_dropdown_item);
binding.severity.setAdapter(adapterResize);
if (adminDomainBlock != null) {
binding.domain.setText(adminDomainBlock.domain);
binding.domain.setEnabled(false);
for (int i = 0; i < severityChoices.length; i++) {
if (adminDomainBlock.severity.equalsIgnoreCase(severityChoices[i])) {
binding.severity.setSelection(i, false);
break;
}
}
binding.obfuscate.setChecked(adminDomainBlock.obfuscate);
binding.rejectMedia.setChecked(adminDomainBlock.reject_media);
binding.rejectReports.setChecked(adminDomainBlock.reject_reports);
binding.privateComment.setText(adminDomainBlock.private_comment);
binding.publicComment.setText(adminDomainBlock.public_comment);
} else {
adminDomainBlock = new AdminDomainBlock();
}
binding.severity.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> adapterView, View view, int position, long l) {
adminDomainBlock.severity = severityChoices[position];
}
@Override
public void onNothingSelected(AdapterView<?> adapterView) {
}
});
binding.obfuscate.setOnCheckedChangeListener((compoundButton, checked) -> adminDomainBlock.obfuscate = checked);
binding.rejectMedia.setOnCheckedChangeListener((compoundButton, checked) -> adminDomainBlock.reject_media = checked);
binding.rejectReports.setOnCheckedChangeListener((compoundButton, checked) -> adminDomainBlock.reject_reports = checked);
adminVM = new ViewModelProvider(AdminDomainBlockActivity.this).get(AdminVM.class);
binding.saveChanges.setOnClickListener(v -> {
adminDomainBlock.domain = binding.domain.getText().toString().trim();
adminDomainBlock.public_comment = binding.publicComment.getText().toString().trim();
adminDomainBlock.private_comment = binding.privateComment.getText().toString().trim();
adminVM.createOrUpdateDomainBlock(MainActivity.currentInstance, MainActivity.currentToken, adminDomainBlock)
.observe(AdminDomainBlockActivity.this, adminDomainBlockResult -> {
if (adminDomainBlockResult != null) {
Toasty.success(AdminDomainBlockActivity.this, getString(R.string.saved_changes), Toasty.LENGTH_SHORT).show();
} else {
Toasty.error(AdminDomainBlockActivity.this, getString(R.string.toast_error), Toasty.LENGTH_SHORT).show();
}
Intent intent = new Intent(Helper.BROADCAST_DATA).putExtra(Helper.ARG_ADMIN_DOMAINBLOCK, adminDomainBlockResult);
LocalBroadcastManager.getInstance(AdminDomainBlockActivity.this).sendBroadcast(intent);
finish();
}
);
});
}
@Override
public boolean onCreateOptionsMenu(@NonNull Menu menu) {
getMenuInflater().inflate(R.menu.menu_admin_domain, menu);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int itemId = item.getItemId();
if (itemId == android.R.id.home) {
finish();
return true;
} else if (itemId == R.id.action_delete) {
if (adminDomainBlock.id != null) {
AlertDialog.Builder builder = new MaterialAlertDialogBuilder(AdminDomainBlockActivity.this);
builder.setMessage(getString(R.string.unblock_domain_confirm, adminDomainBlock.domain));
builder
.setPositiveButton(R.string.unblock_domain, (dialog, which) -> {
adminVM.deleteDomain(MainActivity.currentInstance, MainActivity.currentToken, adminDomainBlock.id)
.observe(AdminDomainBlockActivity.this, adminDomainBlockResult -> {
Intent intent = new Intent(Helper.BROADCAST_DATA).putExtra(Helper.ARG_ADMIN_DOMAINBLOCK_DELETE, adminDomainBlock);
LocalBroadcastManager.getInstance(AdminDomainBlockActivity.this).sendBroadcast(intent);
finish();
}
);
dialog.dismiss();
})
.setNegativeButton(R.string.cancel, (dialog, which) -> dialog.dismiss())
.show();
} else {
finish();
}
}
return true;
}
}

View file

@ -1,4 +1,4 @@
package app.fedilab.android.activities;
package app.fedilab.android.mastodon.activities.admin;
/* Copyright 2022 Thomas Schneider
*
* This file is a part of Fedilab
@ -19,16 +19,14 @@ import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.method.LinkMovementMethod;
import android.text.style.ForegroundColorSpan;
import android.text.style.UnderlineSpan;
import android.util.TypedValue;
import android.view.MenuItem;
import android.view.View;
import android.widget.TextView;
@ -46,6 +44,7 @@ import com.bumptech.glide.Glide;
import com.bumptech.glide.request.target.CustomTarget;
import com.bumptech.glide.request.transition.Transition;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
@ -55,20 +54,24 @@ import java.util.concurrent.TimeUnit;
import app.fedilab.android.BaseMainActivity;
import app.fedilab.android.R;
import app.fedilab.android.client.entities.api.Account;
import app.fedilab.android.client.entities.api.AdminAccount;
import app.fedilab.android.client.entities.api.Attachment;
import app.fedilab.android.databinding.ActivityAdminAccountBinding;
import app.fedilab.android.helper.Helper;
import app.fedilab.android.helper.MastodonHelper;
import app.fedilab.android.helper.SpannableHelper;
import app.fedilab.android.helper.ThemeHelper;
import app.fedilab.android.viewmodel.mastodon.AdminVM;
import app.fedilab.android.viewmodel.mastodon.NodeInfoVM;
import app.fedilab.android.mastodon.activities.BaseBarActivity;
import app.fedilab.android.mastodon.activities.InstanceProfileActivity;
import app.fedilab.android.mastodon.activities.MediaActivity;
import app.fedilab.android.mastodon.client.entities.api.Account;
import app.fedilab.android.mastodon.client.entities.api.Attachment;
import app.fedilab.android.mastodon.client.entities.api.admin.AdminAccount;
import app.fedilab.android.mastodon.client.entities.api.admin.AdminIp;
import app.fedilab.android.mastodon.helper.Helper;
import app.fedilab.android.mastodon.helper.MastodonHelper;
import app.fedilab.android.mastodon.helper.SpannableHelper;
import app.fedilab.android.mastodon.helper.ThemeHelper;
import app.fedilab.android.mastodon.viewmodel.mastodon.AdminVM;
import app.fedilab.android.mastodon.viewmodel.mastodon.NodeInfoVM;
import es.dmoral.toasty.Toasty;
public class AdminReportActivity extends BaseActivity {
public class AdminReportActivity extends BaseBarActivity {
private AdminAccount adminAccount;
private Account account;
@ -79,7 +82,7 @@ public class AdminReportActivity extends BaseActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ThemeHelper.applyTheme(this);
binding = ActivityAdminAccountBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
setSupportActionBar(binding.toolbar);
@ -96,25 +99,18 @@ public class AdminReportActivity extends BaseActivity {
//Remove title
if (actionBar != null) {
actionBar.setDisplayShowTitleEnabled(false);
actionBar.setBackgroundDrawable(new ColorDrawable(ContextCompat.getColor(this, R.color.cyanea_primary)));
}
SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(this);
float scale = sharedpreferences.getFloat(getString(R.string.SET_FONT_SCALE), 1.1f);
binding.title.setTextSize(TypedValue.COMPLEX_UNIT_SP, 18 * 1.1f / scale);
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
}
binding.toolbar.setPopupTheme(Helper.popupStyle());
if (account != null) {
new Thread(() -> {
account = SpannableHelper.convertAccount(AdminReportActivity.this, account);
Handler mainHandler = new Handler(Looper.getMainLooper());
Runnable myRunnable = () -> initializeView(account);
mainHandler.post(myRunnable);
}).start();
initializeView(account);
} else {
Toasty.error(AdminReportActivity.this, getString(R.string.toast_error_loading_account), Toast.LENGTH_LONG).show();
Toasty.error(AdminReportActivity.this, getString(R.string.toast_error), Toast.LENGTH_LONG).show();
finish();
}
}
@ -122,7 +118,7 @@ public class AdminReportActivity extends BaseActivity {
private void initializeView(Account account) {
SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(AdminReportActivity.this);
if (account == null) {
Toasty.error(AdminReportActivity.this, getString(R.string.toast_error_loading_account), Toast.LENGTH_LONG).show();
Toasty.error(AdminReportActivity.this, getString(R.string.toast_error), Toast.LENGTH_LONG).show();
finish();
return;
}
@ -146,7 +142,7 @@ public class AdminReportActivity extends BaseActivity {
binding.email.setText(adminAccount.email);
StringBuilder lastActive = new StringBuilder();
if (adminAccount.ips != null) {
for (AdminAccount.IP ip : adminAccount.ips) {
for (AdminIp ip : adminAccount.ips) {
lastActive.append(Helper.shortDateToString(ip.used_at)).append(" - ").append(ip.ip).append("\r\n");
}
}
@ -272,27 +268,27 @@ public class AdminReportActivity extends BaseActivity {
.asDrawable()
.dontTransform()
.load(targetedUrl).into(
new CustomTarget<Drawable>() {
@Override
public void onResourceReady(@NonNull final Drawable resource, Transition<? super Drawable> transition) {
binding.profilePicture.setImageDrawable(resource);
startPostponedEnterTransition();
}
new CustomTarget<Drawable>() {
@Override
public void onResourceReady(@NonNull final Drawable resource, Transition<? super Drawable> transition) {
binding.profilePicture.setImageDrawable(resource);
startPostponedEnterTransition();
}
@Override
public void onLoadFailed(@Nullable Drawable errorDrawable) {
binding.profilePicture.setImageResource(R.drawable.ic_person);
startPostponedEnterTransition();
}
@Override
public void onLoadFailed(@Nullable Drawable errorDrawable) {
binding.profilePicture.setImageResource(R.drawable.ic_person);
startPostponedEnterTransition();
}
@Override
public void onLoadCleared(@Nullable Drawable placeholder) {
@Override
public void onLoadCleared(@Nullable Drawable placeholder) {
}
}
);
}
}
);
//Load header
MastodonHelper.loadProfileMediaMastodon(binding.bannerPp, account, MastodonHelper.MediaAccountType.HEADER);
MastodonHelper.loadProfileMediaMastodon(AdminReportActivity.this, binding.bannerPp, account, MastodonHelper.MediaAccountType.HEADER);
//Redraws icon for locked accounts
final float scale = getResources().getDisplayMetrics().density;
if (account.locked) {
@ -315,7 +311,7 @@ public class AdminReportActivity extends BaseActivity {
final SpannableString content = new SpannableString(getString(R.string.disclaimer_full));
content.setSpan(new UnderlineSpan(), 0, content.length(), 0);
content.setSpan(new ForegroundColorSpan(ContextCompat.getColor(AdminReportActivity.this, R.color.cyanea_accent_reference)), 0, content.length(),
content.setSpan(new ForegroundColorSpan(ThemeHelper.getAttColor(this, R.attr.colorPrimary)), 0, content.length(),
Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
//This account was moved to another one
@ -331,8 +327,10 @@ public class AdminReportActivity extends BaseActivity {
binding.accountMoved.setMovementMethod(LinkMovementMethod.getInstance());
}
binding.accountDn.setText(account.span_display_name != null ? account.span_display_name : account.display_name, TextView.BufferType.SPANNABLE);
binding.accountDn.setText(
account.getSpanDisplayName(AdminReportActivity.this,
new WeakReference<>(binding.accountDn)),
TextView.BufferType.SPANNABLE);
binding.accountUn.setText(String.format("@%s", account.acct));
binding.accountUn.setOnLongClickListener(v -> {
ClipboardManager clipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
@ -385,12 +383,11 @@ public class AdminReportActivity extends BaseActivity {
binding.instanceInfo.setVisibility(View.VISIBLE);
binding.instanceInfo.setOnClickListener(v -> {
Intent intent = new Intent(AdminReportActivity.this, InstanceProfileActivity.class);
InstanceProfileActivity instanceProfileActivity = new InstanceProfileActivity();
Bundle b = new Bundle();
b.putString(Helper.ARG_INSTANCE, finalAccountInstance);
intent.putExtras(b);
startActivity(intent);
instanceProfileActivity.setArguments(b);
instanceProfileActivity.show(getSupportFragmentManager(), null);
});
}
});

View file

@ -1,4 +1,4 @@
package app.fedilab.android.broadcastreceiver;
package app.fedilab.android.mastodon.broadcastreceiver;
/* Copyright 2021 Thomas Schneider
*
* This file is a part of Fedilab

View file

@ -1,4 +1,4 @@
package app.fedilab.android.broadcastreceiver;
package app.fedilab.android.mastodon.broadcastreceiver;
/* Copyright 2021 Thomas Schneider
*
* This file is a part of Fedilab
@ -14,15 +14,12 @@ package app.fedilab.android.broadcastreceiver;
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see <http://www.gnu.org/licenses>. */
import static app.fedilab.android.helper.Helper.RECEIVE_TOAST_CONTENT;
import static app.fedilab.android.helper.Helper.RECEIVE_TOAST_TYPE;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import app.fedilab.android.helper.Helper;
import app.fedilab.android.mastodon.helper.Helper;
import es.dmoral.toasty.Toasty;
public class ToastMessage extends BroadcastReceiver {
@ -30,8 +27,8 @@ public class ToastMessage extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
Bundle b = intent.getExtras();
if (b != null) {
String type = b.getString(RECEIVE_TOAST_TYPE, null);
String content = b.getString(RECEIVE_TOAST_CONTENT, null);
String type = b.getString(Helper.RECEIVE_TOAST_TYPE, null);
String content = b.getString(Helper.RECEIVE_TOAST_CONTENT, null);
if (type != null && content != null) {
switch (type) {
case Helper.RECEIVE_TOAST_TYPE_ERROR:

View file

@ -1,4 +1,4 @@
package app.fedilab.android.client;
package app.fedilab.android.mastodon.client;
/* Copyright 2021 Thomas Schneider
*
* This file is a part of Fedilab
@ -15,7 +15,7 @@ package app.fedilab.android.client;
* see <http://www.gnu.org/licenses>. */
import app.fedilab.android.client.entities.app.WellKnownNodeinfo;
import app.fedilab.android.mastodon.client.entities.app.WellKnownNodeinfo;
import retrofit2.Call;
import retrofit2.http.GET;
import retrofit2.http.Path;

View file

@ -1,4 +1,4 @@
package app.fedilab.android.client.endpoints;
package app.fedilab.android.mastodon.client.endpoints;
/* Copyright 2021 Thomas Schneider
*
* This file is a part of Fedilab
@ -17,7 +17,7 @@ package app.fedilab.android.client.endpoints;
import java.util.List;
import app.fedilab.android.client.entities.api.JoinMastodonInstance;
import app.fedilab.android.mastodon.client.entities.api.JoinMastodonInstance;
import retrofit2.Call;
import retrofit2.http.GET;
import retrofit2.http.Query;

View file

@ -1,4 +1,4 @@
package app.fedilab.android.client.endpoints;
package app.fedilab.android.mastodon.client.endpoints;
/* Copyright 2021 Thomas Schneider
*
* This file is a part of Fedilab
@ -17,17 +17,18 @@ package app.fedilab.android.client.endpoints;
import java.util.List;
import app.fedilab.android.client.entities.api.Account;
import app.fedilab.android.client.entities.api.FeaturedTag;
import app.fedilab.android.client.entities.api.Filter;
import app.fedilab.android.client.entities.api.IdentityProof;
import app.fedilab.android.client.entities.api.MastodonList;
import app.fedilab.android.client.entities.api.Preferences;
import app.fedilab.android.client.entities.api.RelationShip;
import app.fedilab.android.client.entities.api.Report;
import app.fedilab.android.client.entities.api.Status;
import app.fedilab.android.client.entities.api.Tag;
import app.fedilab.android.client.entities.api.Token;
import app.fedilab.android.mastodon.client.entities.api.Account;
import app.fedilab.android.mastodon.client.entities.api.FamiliarFollowers;
import app.fedilab.android.mastodon.client.entities.api.FeaturedTag;
import app.fedilab.android.mastodon.client.entities.api.IdentityProof;
import app.fedilab.android.mastodon.client.entities.api.MastodonList;
import app.fedilab.android.mastodon.client.entities.api.Preferences;
import app.fedilab.android.mastodon.client.entities.api.RelationShip;
import app.fedilab.android.mastodon.client.entities.api.Report;
import app.fedilab.android.mastodon.client.entities.api.Status;
import app.fedilab.android.mastodon.client.entities.api.Suggestion;
import app.fedilab.android.mastodon.client.entities.api.Tag;
import app.fedilab.android.mastodon.client.entities.api.Token;
import okhttp3.MultipartBody;
import retrofit2.Call;
import retrofit2.http.Body;
@ -40,7 +41,6 @@ import retrofit2.http.Headers;
import retrofit2.http.Multipart;
import retrofit2.http.PATCH;
import retrofit2.http.POST;
import retrofit2.http.PUT;
import retrofit2.http.Part;
import retrofit2.http.Path;
import retrofit2.http.Query;
@ -96,7 +96,7 @@ public interface MastodonAccountsService {
@Field("source[privacy]") String privacy,
@Field("source[sensitive]") Boolean sensitive,
@Field("source[language]") String language,
@Field("fields_attributes") List<app.fedilab.android.client.entities.api.Field.FieldParams> fields
@Field("fields_attributes") List<app.fedilab.android.mastodon.client.entities.api.Field.FieldParams> fields
);
//Get Account
@ -106,6 +106,12 @@ public interface MastodonAccountsService {
@Path("id") String id
);
//Get Account
@GET("accounts/lookup")
Call<Account> lookUpAccount(
@Query("acct") String acct
);
//Get Account statuses
@GET("accounts/{id}/statuses")
Call<List<Status>> getAccountStatuses(
@ -153,6 +159,7 @@ public interface MastodonAccountsService {
@Path("id") String id
);
//Get Identity proofs
@GET("accounts/{id}/identity_proofs")
Call<List<IdentityProof>> getIdentityProofs(
@ -167,7 +174,8 @@ public interface MastodonAccountsService {
@Header("Authorization") String app_token,
@Path("id") String id,
@Field("reblogs") boolean reblogs,
@Field("notify") boolean notify
@Field("notify") boolean notify,
@Field("languages[]") List<String> languages
);
//Follow account
@ -247,6 +255,13 @@ public interface MastodonAccountsService {
@Query("id[]") List<String> ids
);
//Get familiar followers
@GET("accounts/familiar_followers ")
Call<List<FamiliarFollowers>> getFamiliarFollowers(
@Header("Authorization") String token,
@Query("id[]") List<String> ids
);
//Get search
@GET("accounts/search")
Call<List<Account>> searchAccounts(
@ -316,51 +331,9 @@ public interface MastodonAccountsService {
@DELETE("domain_blocks")
Call<Void> removeDomainBlocks(
@Header("Authorization") String token,
@Field("domain") String domain
@Query("domain") String domain
);
//Get filters
@GET("filters")
Call<List<Filter>> getFilters(
@Header("Authorization") String token);
//Get a filter with its id
@GET("filters/{id}")
Call<Filter> getFilter(
@Header("Authorization") String token,
@Path("id") String id);
//Add a filter
@FormUrlEncoded
@POST("filters")
Call<Filter> addFilter(
@Header("Authorization") String token,
@Field("phrase") String phrase,
@Field("context[]") List<String> context,
@Field("irreversible") boolean irreversible,
@Field("whole_word") boolean whole_word,
@Field("expires_in") long expires_in
);
//Edit a filter
@FormUrlEncoded
@PUT("filters/{id}")
Call<Filter> editFilter(
@Header("Authorization") String token,
@Path("id") String id,
@Field("phrase") String phrase,
@Field("context[]") List<String> context,
@Field("irreversible") boolean irreversible,
@Field("whole_word") boolean whole_word,
@Field("expires_in") long expires_in
);
//Remove a filter
@DELETE("filters/{id}")
Call<Void> removeFilter(
@Header("Authorization") String token,
@Path("id") String id
);
//Post a report
@Headers({"Accept: application/json"})
@ -434,7 +407,7 @@ public interface MastodonAccountsService {
//Get user suggestions
@GET("suggestions")
Call<List<Account>> getSuggestions(
Call<List<Suggestion>> getSuggestions(
@Header("Authorization") String token,
@Query("limit") String limit
);
@ -445,4 +418,15 @@ public interface MastodonAccountsService {
@Header("Authorization") String token,
@Path("account_id") String account_id
);
//Get user suggestions
@GET("directory")
Call<List<Account>> getDirectory(
@Header("Authorization") String token,
@Query("offset") Integer offset,
@Query("limit") Integer limit,
@Query("order") String order,
@Query("local") Boolean local
);
}

View file

@ -1,4 +1,4 @@
package app.fedilab.android.client.endpoints;
package app.fedilab.android.mastodon.client.endpoints;
/* Copyright 2021 Thomas Schneider
*
* This file is a part of Fedilab
@ -17,14 +17,17 @@ package app.fedilab.android.client.endpoints;
import java.util.List;
import app.fedilab.android.client.entities.api.AdminAccount;
import app.fedilab.android.client.entities.api.AdminReport;
import app.fedilab.android.mastodon.client.entities.api.admin.AdminAccount;
import app.fedilab.android.mastodon.client.entities.api.admin.AdminDomainBlock;
import app.fedilab.android.mastodon.client.entities.api.admin.AdminReport;
import retrofit2.Call;
import retrofit2.http.DELETE;
import retrofit2.http.Field;
import retrofit2.http.FormUrlEncoded;
import retrofit2.http.GET;
import retrofit2.http.Header;
import retrofit2.http.POST;
import retrofit2.http.PUT;
import retrofit2.http.Path;
import retrofit2.http.Query;
@ -57,6 +60,7 @@ public interface MastodonAdminService {
@Path("id") String id
);
@FormUrlEncoded
@POST("admin/accounts/{account_id}/action")
Call<Void> performAction(
@Header("Authorization") String app_token,
@ -68,35 +72,35 @@ public interface MastodonAdminService {
@Field("send_email_notification") Boolean send_email_notification
);
@FormUrlEncoded
@POST("admin/accounts/{account_id}/approve")
Call<AdminAccount> approve(
@Header("Authorization") String app_token,
@Path("account_id") String account_id
);
@FormUrlEncoded
@POST("admin/accounts/{account_id}/reject")
Call<AdminAccount> reject(
@Header("Authorization") String app_token,
@Path("account_id") String account_id
);
@FormUrlEncoded
@POST("admin/accounts/{account_id}/enable")
Call<AdminAccount> enable(
@Header("Authorization") String app_token,
@Path("account_id") String account_id
);
@FormUrlEncoded
@POST("admin/accounts/{account_id}/unsilence")
Call<AdminAccount> unsilence(
@Header("Authorization") String app_token,
@Path("account_id") String account_id
);
@FormUrlEncoded
@POST("admin/accounts/{account_id}/unsuspend")
Call<AdminAccount> unsuspend(
@Header("Authorization") String app_token,
@ -114,38 +118,115 @@ public interface MastodonAdminService {
@Query("limit") int limit
);
@FormUrlEncoded
//***************** ADMIN REPORTS **************
@GET("admin/reports/{id}")
Call<AdminReport> getReport(
@Header("Authorization") String token,
@Path("id") String id
);
@FormUrlEncoded
@POST("admin/reports/{id}/assign_to_self")
Call<AdminReport> assignToSelf(
@Header("Authorization") String app_token,
@Path("id") String id
);
@FormUrlEncoded
@POST("admin/reports/{id}/unassign")
Call<AdminReport> unassign(
@Header("Authorization") String app_token,
@Path("id") String id
);
@FormUrlEncoded
@POST("admin/reports/{id}/resolve")
Call<AdminReport> resolved(
@Header("Authorization") String app_token,
@Path("id") String id
);
@FormUrlEncoded
@POST("admin/reports/{id}/reopen")
Call<AdminReport> reopen(
@Header("Authorization") String app_token,
@Path("id") String id
);
//*************** ADMIN DOMAINS ****************
@GET("admin/domain_blocks")
Call<List<AdminDomainBlock>> getDomainBlocks(
@Header("Authorization") String token,
@Query("max_id") String max_id,
@Query("limit") int limit
);
@GET("admin/domain_allows")
Call<List<AdminDomainBlock>> getDomainAllows(
@Header("Authorization") String token,
@Query("max_id") String max_id,
@Query("limit") int limit
);
@GET("admin/domain_blocks/{id}")
Call<AdminDomainBlock> getDomainBlock(
@Header("Authorization") String token,
@Path("id") String id
);
@GET("admin/domain_allows/{id}")
Call<AdminDomainBlock> getDomainAllow(
@Header("Authorization") String token,
@Path("id") String id
);
@FormUrlEncoded
@POST("admin/domain_blocks")
Call<AdminDomainBlock> blockDomain(
@Header("Authorization") String app_token,
@Field("domain") String domain,
@Field("severity") String severity,
@Field("reject_media") Boolean reject_media,
@Field("reject_reports") Boolean reject_reports,
@Field("private_comment") String private_comment,
@Field("public_comment") String public_comment,
@Field("obfuscate") Boolean obfuscate
);
@FormUrlEncoded
@POST("admin/domain_allows")
Call<AdminDomainBlock> allowDomain(
@Header("Authorization") String app_token,
@Path("domain") String domain
);
@FormUrlEncoded
@PUT("admin/domain_blocks/{id}")
Call<AdminDomainBlock> updateBlockDomain(
@Header("Authorization") String app_token,
@Path("id") String id,
@Field("severity") String severity,
@Field("reject_media") Boolean reject_media,
@Field("reject_reports") Boolean reject_reports,
@Field("private_comment") String private_comment,
@Field("public_comment") String public_comment,
@Field("obfuscate") Boolean obfuscate
);
@DELETE("admin/domain_blocks/{id}")
Call<Void> deleteBlockDomain(
@Header("Authorization") String app_token,
@Path("id") String id
);
@DELETE("admin/domain_allows/{id}")
Call<Void> deleteAllowDomain(
@Header("Authorization") String app_token,
@Path("id") String id
);
}

View file

@ -1,4 +1,4 @@
package app.fedilab.android.client.endpoints;
package app.fedilab.android.mastodon.client.endpoints;
/* Copyright 2021 Thomas Schneider
*
* This file is a part of Fedilab
@ -17,7 +17,7 @@ package app.fedilab.android.client.endpoints;
import java.util.List;
import app.fedilab.android.client.entities.api.Announcement;
import app.fedilab.android.mastodon.client.entities.api.Announcement;
import retrofit2.Call;
import retrofit2.http.DELETE;
import retrofit2.http.FormUrlEncoded;

View file

@ -1,4 +1,4 @@
package app.fedilab.android.client.endpoints;
package app.fedilab.android.mastodon.client.endpoints;
/* Copyright 2021 Thomas Schneider
*
* This file is a part of Fedilab
@ -15,8 +15,8 @@ package app.fedilab.android.client.endpoints;
* see <http://www.gnu.org/licenses>. */
import app.fedilab.android.client.entities.api.App;
import app.fedilab.android.client.entities.api.Token;
import app.fedilab.android.mastodon.client.entities.api.App;
import app.fedilab.android.mastodon.client.entities.api.Token;
import retrofit2.Call;
import retrofit2.http.Field;
import retrofit2.http.FormUrlEncoded;

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