Compare commits
342 Commits
v2.1.6+for
...
v2.1.6+for
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c8122aa65b | ||
|
|
ef1584de55 | ||
|
|
3075030b1c | ||
|
|
42c56401db | ||
|
|
a18a4383e5 | ||
|
|
375b5b3133 | ||
|
|
4cab916957 | ||
|
|
7902691093 | ||
|
|
d5d9e20a06 | ||
|
|
1eb55428db | ||
|
|
9b82d704f6 | ||
|
|
dbf3d2776e | ||
|
|
c077b9d47c | ||
|
|
34157805a1 | ||
|
|
576da2a3eb | ||
|
|
e99e5b2836 | ||
|
|
fe25974958 | ||
|
|
1a95b4e361 | ||
|
|
35e3d5afc4 | ||
|
|
cc1e13d1bd | ||
|
|
0b622f8f2a | ||
|
|
9cf7da6419 | ||
|
|
812ab7198c | ||
|
|
e8c9253a76 | ||
|
|
c8f633ae3b | ||
|
|
af339a833f | ||
|
|
708142e1b8 | ||
|
|
55f32671c5 | ||
|
|
289db09770 | ||
|
|
89d7dfd694 | ||
|
|
60a998be89 | ||
|
|
128e75bc24 | ||
|
|
69c60d484c | ||
|
|
c70750a508 | ||
|
|
5553ca25a1 | ||
|
|
ff87829e72 | ||
|
|
02983c76b9 | ||
|
|
3e28eb2ccf | ||
|
|
3cf23474e3 | ||
|
|
9f0ff2dcd4 | ||
|
|
8ed9fb6276 | ||
|
|
df7a0ee490 | ||
|
|
2e360dc275 | ||
|
|
8dc88d2fd7 | ||
|
|
901c70efc3 | ||
|
|
3d44e5d2cc | ||
|
|
33ea3da84d | ||
|
|
e97203a6e3 | ||
|
|
b3f2987b14 | ||
|
|
c7426453a5 | ||
|
|
b60c1a5db3 | ||
|
|
664d5cc4c3 | ||
|
|
47d1b182ac | ||
|
|
c33c3d9112 | ||
|
|
ff99e1023a | ||
|
|
8009dc0a75 | ||
|
|
20039ec97e | ||
|
|
172d25eeb0 | ||
|
|
fa04e00032 | ||
|
|
3ff442894d | ||
|
|
edb0823bf9 | ||
|
|
9de83355e1 | ||
|
|
183fb0e8c0 | ||
|
|
d624a04e18 | ||
|
|
303461d803 | ||
|
|
11c7816bb1 | ||
|
|
b5eae13a16 | ||
|
|
59026286a1 | ||
|
|
ef0fbb26a4 | ||
|
|
387b31193f | ||
|
|
95fa547f15 | ||
|
|
3198c9adb1 | ||
|
|
e1af6f4643 | ||
|
|
cc52e491b0 | ||
|
|
b0db0d9f2e | ||
|
|
d699788a12 | ||
|
|
bdbf441e1a | ||
|
|
0deba2885b | ||
|
|
48b39fd3bc | ||
|
|
875b235e6d | ||
|
|
1711682322 | ||
|
|
70f5ec7500 | ||
|
|
d34c73c210 | ||
|
|
50a0586e8a | ||
|
|
1d2ca1e500 | ||
|
|
34b7123a8d | ||
|
|
ec718ff58e | ||
|
|
20a442e27f | ||
|
|
47cb74abc9 | ||
|
|
a11e53c89a | ||
|
|
d721e8ca46 | ||
|
|
23e5dcd030 | ||
|
|
25dd2cfab8 | ||
|
|
8537c7a7ae | ||
|
|
ebd7f9c36c | ||
|
|
49cda3aeb2 | ||
|
|
67cbc8aff2 | ||
|
|
5db44cbf9d | ||
|
|
95858e3280 | ||
|
|
36846acbe5 | ||
|
|
b95d944003 | ||
|
|
f52886af74 | ||
|
|
6cbe406cef | ||
|
|
3097bc7168 | ||
|
|
5f7faa69e8 | ||
|
|
ed24e89a96 | ||
|
|
8ea05c6ebd | ||
|
|
a30fcbbe34 | ||
|
|
39f76f9988 | ||
|
|
5135653cd3 | ||
|
|
2e4f04cd88 | ||
|
|
a44e0e036a | ||
|
|
5d54c1bae4 | ||
|
|
09577074a9 | ||
|
|
53f0e2a933 | ||
|
|
b8dccbbef1 | ||
|
|
2ef17ba051 | ||
|
|
f63daf3a4e | ||
|
|
52b079be2a | ||
|
|
efeca17106 | ||
|
|
6827166c1d | ||
|
|
04483e61e8 | ||
|
|
22fe174922 | ||
|
|
f143da3913 | ||
|
|
7e9f41c74b | ||
|
|
a1474d0d29 | ||
|
|
0dce936ad3 | ||
|
|
6ebbbb4c6c | ||
|
|
dc6ddbd0ee | ||
|
|
86c81d6b53 | ||
|
|
451a92aa36 | ||
|
|
5c42e67e73 | ||
|
|
d20d36d964 | ||
|
|
1a8d46c71e | ||
|
|
91da10eca3 | ||
|
|
3bb0dcee53 | ||
|
|
d3fd4b200f | ||
|
|
fed96864e1 | ||
|
|
3b351bea27 | ||
|
|
254e01dca1 | ||
|
|
19158e1d48 | ||
|
|
bffb78fccf | ||
|
|
a3800592a2 | ||
|
|
22a498dfc9 | ||
|
|
9ea96e32bd | ||
|
|
68f51a123e | ||
|
|
43b1b63581 | ||
|
|
43b4a2c515 | ||
|
|
5b9cfdb689 | ||
|
|
b43cd7103a | ||
|
|
30e4f6e0f5 | ||
|
|
1d0ebf889b | ||
|
|
7c4f1da485 | ||
|
|
8163921014 | ||
|
|
993393dd96 | ||
|
|
82aed43934 | ||
|
|
fa65134c26 | ||
|
|
af4266c739 | ||
|
|
f72ea2e763 | ||
|
|
c5540270a3 | ||
|
|
5840c94395 | ||
|
|
92d7ae67ef | ||
|
|
fc09514a4d | ||
|
|
300fa97781 | ||
|
|
e8f0891f3a | ||
|
|
f25906a694 | ||
|
|
e52699bb1c | ||
|
|
712826451f | ||
|
|
3b3065d8bd | ||
|
|
e11fe7d8cf | ||
|
|
9a2f7475c9 | ||
|
|
6dffb10906 | ||
|
|
71039d6901 | ||
|
|
db18c7a0d0 | ||
|
|
7e80ed6af2 | ||
|
|
bdd2b90581 | ||
|
|
50d017d8ba | ||
|
|
98e003437c | ||
|
|
d5d06af614 | ||
|
|
1c930ca3bb | ||
|
|
0f0c1093d4 | ||
|
|
2ad5dc5a74 | ||
|
|
e02e0865bd | ||
|
|
59ee1af75d | ||
|
|
c04584dfa6 | ||
|
|
190a3b5b08 | ||
|
|
f5a67e65f0 | ||
|
|
498078b6e0 | ||
|
|
de8c289ca7 | ||
|
|
07b205a746 | ||
|
|
a7941310bc | ||
|
|
864b6dcdac | ||
|
|
d3744bb397 | ||
|
|
7d1853bc88 | ||
|
|
9f0db755d1 | ||
|
|
06819806be | ||
|
|
526f5e319b | ||
|
|
30a4d0efd9 | ||
|
|
d419dba44a | ||
|
|
87da6b9b81 | ||
|
|
67cc1553da | ||
|
|
9a985aad29 | ||
|
|
fd98159fce | ||
|
|
42fac30e63 | ||
|
|
18e7f14c16 | ||
|
|
7b263800a6 | ||
|
|
17387a32b2 | ||
|
|
3fe642c2f2 | ||
|
|
9225447409 | ||
|
|
e05dee64b7 | ||
|
|
7f30973b39 | ||
|
|
25da9bb2d0 | ||
|
|
e17b49e704 | ||
|
|
db661b56cb | ||
|
|
638e1bf8e9 | ||
|
|
83786171a7 | ||
|
|
f638a538c1 | ||
|
|
11e2316cbc | ||
|
|
1b372c7dca | ||
|
|
cf4e37fade | ||
|
|
f3fc60ac00 | ||
|
|
1026d99025 | ||
|
|
3fb947fbfe | ||
|
|
f097506d49 | ||
|
|
3df7d74fbf | ||
|
|
3fc17eb9c9 | ||
|
|
67ee74c1a0 | ||
|
|
bcebba8896 | ||
|
|
451b0c1ac5 | ||
|
|
5d08b4923b | ||
|
|
9ba948c721 | ||
|
|
23e7513133 | ||
|
|
aaed8e53c8 | ||
|
|
f2754cc5c9 | ||
|
|
6a65edd089 | ||
|
|
4d49b10585 | ||
|
|
86bfab81bd | ||
|
|
50e313cff0 | ||
|
|
5d07cde6dd | ||
|
|
f84a923102 | ||
|
|
c9eac34ae6 | ||
|
|
181a0577c8 | ||
|
|
0426084194 | ||
|
|
197d0caf44 | ||
|
|
a4a082f76a | ||
|
|
2528d48010 | ||
|
|
5456d71979 | ||
|
|
e36aae3cf3 | ||
|
|
d6040c0895 | ||
|
|
6d12e2dd72 | ||
|
|
ff47e6edba | ||
|
|
327ceb04d4 | ||
|
|
40a34b07de | ||
|
|
f117249bb5 | ||
|
|
1c90164ece | ||
|
|
0d5fb250bc | ||
|
|
e9bd5a373a | ||
|
|
c494d283ba | ||
|
|
cf1d537367 | ||
|
|
517d13b400 | ||
|
|
fae870c93a | ||
|
|
f8e00dcc80 | ||
|
|
5fdbb597bb | ||
|
|
d74b286a9d | ||
|
|
ecb3c521ff | ||
|
|
1d093ce928 | ||
|
|
46b711af2e | ||
|
|
772e6ddb5d | ||
|
|
f84e8443d2 | ||
|
|
250c18ebf1 | ||
|
|
e3d0f38b79 | ||
|
|
c512f97783 | ||
|
|
0594680775 | ||
|
|
f999881f59 | ||
|
|
4fe9192ac6 | ||
|
|
d936702fa9 | ||
|
|
74e284b0de | ||
|
|
4c42b72ed8 | ||
|
|
0e0046df65 | ||
|
|
c80d1d10c2 | ||
|
|
da97971011 | ||
|
|
700447dbe7 | ||
|
|
37e7b5ee93 | ||
|
|
1265afa93f | ||
|
|
1e09481b02 | ||
|
|
9996a5a05e | ||
|
|
f20aac7c81 | ||
|
|
98f7b0bacd | ||
|
|
3f6d3fb3a2 | ||
|
|
663b49c76b | ||
|
|
16e38f2541 | ||
|
|
842cc55e47 | ||
|
|
72db099e6f | ||
|
|
be130bc3a7 | ||
|
|
42253336e1 | ||
|
|
572631e1d7 | ||
|
|
723777a800 | ||
|
|
b825d534c1 | ||
|
|
b9749620a8 | ||
|
|
70ea9989aa | ||
|
|
b3ec9c981c | ||
|
|
bf72085abb | ||
|
|
64dd416b59 | ||
|
|
ab2a920455 | ||
|
|
7580446d60 | ||
|
|
ade18ac6fc | ||
|
|
005c851d72 | ||
|
|
0f1d46c765 | ||
|
|
21fbb07b1d | ||
|
|
58e0ce3970 | ||
|
|
139a7d7c98 | ||
|
|
a1c81e89e8 | ||
|
|
a5c197b496 | ||
|
|
df49ef9d58 | ||
|
|
f747d4c979 | ||
|
|
98677cd307 | ||
|
|
cd3de97d55 | ||
|
|
4853a25710 | ||
|
|
eba9a1da7b | ||
|
|
068c62b060 | ||
|
|
5d7f06eba0 | ||
|
|
fed9dec33a | ||
|
|
7973914a5f | ||
|
|
35efb3f047 | ||
|
|
0a4ed50904 | ||
|
|
002c66174a | ||
|
|
22aac3d943 | ||
|
|
872f47305a | ||
|
|
75d5332411 | ||
|
|
035da8a517 | ||
|
|
4c2c877d41 | ||
|
|
53afc120f3 | ||
|
|
a75ce70615 | ||
|
|
4a3b948760 | ||
|
|
f81283c892 | ||
|
|
7eae879037 | ||
|
|
1b0ce5d893 | ||
|
|
c17745368d | ||
|
|
e78b518654 | ||
|
|
55a8634be2 | ||
|
|
ac891eea53 | ||
|
|
74fa2a3081 |
@@ -15,8 +15,8 @@ android {
|
|||||||
applicationId "org.joinmastodon.android.sk"
|
applicationId "org.joinmastodon.android.sk"
|
||||||
minSdk 23
|
minSdk 23
|
||||||
targetSdk 33
|
targetSdk 33
|
||||||
versionCode 100
|
versionCode 108
|
||||||
versionName "2.1.6+fork.100"
|
versionName "2.1.6+fork.108"
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
resourceConfigurations += ['ar-rSA', 'ar-rDZ', 'be-rBY', 'bn-rBD', 'bs-rBA', 'ca-rES', 'cs-rCZ', 'da-rDK', 'de-rDE', 'el-rGR', 'es-rES', 'eu-rES', 'fa-rIR', 'fi-rFI', 'fil-rPH', 'fr-rFR', 'ga-rIE', 'gd-rGB', 'gl-rES', 'hi-rIN', 'hr-rHR', 'hu-rHU', 'hy-rAM', 'ig-rNG', 'in-rID', 'is-rIS', 'it-rIT', 'iw-rIL', 'ja-rJP', 'kab', 'ko-rKR', 'my-rMM', 'nl-rNL', 'no-rNO', 'oc-rFR', 'pl-rPL', 'pt-rBR', 'pt-rPT', 'ro-rRO', 'ru-rRU', 'si-rLK', 'sl-rSI', 'sv-rSE', 'th-rTH', 'tr-rTR', 'uk-rUA', 'ur-rIN', 'vi-rVN', 'zh-rCN', 'zh-rTW']
|
resourceConfigurations += ['ar-rSA', 'ar-rDZ', 'be-rBY', 'bn-rBD', 'bs-rBA', 'ca-rES', 'cs-rCZ', 'da-rDK', 'de-rDE', 'el-rGR', 'es-rES', 'eu-rES', 'fa-rIR', 'fi-rFI', 'fil-rPH', 'fr-rFR', 'ga-rIE', 'gd-rGB', 'gl-rES', 'hi-rIN', 'hr-rHR', 'hu-rHU', 'hy-rAM', 'ig-rNG', 'in-rID', 'is-rIS', 'it-rIT', 'iw-rIL', 'ja-rJP', 'kab', 'ko-rKR', 'my-rMM', 'nl-rNL', 'no-rNO', 'oc-rFR', 'pl-rPL', 'pt-rBR', 'pt-rPT', 'ro-rRO', 'ru-rRU', 'si-rLK', 'sl-rSI', 'sv-rSE', 'th-rTH', 'tr-rTR', 'uk-rUA', 'ur-rIN', 'vi-rVN', 'zh-rCN', 'zh-rTW']
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,56 +1,43 @@
|
|||||||
13bells.com
|
13bells.com
|
||||||
1611.social
|
1611.social
|
||||||
4aem.com
|
4aem.com
|
||||||
|
5dollah.click
|
||||||
adachi.party
|
adachi.party
|
||||||
anime.website
|
adtension.com
|
||||||
annihilation.social
|
annihilation.social
|
||||||
anon-kenkai.com
|
anon-kenkai.com
|
||||||
asbestos.cafe
|
asbestos.cafe
|
||||||
bae.st
|
bae.st
|
||||||
bajax.us
|
|
||||||
banepo.st
|
banepo.st
|
||||||
baraag.net
|
|
||||||
bassam.social
|
bassam.social
|
||||||
|
battlepenguin.video
|
||||||
beefyboys.win
|
beefyboys.win
|
||||||
beepboop.ga
|
|
||||||
berserker.town
|
|
||||||
bikeshed.party
|
|
||||||
boks.moe
|
|
||||||
boymoder.biz
|
boymoder.biz
|
||||||
brainsoap.net
|
brainsoap.net
|
||||||
breastmilk.club
|
breastmilk.club
|
||||||
brighteon.social
|
brighteon.social
|
||||||
bungle.online
|
cachapa.xyz
|
||||||
|
canary.fedinuke.example.com
|
||||||
|
catgirl.life
|
||||||
cawfee.club
|
cawfee.club
|
||||||
|
childlove.space
|
||||||
clew.lol
|
clew.lol
|
||||||
clubcyberia.co
|
clubcyberia.co
|
||||||
collapsitarian.io
|
|
||||||
comfyboy.club
|
|
||||||
contrapointsfan.club
|
contrapointsfan.club
|
||||||
|
crucible.world
|
||||||
cum.camp
|
cum.camp
|
||||||
cum.salon
|
cum.salon
|
||||||
darknight-coffee.org
|
|
||||||
decayable.ink
|
decayable.ink
|
||||||
dembased.xyz
|
dembased.xyz
|
||||||
desupost.soy
|
|
||||||
detroitriotcity.com
|
detroitriotcity.com
|
||||||
eatthebugs.social
|
djsumdog.com
|
||||||
eientei.org
|
eientei.org
|
||||||
elementality.org
|
|
||||||
eveningzoo.club
|
eveningzoo.club
|
||||||
firedragonstudios.com
|
|
||||||
firefaithfellowship.com
|
|
||||||
fluf.club
|
fluf.club
|
||||||
foxfam.club
|
|
||||||
freak.university
|
freak.university
|
||||||
freeatlantis.com
|
freeatlantis.com
|
||||||
freedomstrike.org
|
|
||||||
freesoftwareextremist.com
|
|
||||||
freespeech.group
|
|
||||||
freespeechextremist.com
|
freespeechextremist.com
|
||||||
freetalklive.com
|
|
||||||
froth.zone
|
froth.zone
|
||||||
fulltermprivacy.com
|
|
||||||
gameliberty.club
|
gameliberty.club
|
||||||
gearlandia.haus
|
gearlandia.haus
|
||||||
genderheretics.xyz
|
genderheretics.xyz
|
||||||
@@ -59,42 +46,34 @@ gleasonator.com
|
|||||||
glee.li
|
glee.li
|
||||||
glindr.org
|
glindr.org
|
||||||
goyim.app
|
goyim.app
|
||||||
goyslop.cafe
|
h5q.net
|
||||||
haeder.net
|
haeder.net
|
||||||
handholding.io
|
handholding.io
|
||||||
hitchhiker.social
|
hitchhiker.social
|
||||||
hunk.city
|
|
||||||
iddqd.social
|
iddqd.social
|
||||||
intkos.link
|
|
||||||
justicewarrior.social
|
|
||||||
kawa-kun.com
|
|
||||||
kitsunemimi.club
|
kitsunemimi.club
|
||||||
kiwifarms.cc
|
kiwifarms.cc
|
||||||
kompost.cz
|
|
||||||
kurosawa.moe
|
kurosawa.moe
|
||||||
|
kyaruc.moe
|
||||||
leafposter.club
|
leafposter.club
|
||||||
leftychan.net
|
|
||||||
lewdieheaven.com
|
lewdieheaven.com
|
||||||
liberdon.com
|
liberdon.com
|
||||||
ligma.pro
|
ligma.pro
|
||||||
lolicon.rocks
|
lolicon.rocks
|
||||||
|
lolison.network
|
||||||
lolison.top
|
lolison.top
|
||||||
lovingexpressions.net
|
lovingexpressions.net
|
||||||
mahodou.moe
|
|
||||||
makemysarcophagus.com
|
makemysarcophagus.com
|
||||||
maladaptive.art
|
|
||||||
marsey.moe
|
marsey.moe
|
||||||
masochi.st
|
|
||||||
mastinator.com
|
mastinator.com
|
||||||
merovingian.club
|
merovingian.club
|
||||||
midwaytrades.com
|
midwaytrades.com
|
||||||
mirr0r.city
|
mirr0r.city
|
||||||
moa.st
|
morale.ch
|
||||||
mouse.services
|
mouse.services
|
||||||
mugicha.club
|
mugicha.club
|
||||||
narrativerry.xyz
|
narrativerry.xyz
|
||||||
natehiggers.online
|
natehiggers.online
|
||||||
neckbeard.xyz
|
|
||||||
needs.vodka
|
needs.vodka
|
||||||
neenster.org
|
neenster.org
|
||||||
nicecrew.digital
|
nicecrew.digital
|
||||||
@@ -103,18 +82,18 @@ noagendasocial.com
|
|||||||
noagendasocial.nl
|
noagendasocial.nl
|
||||||
noagendatube.com
|
noagendatube.com
|
||||||
nobodyhasthe.biz
|
nobodyhasthe.biz
|
||||||
nukem.biz
|
norwoodzero.net
|
||||||
obo.sh
|
nyanide.com
|
||||||
onionfarms.org
|
onionfarms.org
|
||||||
pawlicker.com
|
pawlicker.com
|
||||||
pawoo.net
|
pawoo.net
|
||||||
pedo.school
|
pedo.school
|
||||||
|
peervideo.club
|
||||||
piazza.today
|
piazza.today
|
||||||
pibvt.net
|
pibvt.net
|
||||||
pieville.net
|
pieville.net
|
||||||
pisskey.io
|
pisskey.io
|
||||||
plagu.ee
|
plagu.ee
|
||||||
pmth.us
|
|
||||||
poa.st
|
poa.st
|
||||||
poast.org
|
poast.org
|
||||||
poast.tv
|
poast.tv
|
||||||
@@ -123,17 +102,18 @@ prospeech.space
|
|||||||
quodverum.com
|
quodverum.com
|
||||||
r18.social
|
r18.social
|
||||||
rakket.app
|
rakket.app
|
||||||
|
rapemeat.express
|
||||||
rapemeat.solutions
|
rapemeat.solutions
|
||||||
rdrama.cc
|
rayci.st
|
||||||
rebelbase.site
|
rebelbase.site
|
||||||
retardedniggers.forsale
|
|
||||||
rojogato.com
|
|
||||||
ryona.agency
|
ryona.agency
|
||||||
|
sad.cab
|
||||||
schwartzwelt.xyz
|
schwartzwelt.xyz
|
||||||
seal.cafe
|
seal.cafe
|
||||||
|
shaw.app
|
||||||
shigusegubu.club
|
shigusegubu.club
|
||||||
shitpost.cloud
|
shitpost.cloud
|
||||||
shota.house
|
shortstacksran.ch
|
||||||
silliness.observer
|
silliness.observer
|
||||||
skinheads.eu
|
skinheads.eu
|
||||||
skinheads.io
|
skinheads.io
|
||||||
@@ -148,23 +128,20 @@ sneed.social
|
|||||||
sonichu.com
|
sonichu.com
|
||||||
spinster.xyz
|
spinster.xyz
|
||||||
springbo.cc
|
springbo.cc
|
||||||
starnix.network
|
|
||||||
strelizia.net
|
strelizia.net
|
||||||
syspxl.xyz
|
|
||||||
tastingtraffic.net
|
tastingtraffic.net
|
||||||
teci.world
|
teci.world
|
||||||
theapex.social
|
theapex.social
|
||||||
|
thechimp.zone
|
||||||
|
thenobody.club
|
||||||
thepostearthdestination.com
|
thepostearthdestination.com
|
||||||
tkammer.de
|
tkammer.de
|
||||||
trumpislovetrumpis.life
|
trumpislovetrumpis.life
|
||||||
truthsocial.co.in
|
truthsocial.co.in
|
||||||
urchan.org
|
usualsuspects.lol
|
||||||
varishangout.net
|
varishangout.net
|
||||||
whinge.house
|
vtuberfan.social
|
||||||
whinge.town
|
|
||||||
wideboys.org
|
|
||||||
wolfgirl.bar
|
wolfgirl.bar
|
||||||
xn--p1abe3d.xn--80asehdb
|
xn--p1abe3d.xn--80asehdb
|
||||||
yggdrasil.social
|
yggdrasil.social
|
||||||
youjo.love
|
youjo.love
|
||||||
zztails.gay
|
|
||||||
|
|||||||
@@ -266,7 +266,7 @@ public class AudioPlayerService extends Service{
|
|||||||
private void updateNotification(boolean dismissable, boolean removeNotification){
|
private void updateNotification(boolean dismissable, boolean removeNotification){
|
||||||
Notification.Builder bldr=new Notification.Builder(this)
|
Notification.Builder bldr=new Notification.Builder(this)
|
||||||
.setSmallIcon(R.drawable.ic_ntf_logo)
|
.setSmallIcon(R.drawable.ic_ntf_logo)
|
||||||
.setContentTitle(status.account.displayName)
|
.setContentTitle(status.account.getDisplayName())
|
||||||
.setContentText(HtmlParser.strip(status.content))
|
.setContentText(HtmlParser.strip(status.content))
|
||||||
.setOngoing(!dismissable)
|
.setOngoing(!dismissable)
|
||||||
.setShowWhen(false)
|
.setShowWhen(false)
|
||||||
@@ -281,7 +281,7 @@ public class AudioPlayerService extends Service{
|
|||||||
|
|
||||||
if(playerReady){
|
if(playerReady){
|
||||||
boolean isPlaying=player.isPlaying();
|
boolean isPlaying=player.isPlaying();
|
||||||
bldr.addAction(new Notification.Action.Builder(Icon.createWithResource(this, isPlaying ? R.drawable.ic_pause_24 : R.drawable.ic_play_24),
|
bldr.addAction(new Notification.Action.Builder(Icon.createWithResource(this, isPlaying ? R.drawable.ic_fluent_pause_24_filled : R.drawable.ic_fluent_play_24_filled),
|
||||||
getString(isPlaying ? R.string.pause : R.string.play),
|
getString(isPlaying ? R.string.pause : R.string.play),
|
||||||
PendingIntent.getBroadcast(this, 2, new Intent(ACTION_PLAY_PAUSE), PendingIntent.FLAG_IMMUTABLE))
|
PendingIntent.getBroadcast(this, 2, new Intent(ACTION_PLAY_PAUSE), PendingIntent.FLAG_IMMUTABLE))
|
||||||
.build());
|
.build());
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
package org.joinmastodon.android;
|
package org.joinmastodon.android;
|
||||||
|
|
||||||
import static org.joinmastodon.android.api.MastodonAPIController.gson;
|
import static org.joinmastodon.android.api.MastodonAPIController.gson;
|
||||||
|
import static org.joinmastodon.android.api.session.AccountLocalPreferences.ColorPreference.MATERIAL3;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import androidx.annotation.StringRes;
|
|
||||||
|
|
||||||
import com.google.gson.JsonSyntaxException;
|
import com.google.gson.JsonSyntaxException;
|
||||||
import com.google.gson.reflect.TypeToken;
|
import com.google.gson.reflect.TypeToken;
|
||||||
|
|
||||||
import org.joinmastodon.android.api.session.AccountLocalPreferences;
|
import org.joinmastodon.android.api.session.AccountLocalPreferences;
|
||||||
|
import org.joinmastodon.android.api.session.AccountLocalPreferences.ColorPreference;
|
||||||
import org.joinmastodon.android.api.session.AccountSession;
|
import org.joinmastodon.android.api.session.AccountSession;
|
||||||
import org.joinmastodon.android.api.session.AccountSessionManager;
|
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||||
import org.joinmastodon.android.model.ContentType;
|
import org.joinmastodon.android.model.ContentType;
|
||||||
@@ -25,8 +25,6 @@ import java.util.HashSet;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import androidx.annotation.StringRes;
|
|
||||||
|
|
||||||
public class GlobalUserPreferences{
|
public class GlobalUserPreferences{
|
||||||
private static final String TAG="GlobalUserPreferences";
|
private static final String TAG="GlobalUserPreferences";
|
||||||
|
|
||||||
@@ -53,7 +51,6 @@ public class GlobalUserPreferences{
|
|||||||
public static boolean collapseLongPosts;
|
public static boolean collapseLongPosts;
|
||||||
public static boolean spectatorMode;
|
public static boolean spectatorMode;
|
||||||
public static boolean autoHideFab;
|
public static boolean autoHideFab;
|
||||||
public static boolean compactReblogReplyLine;
|
|
||||||
public static boolean allowRemoteLoading;
|
public static boolean allowRemoteLoading;
|
||||||
public static boolean forwardReportDefault;
|
public static boolean forwardReportDefault;
|
||||||
public static AutoRevealMode autoRevealEqualSpoilers;
|
public static AutoRevealMode autoRevealEqualSpoilers;
|
||||||
@@ -62,6 +59,9 @@ public class GlobalUserPreferences{
|
|||||||
public static boolean displayPronounsInTimelines, displayPronounsInThreads, displayPronounsInUserListings;
|
public static boolean displayPronounsInTimelines, displayPronounsInThreads, displayPronounsInUserListings;
|
||||||
public static boolean overlayMedia;
|
public static boolean overlayMedia;
|
||||||
public static boolean showSuicideHelp;
|
public static boolean showSuicideHelp;
|
||||||
|
public static boolean underlinedLinks;
|
||||||
|
public static ColorPreference color;
|
||||||
|
public static boolean likeIcon;
|
||||||
|
|
||||||
private static SharedPreferences getPrefs(){
|
private static SharedPreferences getPrefs(){
|
||||||
return MastodonApp.context.getSharedPreferences("global", Context.MODE_PRIVATE);
|
return MastodonApp.context.getSharedPreferences("global", Context.MODE_PRIVATE);
|
||||||
@@ -111,7 +111,6 @@ public class GlobalUserPreferences{
|
|||||||
collapseLongPosts=prefs.getBoolean("collapseLongPosts", true);
|
collapseLongPosts=prefs.getBoolean("collapseLongPosts", true);
|
||||||
spectatorMode=prefs.getBoolean("spectatorMode", false);
|
spectatorMode=prefs.getBoolean("spectatorMode", false);
|
||||||
autoHideFab=prefs.getBoolean("autoHideFab", true);
|
autoHideFab=prefs.getBoolean("autoHideFab", true);
|
||||||
compactReblogReplyLine=prefs.getBoolean("compactReblogReplyLine", true);
|
|
||||||
allowRemoteLoading=prefs.getBoolean("allowRemoteLoading", true);
|
allowRemoteLoading=prefs.getBoolean("allowRemoteLoading", true);
|
||||||
autoRevealEqualSpoilers=AutoRevealMode.valueOf(prefs.getString("autoRevealEqualSpoilers", AutoRevealMode.THREADS.name()));
|
autoRevealEqualSpoilers=AutoRevealMode.valueOf(prefs.getString("autoRevealEqualSpoilers", AutoRevealMode.THREADS.name()));
|
||||||
forwardReportDefault=prefs.getBoolean("forwardReportDefault", true);
|
forwardReportDefault=prefs.getBoolean("forwardReportDefault", true);
|
||||||
@@ -122,6 +121,9 @@ public class GlobalUserPreferences{
|
|||||||
displayPronounsInUserListings=prefs.getBoolean("displayPronounsInUserListings", true);
|
displayPronounsInUserListings=prefs.getBoolean("displayPronounsInUserListings", true);
|
||||||
overlayMedia=prefs.getBoolean("overlayMedia", false);
|
overlayMedia=prefs.getBoolean("overlayMedia", false);
|
||||||
showSuicideHelp=prefs.getBoolean("showSuicideHelp", true);
|
showSuicideHelp=prefs.getBoolean("showSuicideHelp", true);
|
||||||
|
underlinedLinks=prefs.getBoolean("underlinedLinks", true);
|
||||||
|
color=ColorPreference.valueOf(prefs.getString("color", MATERIAL3.name()));
|
||||||
|
likeIcon=prefs.getBoolean("likeIcon", false);
|
||||||
|
|
||||||
if (prefs.contains("prefixRepliesWithRe")) {
|
if (prefs.contains("prefixRepliesWithRe")) {
|
||||||
prefixReplies = prefs.getBoolean("prefixRepliesWithRe", false)
|
prefixReplies = prefs.getBoolean("prefixRepliesWithRe", false)
|
||||||
@@ -132,8 +134,11 @@ public class GlobalUserPreferences{
|
|||||||
.apply();
|
.apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(prefs.getInt("migrationLevel", 0) < 61) migrateToUpstreamVersion61();
|
int migrationLevel=prefs.getInt("migrationLevel", BuildConfig.VERSION_CODE);
|
||||||
if(prefs.getInt("migrationLevel", 0) < 101) migrateToVersion101();
|
if(migrationLevel < 61)
|
||||||
|
migrateToUpstreamVersion61();
|
||||||
|
if(migrationLevel < BuildConfig.VERSION_CODE)
|
||||||
|
prefs.edit().putInt("migrationLevel", BuildConfig.VERSION_CODE).apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void save(){
|
public static void save(){
|
||||||
@@ -163,7 +168,6 @@ public class GlobalUserPreferences{
|
|||||||
.putBoolean("collapseLongPosts", collapseLongPosts)
|
.putBoolean("collapseLongPosts", collapseLongPosts)
|
||||||
.putBoolean("spectatorMode", spectatorMode)
|
.putBoolean("spectatorMode", spectatorMode)
|
||||||
.putBoolean("autoHideFab", autoHideFab)
|
.putBoolean("autoHideFab", autoHideFab)
|
||||||
.putBoolean("compactReblogReplyLine", compactReblogReplyLine)
|
|
||||||
.putBoolean("allowRemoteLoading", allowRemoteLoading)
|
.putBoolean("allowRemoteLoading", allowRemoteLoading)
|
||||||
.putString("autoRevealEqualSpoilers", autoRevealEqualSpoilers.name())
|
.putString("autoRevealEqualSpoilers", autoRevealEqualSpoilers.name())
|
||||||
.putBoolean("forwardReportDefault", forwardReportDefault)
|
.putBoolean("forwardReportDefault", forwardReportDefault)
|
||||||
@@ -174,19 +178,33 @@ public class GlobalUserPreferences{
|
|||||||
.putBoolean("displayPronounsInUserListings", displayPronounsInUserListings)
|
.putBoolean("displayPronounsInUserListings", displayPronounsInUserListings)
|
||||||
.putBoolean("overlayMedia", overlayMedia)
|
.putBoolean("overlayMedia", overlayMedia)
|
||||||
.putBoolean("showSuicideHelp", showSuicideHelp)
|
.putBoolean("showSuicideHelp", showSuicideHelp)
|
||||||
|
.putBoolean("underlinedLinks", underlinedLinks)
|
||||||
|
.putString("color", color.name())
|
||||||
|
.putBoolean("likeIcon", likeIcon)
|
||||||
.apply();
|
.apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void migrateToVersion101(){
|
public enum ThemePreference{
|
||||||
Log.d(TAG, "Migrating preferences to version 101!! (copy current theme to local preferences)");
|
AUTO,
|
||||||
|
LIGHT,
|
||||||
AccountSessionManager asm=AccountSessionManager.getInstance();
|
DARK
|
||||||
for(AccountSession session : asm.getLoggedInAccounts()){
|
|
||||||
String accountID=session.getID();
|
|
||||||
AccountLocalPreferences localPrefs=session.getLocalPreferences();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum AutoRevealMode {
|
||||||
|
NEVER,
|
||||||
|
THREADS,
|
||||||
|
DISCUSSIONS
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum PrefixRepliesMode {
|
||||||
|
NEVER,
|
||||||
|
ALWAYS,
|
||||||
|
TO_OTHERS
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//region preferences migrations
|
||||||
|
|
||||||
private static void migrateToUpstreamVersion61(){
|
private static void migrateToUpstreamVersion61(){
|
||||||
Log.d(TAG, "Migrating preferences to upstream version 61!!");
|
Log.d(TAG, "Migrating preferences to upstream version 61!!");
|
||||||
|
|
||||||
@@ -233,25 +251,8 @@ public class GlobalUserPreferences{
|
|||||||
|
|
||||||
localPrefs.save();
|
localPrefs.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
prefs.edit().putInt("migrationLevel", 61).apply();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum ThemePreference{
|
//endregion
|
||||||
AUTO,
|
|
||||||
LIGHT,
|
|
||||||
DARK
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum AutoRevealMode {
|
|
||||||
NEVER,
|
|
||||||
THREADS,
|
|
||||||
DISCUSSIONS
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum PrefixRepliesMode {
|
|
||||||
NEVER,
|
|
||||||
ALWAYS,
|
|
||||||
TO_OTHERS
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ import android.content.Intent;
|
|||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.text.SpannableStringBuilder;
|
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
@@ -33,7 +32,6 @@ import org.joinmastodon.android.model.Preferences;
|
|||||||
import org.joinmastodon.android.model.PushNotification;
|
import org.joinmastodon.android.model.PushNotification;
|
||||||
import org.joinmastodon.android.model.Status;
|
import org.joinmastodon.android.model.Status;
|
||||||
import org.joinmastodon.android.model.StatusPrivacy;
|
import org.joinmastodon.android.model.StatusPrivacy;
|
||||||
import org.joinmastodon.android.ui.text.HtmlParser;
|
|
||||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||||
import org.parceler.Parcels;
|
import org.parceler.Parcels;
|
||||||
|
|
||||||
@@ -212,7 +210,7 @@ public class PushNotificationReceiver extends BroadcastReceiver{
|
|||||||
|
|
||||||
if (!GlobalUserPreferences.uniformNotificationIcon) {
|
if (!GlobalUserPreferences.uniformNotificationIcon) {
|
||||||
builder.setSmallIcon(switch (pn.notificationType) {
|
builder.setSmallIcon(switch (pn.notificationType) {
|
||||||
case FAVORITE -> R.drawable.ic_fluent_star_24_filled;
|
case FAVORITE -> GlobalUserPreferences.likeIcon ? R.drawable.ic_fluent_heart_24_filled : R.drawable.ic_fluent_star_24_filled;
|
||||||
case REBLOG -> R.drawable.ic_fluent_arrow_repeat_all_24_filled;
|
case REBLOG -> R.drawable.ic_fluent_arrow_repeat_all_24_filled;
|
||||||
case FOLLOW -> R.drawable.ic_fluent_person_add_24_filled;
|
case FOLLOW -> R.drawable.ic_fluent_person_add_24_filled;
|
||||||
case MENTION -> R.drawable.ic_fluent_mention_24_filled;
|
case MENTION -> R.drawable.ic_fluent_mention_24_filled;
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import java.io.IOException;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
import me.grishka.appkit.api.Callback;
|
import me.grishka.appkit.api.Callback;
|
||||||
@@ -69,7 +70,7 @@ public class CacheController{
|
|||||||
Status status=MastodonAPIController.gson.fromJson(cursor.getString(0), Status.class);
|
Status status=MastodonAPIController.gson.fromJson(cursor.getString(0), Status.class);
|
||||||
status.postprocess();
|
status.postprocess();
|
||||||
int flags=cursor.getInt(1);
|
int flags=cursor.getInt(1);
|
||||||
status.hasGapAfter=((flags & POST_FLAG_GAP_AFTER)!=0);
|
status.hasGapAfter=((flags & POST_FLAG_GAP_AFTER)!=0) ? status.id : null;
|
||||||
newMaxID=status.id;
|
newMaxID=status.id;
|
||||||
result.add(status);
|
result.add(status);
|
||||||
}while(cursor.moveToNext());
|
}while(cursor.moveToNext());
|
||||||
@@ -113,12 +114,14 @@ public class CacheController{
|
|||||||
values.put("id", s.id);
|
values.put("id", s.id);
|
||||||
values.put("json", MastodonAPIController.gson.toJson(s));
|
values.put("json", MastodonAPIController.gson.toJson(s));
|
||||||
int flags=0;
|
int flags=0;
|
||||||
if(s.hasGapAfter)
|
if(Objects.equals(s.hasGapAfter, s.id))
|
||||||
flags|=POST_FLAG_GAP_AFTER;
|
flags|=POST_FLAG_GAP_AFTER;
|
||||||
values.put("flags", flags);
|
values.put("flags", flags);
|
||||||
values.put("time", s.createdAt.getEpochSecond());
|
values.put("time", s.createdAt.getEpochSecond());
|
||||||
db.insertWithOnConflict("home_timeline", null, values, SQLiteDatabase.CONFLICT_REPLACE);
|
db.insertWithOnConflict("home_timeline", null, values, SQLiteDatabase.CONFLICT_REPLACE);
|
||||||
}
|
}
|
||||||
|
if(!clear)
|
||||||
|
db.delete("home_timeline", "`id` NOT IN (SELECT `id` FROM `home_timeline` ORDER BY `time` DESC LIMIT ?)", new String[]{"1000"});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -270,6 +273,28 @@ public class CacheController{
|
|||||||
|
|
||||||
public void deleteStatus(String id){
|
public void deleteStatus(String id){
|
||||||
runOnDbThread((db)->{
|
runOnDbThread((db)->{
|
||||||
|
String gapId=null;
|
||||||
|
int gapFlags=0;
|
||||||
|
// select to-be-removed and newer row
|
||||||
|
try(Cursor cursor=db.query("home_timeline", new String[]{"id", "flags"}, "`time`>=(SELECT `time` FROM `home_timeline` WHERE `id`=?)", new String[]{id}, null, null, "`time` ASC", "2")){
|
||||||
|
boolean hadGapAfter=false;
|
||||||
|
// always either one or two iterations (only one if there's no newer post)
|
||||||
|
while(cursor.moveToNext()){
|
||||||
|
String currentId=cursor.getString(0);
|
||||||
|
int currentFlags=cursor.getInt(1);
|
||||||
|
if(currentId.equals(id)){
|
||||||
|
hadGapAfter=((currentFlags & POST_FLAG_GAP_AFTER)!=0);
|
||||||
|
}else if(hadGapAfter){
|
||||||
|
gapFlags=currentFlags|POST_FLAG_GAP_AFTER;
|
||||||
|
gapId=currentId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(gapId!=null){
|
||||||
|
ContentValues values=new ContentValues();
|
||||||
|
values.put("flags", gapFlags);
|
||||||
|
db.update("home_timeline", values, "`id`=?", new String[]{gapId});
|
||||||
|
}
|
||||||
db.delete("home_timeline", "`id`=?", new String[]{id});
|
db.delete("home_timeline", "`id`=?", new String[]{id});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,9 +53,7 @@ public class MastodonAPIController{
|
|||||||
.registerTypeAdapter(Status.class, new Status.StatusDeserializer())
|
.registerTypeAdapter(Status.class, new Status.StatusDeserializer())
|
||||||
.create();
|
.create();
|
||||||
private static WorkerThread thread=new WorkerThread("MastodonAPIController");
|
private static WorkerThread thread=new WorkerThread("MastodonAPIController");
|
||||||
private static OkHttpClient httpClient=new OkHttpClient.Builder()
|
private static OkHttpClient httpClient=new OkHttpClient.Builder().build();
|
||||||
.readTimeout(5, TimeUnit.MINUTES)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
private AccountSession session;
|
private AccountSession session;
|
||||||
private static List<String> badDomains = new ArrayList<>();
|
private static List<String> badDomains = new ArrayList<>();
|
||||||
@@ -113,13 +111,13 @@ public class MastodonAPIController{
|
|||||||
}
|
}
|
||||||
|
|
||||||
Request hreq=builder.build();
|
Request hreq=builder.build();
|
||||||
Call call=httpClient.newCall(hreq);
|
OkHttpClient client=req.timeout>0
|
||||||
|
? httpClient.newBuilder().readTimeout(req.timeout, TimeUnit.MILLISECONDS).build()
|
||||||
|
: httpClient;
|
||||||
|
Call call=client.newCall(hreq);
|
||||||
synchronized(req){
|
synchronized(req){
|
||||||
req.okhttpCall=call;
|
req.okhttpCall=call;
|
||||||
}
|
}
|
||||||
if(req.timeout>0){
|
|
||||||
call.timeout().timeout(req.timeout, TimeUnit.MILLISECONDS);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(BuildConfig.DEBUG)
|
if(BuildConfig.DEBUG)
|
||||||
Log.d(TAG, "["+(session==null ? "no-auth" : session.getID())+"] Sending request: "+hreq);
|
Log.d(TAG, "["+(session==null ? "no-auth" : session.getID())+"] Sending request: "+hreq);
|
||||||
|
|||||||
@@ -153,8 +153,9 @@ public abstract class MastodonAPIRequest<T> extends APIRequest<T>{
|
|||||||
headers.put(key, value);
|
headers.put(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void setTimeout(long timeout){
|
public MastodonAPIRequest<T> setTimeout(long timeout){
|
||||||
this.timeout=timeout;
|
this.timeout=timeout;
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String getPathPrefix(){
|
protected String getPathPrefix(){
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ public class PushSubscriptionManager{
|
|||||||
deviceToken=getPrefs().getString("deviceToken", null);
|
deviceToken=getPrefs().getString("deviceToken", null);
|
||||||
int tokenVersion=getPrefs().getInt("version", 0);
|
int tokenVersion=getPrefs().getInt("version", 0);
|
||||||
if(!TextUtils.isEmpty(deviceToken) && tokenVersion==BuildConfig.VERSION_CODE){
|
if(!TextUtils.isEmpty(deviceToken) && tokenVersion==BuildConfig.VERSION_CODE){
|
||||||
registerAllAccountsForPush(true); // TODO: revert this before release
|
registerAllAccountsForPush(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Log.i(TAG, "tryRegisterFCM: no token found or app was updated. Trying to get push token...");
|
Log.i(TAG, "tryRegisterFCM: no token found or app was updated. Trying to get push token...");
|
||||||
|
|||||||
@@ -7,7 +7,10 @@ import org.joinmastodon.android.MastodonApp;
|
|||||||
import org.joinmastodon.android.api.requests.statuses.SetStatusBookmarked;
|
import org.joinmastodon.android.api.requests.statuses.SetStatusBookmarked;
|
||||||
import org.joinmastodon.android.api.requests.statuses.SetStatusFavorited;
|
import org.joinmastodon.android.api.requests.statuses.SetStatusFavorited;
|
||||||
import org.joinmastodon.android.api.requests.statuses.SetStatusReblogged;
|
import org.joinmastodon.android.api.requests.statuses.SetStatusReblogged;
|
||||||
|
import org.joinmastodon.android.events.ReblogDeletedEvent;
|
||||||
import org.joinmastodon.android.events.StatusCountersUpdatedEvent;
|
import org.joinmastodon.android.events.StatusCountersUpdatedEvent;
|
||||||
|
import org.joinmastodon.android.events.StatusCreatedEvent;
|
||||||
|
import org.joinmastodon.android.events.StatusDeletedEvent;
|
||||||
import org.joinmastodon.android.model.Status;
|
import org.joinmastodon.android.model.Status;
|
||||||
import org.joinmastodon.android.model.StatusPrivacy;
|
import org.joinmastodon.android.model.StatusPrivacy;
|
||||||
|
|
||||||
@@ -48,7 +51,7 @@ public class StatusInteractionController{
|
|||||||
runningFavoriteRequests.remove(status.id);
|
runningFavoriteRequests.remove(status.id);
|
||||||
result.favouritesCount = Math.max(0, status.favouritesCount + (favorited ? 1 : -1));
|
result.favouritesCount = Math.max(0, status.favouritesCount + (favorited ? 1 : -1));
|
||||||
cb.accept(result);
|
cb.accept(result);
|
||||||
if (updateCounters) E.post(new StatusCountersUpdatedEvent(result));
|
if(updateCounters) E.post(new StatusCountersUpdatedEvent(result));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -57,13 +60,13 @@ public class StatusInteractionController{
|
|||||||
error.showToast(MastodonApp.context);
|
error.showToast(MastodonApp.context);
|
||||||
status.favourited=!favorited;
|
status.favourited=!favorited;
|
||||||
cb.accept(status);
|
cb.accept(status);
|
||||||
if (updateCounters) E.post(new StatusCountersUpdatedEvent(status));
|
if(updateCounters) E.post(new StatusCountersUpdatedEvent(status));
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.exec(accountID);
|
.exec(accountID);
|
||||||
runningFavoriteRequests.put(status.id, req);
|
runningFavoriteRequests.put(status.id, req);
|
||||||
status.favourited=favorited;
|
status.favourited=favorited;
|
||||||
if (updateCounters) E.post(new StatusCountersUpdatedEvent(status));
|
if(updateCounters) E.post(new StatusCountersUpdatedEvent(status));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setReblogged(Status status, boolean reblogged, StatusPrivacy visibility, Consumer<Status> cb){
|
public void setReblogged(Status status, boolean reblogged, StatusPrivacy visibility, Consumer<Status> cb){
|
||||||
@@ -78,11 +81,15 @@ public class StatusInteractionController{
|
|||||||
.setCallback(new Callback<>(){
|
.setCallback(new Callback<>(){
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(Status reblog){
|
public void onSuccess(Status reblog){
|
||||||
Status result = reblog.getContentStatus();
|
Status result=reblog.getContentStatus();
|
||||||
runningReblogRequests.remove(status.id);
|
runningReblogRequests.remove(status.id);
|
||||||
result.reblogsCount = Math.max(0, status.reblogsCount + (reblogged ? 1 : -1));
|
result.reblogsCount = Math.max(0, status.reblogsCount + (reblogged ? 1 : -1));
|
||||||
cb.accept(result);
|
cb.accept(result);
|
||||||
if (updateCounters) E.post(new StatusCountersUpdatedEvent(result));
|
if(updateCounters){
|
||||||
|
E.post(new StatusCountersUpdatedEvent(result));
|
||||||
|
if(reblogged) E.post(new StatusCreatedEvent(reblog, accountID));
|
||||||
|
else E.post(new ReblogDeletedEvent(status.id, accountID));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -91,13 +98,13 @@ public class StatusInteractionController{
|
|||||||
error.showToast(MastodonApp.context);
|
error.showToast(MastodonApp.context);
|
||||||
status.reblogged=!reblogged;
|
status.reblogged=!reblogged;
|
||||||
cb.accept(status);
|
cb.accept(status);
|
||||||
if (updateCounters) E.post(new StatusCountersUpdatedEvent(status));
|
if(updateCounters) E.post(new StatusCountersUpdatedEvent(status));
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.exec(accountID);
|
.exec(accountID);
|
||||||
runningReblogRequests.put(status.id, req);
|
runningReblogRequests.put(status.id, req);
|
||||||
status.reblogged=reblogged;
|
status.reblogged=reblogged;
|
||||||
if (updateCounters) E.post(new StatusCountersUpdatedEvent(status));
|
if(updateCounters) E.post(new StatusCountersUpdatedEvent(status));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setBookmarked(Status status, boolean bookmarked){
|
public void setBookmarked(Status status, boolean bookmarked){
|
||||||
@@ -118,7 +125,7 @@ public class StatusInteractionController{
|
|||||||
public void onSuccess(Status result){
|
public void onSuccess(Status result){
|
||||||
runningBookmarkRequests.remove(status.id);
|
runningBookmarkRequests.remove(status.id);
|
||||||
cb.accept(result);
|
cb.accept(result);
|
||||||
if (updateCounters) E.post(new StatusCountersUpdatedEvent(result));
|
if(updateCounters) E.post(new StatusCountersUpdatedEvent(result));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -127,12 +134,12 @@ public class StatusInteractionController{
|
|||||||
error.showToast(MastodonApp.context);
|
error.showToast(MastodonApp.context);
|
||||||
status.bookmarked=!bookmarked;
|
status.bookmarked=!bookmarked;
|
||||||
cb.accept(status);
|
cb.accept(status);
|
||||||
if (updateCounters) E.post(new StatusCountersUpdatedEvent(status));
|
if(updateCounters) E.post(new StatusCountersUpdatedEvent(status));
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.exec(accountID);
|
.exec(accountID);
|
||||||
runningBookmarkRequests.put(status.id, req);
|
runningBookmarkRequests.put(status.id, req);
|
||||||
status.bookmarked=bookmarked;
|
status.bookmarked=bookmarked;
|
||||||
if (updateCounters) E.post(new StatusCountersUpdatedEvent(status));
|
if(updateCounters) E.post(new StatusCountersUpdatedEvent(status));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import okhttp3.MultipartBody;
|
|||||||
import okhttp3.RequestBody;
|
import okhttp3.RequestBody;
|
||||||
|
|
||||||
public class PleromaMarkNotificationsRead extends MastodonAPIRequest<List<Notification>> {
|
public class PleromaMarkNotificationsRead extends MastodonAPIRequest<List<Notification>> {
|
||||||
private String maxID;
|
private final String maxID;
|
||||||
public PleromaMarkNotificationsRead(String maxID) {
|
public PleromaMarkNotificationsRead(String maxID) {
|
||||||
super(HttpMethod.POST, "/pleroma/notifications/read", new TypeToken<>(){});
|
super(HttpMethod.POST, "/pleroma/notifications/read", new TypeToken<>(){});
|
||||||
this.maxID = maxID;
|
this.maxID = maxID;
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import androidx.annotation.StringRes;
|
|||||||
|
|
||||||
import com.google.gson.reflect.TypeToken;
|
import com.google.gson.reflect.TypeToken;
|
||||||
|
|
||||||
|
import org.joinmastodon.android.GlobalUserPreferences;
|
||||||
import org.joinmastodon.android.R;
|
import org.joinmastodon.android.R;
|
||||||
import org.joinmastodon.android.model.ContentType;
|
import org.joinmastodon.android.model.ContentType;
|
||||||
import org.joinmastodon.android.model.Emoji;
|
import org.joinmastodon.android.model.Emoji;
|
||||||
@@ -43,7 +44,6 @@ public class AccountLocalPreferences{
|
|||||||
public boolean emojiReactionsEnabled;
|
public boolean emojiReactionsEnabled;
|
||||||
public ShowEmojiReactions showEmojiReactions;
|
public ShowEmojiReactions showEmojiReactions;
|
||||||
public ColorPreference color;
|
public ColorPreference color;
|
||||||
public boolean likeIcon;
|
|
||||||
public ArrayList<Emoji> recentCustomEmoji;
|
public ArrayList<Emoji> recentCustomEmoji;
|
||||||
|
|
||||||
private final static Type recentLanguagesType=new TypeToken<ArrayList<String>>() {}.getType();
|
private final static Type recentLanguagesType=new TypeToken<ArrayList<String>>() {}.getType();
|
||||||
@@ -73,8 +73,7 @@ public class AccountLocalPreferences{
|
|||||||
keepOnlyLatestNotification=prefs.getBoolean("keepOnlyLatestNotification", false);
|
keepOnlyLatestNotification=prefs.getBoolean("keepOnlyLatestNotification", false);
|
||||||
emojiReactionsEnabled=prefs.getBoolean("emojiReactionsEnabled", session.getInstance().isPresent() && session.getInstance().get().isAkkoma());
|
emojiReactionsEnabled=prefs.getBoolean("emojiReactionsEnabled", session.getInstance().isPresent() && session.getInstance().get().isAkkoma());
|
||||||
showEmojiReactions=ShowEmojiReactions.valueOf(prefs.getString("showEmojiReactions", ShowEmojiReactions.HIDE_EMPTY.name()));
|
showEmojiReactions=ShowEmojiReactions.valueOf(prefs.getString("showEmojiReactions", ShowEmojiReactions.HIDE_EMPTY.name()));
|
||||||
color=ColorPreference.valueOf(prefs.getString("color", ColorPreference.MATERIAL3.name()));
|
color=prefs.contains("color") ? ColorPreference.valueOf(prefs.getString("color", null)) : null;
|
||||||
likeIcon=prefs.getBoolean("likeIcon", false);
|
|
||||||
recentCustomEmoji=fromJson(prefs.getString("recentCustomEmoji", null), recentCustomEmojiType, new ArrayList<>());
|
recentCustomEmoji=fromJson(prefs.getString("recentCustomEmoji", null), recentCustomEmojiType, new ArrayList<>());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,6 +85,10 @@ public class AccountLocalPreferences{
|
|||||||
prefs.edit().putLong("notificationsPauseTime", time).apply();
|
prefs.edit().putLong("notificationsPauseTime", time).apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ColorPreference getCurrentColor(){
|
||||||
|
return color!=null ? color : GlobalUserPreferences.color!=null ? GlobalUserPreferences.color : ColorPreference.MATERIAL3;
|
||||||
|
}
|
||||||
|
|
||||||
public void save(){
|
public void save(){
|
||||||
prefs.edit()
|
prefs.edit()
|
||||||
.putBoolean("interactionCounts", showInteractionCounts)
|
.putBoolean("interactionCounts", showInteractionCounts)
|
||||||
@@ -109,8 +112,7 @@ public class AccountLocalPreferences{
|
|||||||
.putBoolean("keepOnlyLatestNotification", keepOnlyLatestNotification)
|
.putBoolean("keepOnlyLatestNotification", keepOnlyLatestNotification)
|
||||||
.putBoolean("emojiReactionsEnabled", emojiReactionsEnabled)
|
.putBoolean("emojiReactionsEnabled", emojiReactionsEnabled)
|
||||||
.putString("showEmojiReactions", showEmojiReactions.name())
|
.putString("showEmojiReactions", showEmojiReactions.name())
|
||||||
.putString("color", color.name())
|
.putString("color", color!=null ? color.name() : null)
|
||||||
.putBoolean("likeIcon", likeIcon)
|
|
||||||
.putString("recentCustomEmoji", gson.toJson(recentCustomEmoji))
|
.putString("recentCustomEmoji", gson.toJson(recentCustomEmoji))
|
||||||
.apply();
|
.apply();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -218,7 +218,7 @@ public class AccountSession{
|
|||||||
|
|
||||||
public void savePreferencesIfPending(){
|
public void savePreferencesIfPending(){
|
||||||
if(preferencesNeedSaving){
|
if(preferencesNeedSaving){
|
||||||
new UpdateAccountCredentialsPreferences(preferences, null, self.discoverable, self.source.indexable)
|
new UpdateAccountCredentialsPreferences(preferences, self.locked, self.discoverable, self.source.indexable)
|
||||||
.setCallback(new Callback<>(){
|
.setCallback(new Callback<>(){
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(Account result){
|
public void onSuccess(Account result){
|
||||||
@@ -270,6 +270,7 @@ public class AccountSession{
|
|||||||
if(s!=null && s.filtered!=null){
|
if(s!=null && s.filtered!=null){
|
||||||
localPreferences.serverSideFiltersSupported=true;
|
localPreferences.serverSideFiltersSupported=true;
|
||||||
localPreferences.save();
|
localPreferences.save();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -279,9 +280,17 @@ public class AccountSession{
|
|||||||
if(filterStatusContainingObject(o, extractor, context, profile)){
|
if(filterStatusContainingObject(o, extractor, context, profile)){
|
||||||
Status s=extractor.apply(o);
|
Status s=extractor.apply(o);
|
||||||
removeUs.add(o);
|
removeUs.add(o);
|
||||||
if(s!=null && s.hasGapAfter && i > 0){
|
if(s!=null && s.hasGapAfter!=null && i>0){
|
||||||
Status prev=extractor.apply(objects.get(i - 1));
|
// oops, we're about to remove an item that has a gap after...
|
||||||
if(prev!=null) prev.hasGapAfter=true;
|
// gotta find the previous status that's not also about to be removed
|
||||||
|
for(int j=i-1; j>=0; j--){
|
||||||
|
T p=objects.get(j);
|
||||||
|
Status prev=extractor.apply(objects.get(j));
|
||||||
|
if(prev!=null && !removeUs.contains(p)){
|
||||||
|
prev.hasGapAfter=s.hasGapAfter;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -295,7 +304,7 @@ public class AccountSession{
|
|||||||
// don't hide own posts in own profile
|
// don't hide own posts in own profile
|
||||||
if(statusIsOnOwnProfile(s, profile))
|
if(statusIsOnOwnProfile(s, profile))
|
||||||
return false;
|
return false;
|
||||||
if(isFilteredType(s))
|
if(isFilteredType(s) && (context == FilterContext.HOME || context == FilterContext.PUBLIC))
|
||||||
return true;
|
return true;
|
||||||
// Even with server-side filters, clients are expected to remove statuses that match a filter that hides them
|
// Even with server-side filters, clients are expected to remove statuses that match a filter that hides them
|
||||||
if(localPreferences.serverSideFiltersSupported){
|
if(localPreferences.serverSideFiltersSupported){
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package org.joinmastodon.android.events;
|
||||||
|
|
||||||
|
public class ReblogDeletedEvent{
|
||||||
|
public final String statusID;
|
||||||
|
public final String accountID;
|
||||||
|
|
||||||
|
public ReblogDeletedEvent(String statusID, String accountID){
|
||||||
|
this.statusID=statusID;
|
||||||
|
this.accountID=accountID;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,5 @@
|
|||||||
package org.joinmastodon.android.events;
|
package org.joinmastodon.android.events;
|
||||||
|
|
||||||
import org.joinmastodon.android.model.ScheduledStatus;
|
|
||||||
|
|
||||||
public class ScheduledStatusDeletedEvent{
|
public class ScheduledStatusDeletedEvent{
|
||||||
public final String id;
|
public final String id;
|
||||||
public final String accountID;
|
public final String accountID;
|
||||||
|
|||||||
@@ -9,5 +9,6 @@ public class StatusCreatedEvent{
|
|||||||
public StatusCreatedEvent(Status status, String accountID){
|
public StatusCreatedEvent(Status status, String accountID){
|
||||||
this.status=status;
|
this.status=status;
|
||||||
this.accountID=accountID;
|
this.accountID=accountID;
|
||||||
|
status.fromStatusCreated=true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,14 +52,14 @@ public class AccountTimelineFragment extends StatusListFragment{
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doLoadData(int offset, int count){
|
protected void doLoadData(int offset, int count){
|
||||||
currentRequest=new GetAccountStatuses(user.id, offset>0 ? getMaxID() : null, null, count, filter)
|
currentRequest=new GetAccountStatuses(user.id, getMaxID(), null, count, filter)
|
||||||
.setCallback(new SimpleCallback<>(this){
|
.setCallback(new SimpleCallback<>(this){
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(List<Status> result){
|
public void onSuccess(List<Status> result){
|
||||||
if(getActivity()==null) return;
|
if(getActivity()==null) return;
|
||||||
boolean empty=result.isEmpty();
|
boolean more=applyMaxID(result);
|
||||||
AccountSessionManager.get(accountID).filterStatuses(result, getFilterContext(), user);
|
AccountSessionManager.get(accountID).filterStatuses(result, getFilterContext(), user);
|
||||||
onDataLoaded(result, !empty);
|
onDataLoaded(result, more);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.exec(accountID);
|
.exec(accountID);
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ public class AnnouncementsFragment extends BaseStatusListFragment<Announcement>
|
|||||||
.setCallback(new SimpleCallback<>(this){
|
.setCallback(new SimpleCallback<>(this){
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(List<Announcement> result){
|
public void onSuccess(List<Announcement> result){
|
||||||
if (getActivity() == null) return;
|
if(getActivity()==null) return;
|
||||||
|
|
||||||
// get unread items first
|
// get unread items first
|
||||||
List<Announcement> data = result.stream().filter(a -> !a.read).collect(toList());
|
List<Announcement> data = result.stream().filter(a -> !a.read).collect(toList());
|
||||||
|
|||||||
@@ -33,7 +33,6 @@ import org.joinmastodon.android.model.Translation;
|
|||||||
import org.joinmastodon.android.ui.BetterItemAnimator;
|
import org.joinmastodon.android.ui.BetterItemAnimator;
|
||||||
import org.joinmastodon.android.ui.M3AlertDialogBuilder;
|
import org.joinmastodon.android.ui.M3AlertDialogBuilder;
|
||||||
import org.joinmastodon.android.ui.displayitems.AccountStatusDisplayItem;
|
import org.joinmastodon.android.ui.displayitems.AccountStatusDisplayItem;
|
||||||
import org.joinmastodon.android.ui.displayitems.EmojiReactionsStatusDisplayItem;
|
|
||||||
import org.joinmastodon.android.ui.displayitems.ExtendedFooterStatusDisplayItem;
|
import org.joinmastodon.android.ui.displayitems.ExtendedFooterStatusDisplayItem;
|
||||||
import org.joinmastodon.android.ui.displayitems.FooterStatusDisplayItem;
|
import org.joinmastodon.android.ui.displayitems.FooterStatusDisplayItem;
|
||||||
import org.joinmastodon.android.ui.displayitems.GapStatusDisplayItem;
|
import org.joinmastodon.android.ui.displayitems.GapStatusDisplayItem;
|
||||||
@@ -89,6 +88,7 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
|||||||
protected Rect tmpRect=new Rect();
|
protected Rect tmpRect=new Rect();
|
||||||
protected TypedObjectPool<MediaGridStatusDisplayItem.GridItemType, MediaAttachmentViewController> attachmentViewsPool=new TypedObjectPool<>(this::makeNewMediaAttachmentView);
|
protected TypedObjectPool<MediaGridStatusDisplayItem.GridItemType, MediaAttachmentViewController> attachmentViewsPool=new TypedObjectPool<>(this::makeNewMediaAttachmentView);
|
||||||
protected boolean currentlyScrolling;
|
protected boolean currentlyScrolling;
|
||||||
|
protected String maxID;
|
||||||
|
|
||||||
public BaseStatusListFragment(){
|
public BaseStatusListFragment(){
|
||||||
super(20);
|
super(20);
|
||||||
@@ -155,6 +155,8 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected String getMaxID(){
|
protected String getMaxID(){
|
||||||
|
if(refreshing) return null;
|
||||||
|
if(maxID!=null) return maxID;
|
||||||
if(!preloadedData.isEmpty())
|
if(!preloadedData.isEmpty())
|
||||||
return preloadedData.get(preloadedData.size()-1).getID();
|
return preloadedData.get(preloadedData.size()-1).getID();
|
||||||
else if(!data.isEmpty())
|
else if(!data.isEmpty())
|
||||||
@@ -163,6 +165,12 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected boolean applyMaxID(List<Status> result){
|
||||||
|
boolean empty=result.isEmpty();
|
||||||
|
if(!empty) maxID=result.get(result.size()-1).id;
|
||||||
|
return !empty;
|
||||||
|
}
|
||||||
|
|
||||||
protected abstract List<StatusDisplayItem> buildDisplayItems(T s);
|
protected abstract List<StatusDisplayItem> buildDisplayItems(T s);
|
||||||
protected abstract void addAccountToKnown(T s);
|
protected abstract void addAccountToKnown(T s);
|
||||||
|
|
||||||
@@ -460,10 +468,14 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
|||||||
protected void updatePoll(String itemID, Status status, Poll poll){
|
protected void updatePoll(String itemID, Status status, Poll poll){
|
||||||
status.poll=poll;
|
status.poll=poll;
|
||||||
int firstOptionIndex=-1, footerIndex=-1;
|
int firstOptionIndex=-1, footerIndex=-1;
|
||||||
|
int spoilerFirstOptionIndex=-1, spoilerFooterIndex=-1;
|
||||||
|
SpoilerStatusDisplayItem spoilerItem=null;
|
||||||
int i=0;
|
int i=0;
|
||||||
for(StatusDisplayItem item:displayItems){
|
for(StatusDisplayItem item:displayItems){
|
||||||
if(item.parentID.equals(itemID)){
|
if(item.parentID.equals(itemID)){
|
||||||
if(item instanceof PollOptionStatusDisplayItem && firstOptionIndex==-1){
|
if(item instanceof SpoilerStatusDisplayItem){
|
||||||
|
spoilerItem=(SpoilerStatusDisplayItem) item;
|
||||||
|
}else if(item instanceof PollOptionStatusDisplayItem && firstOptionIndex==-1){
|
||||||
firstOptionIndex=i;
|
firstOptionIndex=i;
|
||||||
}else if(item instanceof PollFooterStatusDisplayItem){
|
}else if(item instanceof PollFooterStatusDisplayItem){
|
||||||
footerIndex=i;
|
footerIndex=i;
|
||||||
@@ -476,8 +488,16 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
|||||||
throw new IllegalStateException("Can't find all poll items in displayItems");
|
throw new IllegalStateException("Can't find all poll items in displayItems");
|
||||||
List<StatusDisplayItem> pollItems=displayItems.subList(firstOptionIndex, footerIndex+1);
|
List<StatusDisplayItem> pollItems=displayItems.subList(firstOptionIndex, footerIndex+1);
|
||||||
int prevSize=pollItems.size();
|
int prevSize=pollItems.size();
|
||||||
|
if(spoilerItem!=null){
|
||||||
|
spoilerFirstOptionIndex=spoilerItem.contentItems.indexOf(pollItems.get(0));
|
||||||
|
spoilerFooterIndex=spoilerItem.contentItems.indexOf(pollItems.get(pollItems.size()-1));
|
||||||
|
}
|
||||||
pollItems.clear();
|
pollItems.clear();
|
||||||
StatusDisplayItem.buildPollItems(itemID, this, poll, pollItems);
|
StatusDisplayItem.buildPollItems(itemID, this, poll, pollItems);
|
||||||
|
if(spoilerItem!=null){
|
||||||
|
spoilerItem.contentItems.subList(spoilerFirstOptionIndex, spoilerFooterIndex+1).clear();
|
||||||
|
spoilerItem.contentItems.addAll(spoilerFirstOptionIndex, pollItems);
|
||||||
|
}
|
||||||
if(prevSize!=pollItems.size()){
|
if(prevSize!=pollItems.size()){
|
||||||
adapter.notifyItemRangeRemoved(firstOptionIndex, prevSize);
|
adapter.notifyItemRangeRemoved(firstOptionIndex, prevSize);
|
||||||
adapter.notifyItemRangeInserted(firstOptionIndex, pollItems.size());
|
adapter.notifyItemRangeInserted(firstOptionIndex, pollItems.size());
|
||||||
@@ -549,21 +569,21 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
|||||||
|
|
||||||
public void onVisibilityIconClick(HeaderStatusDisplayItem.Holder holder) {
|
public void onVisibilityIconClick(HeaderStatusDisplayItem.Holder holder) {
|
||||||
Status status = holder.getItem().status;
|
Status status = holder.getItem().status;
|
||||||
MediaGridStatusDisplayItem.Holder mediaGrid = findHolderOfType(holder.getItemID(), MediaGridStatusDisplayItem.Holder.class);
|
|
||||||
if (mediaGrid != null) {
|
|
||||||
if (!status.sensitiveRevealed) mediaGrid.revealSensitive();
|
|
||||||
else mediaGrid.hideSensitive();
|
|
||||||
} else {
|
|
||||||
// media grid's methods normally change the status' state - we still want to be able
|
|
||||||
// to do this if the media grid is not bound, tho - so, doing it ourselves here
|
|
||||||
status.sensitiveRevealed = !status.sensitiveRevealed;
|
|
||||||
}
|
|
||||||
if(holder.getItem().hasVisibilityToggle) holder.animateVisibilityToggle(false);
|
if(holder.getItem().hasVisibilityToggle) holder.animateVisibilityToggle(false);
|
||||||
|
MediaGridStatusDisplayItem.Holder mediaGrid=findHolderOfType(holder.getItemID(), MediaGridStatusDisplayItem.Holder.class);
|
||||||
|
if(mediaGrid!=null){
|
||||||
|
if(!status.sensitiveRevealed) mediaGrid.revealSensitive();
|
||||||
|
else mediaGrid.hideSensitive();
|
||||||
|
}else{
|
||||||
|
status.sensitiveRevealed=false;
|
||||||
|
notifyItemChangedAfter(holder.getItem(), MediaGridStatusDisplayItem.class);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onSensitiveRevealed(MediaGridStatusDisplayItem.Holder holder) {
|
public void onSensitiveRevealed(MediaGridStatusDisplayItem.Holder holder) {
|
||||||
HeaderStatusDisplayItem.Holder header = findHolderOfType(holder.getItemID(), HeaderStatusDisplayItem.Holder.class);
|
HeaderStatusDisplayItem.Holder header=findHolderOfType(holder.getItemID(), HeaderStatusDisplayItem.Holder.class);
|
||||||
if(header != null && header.getItem().hasVisibilityToggle) header.animateVisibilityToggle(true);
|
if(header!=null && header.getItem().hasVisibilityToggle) header.animateVisibilityToggle(true);
|
||||||
|
else notifyItemChangedBefore(holder.getItem(), HeaderStatusDisplayItem.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void toggleSpoiler(Status status, String itemID){
|
protected void toggleSpoiler(Status status, String itemID){
|
||||||
@@ -572,8 +592,8 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
|||||||
status.sensitiveRevealed = false;
|
status.sensitiveRevealed = false;
|
||||||
|
|
||||||
SpoilerStatusDisplayItem.Holder spoiler=findHolderOfType(itemID, SpoilerStatusDisplayItem.Holder.class);
|
SpoilerStatusDisplayItem.Holder spoiler=findHolderOfType(itemID, SpoilerStatusDisplayItem.Holder.class);
|
||||||
if(spoiler!=null)
|
if(spoiler!=null) spoiler.rebind();
|
||||||
spoiler.rebind();
|
else notifyItemChanged(itemID, SpoilerStatusDisplayItem.class);
|
||||||
SpoilerStatusDisplayItem spoilerItem=Objects.requireNonNull(findItemOfType(itemID, SpoilerStatusDisplayItem.class));
|
SpoilerStatusDisplayItem spoilerItem=Objects.requireNonNull(findItemOfType(itemID, SpoilerStatusDisplayItem.class));
|
||||||
|
|
||||||
int index=displayItems.indexOf(spoilerItem);
|
int index=displayItems.indexOf(spoilerItem);
|
||||||
@@ -585,39 +605,29 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
|||||||
adapter.notifyItemRangeRemoved(index+1, spoilerItem.contentItems.size());
|
adapter.notifyItemRangeRemoved(index+1, spoilerItem.contentItems.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
TextStatusDisplayItem.Holder text=findHolderOfType(itemID, TextStatusDisplayItem.Holder.class);
|
notifyItemChanged(itemID, TextStatusDisplayItem.class);
|
||||||
if(text!=null)
|
|
||||||
adapter.notifyItemChanged(text.getAbsoluteAdapterPosition()-getMainAdapterOffset());
|
|
||||||
HeaderStatusDisplayItem.Holder header=findHolderOfType(itemID, HeaderStatusDisplayItem.Holder.class);
|
HeaderStatusDisplayItem.Holder header=findHolderOfType(itemID, HeaderStatusDisplayItem.Holder.class);
|
||||||
if(header!=null)
|
if(header!=null) header.rebind();
|
||||||
header.rebind();
|
else notifyItemChanged(itemID, HeaderStatusDisplayItem.class);
|
||||||
|
|
||||||
list.invalidateItemDecorations();
|
list.invalidateItemDecorations();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onEnableExpandable(TextStatusDisplayItem.Holder holder, boolean expandable) {
|
public void onEnableExpandable(TextStatusDisplayItem.Holder holder, boolean expandable) {
|
||||||
if (holder.getItem().status.textExpandable != expandable && list != null) {
|
Status s=holder.getItem().status;
|
||||||
holder.getItem().status.textExpandable = expandable;
|
if(s.textExpandable!=expandable && list!=null) {
|
||||||
HeaderStatusDisplayItem.Holder header = findHolderOfType(holder.getItemID(), HeaderStatusDisplayItem.Holder.class);
|
s.textExpandable=expandable;
|
||||||
if (header != null) header.rebind();
|
HeaderStatusDisplayItem.Holder header=findHolderOfType(holder.getItemID(), HeaderStatusDisplayItem.Holder.class);
|
||||||
|
if(header!=null) header.bindCollapseButton();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onToggleExpanded(Status status, String itemID) {
|
public void onToggleExpanded(Status status, String itemID) {
|
||||||
status.textExpanded = !status.textExpanded;
|
status.textExpanded = !status.textExpanded;
|
||||||
TextStatusDisplayItem.Holder text=findHolderOfType(itemID, TextStatusDisplayItem.Holder.class);
|
notifyItemChanged(itemID, TextStatusDisplayItem.class);
|
||||||
HeaderStatusDisplayItem.Holder header=findHolderOfType(itemID, HeaderStatusDisplayItem.Holder.class);
|
HeaderStatusDisplayItem.Holder header=findHolderOfType(itemID, HeaderStatusDisplayItem.Holder.class);
|
||||||
if (text != null) text.rebind();
|
if(header!=null) header.animateExpandToggle();
|
||||||
if (header != null) header.rebind();
|
else notifyItemChanged(itemID, HeaderStatusDisplayItem.class);
|
||||||
}
|
|
||||||
|
|
||||||
public void updateEmojiReactions(Status status, String itemID){
|
|
||||||
EmojiReactionsStatusDisplayItem.Holder reactions=findHolderOfType(itemID, EmojiReactionsStatusDisplayItem.Holder.class);
|
|
||||||
if(reactions != null){
|
|
||||||
reactions.getItem().status.reactions.clear();
|
|
||||||
reactions.getItem().status.reactions.addAll(status.reactions);
|
|
||||||
reactions.rebind();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onGapClick(GapStatusDisplayItem.Holder item, boolean downwards){}
|
public void onGapClick(GapStatusDisplayItem.Holder item, boolean downwards){}
|
||||||
@@ -676,9 +686,61 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use this as a fallback if findHolderOfType fails to find the ViewHolder.
|
||||||
|
* It might still be bound but off-screen and therefore not a child of the RecyclerView -
|
||||||
|
* resulting in the ViewHolder displaying an outdated state once scrolled back into view.
|
||||||
|
*/
|
||||||
|
protected <I extends StatusDisplayItem> int notifyItemChanged(String id, Class<I> type){
|
||||||
|
boolean encounteredParent=false;
|
||||||
|
for(int i=0; i<displayItems.size(); i++){
|
||||||
|
StatusDisplayItem item=displayItems.get(i);
|
||||||
|
boolean idEquals=id.equals(item.parentID);
|
||||||
|
if(!encounteredParent && idEquals) encounteredParent=true; // reached top of the parent
|
||||||
|
else if(encounteredParent && !idEquals) break; // passed by bottom of the parent. man muss ja wissen wann schluss is
|
||||||
|
if(idEquals && type.isInstance(item)){
|
||||||
|
adapter.notifyItemChanged(i);
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected <I extends StatusDisplayItem> int notifyItemChangedAfter(StatusDisplayItem afterThis, Class<I> type){
|
||||||
|
int startIndex=displayItems.indexOf(afterThis);
|
||||||
|
if(startIndex == -1) throw new IllegalStateException("notifyItemChangedAfter didn't find the passed StatusDisplayItem");
|
||||||
|
String parentID=afterThis.parentID;
|
||||||
|
for(int i=startIndex; i<displayItems.size(); i++){
|
||||||
|
StatusDisplayItem item=displayItems.get(i);
|
||||||
|
if(!parentID.equals(item.parentID)) break; // didn't find anything
|
||||||
|
if(type.isInstance(item)){
|
||||||
|
// found it
|
||||||
|
adapter.notifyItemChanged(i);
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected <I extends StatusDisplayItem> int notifyItemChangedBefore(StatusDisplayItem beforeThis, Class<I> type){
|
||||||
|
int startIndex=displayItems.indexOf(beforeThis);
|
||||||
|
if(startIndex == -1) throw new IllegalStateException("notifyItemChangedBefore didn't find the passed StatusDisplayItem");
|
||||||
|
String parentID=beforeThis.parentID;
|
||||||
|
for(int i=startIndex; i>=0; i--){
|
||||||
|
StatusDisplayItem item=displayItems.get(i);
|
||||||
|
if(!parentID.equals(item.parentID)) break; // didn't find anything
|
||||||
|
if(type.isInstance(item)){
|
||||||
|
// found it
|
||||||
|
adapter.notifyItemChanged(i);
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
protected <I extends StatusDisplayItem, H extends StatusDisplayItem.Holder<I>> H findHolderOfType(String id, Class<H> type){
|
protected <I extends StatusDisplayItem, H extends StatusDisplayItem.Holder<I>> H findHolderOfType(String id, Class<H> type){
|
||||||
for(int i=0;i<list.getChildCount();i++){
|
for(int i=0; i<list.getChildCount(); i++){
|
||||||
RecyclerView.ViewHolder holder=list.getChildViewHolder(list.getChildAt(i));
|
RecyclerView.ViewHolder holder=list.getChildViewHolder(list.getChildAt(i));
|
||||||
if(holder instanceof StatusDisplayItem.Holder<?> itemHolder && itemHolder.getItemID().equals(id) && type.isInstance(holder))
|
if(holder instanceof StatusDisplayItem.Holder<?> itemHolder && itemHolder.getItemID().equals(id) && type.isInstance(holder))
|
||||||
return type.cast(holder);
|
return type.cast(holder);
|
||||||
@@ -800,6 +862,8 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
|||||||
if(text!=null){
|
if(text!=null){
|
||||||
text.updateTranslation(true);
|
text.updateTranslation(true);
|
||||||
imgLoader.bindViewHolder((ImageLoaderRecyclerAdapter) list.getAdapter(), text, text.getAbsoluteAdapterPosition());
|
imgLoader.bindViewHolder((ImageLoaderRecyclerAdapter) list.getAdapter(), text, text.getAbsoluteAdapterPosition());
|
||||||
|
}else{
|
||||||
|
notifyItemChanged(itemID, TextStatusDisplayItem.class);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -811,6 +875,8 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
|||||||
TextStatusDisplayItem.Holder text=findHolderOfType(itemID, TextStatusDisplayItem.Holder.class);
|
TextStatusDisplayItem.Holder text=findHolderOfType(itemID, TextStatusDisplayItem.Holder.class);
|
||||||
if(text!=null){
|
if(text!=null){
|
||||||
text.updateTranslation(true);
|
text.updateTranslation(true);
|
||||||
|
}else{
|
||||||
|
notifyItemChanged(itemID, TextStatusDisplayItem.class);
|
||||||
}
|
}
|
||||||
new M3AlertDialogBuilder(getActivity())
|
new M3AlertDialogBuilder(getActivity())
|
||||||
.setTitle(R.string.error)
|
.setTitle(R.string.error)
|
||||||
@@ -827,6 +893,8 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
|||||||
if(text!=null){
|
if(text!=null){
|
||||||
text.updateTranslation(true);
|
text.updateTranslation(true);
|
||||||
imgLoader.bindViewHolder((ImageLoaderRecyclerAdapter) list.getAdapter(), text, text.getAbsoluteAdapterPosition());
|
imgLoader.bindViewHolder((ImageLoaderRecyclerAdapter) list.getAdapter(), text, text.getAbsoluteAdapterPosition());
|
||||||
|
}else{
|
||||||
|
notifyItemChanged(itemID, TextStatusDisplayItem.class);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ public class BookmarkedStatusListFragment extends StatusListFragment{
|
|||||||
.setCallback(new SimpleCallback<>(this){
|
.setCallback(new SimpleCallback<>(this){
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(HeaderPaginationList<Status> result){
|
public void onSuccess(HeaderPaginationList<Status> result){
|
||||||
if (getActivity() == null) return;
|
if(getActivity()==null) return;
|
||||||
if(result.nextPageUri!=null)
|
if(result.nextPageUri!=null)
|
||||||
nextMaxID=result.nextPageUri.getQueryParameter("max_id");
|
nextMaxID=result.nextPageUri.getQueryParameter("max_id");
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ import android.text.TextWatcher;
|
|||||||
import android.text.format.DateFormat;
|
import android.text.format.DateFormat;
|
||||||
import android.text.style.BackgroundColorSpan;
|
import android.text.style.BackgroundColorSpan;
|
||||||
import android.text.style.ForegroundColorSpan;
|
import android.text.style.ForegroundColorSpan;
|
||||||
import android.view.HapticFeedbackConstants;
|
|
||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
@@ -111,11 +110,11 @@ import java.time.format.DateTimeFormatter;
|
|||||||
import java.time.format.FormatStyle;
|
import java.time.format.FormatStyle;
|
||||||
import java.time.temporal.ChronoUnit;
|
import java.time.temporal.ChronoUnit;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import java.util.function.Consumer;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
@@ -151,7 +150,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
|||||||
|
|
||||||
public LinearLayout mainLayout;
|
public LinearLayout mainLayout;
|
||||||
private SizeListenerLinearLayout contentView;
|
private SizeListenerLinearLayout contentView;
|
||||||
private TextView selfName, selfUsername, selfExtraText, extraText, pronouns;
|
private TextView selfName, selfUsername, selfExtraText, extraText;
|
||||||
private ImageView selfAvatar;
|
private ImageView selfAvatar;
|
||||||
private Account self;
|
private Account self;
|
||||||
private String instanceDomain;
|
private String instanceDomain;
|
||||||
@@ -201,7 +200,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
|||||||
public Instance instance;
|
public Instance instance;
|
||||||
|
|
||||||
public Status editingStatus;
|
public Status editingStatus;
|
||||||
private ScheduledStatus scheduledStatus;
|
public ScheduledStatus scheduledStatus;
|
||||||
private boolean redraftStatus;
|
private boolean redraftStatus;
|
||||||
|
|
||||||
private ContentType contentType;
|
private ContentType contentType;
|
||||||
@@ -327,7 +326,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
|||||||
selfUsername=view.findViewById(R.id.self_username);
|
selfUsername=view.findViewById(R.id.self_username);
|
||||||
selfAvatar=view.findViewById(R.id.self_avatar);
|
selfAvatar=view.findViewById(R.id.self_avatar);
|
||||||
selfExtraText=view.findViewById(R.id.self_extra_text);
|
selfExtraText=view.findViewById(R.id.self_extra_text);
|
||||||
HtmlParser.setTextWithCustomEmoji(selfName, self.displayName, self.emojis);
|
HtmlParser.setTextWithCustomEmoji(selfName, self.getDisplayName(), self.emojis);
|
||||||
selfUsername.setText('@'+self.username+'@'+instanceDomain);
|
selfUsername.setText('@'+self.username+'@'+instanceDomain);
|
||||||
if(self.avatar!=null)
|
if(self.avatar!=null)
|
||||||
ViewImageLoader.load(selfAvatar, null, new UrlImageLoaderRequest(self.avatar));
|
ViewImageLoader.load(selfAvatar, null, new UrlImageLoaderRequest(self.avatar));
|
||||||
@@ -627,7 +626,6 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
|||||||
});
|
});
|
||||||
View originalPost=view.findViewById(R.id.original_post);
|
View originalPost=view.findViewById(R.id.original_post);
|
||||||
extraText=view.findViewById(R.id.extra_text);
|
extraText=view.findViewById(R.id.extra_text);
|
||||||
pronouns=view.findViewById(R.id.pronouns);
|
|
||||||
originalPost.setVisibility(View.VISIBLE);
|
originalPost.setVisibility(View.VISIBLE);
|
||||||
originalPost.setOnClickListener(v->{
|
originalPost.setOnClickListener(v->{
|
||||||
Bundle args=new Bundle();
|
Bundle args=new Bundle();
|
||||||
@@ -667,7 +665,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
|||||||
moreBtn.setBackground(null);
|
moreBtn.setBackground(null);
|
||||||
|
|
||||||
TextView name = view.findViewById(R.id.name);
|
TextView name = view.findViewById(R.id.name);
|
||||||
name.setText(HtmlParser.parseCustomEmoji(status.account.displayName, status.account.emojis));
|
name.setText(HtmlParser.parseCustomEmoji(status.account.getDisplayName(), status.account.emojis));
|
||||||
UiUtils.loadCustomEmojiInTextView(name);
|
UiUtils.loadCustomEmojiInTextView(name);
|
||||||
|
|
||||||
String time = status==null || status.editedAt==null
|
String time = status==null || status.editedAt==null
|
||||||
@@ -701,7 +699,8 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
|||||||
.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, V.dp(16)));
|
.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, V.dp(16)));
|
||||||
}
|
}
|
||||||
|
|
||||||
replyText.setText(getString(quote!=null? R.string.sk_quoting_user : R.string.in_reply_to, status.account.displayName));
|
replyText.setText(HtmlParser.parseCustomEmoji(getString(quote!=null? R.string.sk_quoting_user : R.string.in_reply_to, status.account.getDisplayName()), status.account.emojis));
|
||||||
|
UiUtils.loadCustomEmojiInTextView(replyText);
|
||||||
int visibilityNameRes = switch (status.visibility) {
|
int visibilityNameRes = switch (status.visibility) {
|
||||||
case PUBLIC -> R.string.visibility_public;
|
case PUBLIC -> R.string.visibility_public;
|
||||||
case UNLISTED -> R.string.sk_visibility_unlisted;
|
case UNLISTED -> R.string.sk_visibility_unlisted;
|
||||||
@@ -709,7 +708,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
|||||||
case DIRECT -> R.string.visibility_private;
|
case DIRECT -> R.string.visibility_private;
|
||||||
case LOCAL -> R.string.sk_local_only;
|
case LOCAL -> R.string.sk_local_only;
|
||||||
};
|
};
|
||||||
replyText.setContentDescription(getString(R.string.in_reply_to, status.account.displayName) + ", " + getString(visibilityNameRes));
|
replyText.setContentDescription(getString(R.string.in_reply_to, status.account.getDisplayName()) + ", " + getString(visibilityNameRes));
|
||||||
replyText.setOnClickListener(v->{
|
replyText.setOnClickListener(v->{
|
||||||
scrollView.smoothScrollTo(0, 0);
|
scrollView.smoothScrollTo(0, 0);
|
||||||
});
|
});
|
||||||
@@ -798,6 +797,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressLint("ClickableViewAccessibility")
|
||||||
@Override
|
@Override
|
||||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater){
|
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater){
|
||||||
inflater.inflate(editingStatus==null ? R.menu.compose : R.menu.compose_edit, menu);
|
inflater.inflate(editingStatus==null ? R.menu.compose : R.menu.compose_edit, menu);
|
||||||
@@ -828,19 +828,34 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
|||||||
languageButton = wrap.findViewById(R.id.language_btn);
|
languageButton = wrap.findViewById(R.id.language_btn);
|
||||||
languageButton.setOnClickListener(v->showLanguageAlert());
|
languageButton.setOnClickListener(v->showLanguageAlert());
|
||||||
languageButton.setOnLongClickListener(v->{
|
languageButton.setOnLongClickListener(v->{
|
||||||
languageButton.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
|
|
||||||
if(!getLocalPrefs().bottomEncoding){
|
if(!getLocalPrefs().bottomEncoding){
|
||||||
getLocalPrefs().bottomEncoding=true;
|
getLocalPrefs().bottomEncoding=true;
|
||||||
getLocalPrefs().save();
|
getLocalPrefs().save();
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
publishButton.post(()->publishButton.setMinimumWidth(publishButton.getWidth()));
|
||||||
|
|
||||||
publishButton.setOnClickListener(v -> {
|
publishButton.setOnClickListener(v->{
|
||||||
if(GlobalUserPreferences.altTextReminders && editingStatus==null)
|
Consumer<Boolean> draftCheckComplete=(isDraft)->{
|
||||||
checkAltTextsAndPublish();
|
if(GlobalUserPreferences.altTextReminders && !isDraft) checkAltTextsAndPublish();
|
||||||
else
|
else publish();
|
||||||
publish();
|
};
|
||||||
|
|
||||||
|
boolean isAlreadyDraft=scheduledAt!=null && scheduledAt.isAfter(DRAFTS_AFTER_INSTANT);
|
||||||
|
if(editingStatus!=null && scheduledAt!=null && isAlreadyDraft) {
|
||||||
|
new M3AlertDialogBuilder(getActivity())
|
||||||
|
.setTitle(R.string.sk_save_draft)
|
||||||
|
.setMessage(R.string.sk_save_draft_message)
|
||||||
|
.setPositiveButton(R.string.save, (d, w)->draftCheckComplete.accept(isAlreadyDraft))
|
||||||
|
.setNegativeButton(R.string.publish, (d, w)->{
|
||||||
|
updateScheduledAt(null);
|
||||||
|
draftCheckComplete.accept(false);
|
||||||
|
})
|
||||||
|
.show();
|
||||||
|
}else{
|
||||||
|
draftCheckComplete.accept(isAlreadyDraft);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
draftsBtn.setOnClickListener(v-> draftOptionsPopup.show());
|
draftsBtn.setOnClickListener(v-> draftOptionsPopup.show());
|
||||||
draftsBtn.setOnTouchListener(draftOptionsPopup.getDragToOpenListener());
|
draftsBtn.setOnTouchListener(draftOptionsPopup.getDragToOpenListener());
|
||||||
@@ -852,8 +867,8 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
|||||||
? languageResolver.fromOrFallback(prefs.postingDefaultLanguage)
|
? languageResolver.fromOrFallback(prefs.postingDefaultLanguage)
|
||||||
: languageResolver.getDefault());
|
: languageResolver.getDefault());
|
||||||
|
|
||||||
if (isInstancePixelfed()) spoilerBtn.setVisibility(View.GONE);
|
if(isInstancePixelfed()) spoilerBtn.setVisibility(View.GONE);
|
||||||
if (isInstancePixelfed() || (editingStatus != null && scheduledStatus == null)) {
|
if(isInstancePixelfed() || (editingStatus!=null && !redraftStatus)) {
|
||||||
// editing an already published post
|
// editing an already published post
|
||||||
draftsBtn.setVisibility(View.GONE);
|
draftsBtn.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
@@ -977,7 +992,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected int getNavigationIconDrawableResource(){
|
protected int getNavigationIconDrawableResource(){
|
||||||
return R.drawable.ic_baseline_close_24;
|
return R.drawable.ic_fluent_dismiss_24_regular;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -1053,19 +1068,16 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void actuallyPublish(){
|
private void actuallyPublish(){
|
||||||
actuallyPublish(false);
|
|
||||||
}
|
|
||||||
private void actuallyPublish(boolean force){
|
|
||||||
String text=mainEditText.getText().toString();
|
String text=mainEditText.getText().toString();
|
||||||
CreateStatus.Request req=new CreateStatus.Request();
|
CreateStatus.Request req=new CreateStatus.Request();
|
||||||
if ("bottom".equals(postLang.encoding)) {
|
if("bottom".equals(postLang.encoding)){
|
||||||
text = new StatusTextEncoder(Bottom::encode).encode(text);
|
text=new StatusTextEncoder(Bottom::encode).encode(text);
|
||||||
req.spoilerText = "bottom-encoded emoji spam";
|
req.spoilerText="bottom-encoded emoji spam";
|
||||||
}
|
}
|
||||||
if (localOnly &&
|
if(localOnly &&
|
||||||
AccountSessionManager.get(accountID).getLocalPreferences().glitchInstance &&
|
AccountSessionManager.get(accountID).getLocalPreferences().glitchInstance &&
|
||||||
!GLITCH_LOCAL_ONLY_PATTERN.matcher(text).matches()) {
|
!GLITCH_LOCAL_ONLY_PATTERN.matcher(text).matches()){
|
||||||
text += " " + GLITCH_LOCAL_ONLY_SUFFIX;
|
text+=" "+GLITCH_LOCAL_ONLY_SUFFIX;
|
||||||
}
|
}
|
||||||
req.status=text;
|
req.status=text;
|
||||||
req.localOnly=localOnly;
|
req.localOnly=localOnly;
|
||||||
@@ -1079,19 +1091,6 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
|||||||
req.mediaAttributes=mediaViewController.getAttachmentAttributes();
|
req.mediaAttributes=mediaViewController.getAttachmentAttributes();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ask whether to publish now when editing an existing draft
|
|
||||||
if (!force && editingStatus != null && scheduledAt != null && scheduledAt.isAfter(DRAFTS_AFTER_INSTANT)) {
|
|
||||||
new M3AlertDialogBuilder(getActivity())
|
|
||||||
.setTitle(R.string.sk_save_draft)
|
|
||||||
.setMessage(R.string.sk_save_draft_message)
|
|
||||||
.setPositiveButton(R.string.save, (d, w) -> actuallyPublish(true))
|
|
||||||
.setNegativeButton(R.string.publish, (d, w) -> {
|
|
||||||
updateScheduledAt(null);
|
|
||||||
actuallyPublish();
|
|
||||||
})
|
|
||||||
.show();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(replyTo!=null || (editingStatus != null && editingStatus.inReplyToId!=null)){
|
if(replyTo!=null || (editingStatus != null && editingStatus.inReplyToId!=null)){
|
||||||
req.inReplyToId=editingStatus!=null ? editingStatus.inReplyToId : replyTo.id;
|
req.inReplyToId=editingStatus!=null ? editingStatus.inReplyToId : replyTo.id;
|
||||||
}
|
}
|
||||||
@@ -1286,20 +1285,20 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void confirmDiscardDraftAndFinish(){
|
private void confirmDiscardDraftAndFinish(){
|
||||||
boolean attachmentsPending = mediaViewController.areAnyAttachmentsNotDone();
|
boolean attachmentsPending=mediaViewController.areAnyAttachmentsNotDone();
|
||||||
if (attachmentsPending) new M3AlertDialogBuilder(getActivity())
|
if(attachmentsPending) new M3AlertDialogBuilder(getActivity())
|
||||||
.setTitle(R.string.sk_unfinished_attachments)
|
.setTitle(R.string.sk_unfinished_attachments)
|
||||||
.setMessage(R.string.sk_unfinished_attachments_message)
|
.setMessage(R.string.sk_unfinished_attachments_message)
|
||||||
.setPositiveButton(R.string.edit, (d, w) -> {})
|
.setPositiveButton(R.string.ok, (d, w)->{})
|
||||||
.setNegativeButton(R.string.discard, (d, w) -> Nav.finish(this))
|
.setNegativeButton(R.string.discard, (d, w)->Nav.finish(this))
|
||||||
.show();
|
.show();
|
||||||
else new M3AlertDialogBuilder(getActivity())
|
else new M3AlertDialogBuilder(getActivity())
|
||||||
.setTitle(editingStatus != null ? R.string.sk_confirm_save_changes : R.string.sk_confirm_save_draft)
|
.setTitle(editingStatus!=null ? R.string.sk_confirm_save_changes : R.string.sk_confirm_save_draft)
|
||||||
.setPositiveButton(R.string.save, (d, w) -> {
|
.setPositiveButton(R.string.save, (d, w)->{
|
||||||
updateScheduledAt(scheduledAt == null ? getDraftInstant() : scheduledAt);
|
updateScheduledAt(scheduledAt==null ? getDraftInstant() : scheduledAt);
|
||||||
publish();
|
publish();
|
||||||
})
|
})
|
||||||
.setNegativeButton(R.string.discard, (d, w) -> Nav.finish(this))
|
.setNegativeButton(R.string.discard, (d, w)->Nav.finish(this))
|
||||||
.show();
|
.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1456,8 +1455,8 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void updateHeaders() {
|
private void updateHeaders() {
|
||||||
UiUtils.setExtraTextInfo(getContext(), selfExtraText, null, false, false, localOnly || statusVisibility==StatusPrivacy.LOCAL, null);
|
UiUtils.setExtraTextInfo(getContext(), selfExtraText, false, false, localOnly, null);
|
||||||
if (replyTo != null) UiUtils.setExtraTextInfo(getContext(), extraText, pronouns, true, false, replyTo.localOnly || replyTo.visibility==StatusPrivacy.LOCAL, replyTo.account);
|
if (replyTo != null) UiUtils.setExtraTextInfo(getContext(), extraText, true, false, replyTo.localOnly || replyTo.visibility==StatusPrivacy.LOCAL, replyTo.account);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void buildVisibilityPopup(View v){
|
private void buildVisibilityPopup(View v){
|
||||||
|
|||||||
@@ -63,7 +63,8 @@ public class ComposeImageDescriptionFragment extends MastodonToolbarFragment imp
|
|||||||
accountID=getArguments().getString("account");
|
accountID=getArguments().getString("account");
|
||||||
attachmentID=getArguments().getString("attachment");
|
attachmentID=getArguments().getString("attachment");
|
||||||
themeWrapper=new ContextThemeWrapper(activity, R.style.Theme_Mastodon_Dark);
|
themeWrapper=new ContextThemeWrapper(activity, R.style.Theme_Mastodon_Dark);
|
||||||
ColorPalette.palettes.get(AccountSessionManager.get(accountID).getLocalPreferences().color).apply(themeWrapper, GlobalUserPreferences.ThemePreference.DARK);
|
ColorPalette.palettes.get(AccountSessionManager.get(accountID).getLocalPreferences().getCurrentColor())
|
||||||
|
.apply(themeWrapper, GlobalUserPreferences.ThemePreference.DARK);
|
||||||
setTitle(R.string.add_alt_text);
|
setTitle(R.string.add_alt_text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -169,7 +169,7 @@ public class EditTimelinesFragment extends MastodonRecyclerFragment<TimelineDefi
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void updateOptionsMenu() {
|
private void updateOptionsMenu() {
|
||||||
if (getActivity() == null) return;
|
if(getActivity()==null) return;
|
||||||
optionsMenu.clear();
|
optionsMenu.clear();
|
||||||
timelineByMenuItem.clear();
|
timelineByMenuItem.clear();
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ public class FavoritedStatusListFragment extends StatusListFragment{
|
|||||||
.setCallback(new SimpleCallback<>(this){
|
.setCallback(new SimpleCallback<>(this){
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(HeaderPaginationList<Status> result){
|
public void onSuccess(HeaderPaginationList<Status> result){
|
||||||
if (getActivity() == null) return;
|
if(getActivity()==null) return;
|
||||||
if(result.nextPageUri!=null)
|
if(result.nextPageUri!=null)
|
||||||
nextMaxID=result.nextPageUri.getQueryParameter("max_id");
|
nextMaxID=result.nextPageUri.getQueryParameter("max_id");
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ import org.joinmastodon.android.api.requests.accounts.GetFollowRequests;
|
|||||||
import org.joinmastodon.android.api.session.AccountSessionManager;
|
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||||
import org.joinmastodon.android.model.Account;
|
import org.joinmastodon.android.model.Account;
|
||||||
import org.joinmastodon.android.model.HeaderPaginationList;
|
import org.joinmastodon.android.model.HeaderPaginationList;
|
||||||
import org.joinmastodon.android.model.Instance;
|
|
||||||
import org.joinmastodon.android.model.Relationship;
|
import org.joinmastodon.android.model.Relationship;
|
||||||
import org.joinmastodon.android.ui.OutlineProviders;
|
import org.joinmastodon.android.ui.OutlineProviders;
|
||||||
import org.joinmastodon.android.ui.text.HtmlParser;
|
import org.joinmastodon.android.ui.text.HtmlParser;
|
||||||
@@ -83,7 +82,7 @@ public class FollowRequestsListFragment extends MastodonRecyclerFragment<FollowR
|
|||||||
.setCallback(new SimpleCallback<>(this){
|
.setCallback(new SimpleCallback<>(this){
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(HeaderPaginationList<Account> result){
|
public void onSuccess(HeaderPaginationList<Account> result){
|
||||||
if (getActivity() == null) return;
|
if(getActivity()==null) return;
|
||||||
if(result.nextPageUri!=null)
|
if(result.nextPageUri!=null)
|
||||||
nextMaxID=result.nextPageUri.getQueryParameter("max_id");
|
nextMaxID=result.nextPageUri.getQueryParameter("max_id");
|
||||||
else
|
else
|
||||||
@@ -271,7 +270,7 @@ public class FollowRequestsListFragment extends MastodonRecyclerFragment<FollowR
|
|||||||
followingCount.setVisibility(item.account.followingCount < 0 ? View.GONE : View.VISIBLE);
|
followingCount.setVisibility(item.account.followingCount < 0 ? View.GONE : View.VISIBLE);
|
||||||
followingLabel.setVisibility(item.account.followingCount < 0 ? View.GONE : View.VISIBLE);
|
followingLabel.setVisibility(item.account.followingCount < 0 ? View.GONE : View.VISIBLE);
|
||||||
relationship=relationships.get(item.account.id);
|
relationship=relationships.get(item.account.id);
|
||||||
UiUtils.setExtraTextInfo(getContext(), null, findViewById(R.id.pronouns), true, false, false, item.account);
|
UiUtils.setExtraTextInfo(getContext(), null, true, false, false, item.account);
|
||||||
|
|
||||||
if(relationship==null || !relationship.followedBy){
|
if(relationship==null || !relationship.followedBy){
|
||||||
actionWrap.setVisibility(View.GONE);
|
actionWrap.setVisibility(View.GONE);
|
||||||
@@ -366,9 +365,9 @@ public class FollowRequestsListFragment extends MastodonRecyclerFragment<FollowR
|
|||||||
coverRequest=new UrlImageLoaderRequest(account.header, 1000, 1000);
|
coverRequest=new UrlImageLoaderRequest(account.header, 1000, 1000);
|
||||||
parsedBio=HtmlParser.parse(account.note, account.emojis, Collections.emptyList(), Collections.emptyList(), accountID);
|
parsedBio=HtmlParser.parse(account.note, account.emojis, Collections.emptyList(), Collections.emptyList(), accountID);
|
||||||
if(account.emojis.isEmpty()){
|
if(account.emojis.isEmpty()){
|
||||||
parsedName=account.displayName;
|
parsedName= account.getDisplayName();
|
||||||
}else{
|
}else{
|
||||||
parsedName=HtmlParser.parseCustomEmoji(account.displayName, account.emojis);
|
parsedName=HtmlParser.parseCustomEmoji(account.getDisplayName(), account.emojis);
|
||||||
emojiHelper.setText(new SpannableStringBuilder(parsedName).append(parsedBio));
|
emojiHelper.setText(new SpannableStringBuilder(parsedName).append(parsedBio));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ public class FollowedHashtagsFragment extends MastodonRecyclerFragment<Hashtag>
|
|||||||
.setCallback(new SimpleCallback<>(this){
|
.setCallback(new SimpleCallback<>(this){
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(HeaderPaginationList<Hashtag> result){
|
public void onSuccess(HeaderPaginationList<Hashtag> result){
|
||||||
if (getActivity() == null) return;
|
if(getActivity()==null) return;
|
||||||
if(result.nextPageUri!=null)
|
if(result.nextPageUri!=null)
|
||||||
nextMaxID=result.nextPageUri.getQueryParameter("max_id");
|
nextMaxID=result.nextPageUri.getQueryParameter("max_id");
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -91,14 +91,14 @@ public class HashtagTimelineFragment extends PinnableStatusListFragment{
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doLoadData(int offset, int count){
|
protected void doLoadData(int offset, int count){
|
||||||
currentRequest=new GetHashtagTimeline(hashtagName, offset==0 ? null : getMaxID(), null, count, any, all, none, localOnly, getLocalPrefs().timelineReplyVisibility)
|
currentRequest=new GetHashtagTimeline(hashtagName, getMaxID(), null, count, any, all, none, localOnly, getLocalPrefs().timelineReplyVisibility)
|
||||||
.setCallback(new SimpleCallback<>(this){
|
.setCallback(new SimpleCallback<>(this){
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(List<Status> result){
|
public void onSuccess(List<Status> result){
|
||||||
if(getActivity()==null) return;
|
if(getActivity()==null) return;
|
||||||
boolean empty=result.isEmpty();
|
boolean more=applyMaxID(result);
|
||||||
AccountSessionManager.get(accountID).filterStatuses(result, getFilterContext());
|
AccountSessionManager.get(accountID).filterStatuses(result, getFilterContext());
|
||||||
onDataLoaded(result, !empty);
|
onDataLoaded(result, more);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.exec(accountID);
|
.exec(accountID);
|
||||||
|
|||||||
@@ -32,7 +32,6 @@ import org.joinmastodon.android.events.NotificationsMarkerUpdatedEvent;
|
|||||||
import org.joinmastodon.android.events.StatusDisplaySettingsChangedEvent;
|
import org.joinmastodon.android.events.StatusDisplaySettingsChangedEvent;
|
||||||
import org.joinmastodon.android.fragments.discover.DiscoverFragment;
|
import org.joinmastodon.android.fragments.discover.DiscoverFragment;
|
||||||
import org.joinmastodon.android.model.Account;
|
import org.joinmastodon.android.model.Account;
|
||||||
import org.joinmastodon.android.model.Instance;
|
|
||||||
import org.joinmastodon.android.model.Notification;
|
import org.joinmastodon.android.model.Notification;
|
||||||
import org.joinmastodon.android.model.PaginatedResponse;
|
import org.joinmastodon.android.model.PaginatedResponse;
|
||||||
import org.joinmastodon.android.ui.AccountSwitcherSheet;
|
import org.joinmastodon.android.ui.AccountSwitcherSheet;
|
||||||
@@ -71,14 +70,12 @@ public class HomeFragment extends AppKitFragment implements OnBackPressedListene
|
|||||||
private TextView notificationsBadge;
|
private TextView notificationsBadge;
|
||||||
|
|
||||||
private String accountID;
|
private String accountID;
|
||||||
private boolean isAkkoma;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState){
|
public void onCreate(Bundle savedInstanceState){
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
accountID=getArguments().getString("account");
|
accountID=getArguments().getString("account");
|
||||||
setTitle(R.string.sk_app_name);
|
setTitle(R.string.sk_app_name);
|
||||||
isAkkoma = getInstance().map(Instance::isAkkoma).orElse(false);
|
|
||||||
|
|
||||||
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.N)
|
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.N)
|
||||||
setRetainInstance(true);
|
setRetainInstance(true);
|
||||||
@@ -89,7 +86,6 @@ public class HomeFragment extends AppKitFragment implements OnBackPressedListene
|
|||||||
homeTabFragment=new HomeTabFragment();
|
homeTabFragment=new HomeTabFragment();
|
||||||
homeTabFragment.setArguments(args);
|
homeTabFragment.setArguments(args);
|
||||||
args=new Bundle(args);
|
args=new Bundle(args);
|
||||||
args.putBoolean("disableDiscover", isAkkoma);
|
|
||||||
args.putBoolean("noAutoLoad", true);
|
args.putBoolean("noAutoLoad", true);
|
||||||
discoverFragment=new DiscoverFragment();
|
discoverFragment=new DiscoverFragment();
|
||||||
discoverFragment.setArguments(args);
|
discoverFragment.setArguments(args);
|
||||||
@@ -296,7 +292,7 @@ public class HomeFragment extends AppKitFragment implements OnBackPressedListene
|
|||||||
if(tab==R.id.tab_profile){
|
if(tab==R.id.tab_profile){
|
||||||
ArrayList<String> options=new ArrayList<>();
|
ArrayList<String> options=new ArrayList<>();
|
||||||
for(AccountSession session:AccountSessionManager.getInstance().getLoggedInAccounts()){
|
for(AccountSession session:AccountSessionManager.getInstance().getLoggedInAccounts()){
|
||||||
options.add(session.self.displayName+"\n("+session.self.username+"@"+session.domain+")");
|
options.add(session.self.getDisplayName()+"\n("+session.self.username+"@"+session.domain+")");
|
||||||
}
|
}
|
||||||
new AccountSwitcherSheet(getActivity(), this).show();
|
new AccountSwitcherSheet(getActivity(), this).show();
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -233,21 +233,25 @@ public class HomeTabFragment extends MastodonToolbarFragment implements Scrollab
|
|||||||
|
|
||||||
ViewTreeObserver vto = getToolbar().getViewTreeObserver();
|
ViewTreeObserver vto = getToolbar().getViewTreeObserver();
|
||||||
if (vto.isAlive()) {
|
if (vto.isAlive()) {
|
||||||
vto.addOnGlobalLayoutListener(() -> {
|
vto.addOnGlobalLayoutListener(()->{
|
||||||
Toolbar t = getToolbar();
|
Toolbar t=getToolbar();
|
||||||
if (t == null) return;
|
if(t==null) return;
|
||||||
int toolbarWidth = t.getWidth();
|
int toolbarWidth=t.getWidth();
|
||||||
if (toolbarWidth == 0) return;
|
if(toolbarWidth==0) return;
|
||||||
|
|
||||||
int toolbarFrameWidth = toolbarFrame.getWidth();
|
int toolbarFrameWidth=toolbarFrame.getWidth();
|
||||||
int padding = toolbarWidth - toolbarFrameWidth;
|
int actionsWidth=toolbarWidth-toolbarFrameWidth;
|
||||||
FrameLayout parent = ((FrameLayout) toolbarShowNewPostsBtn.getParent());
|
// margin (4) + padding (12) + icon (24) + margin (8) + chevron (16) + padding (12)
|
||||||
if (padding == parent.getPaddingStart()) return;
|
int switcherWidth=V.dp(76);
|
||||||
|
FrameLayout parent=((FrameLayout) toolbarShowNewPostsBtn.getParent());
|
||||||
|
if(actionsWidth==parent.getPaddingStart()) return;
|
||||||
|
int paddingMax=Math.max(actionsWidth, switcherWidth);
|
||||||
|
int paddingEnd=(Math.max(0, switcherWidth-actionsWidth));
|
||||||
|
|
||||||
// toolbar frame goes from screen edge to beginning of right-aligned option buttons.
|
// toolbar frame goes from screen edge to beginning of right-aligned option buttons.
|
||||||
// centering button by applying the same space on the left
|
// centering button by applying the same space on the left
|
||||||
parent.setPaddingRelative(padding, 0, 0, 0);
|
parent.setPaddingRelative(paddingMax, 0, paddingEnd, 0);
|
||||||
toolbarShowNewPostsBtn.setMaxWidth(toolbarWidth - padding * 2);
|
toolbarShowNewPostsBtn.setMaxWidth(toolbarWidth-paddingMax*2);
|
||||||
|
|
||||||
switcher.setPivotX(V.dp(28)); // padding + half of icon
|
switcher.setPivotX(V.dp(28)); // padding + half of icon
|
||||||
switcher.setPivotY(switcher.getHeight() / 2f);
|
switcher.setPivotY(switcher.getHeight() / 2f);
|
||||||
@@ -287,7 +291,7 @@ public class HomeTabFragment extends MastodonToolbarFragment implements Scrollab
|
|||||||
new GetAnnouncements(false).setCallback(new Callback<>() {
|
new GetAnnouncements(false).setCallback(new Callback<>() {
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(List<Announcement> result) {
|
public void onSuccess(List<Announcement> result) {
|
||||||
if (getActivity() == null) return;
|
if(getActivity()==null) return;
|
||||||
if (result.stream().anyMatch(a -> !a.read)) {
|
if (result.stream().anyMatch(a -> !a.read)) {
|
||||||
announcementsBadged = true;
|
announcementsBadged = true;
|
||||||
announcements.setVisible(false);
|
announcements.setVisible(false);
|
||||||
@@ -381,7 +385,7 @@ public class HomeTabFragment extends MastodonToolbarFragment implements Scrollab
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void updateOverflowMenu() {
|
private void updateOverflowMenu() {
|
||||||
if (getActivity() == null) return;
|
if(getActivity()==null) return;
|
||||||
Menu m = overflowPopup.getMenu();
|
Menu m = overflowPopup.getMenu();
|
||||||
m.clear();
|
m.clear();
|
||||||
overflowPopup.inflate(R.menu.home_overflow);
|
overflowPopup.inflate(R.menu.home_overflow);
|
||||||
@@ -400,9 +404,8 @@ public class HomeTabFragment extends MastodonToolbarFragment implements Scrollab
|
|||||||
addListsToOverflowMenu();
|
addListsToOverflowMenu();
|
||||||
addHashtagsToOverflowMenu();
|
addHashtagsToOverflowMenu();
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P && !UiUtils.isEMUI()) {
|
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.P && !UiUtils.isEMUI())
|
||||||
m.setGroupDividerEnabled(true);
|
m.setGroupDividerEnabled(true);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import java.util.List;
|
|||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import me.grishka.appkit.api.Callback;
|
import me.grishka.appkit.api.Callback;
|
||||||
import me.grishka.appkit.api.ErrorResponse;
|
import me.grishka.appkit.api.ErrorResponse;
|
||||||
@@ -60,7 +61,7 @@ public class HomeTimelineFragment extends StatusListFragment {
|
|||||||
maxID=result.maxID;
|
maxID=result.maxID;
|
||||||
AccountSessionManager.get(accountID).filterStatuses(result.items, getFilterContext());
|
AccountSessionManager.get(accountID).filterStatuses(result.items, getFilterContext());
|
||||||
onDataLoaded(result.items, !empty);
|
onDataLoaded(result.items, !empty);
|
||||||
if(result.isFromCache())
|
if(result.isFromCache() && GlobalUserPreferences.loadNewPosts)
|
||||||
loadNewPosts();
|
loadNewPosts();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -73,7 +74,7 @@ public class HomeTimelineFragment extends StatusListFragment {
|
|||||||
list.addOnScrollListener(new RecyclerView.OnScrollListener(){
|
list.addOnScrollListener(new RecyclerView.OnScrollListener(){
|
||||||
@Override
|
@Override
|
||||||
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy){
|
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy){
|
||||||
if(parent != null && parent.isNewPostsBtnShown() && list.getChildAdapterPosition(list.getChildAt(0))<=getMainAdapterOffset()){
|
if(parent!=null && parent.isNewPostsBtnShown() && list.getChildAdapterPosition(list.getChildAt(0))<=getMainAdapterOffset()){
|
||||||
parent.hideNewPostsButton();
|
parent.hideNewPostsButton();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -86,7 +87,7 @@ public class HomeTimelineFragment extends StatusListFragment {
|
|||||||
if(!getArguments().getBoolean("noAutoLoad")){
|
if(!getArguments().getBoolean("noAutoLoad")){
|
||||||
if(!loaded && !dataLoading){
|
if(!loaded && !dataLoading){
|
||||||
loadData();
|
loadData();
|
||||||
}else if(!dataLoading){
|
}else if(!dataLoading && GlobalUserPreferences.loadNewPosts){
|
||||||
loadNewPosts();
|
loadNewPosts();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -116,46 +117,54 @@ public class HomeTimelineFragment extends StatusListFragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void onStatusCreated(Status status){
|
public void onStatusCreated(Status status){
|
||||||
|
if(status.reblog!=null) return;
|
||||||
prependItems(Collections.singletonList(status), true);
|
prependItems(Collections.singletonList(status), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadNewPosts(){
|
private void loadNewPosts(){
|
||||||
if (!GlobalUserPreferences.loadNewPosts) return;
|
|
||||||
dataLoading=true;
|
dataLoading=true;
|
||||||
|
// we only care about the data that was actually retrieved from the timeline api since
|
||||||
|
// user-created statuses are probably in the wrong position
|
||||||
|
List<Status> dataFromTimeline=data.stream().filter(s->!s.fromStatusCreated).collect(Collectors.toList());
|
||||||
// The idea here is that we request the timeline such that if there are fewer than `limit` posts,
|
// The idea here is that we request the timeline such that if there are fewer than `limit` posts,
|
||||||
// we'll get the currently topmost post as last in the response. This way we know there's no gap
|
// we'll get the currently topmost post as last in the response. This way we know there's no gap
|
||||||
// between the existing and newly loaded parts of the timeline.
|
// between the existing and newly loaded parts of the timeline.
|
||||||
String sinceID=data.size()>1 ? data.get(1).id : "1";
|
String sinceID=dataFromTimeline.size()>1 ? dataFromTimeline.get(1).id : "1";
|
||||||
currentRequest=new GetHomeTimeline(null, null, 20, sinceID, getLocalPrefs().timelineReplyVisibility)
|
currentRequest=new GetHomeTimeline(null, null, 20, sinceID, getLocalPrefs().timelineReplyVisibility)
|
||||||
.setCallback(new Callback<>(){
|
.setCallback(new Callback<>(){
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(List<Status> result){
|
public void onSuccess(List<Status> result){
|
||||||
currentRequest=null;
|
currentRequest=null;
|
||||||
dataLoading=false;
|
dataLoading=false;
|
||||||
|
refreshDone();
|
||||||
if(result.isEmpty() || getActivity()==null)
|
if(result.isEmpty() || getActivity()==null)
|
||||||
return;
|
return;
|
||||||
Status last=result.get(result.size()-1);
|
Status last=result.get(result.size()-1);
|
||||||
List<Status> toAdd;
|
List<Status> toAdd;
|
||||||
if(!data.isEmpty() && last.id.equals(data.get(0).id)){ // This part intersects with the existing one
|
if(!dataFromTimeline.isEmpty() && last.id.equals(dataFromTimeline.get(0).id)){ // This part intersects with the existing one
|
||||||
toAdd=result.subList(0, result.size()-1); // Remove the already known last post
|
toAdd=new ArrayList<>(result.subList(0, result.size()-1)); // Remove the already known last post
|
||||||
}else{
|
}else{
|
||||||
result.get(result.size()-1).hasGapAfter=true;
|
last.hasGapAfter=last.id;
|
||||||
toAdd=result;
|
toAdd=result;
|
||||||
}
|
}
|
||||||
List<Status> toAddUnfiltered=new ArrayList<>(toAdd);
|
if(!toAdd.isEmpty())
|
||||||
|
AccountSessionManager.getInstance().getAccount(accountID).getCacheController().putHomeTimeline(new ArrayList<>(toAdd), false);
|
||||||
|
// removing statuses that come up as duplicates (hopefully only posts and boosts that were locally created
|
||||||
|
// and thus were already prepended to the timeline earlier)
|
||||||
|
List<String> existingIds=data.stream().map(Status::getID).collect(Collectors.toList());
|
||||||
|
toAdd.removeIf(s->existingIds.contains(s.getID()));
|
||||||
AccountSessionManager.get(accountID).filterStatuses(toAdd, getFilterContext());
|
AccountSessionManager.get(accountID).filterStatuses(toAdd, getFilterContext());
|
||||||
if(!toAdd.isEmpty()){
|
if(!toAdd.isEmpty()){
|
||||||
prependItems(toAdd, true);
|
prependItems(toAdd, true);
|
||||||
if(parent != null && GlobalUserPreferences.showNewPostsButton) parent.showNewPostsButton();
|
if(parent != null && GlobalUserPreferences.showNewPostsButton) parent.showNewPostsButton();
|
||||||
}
|
}
|
||||||
if(toAddUnfiltered.isEmpty())
|
|
||||||
AccountSessionManager.getInstance().getAccount(accountID).getCacheController().putHomeTimeline(toAddUnfiltered, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onError(ErrorResponse error){
|
public void onError(ErrorResponse error){
|
||||||
currentRequest=null;
|
currentRequest=null;
|
||||||
dataLoading=false;
|
dataLoading=false;
|
||||||
|
refreshDone();
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.exec(accountID);
|
.exec(accountID);
|
||||||
@@ -173,10 +182,10 @@ public class HomeTimelineFragment extends StatusListFragment {
|
|||||||
gap.loading=true;
|
gap.loading=true;
|
||||||
dataLoading=true;
|
dataLoading=true;
|
||||||
|
|
||||||
String maxID = null;
|
String maxID=null;
|
||||||
String minID = null;
|
String minID=null;
|
||||||
if (downwards) {
|
if (downwards) {
|
||||||
maxID = item.getItemID();
|
maxID=item.getItem().getMaxID();
|
||||||
} else {
|
} else {
|
||||||
int gapPos=displayItems.indexOf(gap);
|
int gapPos=displayItems.indexOf(gap);
|
||||||
StatusDisplayItem nextItem=displayItems.get(gapPos + 1);
|
StatusDisplayItem nextItem=displayItems.get(gapPos + 1);
|
||||||
@@ -193,15 +202,17 @@ public class HomeTimelineFragment extends StatusListFragment {
|
|||||||
int gapPos=displayItems.indexOf(gap);
|
int gapPos=displayItems.indexOf(gap);
|
||||||
if(gapPos==-1)
|
if(gapPos==-1)
|
||||||
return;
|
return;
|
||||||
|
AccountSessionManager.get(accountID).filterStatuses(result, getFilterContext());
|
||||||
if(result.isEmpty()){
|
if(result.isEmpty()){
|
||||||
displayItems.remove(gapPos);
|
displayItems.remove(gapPos);
|
||||||
adapter.notifyItemRemoved(getMainAdapterOffset()+gapPos);
|
adapter.notifyItemRemoved(getMainAdapterOffset()+gapPos);
|
||||||
Status gapStatus=getStatusByID(gap.parentID);
|
Status gapStatus=getStatusByID(gap.parentID);
|
||||||
if(gapStatus!=null){
|
if(gapStatus!=null){
|
||||||
gapStatus.hasGapAfter=false;
|
gapStatus.hasGapAfter=null;
|
||||||
AccountSessionManager.getInstance().getAccount(accountID).getCacheController().putHomeTimeline(Collections.singletonList(gapStatus), false);
|
AccountSessionManager.getInstance().getAccount(accountID).getCacheController().putHomeTimeline(Collections.singletonList(gapStatus), false);
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
|
// TODO: refactor this code. it's too long. incomprehensible, even
|
||||||
if(downwards) {
|
if(downwards) {
|
||||||
Set<String> idsBelowGap=new HashSet<>();
|
Set<String> idsBelowGap=new HashSet<>();
|
||||||
boolean belowGap=false;
|
boolean belowGap=false;
|
||||||
@@ -211,7 +222,7 @@ public class HomeTimelineFragment extends StatusListFragment {
|
|||||||
idsBelowGap.add(s.id);
|
idsBelowGap.add(s.id);
|
||||||
}else if(s.id.equals(gap.parentID)){
|
}else if(s.id.equals(gap.parentID)){
|
||||||
belowGap=true;
|
belowGap=true;
|
||||||
s.hasGapAfter=false;
|
s.hasGapAfter=null;
|
||||||
AccountSessionManager.getInstance().getAccount(accountID).getCacheController().putHomeTimeline(Collections.singletonList(s), false);
|
AccountSessionManager.getInstance().getAccount(accountID).getCacheController().putHomeTimeline(Collections.singletonList(s), false);
|
||||||
}else{
|
}else{
|
||||||
gapPostIndex++;
|
gapPostIndex++;
|
||||||
@@ -224,7 +235,8 @@ public class HomeTimelineFragment extends StatusListFragment {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if(endIndex==result.size()){
|
if(endIndex==result.size()){
|
||||||
result.get(result.size()-1).hasGapAfter=true;
|
Status last=result.get(result.size()-1);
|
||||||
|
last.hasGapAfter=last.id;
|
||||||
}else{
|
}else{
|
||||||
result=result.subList(0, endIndex);
|
result=result.subList(0, endIndex);
|
||||||
}
|
}
|
||||||
@@ -269,7 +281,7 @@ public class HomeTimelineFragment extends StatusListFragment {
|
|||||||
.filter(s->Objects.equals(s.id, gap.parentID))
|
.filter(s->Objects.equals(s.id, gap.parentID))
|
||||||
.findFirst();
|
.findFirst();
|
||||||
if (gapStatus.isPresent()) {
|
if (gapStatus.isPresent()) {
|
||||||
gapStatus.get().hasGapAfter=false;
|
gapStatus.get().hasGapAfter=null;
|
||||||
AccountSessionManager.getInstance().getAccount(accountID).getCacheController().putHomeTimeline(Collections.singletonList(gapStatus.get()), false);
|
AccountSessionManager.getInstance().getAccount(accountID).getCacheController().putHomeTimeline(Collections.singletonList(gapStatus.get()), false);
|
||||||
}
|
}
|
||||||
targetList.clear();
|
targetList.clear();
|
||||||
@@ -320,7 +332,7 @@ public class HomeTimelineFragment extends StatusListFragment {
|
|||||||
currentRequest=null;
|
currentRequest=null;
|
||||||
dataLoading=false;
|
dataLoading=false;
|
||||||
}
|
}
|
||||||
if (parent != null) parent.hideNewPostsButton();
|
if(parent!=null) parent.hideNewPostsButton();
|
||||||
super.onRefresh();
|
super.onRefresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ public class ListTimelineFragment extends PinnableStatusListFragment {
|
|||||||
new GetList(listID).setCallback(new Callback<>() {
|
new GetList(listID).setCallback(new Callback<>() {
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(ListTimeline listTimeline) {
|
public void onSuccess(ListTimeline listTimeline) {
|
||||||
if (getActivity() == null) return;
|
if(getActivity()==null) return;
|
||||||
// TODO: save updated info
|
// TODO: save updated info
|
||||||
if (!listTimeline.title.equals(listTitle)) setTitle(listTimeline.title);
|
if (!listTimeline.title.equals(listTitle)) setTitle(listTimeline.title);
|
||||||
if (listTimeline.repliesPolicy != null && !listTimeline.repliesPolicy.equals(repliesPolicy)) {
|
if (listTimeline.repliesPolicy != null && !listTimeline.repliesPolicy.equals(repliesPolicy)) {
|
||||||
@@ -100,7 +100,7 @@ public class ListTimelineFragment extends PinnableStatusListFragment {
|
|||||||
new UpdateList(listID, newTitle, editor.isExclusive(), editor.getRepliesPolicy()).setCallback(new Callback<>() {
|
new UpdateList(listID, newTitle, editor.isExclusive(), editor.getRepliesPolicy()).setCallback(new Callback<>() {
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(ListTimeline list) {
|
public void onSuccess(ListTimeline list) {
|
||||||
if (getActivity() == null) return;
|
if(getActivity()==null) return;
|
||||||
setTitle(list.title);
|
setTitle(list.title);
|
||||||
listTitle = list.title;
|
listTitle = list.title;
|
||||||
repliesPolicy = list.repliesPolicy;
|
repliesPolicy = list.repliesPolicy;
|
||||||
@@ -133,14 +133,14 @@ public class ListTimelineFragment extends PinnableStatusListFragment {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doLoadData(int offset, int count) {
|
protected void doLoadData(int offset, int count) {
|
||||||
currentRequest=new GetListTimeline(listID, offset==0 ? null : getMaxID(), null, count, null, getLocalPrefs().timelineReplyVisibility)
|
currentRequest=new GetListTimeline(listID, getMaxID(), null, count, null, getLocalPrefs().timelineReplyVisibility)
|
||||||
.setCallback(new SimpleCallback<>(this) {
|
.setCallback(new SimpleCallback<>(this) {
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(List<Status> result) {
|
public void onSuccess(List<Status> result) {
|
||||||
if(getActivity()==null) return;
|
if(getActivity()==null) return;
|
||||||
boolean empty=result.isEmpty();
|
boolean more=applyMaxID(result);
|
||||||
AccountSessionManager.get(accountID).filterStatuses(result, getFilterContext());
|
AccountSessionManager.get(accountID).filterStatuses(result, getFilterContext());
|
||||||
onDataLoaded(result, !empty);
|
onDataLoaded(result, more);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.exec(accountID);
|
.exec(accountID);
|
||||||
|
|||||||
@@ -140,7 +140,7 @@ public class ListsFragment extends MastodonRecyclerFragment<ListTimeline> implem
|
|||||||
.setCallback(new SimpleCallback<>(this) {
|
.setCallback(new SimpleCallback<>(this) {
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(List<ListTimeline> lists) {
|
public void onSuccess(List<ListTimeline> lists) {
|
||||||
if (getActivity() == null) return;
|
if(getActivity()==null) return;
|
||||||
for (ListTimeline l : lists) userInListBefore.put(l.id, true);
|
for (ListTimeline l : lists) userInListBefore.put(l.id, true);
|
||||||
userInList.putAll(userInListBefore);
|
userInList.putAll(userInListBefore);
|
||||||
if (profileAccountId == null || !lists.isEmpty()) onDataLoaded(lists, false);
|
if (profileAccountId == null || !lists.isEmpty()) onDataLoaded(lists, false);
|
||||||
@@ -149,7 +149,7 @@ public class ListsFragment extends MastodonRecyclerFragment<ListTimeline> implem
|
|||||||
currentRequest=new GetLists().setCallback(new SimpleCallback<>(ListsFragment.this) {
|
currentRequest=new GetLists().setCallback(new SimpleCallback<>(ListsFragment.this) {
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(List<ListTimeline> allLists) {
|
public void onSuccess(List<ListTimeline> allLists) {
|
||||||
if (getActivity() == null) return;
|
if(getActivity()==null) return;
|
||||||
List<ListTimeline> newLists = new ArrayList<>();
|
List<ListTimeline> newLists = new ArrayList<>();
|
||||||
for (ListTimeline l : allLists) {
|
for (ListTimeline l : allLists) {
|
||||||
if (lists.stream().noneMatch(e -> e.id.equals(l.id))) newLists.add(l);
|
if (lists.stream().noneMatch(e -> e.id.equals(l.id))) newLists.add(l);
|
||||||
|
|||||||
@@ -254,7 +254,7 @@ public class NotificationsFragment extends MastodonToolbarFragment implements Sc
|
|||||||
new GetFollowRequests(null, 1).setCallback(new Callback<>() {
|
new GetFollowRequests(null, 1).setCallback(new Callback<>() {
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(HeaderPaginationList<Account> accounts) {
|
public void onSuccess(HeaderPaginationList<Account> accounts) {
|
||||||
if (getActivity() == null) return;
|
if(getActivity()==null) return;
|
||||||
getToolbar().getMenu().findItem(R.id.follow_requests).setVisible(!accounts.isEmpty());
|
getToolbar().getMenu().findItem(R.id.follow_requests).setVisible(!accounts.isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -238,7 +238,7 @@ public class NotificationsListFragment extends BaseStatusListFragment<Notificati
|
|||||||
continue;
|
continue;
|
||||||
Status contentStatus=ntf.status.getContentStatus();
|
Status contentStatus=ntf.status.getContentStatus();
|
||||||
if(contentStatus.poll!=null && contentStatus.poll.id.equals(ev.poll.id)){
|
if(contentStatus.poll!=null && contentStatus.poll.id.equals(ev.poll.id)){
|
||||||
updatePoll(ntf.id, ntf.status, ev.poll);
|
updatePoll(ntf.id, contentStatus, ev.poll);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -482,7 +482,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
|||||||
.setCallback(new SimpleCallback<>(this){
|
.setCallback(new SimpleCallback<>(this){
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(Account result){
|
public void onSuccess(Account result){
|
||||||
if (getActivity() == null) return;
|
if(getActivity()==null) return;
|
||||||
onAccountLoaded(result);
|
onAccountLoaded(result);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -621,14 +621,14 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
|||||||
|
|
||||||
@SuppressLint("SetTextI18n")
|
@SuppressLint("SetTextI18n")
|
||||||
private void bindHeaderView(){
|
private void bindHeaderView(){
|
||||||
setTitle(account.displayName);
|
setTitle(account.getDisplayName());
|
||||||
setSubtitle(getResources().getQuantityString(R.plurals.x_posts, (int)(account.statusesCount%1000), account.statusesCount));
|
setSubtitle(getResources().getQuantityString(R.plurals.x_posts, (int)(account.statusesCount%1000), account.statusesCount));
|
||||||
ViewImageLoader.load(avatar, null, new UrlImageLoaderRequest(
|
ViewImageLoader.load(avatar, null, new UrlImageLoaderRequest(
|
||||||
TextUtils.isEmpty(account.avatar) ? getSession().getDefaultAvatarUrl() :
|
TextUtils.isEmpty(account.avatar) ? getSession().getDefaultAvatarUrl() :
|
||||||
GlobalUserPreferences.playGifs ? account.avatar : account.avatarStatic,
|
GlobalUserPreferences.playGifs ? account.avatar : account.avatarStatic,
|
||||||
V.dp(100), V.dp(100)));
|
V.dp(100), V.dp(100)));
|
||||||
ViewImageLoader.load(cover, null, new UrlImageLoaderRequest(GlobalUserPreferences.playGifs ? account.header : account.headerStatic, 1000, 1000));
|
ViewImageLoader.load(cover, null, new UrlImageLoaderRequest(GlobalUserPreferences.playGifs ? account.header : account.headerStatic, 1000, 1000));
|
||||||
SpannableStringBuilder ssb=new SpannableStringBuilder(account.displayName);
|
SpannableStringBuilder ssb=new SpannableStringBuilder(account.getDisplayName());
|
||||||
if(AccountSessionManager.get(accountID).getLocalPreferences().customEmojiInNames)
|
if(AccountSessionManager.get(accountID).getLocalPreferences().customEmojiInNames)
|
||||||
HtmlParser.parseCustomEmoji(ssb, account.emojis);
|
HtmlParser.parseCustomEmoji(ssb, account.emojis);
|
||||||
name.setText(ssb);
|
name.setText(ssb);
|
||||||
@@ -755,20 +755,21 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
|||||||
boolean hasMultipleAccounts = AccountSessionManager.getInstance().getLoggedInAccounts().size() > 1;
|
boolean hasMultipleAccounts = AccountSessionManager.getInstance().getLoggedInAccounts().size() > 1;
|
||||||
MenuItem openWithAccounts = menu.findItem(R.id.open_with_account);
|
MenuItem openWithAccounts = menu.findItem(R.id.open_with_account);
|
||||||
openWithAccounts.setVisible(hasMultipleAccounts);
|
openWithAccounts.setVisible(hasMultipleAccounts);
|
||||||
SubMenu accountsMenu = openWithAccounts.getSubMenu();
|
SubMenu accountsMenu=openWithAccounts.getSubMenu();
|
||||||
if (hasMultipleAccounts) {
|
if(hasMultipleAccounts){
|
||||||
accountsMenu.clear();
|
accountsMenu.clear();
|
||||||
UiUtils.populateAccountsMenu(accountID, accountsMenu, s-> UiUtils.openURL(
|
UiUtils.populateAccountsMenu(accountID, accountsMenu, s-> UiUtils.openURL(
|
||||||
getActivity(), s.getID(), account.url, false
|
getActivity(), s.getID(), account.url, false
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
menu.findItem(R.id.share).setTitle(R.string.share_user);
|
|
||||||
if(isOwnProfile) {
|
if(isOwnProfile) {
|
||||||
if (isInstancePixelfed()) menu.findItem(R.id.scheduled).setVisible(false);
|
if (isInstancePixelfed()) menu.findItem(R.id.scheduled).setVisible(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
MenuItem mute = menu.findItem(R.id.mute);
|
menu.findItem(R.id.manage_user_lists).setTitle(getString(R.string.sk_lists_with_user, account.getShortUsername()));
|
||||||
|
MenuItem mute=menu.findItem(R.id.mute);
|
||||||
mute.setTitle(getString(relationship.muting ? R.string.unmute_user : R.string.mute_user, account.getShortUsername()));
|
mute.setTitle(getString(relationship.muting ? R.string.unmute_user : R.string.mute_user, account.getShortUsername()));
|
||||||
mute.setIcon(relationship.muting ? R.drawable.ic_fluent_speaker_0_24_regular : R.drawable.ic_fluent_speaker_off_24_regular);
|
mute.setIcon(relationship.muting ? R.drawable.ic_fluent_speaker_0_24_regular : R.drawable.ic_fluent_speaker_off_24_regular);
|
||||||
UiUtils.insetPopupMenuIcon(getContext(), mute);
|
UiUtils.insetPopupMenuIcon(getContext(), mute);
|
||||||
@@ -776,19 +777,22 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
|||||||
menu.findItem(R.id.report).setTitle(getString(R.string.report_user, account.getShortUsername()));
|
menu.findItem(R.id.report).setTitle(getString(R.string.report_user, account.getShortUsername()));
|
||||||
menu.findItem(R.id.manage_user_lists).setVisible(relationship.following);
|
menu.findItem(R.id.manage_user_lists).setVisible(relationship.following);
|
||||||
menu.findItem(R.id.soft_block).setVisible(relationship.followedBy && !relationship.following);
|
menu.findItem(R.id.soft_block).setVisible(relationship.followedBy && !relationship.following);
|
||||||
|
MenuItem hideBoosts=menu.findItem(R.id.hide_boosts);
|
||||||
if (relationship.following) {
|
if (relationship.following) {
|
||||||
MenuItem hideBoosts = menu.findItem(R.id.hide_boosts);
|
|
||||||
hideBoosts.setTitle(getString(relationship.showingReblogs ? R.string.hide_boosts_from_user : R.string.show_boosts_from_user, account.getShortUsername()));
|
hideBoosts.setTitle(getString(relationship.showingReblogs ? R.string.hide_boosts_from_user : R.string.show_boosts_from_user, account.getShortUsername()));
|
||||||
hideBoosts.setIcon(relationship.showingReblogs ? R.drawable.ic_fluent_arrow_repeat_all_off_24_regular : R.drawable.ic_fluent_arrow_repeat_all_24_regular);
|
hideBoosts.setIcon(relationship.showingReblogs ? R.drawable.ic_fluent_arrow_repeat_all_off_24_regular : R.drawable.ic_fluent_arrow_repeat_all_24_regular);
|
||||||
UiUtils.insetPopupMenuIcon(getContext(), hideBoosts);
|
UiUtils.insetPopupMenuIcon(getContext(), hideBoosts);
|
||||||
menu.findItem(R.id.manage_user_lists).setTitle(getString(R.string.sk_lists_with_user, account.getShortUsername()));
|
hideBoosts.setVisible(true);
|
||||||
} else {
|
} else {
|
||||||
menu.findItem(R.id.hide_boosts).setVisible(false);
|
hideBoosts.setVisible(false);
|
||||||
|
}
|
||||||
|
MenuItem blockDomain=menu.findItem(R.id.block_domain);
|
||||||
|
if(!account.isLocal()){
|
||||||
|
blockDomain.setTitle(getString(relationship.domainBlocking ? R.string.unblock_domain : R.string.block_domain, account.getDomain()));
|
||||||
|
blockDomain.setVisible(true);
|
||||||
|
}else{
|
||||||
|
blockDomain.setVisible(false);
|
||||||
}
|
}
|
||||||
if(!account.isLocal())
|
|
||||||
menu.findItem(R.id.block_domain).setTitle(getString(relationship.domainBlocking ? R.string.unblock_domain : R.string.block_domain, account.getDomain()));
|
|
||||||
else
|
|
||||||
menu.findItem(R.id.block_domain).setVisible(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -800,11 +804,11 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
|||||||
intent.putExtra(Intent.EXTRA_TEXT, account.url);
|
intent.putExtra(Intent.EXTRA_TEXT, account.url);
|
||||||
startActivity(Intent.createChooser(intent, item.getTitle()));
|
startActivity(Intent.createChooser(intent, item.getTitle()));
|
||||||
}else if(id==R.id.mute){
|
}else if(id==R.id.mute){
|
||||||
confirmToggleMuted();
|
UiUtils.confirmToggleMuteUser(getActivity(), accountID, account, relationship.muting, this::updateRelationship);
|
||||||
}else if(id==R.id.block){
|
}else if(id==R.id.block){
|
||||||
confirmToggleBlocked();
|
UiUtils.confirmToggleBlockUser(getActivity(), accountID, account, relationship.blocking, this::updateRelationship);
|
||||||
}else if(id==R.id.soft_block){
|
}else if(id==R.id.soft_block){
|
||||||
confirmSoftBlockUser();
|
UiUtils.confirmSoftBlockUser(getActivity(), accountID, account, this::updateRelationship);
|
||||||
}else if(id==R.id.report){
|
}else if(id==R.id.report){
|
||||||
Bundle args=new Bundle();
|
Bundle args=new Bundle();
|
||||||
args.putString("account", accountID);
|
args.putString("account", accountID);
|
||||||
@@ -894,7 +898,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void updateRelationship(){
|
private void updateRelationship(){
|
||||||
if (getActivity() == null) return;
|
if(getActivity()==null) return;
|
||||||
invalidateOptionsMenu();
|
invalidateOptionsMenu();
|
||||||
actionButton.setVisibility(View.VISIBLE);
|
actionButton.setVisibility(View.VISIBLE);
|
||||||
notifyButton.setVisibility(relationship.following ? View.VISIBLE : View.GONE);
|
notifyButton.setVisibility(relationship.following ? View.VISIBLE : View.GONE);
|
||||||
@@ -1101,7 +1105,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
|||||||
updateMetadataHeight();
|
updateMetadataHeight();
|
||||||
|
|
||||||
Toolbar toolbar=getToolbar();
|
Toolbar toolbar=getToolbar();
|
||||||
Drawable close=getToolbarContext().getDrawable(R.drawable.ic_baseline_close_24).mutate();
|
Drawable close=getToolbarContext().getDrawable(R.drawable.ic_fluent_dismiss_24_regular).mutate();
|
||||||
close.setTint(UiUtils.getThemeColor(getToolbarContext(), R.attr.colorM3OnSurfaceVariant));
|
close.setTint(UiUtils.getThemeColor(getToolbarContext(), R.attr.colorM3OnSurfaceVariant));
|
||||||
toolbar.setNavigationIcon(close);
|
toolbar.setNavigationIcon(close);
|
||||||
toolbar.setNavigationContentDescription(R.string.discard);
|
toolbar.setNavigationContentDescription(R.string.discard);
|
||||||
@@ -1177,6 +1181,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
|||||||
imm.hideSoftInputFromWindow(content.getWindowToken(), 0);
|
imm.hideSoftInputFromWindow(content.getWindowToken(), 0);
|
||||||
V.setVisibilityAnimated(fab, View.VISIBLE);
|
V.setVisibilityAnimated(fab, View.VISIBLE);
|
||||||
bindHeaderView();
|
bindHeaderView();
|
||||||
|
V.setVisibilityAnimated(fab, View.VISIBLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void saveAndExitEditMode(){
|
private void saveAndExitEditMode(){
|
||||||
@@ -1191,7 +1196,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
|||||||
savingEdits=false;
|
savingEdits=false;
|
||||||
account=result;
|
account=result;
|
||||||
AccountSessionManager.getInstance().updateAccountInfo(accountID, account);
|
AccountSessionManager.getInstance().updateAccountInfo(accountID, account);
|
||||||
if (getActivity() == null) return;
|
if(getActivity()==null) return;
|
||||||
exitEditMode();
|
exitEditMode();
|
||||||
setActionProgressVisible(false);
|
setActionProgressVisible(false);
|
||||||
}
|
}
|
||||||
@@ -1206,18 +1211,6 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
|||||||
.exec(accountID);
|
.exec(accountID);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void confirmToggleMuted(){
|
|
||||||
UiUtils.confirmToggleMuteUser(getActivity(), accountID, account, relationship.muting, this::updateRelationship);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void confirmToggleBlocked(){
|
|
||||||
UiUtils.confirmToggleBlockUser(getActivity(), accountID, account, relationship.blocking, this::updateRelationship);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void confirmSoftBlockUser(){
|
|
||||||
UiUtils.confirmSoftBlockUser(getActivity(), accountID, account, this::updateRelationship);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateRelationship(Relationship r){
|
private void updateRelationship(Relationship r){
|
||||||
relationship=r;
|
relationship=r;
|
||||||
updateRelationship();
|
updateRelationship();
|
||||||
|
|||||||
@@ -119,6 +119,15 @@ public class ScheduledStatusListFragment extends BaseStatusListFragment<Schedule
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onShown(){
|
||||||
|
super.onShown();
|
||||||
|
// because, for some reason, when navigating back from compose fragment,
|
||||||
|
// match_parent would otherwise be incorrect (leaving a gap for the keyboard
|
||||||
|
// where there is none)
|
||||||
|
list.post(list::requestLayout);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doLoadData(int offset, int count){
|
protected void doLoadData(int offset, int count){
|
||||||
currentRequest=new GetScheduledStatuses(offset==0 ? null : nextMaxID, count)
|
currentRequest=new GetScheduledStatuses(offset==0 ? null : nextMaxID, count)
|
||||||
@@ -129,7 +138,7 @@ public class ScheduledStatusListFragment extends BaseStatusListFragment<Schedule
|
|||||||
nextMaxID=result.nextPageUri.getQueryParameter("max_id");
|
nextMaxID=result.nextPageUri.getQueryParameter("max_id");
|
||||||
else
|
else
|
||||||
nextMaxID=null;
|
nextMaxID=null;
|
||||||
if (getActivity() == null) return;
|
if(getActivity()==null) return;
|
||||||
onDataLoaded(result, nextMaxID!=null);
|
onDataLoaded(result, nextMaxID!=null);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -9,10 +9,12 @@ import com.squareup.otto.Subscribe;
|
|||||||
|
|
||||||
import org.joinmastodon.android.E;
|
import org.joinmastodon.android.E;
|
||||||
import org.joinmastodon.android.GlobalUserPreferences;
|
import org.joinmastodon.android.GlobalUserPreferences;
|
||||||
|
import org.joinmastodon.android.api.CacheController;
|
||||||
import org.joinmastodon.android.api.session.AccountLocalPreferences;
|
import org.joinmastodon.android.api.session.AccountLocalPreferences;
|
||||||
import org.joinmastodon.android.api.session.AccountSessionManager;
|
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||||
import org.joinmastodon.android.events.EmojiReactionsUpdatedEvent;
|
import org.joinmastodon.android.events.EmojiReactionsUpdatedEvent;
|
||||||
import org.joinmastodon.android.events.PollUpdatedEvent;
|
import org.joinmastodon.android.events.PollUpdatedEvent;
|
||||||
|
import org.joinmastodon.android.events.ReblogDeletedEvent;
|
||||||
import org.joinmastodon.android.events.RemoveAccountPostsEvent;
|
import org.joinmastodon.android.events.RemoveAccountPostsEvent;
|
||||||
import org.joinmastodon.android.events.StatusCountersUpdatedEvent;
|
import org.joinmastodon.android.events.StatusCountersUpdatedEvent;
|
||||||
import org.joinmastodon.android.events.StatusCreatedEvent;
|
import org.joinmastodon.android.events.StatusCreatedEvent;
|
||||||
@@ -23,12 +25,18 @@ import org.joinmastodon.android.model.Status;
|
|||||||
import org.joinmastodon.android.ui.displayitems.EmojiReactionsStatusDisplayItem;
|
import org.joinmastodon.android.ui.displayitems.EmojiReactionsStatusDisplayItem;
|
||||||
import org.joinmastodon.android.ui.displayitems.ExtendedFooterStatusDisplayItem;
|
import org.joinmastodon.android.ui.displayitems.ExtendedFooterStatusDisplayItem;
|
||||||
import org.joinmastodon.android.ui.displayitems.FooterStatusDisplayItem;
|
import org.joinmastodon.android.ui.displayitems.FooterStatusDisplayItem;
|
||||||
|
import org.joinmastodon.android.ui.displayitems.GapStatusDisplayItem;
|
||||||
import org.joinmastodon.android.ui.displayitems.StatusDisplayItem;
|
import org.joinmastodon.android.ui.displayitems.StatusDisplayItem;
|
||||||
import org.joinmastodon.android.ui.displayitems.TextStatusDisplayItem;
|
import org.joinmastodon.android.ui.displayitems.TextStatusDisplayItem;
|
||||||
import org.parceler.Parcels;
|
import org.parceler.Parcels;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.function.BiPredicate;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
import java.util.function.Supplier;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
@@ -142,12 +150,12 @@ public abstract class StatusListFragment extends BaseStatusListFragment<Status>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Status getContentStatusByID(String id){
|
public Status getContentStatusByID(String id){
|
||||||
Status s=getStatusByID(id);
|
Status s=getStatusByID(id);
|
||||||
return s==null ? null : s.getContentStatus();
|
return s==null ? null : s.getContentStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Status getStatusByID(String id){
|
public Status getStatusByID(String id){
|
||||||
for(Status s:data){
|
for(Status s:data){
|
||||||
if(s.id.equals(id)){
|
if(s.id.equals(id)){
|
||||||
return s;
|
return s;
|
||||||
@@ -174,41 +182,73 @@ public abstract class StatusListFragment extends BaseStatusListFragment<Status>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void removeStatus(Status status){
|
private boolean removeStatusDisplayItems(String parentID, int firstIndex, int ancestorFirstIndex, int ancestorLastIndex){
|
||||||
data.remove(status);
|
|
||||||
preloadedData.remove(status);
|
|
||||||
int index=-1, ancestorFirstIndex = -1, ancestorLastIndex = -1;
|
|
||||||
for(int i=0;i<displayItems.size();i++){
|
|
||||||
StatusDisplayItem item = displayItems.get(i);
|
|
||||||
if(status.id.equals(item.parentID)){
|
|
||||||
index=i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (item.parentID.equals(status.inReplyToId)) {
|
|
||||||
if (ancestorFirstIndex == -1) ancestorFirstIndex = i;
|
|
||||||
ancestorLastIndex = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// did we find an ancestor that is also the status' neighbor?
|
// did we find an ancestor that is also the status' neighbor?
|
||||||
if (ancestorFirstIndex >= 0 && ancestorLastIndex == index - 1) {
|
if(ancestorFirstIndex>=0 && ancestorLastIndex==firstIndex-1){
|
||||||
for (int i = ancestorFirstIndex; i <= ancestorLastIndex; i++) {
|
// update ancestor to have no descendant anymore
|
||||||
StatusDisplayItem item = displayItems.get(i);
|
displayItems.subList(ancestorFirstIndex, ancestorLastIndex+1).forEach(i->i.hasDescendantNeighbor=false);
|
||||||
// update ancestor to have no descendant anymore
|
adapter.notifyItemRangeChanged(ancestorFirstIndex, ancestorLastIndex-ancestorFirstIndex+1);
|
||||||
if (item.parentID.equals(status.inReplyToId)) item.hasDescendantNeighbor = false;
|
|
||||||
}
|
|
||||||
adapter.notifyItemRangeChanged(ancestorFirstIndex, ancestorLastIndex - ancestorFirstIndex + 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(index==-1)
|
if(firstIndex==-1) return false;
|
||||||
return;
|
int lastIndex=firstIndex;
|
||||||
int lastIndex;
|
while(lastIndex<displayItems.size()){
|
||||||
for(lastIndex=index;lastIndex<displayItems.size();lastIndex++){
|
StatusDisplayItem item=displayItems.get(lastIndex);
|
||||||
if(!displayItems.get(lastIndex).parentID.equals(status.id))
|
if(!item.parentID.equals(parentID) || item instanceof GapStatusDisplayItem) break;
|
||||||
break;
|
lastIndex++;
|
||||||
}
|
}
|
||||||
displayItems.subList(index, lastIndex).clear();
|
int count=lastIndex-firstIndex;
|
||||||
adapter.notifyItemRangeRemoved(index, lastIndex-index);
|
if(count<1) return false;
|
||||||
|
displayItems.subList(firstIndex, lastIndex).clear();
|
||||||
|
adapter.notifyItemRangeRemoved(firstIndex, count);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void removeStatus(Status status){
|
||||||
|
final AccountSessionManager asm=AccountSessionManager.getInstance();
|
||||||
|
final CacheController cache=AccountSessionManager.get(accountID).getCacheController();
|
||||||
|
final boolean unReblogging=status.reblog!=null && asm.isSelf(accountID, status.account);
|
||||||
|
final Predicate<Status> isToBeRemovedReblog=item->item!=null && item.reblog!=null
|
||||||
|
&& item.reblog.id.equals(status.reblog.id)
|
||||||
|
&& asm.isSelf(accountID, item.account);
|
||||||
|
final BiPredicate<String, Supplier<String>> isToBeRemovedContent=(parentId, contentIdSupplier)->
|
||||||
|
parentId.equals(status.id) || contentIdSupplier.get().equals(status.id);
|
||||||
|
|
||||||
|
int ancestorFirstIndex=-1, ancestorLastIndex=-1;
|
||||||
|
for(int i=0;i<displayItems.size();i++){
|
||||||
|
StatusDisplayItem item=displayItems.get(i);
|
||||||
|
// we found a status that the to-be-removed status replies to!
|
||||||
|
// storing indices to maybe update its display items
|
||||||
|
if(item.parentID.equals(status.inReplyToId)){
|
||||||
|
if(ancestorFirstIndex==-1) ancestorFirstIndex=i;
|
||||||
|
ancestorLastIndex=i;
|
||||||
|
}
|
||||||
|
// if we're un-reblogging, we compare the reblogged status's id with the current status's
|
||||||
|
if(unReblogging
|
||||||
|
? isToBeRemovedReblog.test(getStatusByID(item.parentID))
|
||||||
|
: isToBeRemovedContent.test(item.parentID, item::getContentStatusID)){
|
||||||
|
// if statuses are removed from index i, the next iteration should be on the same index again
|
||||||
|
if(removeStatusDisplayItems(item.parentID, i, ancestorFirstIndex, ancestorLastIndex)) i--;
|
||||||
|
// resetting in case we find another occurrence of the same status that also has ancestors
|
||||||
|
// (we won't - unless the timeline is being especially weird)
|
||||||
|
ancestorFirstIndex=-1; ancestorLastIndex=-1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Consumer<List<Status>> removeStatusFromData=(list)->{
|
||||||
|
Iterator<Status> it=list.iterator();
|
||||||
|
while(it.hasNext()){
|
||||||
|
Status s=it.next();
|
||||||
|
if(unReblogging
|
||||||
|
? isToBeRemovedReblog.test(s)
|
||||||
|
: isToBeRemovedContent.test(s.id, s::getContentStatusID)){
|
||||||
|
it.remove();
|
||||||
|
cache.deleteStatus(s.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
removeStatusFromData.accept(data);
|
||||||
|
removeStatusFromData.accept(preloadedData);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -277,6 +317,22 @@ public abstract class StatusListFragment extends BaseStatusListFragment<Status>
|
|||||||
removeStatus(status);
|
removeStatus(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
public void onReblogDeleted(ReblogDeletedEvent ev){
|
||||||
|
AccountSessionManager asm=AccountSessionManager.getInstance();
|
||||||
|
if(!ev.accountID.equals(accountID))
|
||||||
|
return;
|
||||||
|
for(Status item : data){
|
||||||
|
boolean itemIsOwnReblog=item.reblog!=null
|
||||||
|
&& item.getContentStatusID().equals(ev.statusID)
|
||||||
|
&& asm.isSelf(accountID, item.account);
|
||||||
|
if(itemIsOwnReblog){
|
||||||
|
removeStatus(item);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Subscribe
|
@Subscribe
|
||||||
public void onStatusCreated(StatusCreatedEvent ev){
|
public void onStatusCreated(StatusCreatedEvent ev){
|
||||||
if(!ev.accountID.equals(accountID))
|
if(!ev.accountID.equals(accountID))
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ public class ThreadFragment extends StatusListFragment implements ProvidesAssist
|
|||||||
knownAccounts.put(inReplyToAccount.id, inReplyToAccount);
|
knownAccounts.put(inReplyToAccount.id, inReplyToAccount);
|
||||||
data.add(mainStatus);
|
data.add(mainStatus);
|
||||||
onAppendItems(Collections.singletonList(mainStatus));
|
onAppendItems(Collections.singletonList(mainStatus));
|
||||||
setTitle(HtmlParser.parseCustomEmoji(getString(R.string.post_from_user, mainStatus.account.displayName), mainStatus.account.emojis));
|
setTitle(HtmlParser.parseCustomEmoji(getString(R.string.post_from_user, mainStatus.account.getDisplayName()), mainStatus.account.emojis));
|
||||||
transitionFinished = getArguments().getBoolean("noTransition", false);
|
transitionFinished = getArguments().getBoolean("noTransition", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ public abstract class BaseAccountListFragment extends MastodonRecyclerFragment<A
|
|||||||
for(Relationship rel:result){
|
for(Relationship rel:result){
|
||||||
relationships.put(rel.id, rel);
|
relationships.put(rel.id, rel);
|
||||||
}
|
}
|
||||||
if (getActivity() == null) return;
|
if(getActivity()==null) return;
|
||||||
if(list==null)
|
if(list==null)
|
||||||
return;
|
return;
|
||||||
for(int i=0;i<list.getChildCount();i++){
|
for(int i=0;i<list.getChildCount();i++){
|
||||||
|
|||||||
@@ -133,7 +133,7 @@ public abstract class PaginatedAccountListFragment<T> extends BaseAccountListFra
|
|||||||
nextMaxID=result.nextPageUri.getQueryParameter("max_id");
|
nextMaxID=result.nextPageUri.getQueryParameter("max_id");
|
||||||
else
|
else
|
||||||
nextMaxID=null;
|
nextMaxID=null;
|
||||||
if (getActivity() == null) return;
|
if(getActivity()==null) return;
|
||||||
List<AccountViewModel> items = result.stream()
|
List<AccountViewModel> items = result.stream()
|
||||||
.filter(a -> d.size() > 1000 || d.stream()
|
.filter(a -> d.size() > 1000 || d.stream()
|
||||||
.noneMatch(i -> i.account.url.equals(a.url)))
|
.noneMatch(i -> i.account.url.equals(a.url)))
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ import me.grishka.appkit.utils.MergeRecyclerAdapter;
|
|||||||
|
|
||||||
public class BubbleTimelineFragment extends StatusListFragment {
|
public class BubbleTimelineFragment extends StatusListFragment {
|
||||||
private DiscoverInfoBannerHelper bannerHelper;
|
private DiscoverInfoBannerHelper bannerHelper;
|
||||||
private String maxID;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState){
|
public void onCreate(Bundle savedInstanceState){
|
||||||
@@ -35,15 +34,14 @@ public class BubbleTimelineFragment extends StatusListFragment {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doLoadData(int offset, int count){
|
protected void doLoadData(int offset, int count){
|
||||||
currentRequest=new GetBubbleTimeline(refreshing ? null : maxID, count, getLocalPrefs().timelineReplyVisibility)
|
currentRequest=new GetBubbleTimeline(getMaxID(), count, getLocalPrefs().timelineReplyVisibility)
|
||||||
.setCallback(new SimpleCallback<>(this){
|
.setCallback(new SimpleCallback<>(this){
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(List<Status> result){
|
public void onSuccess(List<Status> result){
|
||||||
if(getActivity()==null) return;
|
if(getActivity()==null) return;
|
||||||
boolean empty=result.isEmpty();
|
boolean more=applyMaxID(result);
|
||||||
if(!empty) maxID=result.get(result.size()-1).id;
|
|
||||||
AccountSessionManager.get(accountID).filterStatuses(result, getFilterContext());
|
AccountSessionManager.get(accountID).filterStatuses(result, getFilterContext());
|
||||||
onDataLoaded(result, !empty);
|
onDataLoaded(result, more);
|
||||||
bannerHelper.onBannerBecameVisible();
|
bannerHelper.onBannerBecameVisible();
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import android.graphics.Rect;
|
|||||||
import android.graphics.drawable.Animatable;
|
import android.graphics.drawable.Animatable;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.text.SpannableStringBuilder;
|
import android.text.SpannableStringBuilder;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
@@ -65,6 +66,8 @@ public class DiscoverAccountsFragment extends MastodonRecyclerFragment<DiscoverA
|
|||||||
public void onCreate(Bundle savedInstanceState){
|
public void onCreate(Bundle savedInstanceState){
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
accountID=getArguments().getString("account");
|
accountID=getArguments().getString("account");
|
||||||
|
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.N)
|
||||||
|
setRetainInstance(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -77,7 +80,7 @@ public class DiscoverAccountsFragment extends MastodonRecyclerFragment<DiscoverA
|
|||||||
.setCallback(new SimpleCallback<>(this){
|
.setCallback(new SimpleCallback<>(this){
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(List<FollowSuggestion> result){
|
public void onSuccess(List<FollowSuggestion> result){
|
||||||
if (getActivity() == null) return;
|
if(getActivity()==null) return;
|
||||||
onDataLoaded(result.stream().map(fs->new AccountWrapper(fs.account)).collect(Collectors.toList()), false);
|
onDataLoaded(result.stream().map(fs->new AccountWrapper(fs.account)).collect(Collectors.toList()), false);
|
||||||
loadRelationships();
|
loadRelationships();
|
||||||
}
|
}
|
||||||
@@ -112,7 +115,7 @@ public class DiscoverAccountsFragment extends MastodonRecyclerFragment<DiscoverA
|
|||||||
public void onSuccess(List<Relationship> result){
|
public void onSuccess(List<Relationship> result){
|
||||||
relationshipsRequest=null;
|
relationshipsRequest=null;
|
||||||
relationships=result.stream().collect(Collectors.toMap(rel->rel.id, Function.identity()));
|
relationships=result.stream().collect(Collectors.toMap(rel->rel.id, Function.identity()));
|
||||||
if (getActivity() == null) return;
|
if(getActivity()==null) return;
|
||||||
if(list==null)
|
if(list==null)
|
||||||
return;
|
return;
|
||||||
for(int i=0;i<list.getChildCount();i++){
|
for(int i=0;i<list.getChildCount();i++){
|
||||||
@@ -258,7 +261,7 @@ public class DiscoverAccountsFragment extends MastodonRecyclerFragment<DiscoverA
|
|||||||
followingCount.setVisibility(item.account.followingCount < 0 ? View.GONE : View.VISIBLE);
|
followingCount.setVisibility(item.account.followingCount < 0 ? View.GONE : View.VISIBLE);
|
||||||
followingLabel.setVisibility(item.account.followingCount < 0 ? View.GONE : View.VISIBLE);
|
followingLabel.setVisibility(item.account.followingCount < 0 ? View.GONE : View.VISIBLE);
|
||||||
relationship=relationships.get(item.account.id);
|
relationship=relationships.get(item.account.id);
|
||||||
UiUtils.setExtraTextInfo(getContext(), null, findViewById(R.id.pronouns), true, false, false, item.account);
|
UiUtils.setExtraTextInfo(getContext(), null, true, false, false, item.account);
|
||||||
|
|
||||||
if(relationship==null){
|
if(relationship==null){
|
||||||
actionWrap.setVisibility(View.GONE);
|
actionWrap.setVisibility(View.GONE);
|
||||||
@@ -327,9 +330,9 @@ public class DiscoverAccountsFragment extends MastodonRecyclerFragment<DiscoverA
|
|||||||
coverRequest=new UrlImageLoaderRequest(account.header, 1000, 1000);
|
coverRequest=new UrlImageLoaderRequest(account.header, 1000, 1000);
|
||||||
parsedBio=HtmlParser.parse(account.note, account.emojis, Collections.emptyList(), Collections.emptyList(), accountID);
|
parsedBio=HtmlParser.parse(account.note, account.emojis, Collections.emptyList(), Collections.emptyList(), accountID);
|
||||||
if(account.emojis.isEmpty()){
|
if(account.emojis.isEmpty()){
|
||||||
parsedName=account.displayName;
|
parsedName= account.getDisplayName();
|
||||||
}else{
|
}else{
|
||||||
parsedName=HtmlParser.parseCustomEmoji(account.displayName, account.emojis);
|
parsedName=HtmlParser.parseCustomEmoji(account.getDisplayName(), account.emojis);
|
||||||
emojiHelper.setText(new SpannableStringBuilder(parsedName).append(parsedBio));
|
emojiHelper.setText(new SpannableStringBuilder(parsedName).append(parsedBio));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,8 +13,10 @@ import android.widget.LinearLayout;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import org.joinmastodon.android.R;
|
import org.joinmastodon.android.R;
|
||||||
|
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||||
import org.joinmastodon.android.fragments.IsOnTop;
|
import org.joinmastodon.android.fragments.IsOnTop;
|
||||||
import org.joinmastodon.android.fragments.ScrollableToTop;
|
import org.joinmastodon.android.fragments.ScrollableToTop;
|
||||||
|
import org.joinmastodon.android.model.Instance;
|
||||||
import org.joinmastodon.android.model.SearchResult;
|
import org.joinmastodon.android.model.SearchResult;
|
||||||
import org.joinmastodon.android.ui.OutlineProviders;
|
import org.joinmastodon.android.ui.OutlineProviders;
|
||||||
import org.joinmastodon.android.ui.SimpleViewHolder;
|
import org.joinmastodon.android.ui.SimpleViewHolder;
|
||||||
@@ -96,8 +98,6 @@ public class DiscoverFragment extends AppKitFragment implements ScrollableToTop,
|
|||||||
pager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback(){
|
pager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback(){
|
||||||
@Override
|
@Override
|
||||||
public void onPageSelected(int position){
|
public void onPageSelected(int position){
|
||||||
if(position==0)
|
|
||||||
return;
|
|
||||||
Fragment _page=getFragmentForPage(position);
|
Fragment _page=getFragmentForPage(position);
|
||||||
if(_page instanceof BaseRecyclerFragment<?> page){
|
if(_page instanceof BaseRecyclerFragment<?> page){
|
||||||
if(!page.loaded && !page.isDataLoading())
|
if(!page.loaded && !page.isDataLoading())
|
||||||
@@ -157,7 +157,7 @@ public class DiscoverFragment extends AppKitFragment implements ScrollableToTop,
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
disableDiscover=getArguments().getBoolean("disableDiscover");
|
disableDiscover=AccountSessionManager.get(accountID).getInstance().map(Instance::isAkkoma).orElse(false);
|
||||||
searchView=view.findViewById(R.id.search_fragment);
|
searchView=view.findViewById(R.id.search_fragment);
|
||||||
if(searchFragment==null){
|
if(searchFragment==null){
|
||||||
searchFragment=new SearchFragment();
|
searchFragment=new SearchFragment();
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ package org.joinmastodon.android.fragments.discover;
|
|||||||
|
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.text.TextUtils;
|
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
@@ -14,14 +14,12 @@ import org.joinmastodon.android.api.requests.trends.GetTrendingLinks;
|
|||||||
import org.joinmastodon.android.fragments.ScrollableToTop;
|
import org.joinmastodon.android.fragments.ScrollableToTop;
|
||||||
import org.joinmastodon.android.model.Card;
|
import org.joinmastodon.android.model.Card;
|
||||||
import org.joinmastodon.android.model.viewmodel.CardViewModel;
|
import org.joinmastodon.android.model.viewmodel.CardViewModel;
|
||||||
import org.joinmastodon.android.ui.DividerItemDecoration;
|
|
||||||
import org.joinmastodon.android.ui.OutlineProviders;
|
import org.joinmastodon.android.ui.OutlineProviders;
|
||||||
import org.joinmastodon.android.ui.drawables.BlurhashCrossfadeDrawable;
|
import org.joinmastodon.android.ui.drawables.BlurhashCrossfadeDrawable;
|
||||||
import org.joinmastodon.android.ui.utils.DiscoverInfoBannerHelper;
|
import org.joinmastodon.android.ui.utils.DiscoverInfoBannerHelper;
|
||||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@@ -32,11 +30,9 @@ import me.grishka.appkit.api.SimpleCallback;
|
|||||||
import me.grishka.appkit.fragments.BaseRecyclerFragment;
|
import me.grishka.appkit.fragments.BaseRecyclerFragment;
|
||||||
import me.grishka.appkit.imageloader.ImageLoaderRecyclerAdapter;
|
import me.grishka.appkit.imageloader.ImageLoaderRecyclerAdapter;
|
||||||
import me.grishka.appkit.imageloader.ImageLoaderViewHolder;
|
import me.grishka.appkit.imageloader.ImageLoaderViewHolder;
|
||||||
import me.grishka.appkit.imageloader.ListImageLoaderAdapter;
|
|
||||||
import me.grishka.appkit.imageloader.ListImageLoaderWrapper;
|
import me.grishka.appkit.imageloader.ListImageLoaderWrapper;
|
||||||
import me.grishka.appkit.imageloader.RecyclerViewDelegate;
|
import me.grishka.appkit.imageloader.RecyclerViewDelegate;
|
||||||
import me.grishka.appkit.imageloader.requests.ImageLoaderRequest;
|
import me.grishka.appkit.imageloader.requests.ImageLoaderRequest;
|
||||||
import me.grishka.appkit.imageloader.requests.UrlImageLoaderRequest;
|
|
||||||
import me.grishka.appkit.utils.BindableViewHolder;
|
import me.grishka.appkit.utils.BindableViewHolder;
|
||||||
import me.grishka.appkit.utils.MergeRecyclerAdapter;
|
import me.grishka.appkit.utils.MergeRecyclerAdapter;
|
||||||
import me.grishka.appkit.utils.SingleViewRecyclerAdapter;
|
import me.grishka.appkit.utils.SingleViewRecyclerAdapter;
|
||||||
@@ -60,6 +56,8 @@ public class DiscoverNewsFragment extends BaseRecyclerFragment<CardViewModel> im
|
|||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
accountID=getArguments().getString("account");
|
accountID=getArguments().getString("account");
|
||||||
bannerHelper=new DiscoverInfoBannerHelper(DiscoverInfoBannerHelper.BannerType.TRENDING_LINKS, accountID);
|
bannerHelper=new DiscoverInfoBannerHelper(DiscoverInfoBannerHelper.BannerType.TRENDING_LINKS, accountID);
|
||||||
|
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.N)
|
||||||
|
setRetainInstance(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import me.grishka.appkit.utils.MergeRecyclerAdapter;
|
|||||||
|
|
||||||
public class DiscoverPostsFragment extends StatusListFragment{
|
public class DiscoverPostsFragment extends StatusListFragment{
|
||||||
private DiscoverInfoBannerHelper bannerHelper;
|
private DiscoverInfoBannerHelper bannerHelper;
|
||||||
|
private int offset;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState){
|
public void onCreate(Bundle savedInstanceState){
|
||||||
@@ -26,13 +27,15 @@ public class DiscoverPostsFragment extends StatusListFragment{
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doLoadData(int offset, int count){
|
protected void doLoadData(int o, int count){
|
||||||
|
if(refreshing) offset=0;
|
||||||
currentRequest=new GetTrendingStatuses(offset, count)
|
currentRequest=new GetTrendingStatuses(offset, count)
|
||||||
.setCallback(new SimpleCallback<>(this){
|
.setCallback(new SimpleCallback<>(this){
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(List<Status> result){
|
public void onSuccess(List<Status> result){
|
||||||
if(getActivity()==null) return;
|
if(getActivity()==null) return;
|
||||||
boolean empty=result.isEmpty();
|
boolean empty=result.isEmpty();
|
||||||
|
offset+=result.size();
|
||||||
AccountSessionManager.get(accountID).filterStatuses(result, getFilterContext());
|
AccountSessionManager.get(accountID).filterStatuses(result, getFilterContext());
|
||||||
onDataLoaded(result, !empty);
|
onDataLoaded(result, !empty);
|
||||||
bannerHelper.onBannerBecameVisible();
|
bannerHelper.onBannerBecameVisible();
|
||||||
|
|||||||
@@ -29,15 +29,14 @@ public class FederatedTimelineFragment extends StatusListFragment{
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doLoadData(int offset, int count){
|
protected void doLoadData(int offset, int count){
|
||||||
currentRequest=new GetPublicTimeline(false, false, refreshing ? null : maxID, count, getLocalPrefs().timelineReplyVisibility)
|
currentRequest=new GetPublicTimeline(false, false, getMaxID(), count, getLocalPrefs().timelineReplyVisibility)
|
||||||
.setCallback(new SimpleCallback<>(this){
|
.setCallback(new SimpleCallback<>(this){
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(List<Status> result){
|
public void onSuccess(List<Status> result){
|
||||||
if(getActivity()==null) return;
|
if(getActivity()==null) return;
|
||||||
boolean empty=result.isEmpty();
|
boolean more=applyMaxID(result);
|
||||||
if(!empty) maxID=result.get(result.size()-1).id;
|
|
||||||
AccountSessionManager.get(accountID).filterStatuses(result, getFilterContext());
|
AccountSessionManager.get(accountID).filterStatuses(result, getFilterContext());
|
||||||
onDataLoaded(result, !empty);
|
onDataLoaded(result, more);
|
||||||
bannerHelper.onBannerBecameVisible();
|
bannerHelper.onBannerBecameVisible();
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -29,15 +29,14 @@ public class LocalTimelineFragment extends StatusListFragment{
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doLoadData(int offset, int count){
|
protected void doLoadData(int offset, int count){
|
||||||
currentRequest=new GetPublicTimeline(true, false, refreshing ? null : maxID, count, getLocalPrefs().timelineReplyVisibility)
|
currentRequest=new GetPublicTimeline(true, false, getMaxID(), count, getLocalPrefs().timelineReplyVisibility)
|
||||||
.setCallback(new SimpleCallback<>(this){
|
.setCallback(new SimpleCallback<>(this){
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(List<Status> result){
|
public void onSuccess(List<Status> result){
|
||||||
if(getActivity()==null) return;
|
if(getActivity()==null) return;
|
||||||
boolean empty=result.isEmpty();
|
boolean more=applyMaxID(result);
|
||||||
if(!empty) maxID=result.get(result.size()-1).id;
|
|
||||||
AccountSessionManager.get(accountID).filterStatuses(result, getFilterContext());
|
AccountSessionManager.get(accountID).filterStatuses(result, getFilterContext());
|
||||||
onDataLoaded(result, !empty);
|
onDataLoaded(result, more);
|
||||||
bannerHelper.onBannerBecameVisible();
|
bannerHelper.onBannerBecameVisible();
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ import java.util.stream.Collectors;
|
|||||||
import me.grishka.appkit.Nav;
|
import me.grishka.appkit.Nav;
|
||||||
import me.grishka.appkit.api.Callback;
|
import me.grishka.appkit.api.Callback;
|
||||||
import me.grishka.appkit.api.ErrorResponse;
|
import me.grishka.appkit.api.ErrorResponse;
|
||||||
|
import me.grishka.appkit.api.SimpleCallback;
|
||||||
import me.grishka.appkit.utils.V;
|
import me.grishka.appkit.utils.V;
|
||||||
|
|
||||||
public class SearchFragment extends BaseStatusListFragment<SearchResult>{
|
public class SearchFragment extends BaseStatusListFragment<SearchResult>{
|
||||||
@@ -142,7 +143,7 @@ public class SearchFragment extends BaseStatusListFragment<SearchResult>{
|
|||||||
}*/
|
}*/
|
||||||
int offset=_offset;
|
int offset=_offset;
|
||||||
currentRequest=new GetSearchResults(currentQuery, type, type==null, maxID, offset, type==null ? 0 : count)
|
currentRequest=new GetSearchResults(currentQuery, type, type==null, maxID, offset, type==null ? 0 : count)
|
||||||
.setCallback(new Callback<>(){
|
.setCallback(new SimpleCallback<>(this){
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(SearchResults result){
|
public void onSuccess(SearchResults result){
|
||||||
ArrayList<SearchResult> results=new ArrayList<>();
|
ArrayList<SearchResult> results=new ArrayList<>();
|
||||||
@@ -165,16 +166,8 @@ public class SearchFragment extends BaseStatusListFragment<SearchResult>{
|
|||||||
unfilteredResults=results;
|
unfilteredResults=results;
|
||||||
onDataLoaded(filterSearchResults(results), type!=null && !results.isEmpty());
|
onDataLoaded(filterSearchResults(results), type!=null && !results.isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onError(ErrorResponse error){
|
|
||||||
currentRequest=null;
|
|
||||||
Activity a=getActivity();
|
|
||||||
if(a==null)
|
|
||||||
return;
|
|
||||||
error.showToast(a);
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
.setTimeout(180000) // 3 minutes (searches can take a long time)
|
||||||
.exec(accountID);
|
.exec(accountID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -115,7 +115,7 @@ public class SearchQueryFragment extends MastodonRecyclerFragment<SearchResultVi
|
|||||||
onDataLoaded(results.stream().map(sr->{
|
onDataLoaded(results.stream().map(sr->{
|
||||||
SearchResultViewModel vm=new SearchResultViewModel(sr, accountID, true);
|
SearchResultViewModel vm=new SearchResultViewModel(sr, accountID, true);
|
||||||
if(sr.type==SearchResult.Type.HASHTAG){
|
if(sr.type==SearchResult.Type.HASHTAG){
|
||||||
vm.hashtagItem.onClick=()->openHashtag(sr);
|
vm.hashtagItem.setOnClick(i->openHashtag(sr));
|
||||||
}
|
}
|
||||||
return vm;
|
return vm;
|
||||||
}).collect(Collectors.toList()), false);
|
}).collect(Collectors.toList()), false);
|
||||||
@@ -132,7 +132,7 @@ public class SearchQueryFragment extends MastodonRecyclerFragment<SearchResultVi
|
|||||||
.map(sr->{
|
.map(sr->{
|
||||||
SearchResultViewModel vm=new SearchResultViewModel(sr, accountID, false);
|
SearchResultViewModel vm=new SearchResultViewModel(sr, accountID, false);
|
||||||
if(sr.type==SearchResult.Type.HASHTAG){
|
if(sr.type==SearchResult.Type.HASHTAG){
|
||||||
vm.hashtagItem.onClick=()->openHashtag(sr);
|
vm.hashtagItem.setOnClick(i->openHashtag(sr));
|
||||||
}
|
}
|
||||||
return vm;
|
return vm;
|
||||||
})
|
})
|
||||||
@@ -429,11 +429,11 @@ public class SearchQueryFragment extends MastodonRecyclerFragment<SearchResultVi
|
|||||||
wrapSuicideDialog(()->deliverResult(currentQuery, null));
|
wrapSuicideDialog(()->deliverResult(currentQuery, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onOpenURLClick(){
|
private void onOpenURLClick(ListItem<?> item_){
|
||||||
UiUtils.openURL(getContext(), accountID, searchViewHelper.getQuery(), false);
|
UiUtils.openURL(getContext(), accountID, searchViewHelper.getQuery(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onGoToHashtagClick(){
|
private void onGoToHashtagClick(ListItem<?> item_){
|
||||||
wrapSuicideDialog(()->{
|
wrapSuicideDialog(()->{
|
||||||
String q=searchViewHelper.getQuery();
|
String q=searchViewHelper.getQuery();
|
||||||
if(q.startsWith("#"))
|
if(q.startsWith("#"))
|
||||||
@@ -442,7 +442,7 @@ public class SearchQueryFragment extends MastodonRecyclerFragment<SearchResultVi
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onGoToAccountClick(){
|
private void onGoToAccountClick(ListItem<?> item_){
|
||||||
String q=searchViewHelper.getQuery();
|
String q=searchViewHelper.getQuery();
|
||||||
if(!q.startsWith("@")){
|
if(!q.startsWith("@")){
|
||||||
q="@"+q;
|
q="@"+q;
|
||||||
@@ -459,11 +459,11 @@ public class SearchQueryFragment extends MastodonRecyclerFragment<SearchResultVi
|
|||||||
}).ifPresent(progress -> progress.wrapProgress((Activity) getContext(), R.string.loading, true));
|
}).ifPresent(progress -> progress.wrapProgress((Activity) getContext(), R.string.loading, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onGoToStatusSearchClick(){
|
private void onGoToStatusSearchClick(ListItem<?> item_){
|
||||||
wrapSuicideDialog(()->deliverResult(searchViewHelper.getQuery(), SearchResult.Type.STATUS));
|
wrapSuicideDialog(()->deliverResult(searchViewHelper.getQuery(), SearchResult.Type.STATUS));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onGoToAccountSearchClick(){
|
private void onGoToAccountSearchClick(ListItem<?> item_){
|
||||||
wrapSuicideDialog(()->deliverResult(searchViewHelper.getQuery(), SearchResult.Type.ACCOUNT));
|
wrapSuicideDialog(()->deliverResult(searchViewHelper.getQuery(), SearchResult.Type.ACCOUNT));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.joinmastodon.android.fragments.discover;
|
package org.joinmastodon.android.fragments.discover;
|
||||||
|
|
||||||
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
@@ -9,8 +10,6 @@ import org.joinmastodon.android.R;
|
|||||||
import org.joinmastodon.android.api.requests.trends.GetTrendingHashtags;
|
import org.joinmastodon.android.api.requests.trends.GetTrendingHashtags;
|
||||||
import org.joinmastodon.android.fragments.ScrollableToTop;
|
import org.joinmastodon.android.fragments.ScrollableToTop;
|
||||||
import org.joinmastodon.android.model.Hashtag;
|
import org.joinmastodon.android.model.Hashtag;
|
||||||
import org.joinmastodon.android.ui.DividerItemDecoration;
|
|
||||||
import org.joinmastodon.android.ui.utils.DiscoverInfoBannerHelper;
|
|
||||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||||
import org.joinmastodon.android.ui.views.HashtagChartView;
|
import org.joinmastodon.android.ui.views.HashtagChartView;
|
||||||
|
|
||||||
@@ -34,6 +33,8 @@ public class TrendingHashtagsFragment extends BaseRecyclerFragment<Hashtag> impl
|
|||||||
public void onCreate(Bundle savedInstanceState){
|
public void onCreate(Bundle savedInstanceState){
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
accountID=getArguments().getString("account");
|
accountID=getArguments().getString("account");
|
||||||
|
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.N)
|
||||||
|
setRetainInstance(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -83,9 +83,10 @@ public class CustomWelcomeFragment extends InstanceCatalogFragment {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void updateFilteredList(){
|
protected void updateFilteredList(){
|
||||||
boolean addFakeInstance = currentSearchQuery.length()>0 && currentSearchQuery.matches("^\\S+\\.[^\\.]+$");
|
String query=getCurrentSearchQuery();
|
||||||
|
boolean addFakeInstance=query.length()>0 && query.matches("^\\S+\\.[^\\.]+$");
|
||||||
if(addFakeInstance){
|
if(addFakeInstance){
|
||||||
fakeInstance.domain=fakeInstance.normalizedDomain=currentSearchQuery;
|
fakeInstance.domain=fakeInstance.normalizedDomain=query;
|
||||||
fakeInstance.description=getString(R.string.loading_instance);
|
fakeInstance.description=getString(R.string.loading_instance);
|
||||||
if(filteredData.size()>0 && filteredData.get(0)==fakeInstance){
|
if(filteredData.size()>0 && filteredData.get(0)==fakeInstance){
|
||||||
if(list.findViewHolderForAdapterPosition(1) instanceof InstanceViewHolder ivh){
|
if(list.findViewHolderForAdapterPosition(1) instanceof InstanceViewHolder ivh){
|
||||||
@@ -99,12 +100,12 @@ public class CustomWelcomeFragment extends InstanceCatalogFragment {
|
|||||||
}
|
}
|
||||||
ArrayList<CatalogInstance> prevData=new ArrayList<>(filteredData);
|
ArrayList<CatalogInstance> prevData=new ArrayList<>(filteredData);
|
||||||
filteredData.clear();
|
filteredData.clear();
|
||||||
if(currentSearchQuery.length()>0){
|
if(query.length()>0){
|
||||||
boolean foundExactMatch=false;
|
boolean foundExactMatch=false;
|
||||||
for(CatalogInstance inst:data){
|
for(CatalogInstance inst:data){
|
||||||
if(inst.normalizedDomain.contains(currentSearchQuery)){
|
if(inst.normalizedDomain.contains(query)){
|
||||||
filteredData.add(inst);
|
filteredData.add(inst);
|
||||||
if(inst.normalizedDomain.equals(currentSearchQuery))
|
if(inst.normalizedDomain.equals(query))
|
||||||
foundExactMatch=true;
|
foundExactMatch=true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -93,10 +93,10 @@ abstract class InstanceCatalogFragment extends MastodonRecyclerFragment<CatalogI
|
|||||||
currentSearchQuery=searchEdit.getText().toString().toLowerCase().trim();
|
currentSearchQuery=searchEdit.getText().toString().toLowerCase().trim();
|
||||||
updateFilteredList();
|
updateFilteredList();
|
||||||
searchEdit.removeCallbacks(searchDebouncer);
|
searchEdit.removeCallbacks(searchDebouncer);
|
||||||
Instance instance=instancesCache.get(normalizeInstanceDomain(currentSearchQuery));
|
Instance instance=instancesCache.get(normalizeInstanceDomain(getCurrentSearchQuery()));
|
||||||
if(instance==null){
|
if(instance==null){
|
||||||
showProgressDialog();
|
showProgressDialog();
|
||||||
loadInstanceInfo(currentSearchQuery, false);
|
loadInstanceInfo(getCurrentSearchQuery(), false);
|
||||||
}else{
|
}else{
|
||||||
proceedWithAuthOrSignup(instance);
|
proceedWithAuthOrSignup(instance);
|
||||||
}
|
}
|
||||||
@@ -106,7 +106,7 @@ abstract class InstanceCatalogFragment extends MastodonRecyclerFragment<CatalogI
|
|||||||
protected void onSearchChangedDebounced(){
|
protected void onSearchChangedDebounced(){
|
||||||
currentSearchQuery=searchEdit.getText().toString().toLowerCase().trim();
|
currentSearchQuery=searchEdit.getText().toString().toLowerCase().trim();
|
||||||
updateFilteredList();
|
updateFilteredList();
|
||||||
loadInstanceInfo(currentSearchQuery, false);
|
loadInstanceInfo(getCurrentSearchQuery(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected List<CatalogInstance> sortInstances(List<CatalogInstance> result){
|
protected List<CatalogInstance> sortInstances(List<CatalogInstance> result){
|
||||||
@@ -126,9 +126,16 @@ abstract class InstanceCatalogFragment extends MastodonRecyclerFragment<CatalogI
|
|||||||
instanceProgressDialog.show();
|
instanceProgressDialog.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected String getCurrentSearchQuery(){
|
||||||
|
String[] parts=currentSearchQuery.split("@");
|
||||||
|
return parts.length>0 ? parts[parts.length-1] : "";
|
||||||
|
}
|
||||||
|
|
||||||
protected String normalizeInstanceDomain(String _domain){
|
protected String normalizeInstanceDomain(String _domain){
|
||||||
if(TextUtils.isEmpty(_domain))
|
if(TextUtils.isEmpty(_domain))
|
||||||
return null;
|
return null;
|
||||||
|
String[] parts=_domain.split("@");
|
||||||
|
_domain=parts[parts.length - 1];
|
||||||
if(_domain.contains(":")){
|
if(_domain.contains(":")){
|
||||||
try{
|
try{
|
||||||
_domain=Uri.parse(_domain).getAuthority();
|
_domain=Uri.parse(_domain).getAuthority();
|
||||||
@@ -198,7 +205,7 @@ abstract class InstanceCatalogFragment extends MastodonRecyclerFragment<CatalogI
|
|||||||
instanceProgressDialog=null;
|
instanceProgressDialog=null;
|
||||||
proceedWithAuthOrSignup(result);
|
proceedWithAuthOrSignup(result);
|
||||||
}
|
}
|
||||||
if(Objects.equals(domain, currentSearchQuery) || Objects.equals(currentSearchQuery, redirects.get(domain)) || Objects.equals(currentSearchQuery, redirectsInverse.get(domain))){
|
if(Objects.equals(domain, getCurrentSearchQuery()) || Objects.equals(getCurrentSearchQuery(), redirects.get(domain)) || Objects.equals(getCurrentSearchQuery(), redirectsInverse.get(domain))){
|
||||||
boolean found=false;
|
boolean found=false;
|
||||||
for(CatalogInstance ci:filteredData){
|
for(CatalogInstance ci:filteredData){
|
||||||
if(ci.domain.equals(domain) && ci!=fakeInstance){
|
if(ci.domain.equals(domain) && ci!=fakeInstance){
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package org.joinmastodon.android.fragments.onboarding;
|
|||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Build;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ public class ReportAddPostsChoiceFragment extends StatusListFragment{
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doLoadData(int offset, int count){
|
protected void doLoadData(int offset, int count){
|
||||||
currentRequest=new GetAccountStatuses(reportAccount.id, offset>0 ? getMaxID() : null, null, count, GetAccountStatuses.Filter.OWN_POSTS_AND_REPLIES)
|
currentRequest=new GetAccountStatuses(reportAccount.id, getMaxID(), null, count, GetAccountStatuses.Filter.OWN_POSTS_AND_REPLIES)
|
||||||
.setCallback(new SimpleCallback<>(this){
|
.setCallback(new SimpleCallback<>(this){
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(List<Status> result){
|
public void onSuccess(List<Status> result){
|
||||||
@@ -104,8 +104,8 @@ public class ReportAddPostsChoiceFragment extends StatusListFragment{
|
|||||||
else
|
else
|
||||||
selectedIDs.add(id);
|
selectedIDs.add(id);
|
||||||
CheckableHeaderStatusDisplayItem.Holder holder=findHolderOfType(id, CheckableHeaderStatusDisplayItem.Holder.class);
|
CheckableHeaderStatusDisplayItem.Holder holder=findHolderOfType(id, CheckableHeaderStatusDisplayItem.Holder.class);
|
||||||
if(holder!=null)
|
if(holder!=null) holder.rebind();
|
||||||
holder.rebind();
|
else notifyItemChanged(id, CheckableHeaderStatusDisplayItem.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -34,7 +34,6 @@ import me.grishka.appkit.api.Callback;
|
|||||||
import me.grishka.appkit.api.ErrorResponse;
|
import me.grishka.appkit.api.ErrorResponse;
|
||||||
import me.grishka.appkit.imageloader.ViewImageLoader;
|
import me.grishka.appkit.imageloader.ViewImageLoader;
|
||||||
import me.grishka.appkit.imageloader.requests.UrlImageLoaderRequest;
|
import me.grishka.appkit.imageloader.requests.UrlImageLoaderRequest;
|
||||||
import me.grishka.appkit.utils.CubicBezierInterpolator;
|
|
||||||
import me.grishka.appkit.utils.V;
|
import me.grishka.appkit.utils.V;
|
||||||
|
|
||||||
public class ReportDoneFragment extends MastodonToolbarFragment{
|
public class ReportDoneFragment extends MastodonToolbarFragment{
|
||||||
@@ -227,7 +226,7 @@ public class ReportDoneFragment extends MastodonToolbarFragment{
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected int getNavigationIconDrawableResource(){
|
protected int getNavigationIconDrawableResource(){
|
||||||
return R.drawable.ic_baseline_close_24;
|
return R.drawable.ic_fluent_dismiss_24_regular;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ public class EditFilterFragment extends BaseSettingsFragment<Void> implements On
|
|||||||
durationItem=new ListItem<>(R.string.settings_filter_duration, 0, this::onDurationClick),
|
durationItem=new ListItem<>(R.string.settings_filter_duration, 0, this::onDurationClick),
|
||||||
wordsItem=new ListItem<>(R.string.settings_filter_muted_words, 0, this::onWordsClick),
|
wordsItem=new ListItem<>(R.string.settings_filter_muted_words, 0, this::onWordsClick),
|
||||||
contextItem=new ListItem<>(R.string.settings_filter_context, 0, this::onContextClick),
|
contextItem=new ListItem<>(R.string.settings_filter_context, 0, this::onContextClick),
|
||||||
cwItem=new CheckableListItem<>(R.string.settings_filter_show_cw, R.string.settings_filter_show_cw_explanation, CheckableListItem.Style.SWITCH, filter==null || filter.filterAction==FilterAction.WARN, ()->toggleCheckableItem(cwItem))
|
cwItem=new CheckableListItem<>(R.string.settings_filter_show_cw, R.string.settings_filter_show_cw_explanation, CheckableListItem.Style.SWITCH, filter==null || filter.filterAction==FilterAction.WARN, this::toggleCheckableItem)
|
||||||
));
|
));
|
||||||
|
|
||||||
if(filter!=null){
|
if(filter!=null){
|
||||||
@@ -113,7 +113,7 @@ public class EditFilterFragment extends BaseSettingsFragment<Void> implements On
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onDurationClick(){
|
private void onDurationClick(ListItem<Void> item_){
|
||||||
int[] durationOptions={
|
int[] durationOptions={
|
||||||
1800,
|
1800,
|
||||||
3600,
|
3600,
|
||||||
@@ -182,21 +182,21 @@ public class EditFilterFragment extends BaseSettingsFragment<Void> implements On
|
|||||||
alert.setOnDismissListener(dialog->callback.accept(null));
|
alert.setOnDismissListener(dialog->callback.accept(null));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onWordsClick(){
|
private void onWordsClick(ListItem<Void> item){
|
||||||
Bundle args=new Bundle();
|
Bundle args=new Bundle();
|
||||||
args.putString("account", accountID);
|
args.putString("account", accountID);
|
||||||
args.putParcelableArrayList("words", (ArrayList<? extends Parcelable>) keywords.stream().map(Parcels::wrap).collect(Collectors.toCollection(ArrayList::new)));
|
args.putParcelableArrayList("words", (ArrayList<? extends Parcelable>) keywords.stream().map(Parcels::wrap).collect(Collectors.toCollection(ArrayList::new)));
|
||||||
Nav.goForResult(getActivity(), FilterWordsFragment.class, args, WORDS_RESULT, this);
|
Nav.goForResult(getActivity(), FilterWordsFragment.class, args, WORDS_RESULT, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onContextClick(){
|
private void onContextClick(ListItem<Void> item){
|
||||||
Bundle args=new Bundle();
|
Bundle args=new Bundle();
|
||||||
args.putString("account", accountID);
|
args.putString("account", accountID);
|
||||||
args.putSerializable("context", context);
|
args.putSerializable("context", context);
|
||||||
Nav.goForResult(getActivity(), FilterContextFragment.class, args, CONTEXT_RESULT, this);
|
Nav.goForResult(getActivity(), FilterContextFragment.class, args, CONTEXT_RESULT, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onDeleteClick(){
|
private void onDeleteClick(ListItem<Void> item_){
|
||||||
AlertDialog alert=new M3AlertDialogBuilder(getActivity())
|
AlertDialog alert=new M3AlertDialogBuilder(getActivity())
|
||||||
.setTitle(getString(R.string.settings_delete_filter_title, filter.title))
|
.setTitle(getString(R.string.settings_delete_filter_title, filter.title))
|
||||||
.setMessage(R.string.settings_delete_filter_confirmation)
|
.setMessage(R.string.settings_delete_filter_confirmation)
|
||||||
|
|||||||
@@ -22,10 +22,9 @@ public class FilterContextFragment extends BaseSettingsFragment<FilterContext> i
|
|||||||
setTitle(R.string.settings_filter_context);
|
setTitle(R.string.settings_filter_context);
|
||||||
context=(EnumSet<FilterContext>) getArguments().getSerializable("context");
|
context=(EnumSet<FilterContext>) getArguments().getSerializable("context");
|
||||||
onDataLoaded(Arrays.stream(FilterContext.values()).map(c->{
|
onDataLoaded(Arrays.stream(FilterContext.values()).map(c->{
|
||||||
CheckableListItem<FilterContext> item=new CheckableListItem<>(c.getDisplayNameRes(), 0, CheckableListItem.Style.CHECKBOX, context.contains(c), null);
|
CheckableListItem<FilterContext> item=new CheckableListItem<>(c.getDisplayNameRes(), 0, CheckableListItem.Style.CHECKBOX, context.contains(c), this::toggleCheckableItem);
|
||||||
item.parentObject=c;
|
item.parentObject=c;
|
||||||
item.isEnabled=true;
|
item.isEnabled=true;
|
||||||
item.onClick=()->toggleCheckableItem(item);
|
|
||||||
return item;
|
return item;
|
||||||
}).collect(Collectors.toList()));
|
}).collect(Collectors.toList()));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,6 @@
|
|||||||
package org.joinmastodon.android.fragments.settings;
|
package org.joinmastodon.android.fragments.settings;
|
||||||
|
|
||||||
import android.animation.Animator;
|
|
||||||
import android.animation.AnimatorListenerAdapter;
|
|
||||||
import android.animation.IntEvaluator;
|
|
||||||
import android.animation.ObjectAnimator;
|
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
import android.graphics.drawable.Drawable;
|
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Parcelable;
|
import android.os.Parcelable;
|
||||||
@@ -27,6 +22,7 @@ import org.joinmastodon.android.model.FilterKeyword;
|
|||||||
import org.joinmastodon.android.model.viewmodel.CheckableListItem;
|
import org.joinmastodon.android.model.viewmodel.CheckableListItem;
|
||||||
import org.joinmastodon.android.model.viewmodel.ListItem;
|
import org.joinmastodon.android.model.viewmodel.ListItem;
|
||||||
import org.joinmastodon.android.ui.M3AlertDialogBuilder;
|
import org.joinmastodon.android.ui.M3AlertDialogBuilder;
|
||||||
|
import org.joinmastodon.android.ui.utils.ActionModeHelper;
|
||||||
import org.joinmastodon.android.ui.utils.SimpleTextWatcher;
|
import org.joinmastodon.android.ui.utils.SimpleTextWatcher;
|
||||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||||
import org.joinmastodon.android.ui.views.FloatingHintEditTextLayout;
|
import org.joinmastodon.android.ui.views.FloatingHintEditTextLayout;
|
||||||
@@ -37,7 +33,6 @@ import java.util.Collections;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import me.grishka.appkit.FragmentStackActivity;
|
|
||||||
import me.grishka.appkit.fragments.OnBackPressedListener;
|
import me.grishka.appkit.fragments.OnBackPressedListener;
|
||||||
import me.grishka.appkit.utils.V;
|
import me.grishka.appkit.utils.V;
|
||||||
|
|
||||||
@@ -60,7 +55,7 @@ public class FilterWordsFragment extends BaseSettingsFragment<FilterKeyword> imp
|
|||||||
FilterKeyword word=Parcels.unwrap(p);
|
FilterKeyword word=Parcels.unwrap(p);
|
||||||
ListItem<FilterKeyword> item=new ListItem<>(word.keyword, null, null, word);
|
ListItem<FilterKeyword> item=new ListItem<>(word.keyword, null, null, word);
|
||||||
item.isEnabled=true;
|
item.isEnabled=true;
|
||||||
item.onClick=()->onWordClick(item);
|
item.setOnClick(this::onWordClick);
|
||||||
return item;
|
return item;
|
||||||
}).collect(Collectors.toList()));
|
}).collect(Collectors.toList()));
|
||||||
setHasOptionsMenu(true);
|
setHasOptionsMenu(true);
|
||||||
@@ -97,7 +92,7 @@ public class FilterWordsFragment extends BaseSettingsFragment<FilterKeyword> imp
|
|||||||
public void onViewCreated(View view, Bundle savedInstanceState){
|
public void onViewCreated(View view, Bundle savedInstanceState){
|
||||||
super.onViewCreated(view, savedInstanceState);
|
super.onViewCreated(view, savedInstanceState);
|
||||||
fab=view.findViewById(R.id.fab);
|
fab=view.findViewById(R.id.fab);
|
||||||
fab.setImageResource(R.drawable.ic_add_24px);
|
fab.setImageResource(R.drawable.ic_fluent_add_24_regular);
|
||||||
fab.setContentDescription(getString(R.string.add_muted_word));
|
fab.setContentDescription(getString(R.string.add_muted_word));
|
||||||
fab.setOnClickListener(v->onFabClick());
|
fab.setOnClickListener(v->onFabClick());
|
||||||
}
|
}
|
||||||
@@ -114,7 +109,7 @@ public class FilterWordsFragment extends BaseSettingsFragment<FilterKeyword> imp
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater){
|
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater){
|
||||||
inflater.inflate(R.menu.settings_filter_words, menu);
|
inflater.inflate(R.menu.selectable_list, menu);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -174,7 +169,7 @@ public class FilterWordsFragment extends BaseSettingsFragment<FilterKeyword> imp
|
|||||||
w.keyword=input;
|
w.keyword=input;
|
||||||
ListItem<FilterKeyword> item=new ListItem<>(w.keyword, null, null, w);
|
ListItem<FilterKeyword> item=new ListItem<>(w.keyword, null, null, w);
|
||||||
item.isEnabled=true;
|
item.isEnabled=true;
|
||||||
item.onClick=()->onWordClick(item);
|
item.setOnClick(this::onWordClick);
|
||||||
data.add(item);
|
data.add(item);
|
||||||
itemsAdapter.notifyItemInserted(data.size()-1);
|
itemsAdapter.notifyItemInserted(data.size()-1);
|
||||||
}else{
|
}else{
|
||||||
@@ -228,29 +223,15 @@ public class FilterWordsFragment extends BaseSettingsFragment<FilterKeyword> imp
|
|||||||
return;
|
return;
|
||||||
V.setVisibilityAnimated(fab, View.GONE);
|
V.setVisibilityAnimated(fab, View.GONE);
|
||||||
|
|
||||||
actionMode=getActivity().startActionMode(new ActionMode.Callback(){
|
actionMode=ActionModeHelper.startActionMode(this, ()->elevationOnScrollListener.getCurrentStatusBarColor(), new ActionMode.Callback(){
|
||||||
@Override
|
@Override
|
||||||
public boolean onCreateActionMode(ActionMode mode, Menu menu){
|
public boolean onCreateActionMode(ActionMode mode, Menu menu){
|
||||||
ObjectAnimator anim=ObjectAnimator.ofInt(getActivity().getWindow(), "statusBarColor", elevationOnScrollListener.getCurrentStatusBarColor(), UiUtils.getThemeColor(getActivity(), R.attr.colorM3Primary));
|
|
||||||
anim.setEvaluator(new IntEvaluator(){
|
|
||||||
@Override
|
|
||||||
public Integer evaluate(float fraction, Integer startValue, Integer endValue){
|
|
||||||
return UiUtils.alphaBlendColors(startValue, endValue, fraction);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
anim.start();
|
|
||||||
((FragmentStackActivity) getActivity()).invalidateSystemBarColors(FilterWordsFragment.this);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onPrepareActionMode(ActionMode mode, Menu menu){
|
public boolean onPrepareActionMode(ActionMode mode, Menu menu){
|
||||||
mode.getMenuInflater().inflate(R.menu.settings_filter_words_action_mode, menu);
|
mode.getMenuInflater().inflate(R.menu.settings_filter_words_action_mode, menu);
|
||||||
for(int i=0;i<menu.size();i++){
|
|
||||||
Drawable icon=menu.getItem(i).getIcon().mutate();
|
|
||||||
icon.setTint(UiUtils.getThemeColor(getActivity(), R.attr.colorM3OnPrimary));
|
|
||||||
menu.getItem(i).setIcon(icon);
|
|
||||||
}
|
|
||||||
deleteItem=menu.findItem(R.id.delete);
|
deleteItem=menu.findItem(R.id.delete);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -266,21 +247,6 @@ public class FilterWordsFragment extends BaseSettingsFragment<FilterKeyword> imp
|
|||||||
@Override
|
@Override
|
||||||
public void onDestroyActionMode(ActionMode mode){
|
public void onDestroyActionMode(ActionMode mode){
|
||||||
leaveSelectionMode(true);
|
leaveSelectionMode(true);
|
||||||
ObjectAnimator anim=ObjectAnimator.ofInt(getActivity().getWindow(), "statusBarColor", UiUtils.getThemeColor(getActivity(), R.attr.colorM3Primary), elevationOnScrollListener.getCurrentStatusBarColor());
|
|
||||||
anim.setEvaluator(new IntEvaluator(){
|
|
||||||
@Override
|
|
||||||
public Integer evaluate(float fraction, Integer startValue, Integer endValue){
|
|
||||||
return UiUtils.alphaBlendColors(startValue, endValue, fraction);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
anim.addListener(new AnimatorListenerAdapter(){
|
|
||||||
@Override
|
|
||||||
public void onAnimationEnd(Animator animation){
|
|
||||||
getActivity().getWindow().setStatusBarColor(0);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
anim.start();
|
|
||||||
((FragmentStackActivity) getActivity()).invalidateSystemBarColors(FilterWordsFragment.this);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -289,7 +255,7 @@ public class FilterWordsFragment extends BaseSettingsFragment<FilterKeyword> imp
|
|||||||
ListItem<FilterKeyword> item=data.get(i);
|
ListItem<FilterKeyword> item=data.get(i);
|
||||||
CheckableListItem<FilterKeyword> newItem=new CheckableListItem<>(item.title, null, CheckableListItem.Style.CHECKBOX, selectAll, null);
|
CheckableListItem<FilterKeyword> newItem=new CheckableListItem<>(item.title, null, CheckableListItem.Style.CHECKBOX, selectAll, null);
|
||||||
newItem.isEnabled=true;
|
newItem.isEnabled=true;
|
||||||
newItem.onClick=()->onSelectionModeWordClick(newItem);
|
newItem.setOnClick(this::onSelectionModeWordClick);
|
||||||
newItem.parentObject=item.parentObject;
|
newItem.parentObject=item.parentObject;
|
||||||
if(selectAll)
|
if(selectAll)
|
||||||
selectedItems.add(newItem);
|
selectedItems.add(newItem);
|
||||||
@@ -313,7 +279,7 @@ public class FilterWordsFragment extends BaseSettingsFragment<FilterKeyword> imp
|
|||||||
ListItem<FilterKeyword> item=data.get(i);
|
ListItem<FilterKeyword> item=data.get(i);
|
||||||
ListItem<FilterKeyword> newItem=new ListItem<>(item.title, null, null);
|
ListItem<FilterKeyword> newItem=new ListItem<>(item.title, null, null);
|
||||||
newItem.isEnabled=true;
|
newItem.isEnabled=true;
|
||||||
newItem.onClick=()->onWordClick(newItem);
|
newItem.setOnClick(this::onWordClick);
|
||||||
newItem.parentObject=item.parentObject;
|
newItem.parentObject=item.parentObject;
|
||||||
data.set(i, newItem);
|
data.set(i, newItem);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ import org.joinmastodon.android.model.viewmodel.ListItem;
|
|||||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
import me.grishka.appkit.imageloader.ImageCache;
|
import me.grishka.appkit.imageloader.ImageCache;
|
||||||
@@ -26,23 +25,32 @@ import me.grishka.appkit.utils.V;
|
|||||||
|
|
||||||
public class SettingsAboutAppFragment extends BaseSettingsFragment<Void>{
|
public class SettingsAboutAppFragment extends BaseSettingsFragment<Void>{
|
||||||
private ListItem<Void> mediaCacheItem;
|
private ListItem<Void> mediaCacheItem;
|
||||||
|
private AccountSession session;
|
||||||
|
private boolean timelineCacheCleared=false;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState){
|
public void onCreate(Bundle savedInstanceState){
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
setTitle(getString(R.string.about_app, getString(R.string.sk_app_name)));
|
setTitle(getString(R.string.about_app, getString(R.string.sk_app_name)));
|
||||||
AccountSession s=AccountSessionManager.get(accountID);
|
session=AccountSessionManager.get(accountID);
|
||||||
onDataLoaded(List.of(
|
onDataLoaded(List.of(
|
||||||
new ListItem<>(R.string.sk_settings_donate, 0, R.drawable.ic_fluent_heart_24_regular, ()->UiUtils.openHashtagTimeline(getActivity(), accountID, getString(R.string.donate_hashtag))),
|
new ListItem<>(R.string.sk_settings_donate, 0, R.drawable.ic_fluent_heart_24_regular, i->UiUtils.openHashtagTimeline(getActivity(), accountID, getString(R.string.donate_hashtag))),
|
||||||
new ListItem<>(R.string.sk_settings_contribute, 0, R.drawable.ic_fluent_open_24_regular, ()->UiUtils.launchWebBrowser(getActivity(), getString(R.string.repo_url))),
|
new ListItem<>(R.string.sk_settings_contribute, 0, R.drawable.ic_fluent_open_24_regular, i->UiUtils.launchWebBrowser(getActivity(), getString(R.string.repo_url))),
|
||||||
new ListItem<>(R.string.settings_tos, 0, R.drawable.ic_fluent_open_24_regular, ()->UiUtils.launchWebBrowser(getActivity(), "https://"+s.domain+"/terms")),
|
new ListItem<>(R.string.settings_tos, 0, R.drawable.ic_fluent_open_24_regular, i->UiUtils.launchWebBrowser(getActivity(), "https://"+session.domain+"/terms")),
|
||||||
new ListItem<>(R.string.settings_privacy_policy, 0, R.drawable.ic_fluent_open_24_regular, ()->UiUtils.launchWebBrowser(getActivity(), getString(R.string.privacy_policy_url)), 0, true),
|
new ListItem<>(R.string.settings_privacy_policy, 0, R.drawable.ic_fluent_open_24_regular, i->UiUtils.launchWebBrowser(getActivity(), getString(R.string.privacy_policy_url)), 0, true),
|
||||||
mediaCacheItem=new ListItem<>(R.string.settings_clear_cache, 0, this::onClearMediaCacheClick)
|
mediaCacheItem=new ListItem<>(R.string.settings_clear_cache, 0, this::onClearMediaCacheClick),
|
||||||
|
new ListItem<>(getString(R.string.sk_settings_clear_timeline_cache), session.domain, this::onClearTimelineCacheClick)
|
||||||
));
|
));
|
||||||
|
|
||||||
updateMediaCacheItem();
|
updateMediaCacheItem();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onHidden(){
|
||||||
|
super.onHidden();
|
||||||
|
if(timelineCacheCleared) getActivity().recreate();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doLoadData(int offset, int count){}
|
protected void doLoadData(int offset, int count){}
|
||||||
|
|
||||||
@@ -63,7 +71,7 @@ public class SettingsAboutAppFragment extends BaseSettingsFragment<Void>{
|
|||||||
return adapter;
|
return adapter;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onClearMediaCacheClick(){
|
private void onClearMediaCacheClick(ListItem<?> item){
|
||||||
MastodonAPIController.runInBackground(()->{
|
MastodonAPIController.runInBackground(()->{
|
||||||
Activity activity=getActivity();
|
Activity activity=getActivity();
|
||||||
ImageCache.getInstance(getActivity()).clear();
|
ImageCache.getInstance(getActivity()).clear();
|
||||||
@@ -74,6 +82,12 @@ public class SettingsAboutAppFragment extends BaseSettingsFragment<Void>{
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void onClearTimelineCacheClick(ListItem<?> item){
|
||||||
|
session.getCacheController().putHomeTimeline(List.of(), true);
|
||||||
|
Toast.makeText(getContext(), R.string.sk_timeline_cache_cleared, Toast.LENGTH_SHORT).show();
|
||||||
|
timelineCacheCleared=true;
|
||||||
|
}
|
||||||
|
|
||||||
private void updateMediaCacheItem(){
|
private void updateMediaCacheItem(){
|
||||||
long size=ImageCache.getInstance(getActivity()).getDiskCache().size();
|
long size=ImageCache.getInstance(getActivity()).getDiskCache().size();
|
||||||
mediaCacheItem.subtitle=UiUtils.formatFileSize(getActivity(), size, false);
|
mediaCacheItem.subtitle=UiUtils.formatFileSize(getActivity(), size, false);
|
||||||
|
|||||||
@@ -46,20 +46,20 @@ public class SettingsBehaviorFragment extends BaseSettingsFragment<Void> impleme
|
|||||||
|
|
||||||
List<ListItem<Void>> items = new ArrayList<>(List.of(
|
List<ListItem<Void>> items = new ArrayList<>(List.of(
|
||||||
languageItem=new ListItem<>(getString(R.string.default_post_language), postLanguage!=null ? postLanguage.getDisplayName(getContext()) : null, R.drawable.ic_fluent_local_language_24_regular, this::onDefaultLanguageClick),
|
languageItem=new ListItem<>(getString(R.string.default_post_language), postLanguage!=null ? postLanguage.getDisplayName(getContext()) : null, R.drawable.ic_fluent_local_language_24_regular, this::onDefaultLanguageClick),
|
||||||
altTextItem=new CheckableListItem<>(R.string.settings_alt_text_reminders, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.altTextReminders, R.drawable.ic_fluent_image_alt_text_24_regular, ()->toggleCheckableItem(altTextItem)),
|
altTextItem=new CheckableListItem<>(R.string.settings_alt_text_reminders, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.altTextReminders, R.drawable.ic_fluent_image_alt_text_24_regular, i->toggleCheckableItem(altTextItem)),
|
||||||
playGifsItem=new CheckableListItem<>(R.string.settings_gif, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.playGifs, R.drawable.ic_fluent_gif_24_regular, ()->toggleCheckableItem(playGifsItem)),
|
playGifsItem=new CheckableListItem<>(R.string.settings_gif, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.playGifs, R.drawable.ic_fluent_gif_24_regular, i->toggleCheckableItem(playGifsItem)),
|
||||||
overlayMediaItem=new CheckableListItem<>(R.string.sk_settings_continues_playback, R.string.sk_settings_continues_playback_summary, CheckableListItem.Style.SWITCH, GlobalUserPreferences.overlayMedia, R.drawable.ic_fluent_play_circle_hint_24_regular, ()->toggleCheckableItem(overlayMediaItem)),
|
overlayMediaItem=new CheckableListItem<>(R.string.sk_settings_continues_playback, R.string.sk_settings_continues_playback_summary, CheckableListItem.Style.SWITCH, GlobalUserPreferences.overlayMedia, R.drawable.ic_fluent_play_circle_hint_24_regular, i->toggleCheckableItem(overlayMediaItem)),
|
||||||
customTabsItem=new CheckableListItem<>(R.string.settings_custom_tabs, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.useCustomTabs, R.drawable.ic_fluent_link_24_regular, ()->toggleCheckableItem(customTabsItem)),
|
customTabsItem=new CheckableListItem<>(R.string.settings_custom_tabs, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.useCustomTabs, R.drawable.ic_fluent_link_24_regular, i->toggleCheckableItem(customTabsItem)),
|
||||||
confirmUnfollowItem=new CheckableListItem<>(R.string.settings_confirm_unfollow, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.confirmUnfollow, R.drawable.ic_fluent_person_delete_24_regular, ()->toggleCheckableItem(confirmUnfollowItem)),
|
confirmUnfollowItem=new CheckableListItem<>(R.string.settings_confirm_unfollow, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.confirmUnfollow, R.drawable.ic_fluent_person_delete_24_regular, i->toggleCheckableItem(confirmUnfollowItem)),
|
||||||
confirmBoostItem=new CheckableListItem<>(R.string.settings_confirm_boost, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.confirmBoost, R.drawable.ic_fluent_arrow_repeat_all_24_regular, ()->toggleCheckableItem(confirmBoostItem)),
|
confirmBoostItem=new CheckableListItem<>(R.string.settings_confirm_boost, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.confirmBoost, R.drawable.ic_fluent_arrow_repeat_all_24_regular, i->toggleCheckableItem(confirmBoostItem)),
|
||||||
confirmDeleteItem=new CheckableListItem<>(R.string.settings_confirm_delete_post, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.confirmDeletePost, R.drawable.ic_fluent_delete_24_regular, ()->toggleCheckableItem(confirmDeleteItem)),
|
confirmDeleteItem=new CheckableListItem<>(R.string.settings_confirm_delete_post, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.confirmDeletePost, R.drawable.ic_fluent_delete_24_regular, i->toggleCheckableItem(confirmDeleteItem)),
|
||||||
prefixRepliesItem=new ListItem<>(R.string.sk_settings_prefix_reply_cw_with_re, getPrefixWithRepliesString(), R.drawable.ic_fluent_arrow_reply_24_regular, this::onPrefixRepliesClick),
|
prefixRepliesItem=new ListItem<>(R.string.sk_settings_prefix_reply_cw_with_re, getPrefixWithRepliesString(), R.drawable.ic_fluent_arrow_reply_24_regular, this::onPrefixRepliesClick),
|
||||||
forwardReportsItem=new CheckableListItem<>(R.string.sk_settings_forward_report_default, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.forwardReportDefault, R.drawable.ic_fluent_arrow_forward_24_regular, ()->toggleCheckableItem(forwardReportsItem)),
|
forwardReportsItem=new CheckableListItem<>(R.string.sk_settings_forward_report_default, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.forwardReportDefault, R.drawable.ic_fluent_arrow_forward_24_regular, i->toggleCheckableItem(forwardReportsItem)),
|
||||||
loadNewPostsItem=new CheckableListItem<>(R.string.sk_settings_load_new_posts, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.loadNewPosts, R.drawable.ic_fluent_arrow_sync_24_regular, this::onLoadNewPostsClick),
|
loadNewPostsItem=new CheckableListItem<>(R.string.sk_settings_load_new_posts, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.loadNewPosts, R.drawable.ic_fluent_arrow_sync_24_regular, i->onLoadNewPostsClick()),
|
||||||
seeNewPostsBtnItem=new CheckableListItem<>(R.string.sk_settings_see_new_posts_button, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.showNewPostsButton, R.drawable.ic_fluent_arrow_up_24_regular, ()->toggleCheckableItem(seeNewPostsBtnItem)),
|
seeNewPostsBtnItem=new CheckableListItem<>(R.string.sk_settings_see_new_posts_button, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.showNewPostsButton, R.drawable.ic_fluent_arrow_up_24_regular, i->toggleCheckableItem(seeNewPostsBtnItem)),
|
||||||
remoteLoadingItem=new CheckableListItem<>(R.string.sk_settings_allow_remote_loading, R.string.sk_settings_allow_remote_loading_explanation, CheckableListItem.Style.SWITCH, GlobalUserPreferences.allowRemoteLoading, R.drawable.ic_fluent_communication_24_regular, ()->toggleCheckableItem(remoteLoadingItem), true),
|
remoteLoadingItem=new CheckableListItem<>(R.string.sk_settings_allow_remote_loading, R.string.sk_settings_allow_remote_loading_explanation, CheckableListItem.Style.SWITCH, GlobalUserPreferences.allowRemoteLoading, R.drawable.ic_fluent_communication_24_regular, i->toggleCheckableItem(remoteLoadingItem), true),
|
||||||
showBoostsItem=new CheckableListItem<>(R.string.sk_settings_show_boosts, 0, CheckableListItem.Style.SWITCH, lp.showBoosts, R.drawable.ic_fluent_arrow_repeat_all_24_regular, ()->toggleCheckableItem(showBoostsItem)),
|
showBoostsItem=new CheckableListItem<>(R.string.sk_settings_show_boosts, 0, CheckableListItem.Style.SWITCH, lp.showBoosts, R.drawable.ic_fluent_arrow_repeat_all_24_regular, i->toggleCheckableItem(showBoostsItem)),
|
||||||
showRepliesItem=new CheckableListItem<>(R.string.sk_settings_show_replies, 0, CheckableListItem.Style.SWITCH, lp.showReplies, R.drawable.ic_fluent_arrow_reply_24_regular, ()->toggleCheckableItem(showRepliesItem))
|
showRepliesItem=new CheckableListItem<>(R.string.sk_settings_show_replies, 0, CheckableListItem.Style.SWITCH, lp.showReplies, R.drawable.ic_fluent_arrow_reply_24_regular, i->toggleCheckableItem(showRepliesItem))
|
||||||
));
|
));
|
||||||
|
|
||||||
if(isInstanceAkkoma()) items.add(
|
if(isInstanceAkkoma()) items.add(
|
||||||
@@ -93,7 +93,7 @@ public class SettingsBehaviorFragment extends BaseSettingsFragment<Void> impleme
|
|||||||
@Override
|
@Override
|
||||||
protected void doLoadData(int offset, int count){}
|
protected void doLoadData(int offset, int count){}
|
||||||
|
|
||||||
private void onDefaultLanguageClick(){
|
private void onDefaultLanguageClick(ListItem<?> item){
|
||||||
if (languageResolver == null) return;
|
if (languageResolver == null) return;
|
||||||
ComposeLanguageAlertViewController vc=new ComposeLanguageAlertViewController(getActivity(), null, new ComposeLanguageAlertViewController.SelectedOption(postLanguage), null, languageResolver);
|
ComposeLanguageAlertViewController vc=new ComposeLanguageAlertViewController(getActivity(), null, new ComposeLanguageAlertViewController.SelectedOption(postLanguage), null, languageResolver);
|
||||||
new M3AlertDialogBuilder(getActivity())
|
new M3AlertDialogBuilder(getActivity())
|
||||||
@@ -112,14 +112,14 @@ public class SettingsBehaviorFragment extends BaseSettingsFragment<Void> impleme
|
|||||||
.show();
|
.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onPrefixRepliesClick(){
|
private void onPrefixRepliesClick(ListItem<?> item){
|
||||||
int selected=GlobalUserPreferences.prefixReplies.ordinal();
|
int selected=GlobalUserPreferences.prefixReplies.ordinal();
|
||||||
int[] newSelected={selected};
|
int[] newSelected={selected};
|
||||||
new M3AlertDialogBuilder(getActivity())
|
new M3AlertDialogBuilder(getActivity())
|
||||||
.setTitle(R.string.sk_settings_prefix_reply_cw_with_re)
|
.setTitle(R.string.sk_settings_prefix_reply_cw_with_re)
|
||||||
.setSingleChoiceItems((String[]) IntStream.of(R.string.sk_settings_prefix_replies_never, R.string.sk_settings_prefix_replies_always, R.string.sk_settings_prefix_replies_to_others).mapToObj(this::getString).toArray(String[]::new),
|
.setSingleChoiceItems((String[]) IntStream.of(R.string.sk_settings_prefix_replies_never, R.string.sk_settings_prefix_replies_always, R.string.sk_settings_prefix_replies_to_others).mapToObj(this::getString).toArray(String[]::new),
|
||||||
selected, (dlg, item)->newSelected[0]=item)
|
selected, (dlg, which)->newSelected[0]=which)
|
||||||
.setPositiveButton(R.string.ok, (dlg, item)->{
|
.setPositiveButton(R.string.ok, (dlg, which)->{
|
||||||
GlobalUserPreferences.prefixReplies=GlobalUserPreferences.PrefixRepliesMode.values()[newSelected[0]];
|
GlobalUserPreferences.prefixReplies=GlobalUserPreferences.PrefixRepliesMode.values()[newSelected[0]];
|
||||||
prefixRepliesItem.subtitleRes=getPrefixWithRepliesString();
|
prefixRepliesItem.subtitleRes=getPrefixWithRepliesString();
|
||||||
rebindItem(prefixRepliesItem);
|
rebindItem(prefixRepliesItem);
|
||||||
@@ -128,7 +128,7 @@ public class SettingsBehaviorFragment extends BaseSettingsFragment<Void> impleme
|
|||||||
.show();
|
.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onReplyVisibilityClick(){
|
private void onReplyVisibilityClick(ListItem<?> item){
|
||||||
AccountLocalPreferences lp=getLocalPrefs();
|
AccountLocalPreferences lp=getLocalPrefs();
|
||||||
int selected=lp.timelineReplyVisibility==null ? 2 : switch(lp.timelineReplyVisibility){
|
int selected=lp.timelineReplyVisibility==null ? 2 : switch(lp.timelineReplyVisibility){
|
||||||
case "following" -> 0;
|
case "following" -> 0;
|
||||||
@@ -139,8 +139,8 @@ public class SettingsBehaviorFragment extends BaseSettingsFragment<Void> impleme
|
|||||||
new M3AlertDialogBuilder(getActivity())
|
new M3AlertDialogBuilder(getActivity())
|
||||||
.setTitle(R.string.sk_settings_prefix_reply_cw_with_re)
|
.setTitle(R.string.sk_settings_prefix_reply_cw_with_re)
|
||||||
.setSingleChoiceItems((String[]) IntStream.of(R.string.sk_settings_reply_visibility_following, R.string.sk_settings_reply_visibility_self, R.string.sk_settings_reply_visibility_all).mapToObj(this::getString).toArray(String[]::new),
|
.setSingleChoiceItems((String[]) IntStream.of(R.string.sk_settings_reply_visibility_following, R.string.sk_settings_reply_visibility_self, R.string.sk_settings_reply_visibility_all).mapToObj(this::getString).toArray(String[]::new),
|
||||||
selected, (dlg, item)->newSelected[0]=item)
|
selected, (dlg, which)->newSelected[0]=which)
|
||||||
.setPositiveButton(R.string.ok, (dlg, item)->{
|
.setPositiveButton(R.string.ok, (dlg, which)->{
|
||||||
lp.timelineReplyVisibility=switch(newSelected[0]){
|
lp.timelineReplyVisibility=switch(newSelected[0]){
|
||||||
case 0 -> "following";
|
case 0 -> "following";
|
||||||
case 1 -> "self";
|
case 1 -> "self";
|
||||||
@@ -167,7 +167,7 @@ public class SettingsBehaviorFragment extends BaseSettingsFragment<Void> impleme
|
|||||||
GlobalUserPreferences.overlayMedia=overlayMediaItem.checked;
|
GlobalUserPreferences.overlayMedia=overlayMediaItem.checked;
|
||||||
GlobalUserPreferences.useCustomTabs=customTabsItem.checked;
|
GlobalUserPreferences.useCustomTabs=customTabsItem.checked;
|
||||||
GlobalUserPreferences.altTextReminders=altTextItem.checked;
|
GlobalUserPreferences.altTextReminders=altTextItem.checked;
|
||||||
GlobalUserPreferences.confirmUnfollow=customTabsItem.checked;
|
GlobalUserPreferences.confirmUnfollow=confirmUnfollowItem.checked;
|
||||||
GlobalUserPreferences.confirmBoost=confirmBoostItem.checked;
|
GlobalUserPreferences.confirmBoost=confirmBoostItem.checked;
|
||||||
GlobalUserPreferences.confirmDeletePost=confirmDeleteItem.checked;
|
GlobalUserPreferences.confirmDeletePost=confirmDeleteItem.checked;
|
||||||
GlobalUserPreferences.forwardReportDefault=forwardReportsItem.checked;
|
GlobalUserPreferences.forwardReportDefault=forwardReportsItem.checked;
|
||||||
@@ -176,6 +176,8 @@ public class SettingsBehaviorFragment extends BaseSettingsFragment<Void> impleme
|
|||||||
GlobalUserPreferences.allowRemoteLoading=remoteLoadingItem.checked;
|
GlobalUserPreferences.allowRemoteLoading=remoteLoadingItem.checked;
|
||||||
GlobalUserPreferences.save();
|
GlobalUserPreferences.save();
|
||||||
AccountLocalPreferences lp=getLocalPrefs();
|
AccountLocalPreferences lp=getLocalPrefs();
|
||||||
|
boolean restartPlease=lp.showBoosts!=showBoostsItem.checked
|
||||||
|
|| lp.showReplies!=showRepliesItem.checked;
|
||||||
lp.showBoosts=showBoostsItem.checked;
|
lp.showBoosts=showBoostsItem.checked;
|
||||||
lp.showReplies=showRepliesItem.checked;
|
lp.showReplies=showRepliesItem.checked;
|
||||||
lp.save();
|
lp.save();
|
||||||
@@ -186,6 +188,7 @@ public class SettingsBehaviorFragment extends BaseSettingsFragment<Void> impleme
|
|||||||
s.preferences.postingDefaultLanguage=newPostLanguage.language.getLanguage();
|
s.preferences.postingDefaultLanguage=newPostLanguage.language.getLanguage();
|
||||||
s.savePreferencesLater();
|
s.savePreferencesLater();
|
||||||
}
|
}
|
||||||
|
if(restartPlease) getActivity().recreate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ public class SettingsDebugFragment extends BaseSettingsFragment<Void>{
|
|||||||
@Override
|
@Override
|
||||||
protected void doLoadData(int offset, int count){}
|
protected void doLoadData(int offset, int count){}
|
||||||
|
|
||||||
private void onTestEmailConfirmClick(){
|
private void onTestEmailConfirmClick(ListItem<?> item){
|
||||||
AccountSession sess=AccountSessionManager.getInstance().getAccount(accountID);
|
AccountSession sess=AccountSessionManager.getInstance().getAccount(accountID);
|
||||||
sess.activated=false;
|
sess.activated=false;
|
||||||
sess.activationInfo=new AccountActivationInfo("test@email", System.currentTimeMillis());
|
sess.activationInfo=new AccountActivationInfo("test@email", System.currentTimeMillis());
|
||||||
@@ -49,18 +49,18 @@ public class SettingsDebugFragment extends BaseSettingsFragment<Void>{
|
|||||||
Nav.goClearingStack(getActivity(), AccountActivationFragment.class, args);
|
Nav.goClearingStack(getActivity(), AccountActivationFragment.class, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onForceSelfUpdateClick(){
|
private void onForceSelfUpdateClick(ListItem<?> item){
|
||||||
GithubSelfUpdater.forceUpdate=true;
|
GithubSelfUpdater.forceUpdate=true;
|
||||||
GithubSelfUpdater.getInstance().maybeCheckForUpdates();
|
GithubSelfUpdater.getInstance().maybeCheckForUpdates();
|
||||||
restartUI();
|
restartUI();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onResetUpdaterClick(){
|
private void onResetUpdaterClick(ListItem<?> item){
|
||||||
GithubSelfUpdater.getInstance().reset();
|
GithubSelfUpdater.getInstance().reset();
|
||||||
restartUI();
|
restartUI();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onResetDiscoverBannersClick(){
|
private void onResetDiscoverBannersClick(ListItem<?> item){
|
||||||
DiscoverInfoBannerHelper.reset();
|
DiscoverInfoBannerHelper.reset();
|
||||||
restartUI();
|
restartUI();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package org.joinmastodon.android.fragments.settings;
|
package org.joinmastodon.android.fragments.settings;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
|
import android.app.AlertDialog;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
@@ -28,6 +29,8 @@ import org.joinmastodon.android.ui.views.TextInputFrameLayout;
|
|||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.IntStream;
|
import java.util.stream.IntStream;
|
||||||
|
|
||||||
import me.grishka.appkit.FragmentStackActivity;
|
import me.grishka.appkit.FragmentStackActivity;
|
||||||
@@ -38,7 +41,7 @@ public class SettingsDisplayFragment extends BaseSettingsFragment<Void>{
|
|||||||
private CheckableListItem<Void> revealCWsItem, hideSensitiveMediaItem, interactionCountsItem, emojiInNamesItem;
|
private CheckableListItem<Void> revealCWsItem, hideSensitiveMediaItem, interactionCountsItem, emojiInNamesItem;
|
||||||
|
|
||||||
// MEGALODON
|
// MEGALODON
|
||||||
private CheckableListItem<Void> trueBlackModeItem, marqueeItem, disableSwipeItem, reduceMotionItem, altIndicatorItem, noAltIndicatorItem, collapsePostsItem, spectatorModeItem, hideFabItem, translateOpenedItem, disablePillItem, showNavigationLabelsItem, likeIconItem;
|
private CheckableListItem<Void> trueBlackModeItem, marqueeItem, disableSwipeItem, reduceMotionItem, altIndicatorItem, noAltIndicatorItem, collapsePostsItem, spectatorModeItem, hideFabItem, translateOpenedItem, disablePillItem, showNavigationLabelsItem, likeIconItem, underlinedLinksItem;
|
||||||
private ListItem<Void> colorItem, publishTextItem, autoRevealCWsItem;
|
private ListItem<Void> colorItem, publishTextItem, autoRevealCWsItem;
|
||||||
private CheckableListItem<Void> pronounsInUserListingsItem, pronounsInTimelinesItem, pronounsInThreadsItem;
|
private CheckableListItem<Void> pronounsInUserListingsItem, pronounsInTimelinesItem, pronounsInThreadsItem;
|
||||||
|
|
||||||
@@ -52,29 +55,30 @@ public class SettingsDisplayFragment extends BaseSettingsFragment<Void>{
|
|||||||
lp=s.getLocalPreferences();
|
lp=s.getLocalPreferences();
|
||||||
onDataLoaded(List.of(
|
onDataLoaded(List.of(
|
||||||
themeItem=new ListItem<>(R.string.settings_theme, getAppearanceValue(), R.drawable.ic_fluent_weather_moon_24_regular, this::onAppearanceClick),
|
themeItem=new ListItem<>(R.string.settings_theme, getAppearanceValue(), R.drawable.ic_fluent_weather_moon_24_regular, this::onAppearanceClick),
|
||||||
colorItem=new ListItem<>(R.string.sk_settings_color_palette, getColorPaletteValue(), R.drawable.ic_fluent_color_24_regular, this::onColorClick),
|
colorItem=new ListItem<>(getString(R.string.sk_settings_color_palette), getColorPaletteValue(), R.drawable.ic_fluent_color_24_regular, this::onColorClick),
|
||||||
trueBlackModeItem=new CheckableListItem<>(R.string.sk_settings_true_black, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.trueBlackTheme, R.drawable.ic_fluent_dark_theme_24_regular, this::onTrueBlackModeClick, true),
|
trueBlackModeItem=new CheckableListItem<>(R.string.sk_settings_true_black, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.trueBlackTheme, R.drawable.ic_fluent_dark_theme_24_regular, i->onTrueBlackModeClick(), true),
|
||||||
publishTextItem=new ListItem<>(getString(R.string.sk_settings_publish_button_text), getPublishButtonText(), R.drawable.ic_fluent_send_24_regular, this::onPublishTextClick),
|
publishTextItem=new ListItem<>(getString(R.string.sk_settings_publish_button_text), getPublishButtonText(), R.drawable.ic_fluent_send_24_regular, this::onPublishTextClick),
|
||||||
autoRevealCWsItem=new ListItem<>(R.string.sk_settings_auto_reveal_equal_spoilers, getAutoRevealSpoilersText(), R.drawable.ic_fluent_eye_24_regular, this::onAutoRevealSpoilersClick),
|
autoRevealCWsItem=new ListItem<>(R.string.sk_settings_auto_reveal_equal_spoilers, getAutoRevealSpoilersText(), R.drawable.ic_fluent_eye_24_regular, this::onAutoRevealSpoilersClick),
|
||||||
revealCWsItem=new CheckableListItem<>(R.string.sk_settings_always_reveal_content_warnings, 0, CheckableListItem.Style.SWITCH, lp.revealCWs, R.drawable.ic_fluent_chat_warning_24_regular, ()->toggleCheckableItem(revealCWsItem)),
|
revealCWsItem=new CheckableListItem<>(R.string.sk_settings_always_reveal_content_warnings, 0, CheckableListItem.Style.SWITCH, lp.revealCWs, R.drawable.ic_fluent_chat_warning_24_regular, i->toggleCheckableItem(revealCWsItem)),
|
||||||
hideSensitiveMediaItem=new CheckableListItem<>(R.string.settings_hide_sensitive_media, 0, CheckableListItem.Style.SWITCH, lp.hideSensitiveMedia, R.drawable.ic_fluent_flag_24_regular, ()->toggleCheckableItem(hideSensitiveMediaItem)),
|
hideSensitiveMediaItem=new CheckableListItem<>(R.string.settings_hide_sensitive_media, 0, CheckableListItem.Style.SWITCH, lp.hideSensitiveMedia, R.drawable.ic_fluent_flag_24_regular, i->toggleCheckableItem(hideSensitiveMediaItem)),
|
||||||
interactionCountsItem=new CheckableListItem<>(R.string.settings_show_interaction_counts, 0, CheckableListItem.Style.SWITCH, lp.showInteractionCounts, R.drawable.ic_fluent_number_row_24_regular, ()->toggleCheckableItem(interactionCountsItem)),
|
interactionCountsItem=new CheckableListItem<>(R.string.settings_show_interaction_counts, 0, CheckableListItem.Style.SWITCH, lp.showInteractionCounts, R.drawable.ic_fluent_number_row_24_regular, i->toggleCheckableItem(interactionCountsItem)),
|
||||||
emojiInNamesItem=new CheckableListItem<>(R.string.settings_show_emoji_in_names, 0, CheckableListItem.Style.SWITCH, lp.customEmojiInNames, R.drawable.ic_fluent_emoji_24_regular, ()->toggleCheckableItem(emojiInNamesItem)),
|
emojiInNamesItem=new CheckableListItem<>(R.string.settings_show_emoji_in_names, 0, CheckableListItem.Style.SWITCH, lp.customEmojiInNames, R.drawable.ic_fluent_emoji_24_regular, i->toggleCheckableItem(emojiInNamesItem)),
|
||||||
marqueeItem=new CheckableListItem<>(R.string.sk_settings_enable_marquee, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.toolbarMarquee, R.drawable.ic_fluent_text_more_24_regular, ()->toggleCheckableItem(marqueeItem)),
|
marqueeItem=new CheckableListItem<>(R.string.sk_settings_enable_marquee, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.toolbarMarquee, R.drawable.ic_fluent_text_more_24_regular, i->toggleCheckableItem(marqueeItem)),
|
||||||
reduceMotionItem=new CheckableListItem<>(R.string.sk_settings_reduce_motion, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.reduceMotion, R.drawable.ic_fluent_star_emphasis_24_regular, ()->toggleCheckableItem(reduceMotionItem)),
|
reduceMotionItem=new CheckableListItem<>(R.string.sk_settings_reduce_motion, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.reduceMotion, R.drawable.ic_fluent_star_emphasis_24_regular, i->toggleCheckableItem(reduceMotionItem)),
|
||||||
disableSwipeItem=new CheckableListItem<>(R.string.sk_settings_tabs_disable_swipe, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.disableSwipe, R.drawable.ic_fluent_swipe_right_24_regular, ()->toggleCheckableItem(disableSwipeItem)),
|
disableSwipeItem=new CheckableListItem<>(R.string.sk_settings_tabs_disable_swipe, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.disableSwipe, R.drawable.ic_fluent_swipe_right_24_regular, i->toggleCheckableItem(disableSwipeItem)),
|
||||||
altIndicatorItem=new CheckableListItem<>(R.string.sk_settings_show_alt_indicator, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.showAltIndicator, R.drawable.ic_fluent_scan_text_24_regular, ()->toggleCheckableItem(altIndicatorItem)),
|
altIndicatorItem=new CheckableListItem<>(R.string.sk_settings_show_alt_indicator, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.showAltIndicator, R.drawable.ic_fluent_scan_text_24_regular, i->toggleCheckableItem(altIndicatorItem)),
|
||||||
noAltIndicatorItem=new CheckableListItem<>(R.string.sk_settings_show_no_alt_indicator, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.showNoAltIndicator, R.drawable.ic_fluent_important_24_regular, ()->toggleCheckableItem(noAltIndicatorItem)),
|
noAltIndicatorItem=new CheckableListItem<>(R.string.sk_settings_show_no_alt_indicator, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.showNoAltIndicator, R.drawable.ic_fluent_important_24_regular, i->toggleCheckableItem(noAltIndicatorItem)),
|
||||||
collapsePostsItem=new CheckableListItem<>(R.string.sk_settings_collapse_long_posts, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.collapseLongPosts, R.drawable.ic_fluent_chevron_down_24_regular, ()->toggleCheckableItem(collapsePostsItem)),
|
collapsePostsItem=new CheckableListItem<>(R.string.sk_settings_collapse_long_posts, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.collapseLongPosts, R.drawable.ic_fluent_chevron_down_24_regular, i->toggleCheckableItem(collapsePostsItem)),
|
||||||
spectatorModeItem=new CheckableListItem<>(R.string.sk_settings_hide_interaction, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.spectatorMode, R.drawable.ic_fluent_star_off_24_regular, ()->toggleCheckableItem(spectatorModeItem)),
|
spectatorModeItem=new CheckableListItem<>(R.string.sk_settings_hide_interaction, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.spectatorMode, R.drawable.ic_fluent_star_off_24_regular, i->toggleCheckableItem(spectatorModeItem)),
|
||||||
hideFabItem=new CheckableListItem<>(R.string.sk_settings_hide_fab, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.autoHideFab, R.drawable.ic_fluent_edit_24_regular, ()->toggleCheckableItem(hideFabItem)),
|
hideFabItem=new CheckableListItem<>(R.string.sk_settings_hide_fab, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.autoHideFab, R.drawable.ic_fluent_edit_24_regular, i->toggleCheckableItem(hideFabItem)),
|
||||||
translateOpenedItem=new CheckableListItem<>(R.string.sk_settings_translate_only_opened, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.translateButtonOpenedOnly, R.drawable.ic_fluent_translate_24_regular, ()->toggleCheckableItem(translateOpenedItem)),
|
translateOpenedItem=new CheckableListItem<>(R.string.sk_settings_translate_only_opened, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.translateButtonOpenedOnly, R.drawable.ic_fluent_translate_24_regular, i->toggleCheckableItem(translateOpenedItem)),
|
||||||
disablePillItem=new CheckableListItem<>(R.string.sk_disable_pill_shaped_active_indicator, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.disableM3PillActiveIndicator, R.drawable.ic_fluent_pill_24_regular, ()->toggleCheckableItem(disablePillItem)),
|
likeIconItem=new CheckableListItem<>(R.string.sk_settings_like_icon, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.likeIcon, R.drawable.ic_fluent_heart_24_regular, i->toggleCheckableItem(likeIconItem)),
|
||||||
likeIconItem=new CheckableListItem<>(R.string.sk_settings_like_icon, 0, CheckableListItem.Style.SWITCH, lp.likeIcon, R.drawable.ic_fluent_heart_24_regular, ()->toggleCheckableItem(likeIconItem)),
|
underlinedLinksItem=new CheckableListItem<>(R.string.sk_settings_underlined_links, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.underlinedLinks, R.drawable.ic_fluent_text_underline_24_regular, i->toggleCheckableItem(underlinedLinksItem)),
|
||||||
showNavigationLabelsItem=new CheckableListItem<>(R.string.sk_settings_show_labels_in_navigation_bar, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.showNavigationLabels, R.drawable.ic_fluent_tag_24_regular, ()->toggleCheckableItem(showNavigationLabelsItem), true),
|
disablePillItem=new CheckableListItem<>(R.string.sk_disable_pill_shaped_active_indicator, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.disableM3PillActiveIndicator, R.drawable.ic_fluent_pill_24_regular, i->toggleCheckableItem(disablePillItem)),
|
||||||
pronounsInTimelinesItem=new CheckableListItem<>(R.string.sk_settings_display_pronouns_in_timelines, 0, CheckableListItem.Style.CHECKBOX, GlobalUserPreferences.displayPronounsInTimelines, 0, ()->toggleCheckableItem(pronounsInTimelinesItem)),
|
showNavigationLabelsItem=new CheckableListItem<>(R.string.sk_settings_show_labels_in_navigation_bar, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.showNavigationLabels, R.drawable.ic_fluent_tag_24_regular, i->toggleCheckableItem(showNavigationLabelsItem), true),
|
||||||
pronounsInThreadsItem=new CheckableListItem<>(R.string.sk_settings_display_pronouns_in_threads, 0, CheckableListItem.Style.CHECKBOX, GlobalUserPreferences.displayPronounsInThreads, 0, ()->toggleCheckableItem(pronounsInThreadsItem)),
|
pronounsInTimelinesItem=new CheckableListItem<>(R.string.sk_settings_display_pronouns_in_timelines, 0, CheckableListItem.Style.CHECKBOX, GlobalUserPreferences.displayPronounsInTimelines, 0, i->toggleCheckableItem(pronounsInTimelinesItem)),
|
||||||
pronounsInUserListingsItem=new CheckableListItem<>(R.string.sk_settings_display_pronouns_in_user_listings, 0, CheckableListItem.Style.CHECKBOX, GlobalUserPreferences.displayPronounsInUserListings, 0, ()->toggleCheckableItem(pronounsInUserListingsItem))
|
pronounsInThreadsItem=new CheckableListItem<>(R.string.sk_settings_display_pronouns_in_threads, 0, CheckableListItem.Style.CHECKBOX, GlobalUserPreferences.displayPronounsInThreads, 0, i->toggleCheckableItem(pronounsInThreadsItem)),
|
||||||
|
pronounsInUserListingsItem=new CheckableListItem<>(R.string.sk_settings_display_pronouns_in_user_listings, 0, CheckableListItem.Style.CHECKBOX, GlobalUserPreferences.displayPronounsInUserListings, 0, i->toggleCheckableItem(pronounsInUserListingsItem))
|
||||||
));
|
));
|
||||||
trueBlackModeItem.checkedChangeListener=checked->onTrueBlackModeClick();
|
trueBlackModeItem.checkedChangeListener=checked->onTrueBlackModeClick();
|
||||||
}
|
}
|
||||||
@@ -96,16 +100,14 @@ public class SettingsDisplayFragment extends BaseSettingsFragment<Void>{
|
|||||||
protected void onHidden(){
|
protected void onHidden(){
|
||||||
super.onHidden();
|
super.onHidden();
|
||||||
|
|
||||||
boolean restartPlease=
|
boolean restartPlease=GlobalUserPreferences.disableM3PillActiveIndicator!=disablePillItem.checked
|
||||||
GlobalUserPreferences.disableM3PillActiveIndicator!=disablePillItem.checked ||
|
|| GlobalUserPreferences.showNavigationLabels!=showNavigationLabelsItem.checked
|
||||||
GlobalUserPreferences.showNavigationLabels!=showNavigationLabelsItem.checked ||
|
|| GlobalUserPreferences.likeIcon!=likeIconItem.checked;
|
||||||
lp.likeIcon!=likeIconItem.checked;
|
|
||||||
|
|
||||||
lp.revealCWs=revealCWsItem.checked;
|
lp.revealCWs=revealCWsItem.checked;
|
||||||
lp.hideSensitiveMedia=hideSensitiveMediaItem.checked;
|
lp.hideSensitiveMedia=hideSensitiveMediaItem.checked;
|
||||||
lp.showInteractionCounts=interactionCountsItem.checked;
|
lp.showInteractionCounts=interactionCountsItem.checked;
|
||||||
lp.customEmojiInNames=emojiInNamesItem.checked;
|
lp.customEmojiInNames=emojiInNamesItem.checked;
|
||||||
lp.likeIcon=likeIconItem.checked;
|
|
||||||
lp.save();
|
lp.save();
|
||||||
GlobalUserPreferences.toolbarMarquee=marqueeItem.checked;
|
GlobalUserPreferences.toolbarMarquee=marqueeItem.checked;
|
||||||
GlobalUserPreferences.reduceMotion=reduceMotionItem.checked;
|
GlobalUserPreferences.reduceMotion=reduceMotionItem.checked;
|
||||||
@@ -116,6 +118,8 @@ public class SettingsDisplayFragment extends BaseSettingsFragment<Void>{
|
|||||||
GlobalUserPreferences.spectatorMode=spectatorModeItem.checked;
|
GlobalUserPreferences.spectatorMode=spectatorModeItem.checked;
|
||||||
GlobalUserPreferences.autoHideFab=hideFabItem.checked;
|
GlobalUserPreferences.autoHideFab=hideFabItem.checked;
|
||||||
GlobalUserPreferences.translateButtonOpenedOnly=translateOpenedItem.checked;
|
GlobalUserPreferences.translateButtonOpenedOnly=translateOpenedItem.checked;
|
||||||
|
GlobalUserPreferences.likeIcon=likeIconItem.checked;
|
||||||
|
GlobalUserPreferences.underlinedLinks=underlinedLinksItem.checked;
|
||||||
GlobalUserPreferences.disableM3PillActiveIndicator=disablePillItem.checked;
|
GlobalUserPreferences.disableM3PillActiveIndicator=disablePillItem.checked;
|
||||||
GlobalUserPreferences.showNavigationLabels=showNavigationLabelsItem.checked;
|
GlobalUserPreferences.showNavigationLabels=showNavigationLabelsItem.checked;
|
||||||
GlobalUserPreferences.displayPronounsInTimelines=pronounsInTimelinesItem.checked;
|
GlobalUserPreferences.displayPronounsInTimelines=pronounsInTimelinesItem.checked;
|
||||||
@@ -134,17 +138,11 @@ public class SettingsDisplayFragment extends BaseSettingsFragment<Void>{
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private @StringRes int getColorPaletteValue(){
|
private String getColorPaletteValue(){
|
||||||
return switch(AccountSessionManager.get(accountID).getLocalPreferences().color){
|
ColorPreference color=AccountSessionManager.get(accountID).getLocalPreferences().color;
|
||||||
case MATERIAL3 -> R.string.sk_color_palette_material3;
|
return color==null
|
||||||
case PINK -> R.string.sk_color_palette_pink;
|
? getString(R.string.sk_settings_color_palette_default, getString(GlobalUserPreferences.color.getName()))
|
||||||
case PURPLE -> R.string.sk_color_palette_purple;
|
: getString(color.getName());
|
||||||
case GREEN -> R.string.sk_color_palette_green;
|
|
||||||
case BLUE -> R.string.sk_color_palette_blue;
|
|
||||||
case BROWN -> R.string.sk_color_palette_brown;
|
|
||||||
case RED -> R.string.sk_color_palette_red;
|
|
||||||
case YELLOW -> R.string.sk_color_palette_yellow;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getPublishButtonText() {
|
private String getPublishButtonText() {
|
||||||
@@ -168,7 +166,7 @@ public class SettingsDisplayFragment extends BaseSettingsFragment<Void>{
|
|||||||
maybeApplyNewThemeRightNow(null, null, prev);
|
maybeApplyNewThemeRightNow(null, null, prev);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onAppearanceClick(){
|
private void onAppearanceClick(ListItem<?> item_){
|
||||||
int selected=switch(GlobalUserPreferences.theme){
|
int selected=switch(GlobalUserPreferences.theme){
|
||||||
case LIGHT -> 0;
|
case LIGHT -> 0;
|
||||||
case DARK -> 1;
|
case DARK -> 1;
|
||||||
@@ -199,30 +197,44 @@ public class SettingsDisplayFragment extends BaseSettingsFragment<Void>{
|
|||||||
.show();
|
.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onColorClick(){
|
private void onColorClick(ListItem<?> item_){
|
||||||
int selected=lp.color.ordinal();
|
boolean multiple=AccountSessionManager.getInstance().getLoggedInAccounts().size() > 1;
|
||||||
|
int indexOffset=multiple ? 1 : 0;
|
||||||
|
int selected=lp.color==null ? 0 : lp.color.ordinal() + indexOffset;
|
||||||
int[] newSelected={selected};
|
int[] newSelected={selected};
|
||||||
String[] names=Arrays.stream(ColorPreference.values()).map(ColorPreference::getName).map(this::getString).toArray(String[]::new);
|
List<String> items=Arrays.stream(ColorPreference.values()).map(ColorPreference::getName).map(this::getString).collect(Collectors.toList());
|
||||||
new M3AlertDialogBuilder(getActivity())
|
if(multiple)
|
||||||
|
items.add(0, getString(R.string.sk_settings_color_palette_default, items.get(GlobalUserPreferences.color.ordinal())));
|
||||||
|
|
||||||
|
Consumer<Boolean> save=(asDefault)->{
|
||||||
|
boolean defaultSelected=multiple && newSelected[0]==0;
|
||||||
|
ColorPreference pref=defaultSelected ? null : ColorPreference.values()[newSelected[0]-indexOffset];
|
||||||
|
if(pref!=lp.color){
|
||||||
|
ColorPreference prev=lp.color;
|
||||||
|
lp.color=asDefault ? null : pref;
|
||||||
|
lp.save();
|
||||||
|
if((asDefault || !multiple) && pref!=null){
|
||||||
|
GlobalUserPreferences.color=pref;
|
||||||
|
GlobalUserPreferences.save();
|
||||||
|
}
|
||||||
|
colorItem.subtitle=getColorPaletteValue();
|
||||||
|
rebindItem(colorItem);
|
||||||
|
if(prev==null && pref!=null) restartActivityToApplyNewTheme();
|
||||||
|
else maybeApplyNewThemeRightNow(null, prev, null);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
AlertDialog.Builder alert=new M3AlertDialogBuilder(getActivity())
|
||||||
.setTitle(R.string.sk_settings_color_palette)
|
.setTitle(R.string.sk_settings_color_palette)
|
||||||
.setSingleChoiceItems(names,
|
.setSingleChoiceItems(items.stream().toArray(String[]::new),
|
||||||
selected, (dlg, item)->newSelected[0]=item)
|
selected, (dlg, item)->newSelected[0]=item)
|
||||||
.setPositiveButton(R.string.ok, (dlg, item)->{
|
.setPositiveButton(R.string.ok, (dlg, item)->save.accept(false))
|
||||||
ColorPreference pref=ColorPreference.values()[newSelected[0]];
|
.setNegativeButton(R.string.cancel, null);
|
||||||
if(pref!=lp.color){
|
if(multiple) alert.setNeutralButton(R.string.sk_set_as_default, (dlg, item)->save.accept(true));
|
||||||
ColorPreference prev=lp.color;
|
alert.show();
|
||||||
lp.color=pref;
|
|
||||||
GlobalUserPreferences.save();
|
|
||||||
colorItem.subtitleRes=getColorPaletteValue();
|
|
||||||
rebindItem(colorItem);
|
|
||||||
maybeApplyNewThemeRightNow(null, prev, null);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.setNegativeButton(R.string.cancel, null)
|
|
||||||
.show();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onPublishTextClick(){
|
private void onPublishTextClick(ListItem<?> item_){
|
||||||
TextInputFrameLayout input = new TextInputFrameLayout(
|
TextInputFrameLayout input = new TextInputFrameLayout(
|
||||||
getContext(),
|
getContext(),
|
||||||
getString(R.string.publish),
|
getString(R.string.publish),
|
||||||
@@ -245,7 +257,7 @@ public class SettingsDisplayFragment extends BaseSettingsFragment<Void>{
|
|||||||
.show();
|
.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onAutoRevealSpoilersClick(){
|
private void onAutoRevealSpoilersClick(ListItem<?> item_){
|
||||||
int selected=GlobalUserPreferences.autoRevealEqualSpoilers.ordinal();
|
int selected=GlobalUserPreferences.autoRevealEqualSpoilers.ordinal();
|
||||||
int[] newSelected={selected};
|
int[] newSelected={selected};
|
||||||
new M3AlertDialogBuilder(getActivity())
|
new M3AlertDialogBuilder(getActivity())
|
||||||
@@ -264,14 +276,14 @@ public class SettingsDisplayFragment extends BaseSettingsFragment<Void>{
|
|||||||
private void maybeApplyNewThemeRightNow(GlobalUserPreferences.ThemePreference prevTheme, ColorPreference prevColor, Boolean prevTrueBlack){
|
private void maybeApplyNewThemeRightNow(GlobalUserPreferences.ThemePreference prevTheme, ColorPreference prevColor, Boolean prevTrueBlack){
|
||||||
if(prevTheme==null) prevTheme=GlobalUserPreferences.theme;
|
if(prevTheme==null) prevTheme=GlobalUserPreferences.theme;
|
||||||
if(prevTrueBlack==null) prevTrueBlack=GlobalUserPreferences.trueBlackTheme;
|
if(prevTrueBlack==null) prevTrueBlack=GlobalUserPreferences.trueBlackTheme;
|
||||||
if(prevColor==null) prevColor=lp.color;
|
if(prevColor==null) prevColor=lp.getCurrentColor();
|
||||||
|
|
||||||
boolean isCurrentDark=prevTheme==GlobalUserPreferences.ThemePreference.DARK ||
|
boolean isCurrentDark=prevTheme==GlobalUserPreferences.ThemePreference.DARK ||
|
||||||
(prevTheme==GlobalUserPreferences.ThemePreference.AUTO && Build.VERSION.SDK_INT>=30 && getResources().getConfiguration().isNightModeActive());
|
(prevTheme==GlobalUserPreferences.ThemePreference.AUTO && Build.VERSION.SDK_INT>=30 && getResources().getConfiguration().isNightModeActive());
|
||||||
boolean isNewDark=GlobalUserPreferences.theme==GlobalUserPreferences.ThemePreference.DARK ||
|
boolean isNewDark=GlobalUserPreferences.theme==GlobalUserPreferences.ThemePreference.DARK ||
|
||||||
(GlobalUserPreferences.theme==GlobalUserPreferences.ThemePreference.AUTO && Build.VERSION.SDK_INT>=30 && getResources().getConfiguration().isNightModeActive());
|
(GlobalUserPreferences.theme==GlobalUserPreferences.ThemePreference.AUTO && Build.VERSION.SDK_INT>=30 && getResources().getConfiguration().isNightModeActive());
|
||||||
boolean isNewBlack=GlobalUserPreferences.trueBlackTheme;
|
boolean isNewBlack=GlobalUserPreferences.trueBlackTheme;
|
||||||
if(isCurrentDark!=isNewDark || prevColor!=lp.color || (isNewDark && prevTrueBlack!=isNewBlack)){
|
if(isCurrentDark!=isNewDark || prevColor!=lp.getCurrentColor() || (isNewDark && prevTrueBlack!=isNewBlack)){
|
||||||
restartActivityToApplyNewTheme();
|
restartActivityToApplyNewTheme();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ public class SettingsFiltersFragment extends BaseSettingsFragment<Filter>{
|
|||||||
MergeRecyclerAdapter adapter=new MergeRecyclerAdapter();
|
MergeRecyclerAdapter adapter=new MergeRecyclerAdapter();
|
||||||
adapter.addAdapter(super.getAdapter());
|
adapter.addAdapter(super.getAdapter());
|
||||||
adapter.addAdapter(new GenericListItemsAdapter<>(Collections.singletonList(
|
adapter.addAdapter(new GenericListItemsAdapter<>(Collections.singletonList(
|
||||||
new ListItem<Void>(R.string.settings_add_filter, 0, R.drawable.ic_add_24px, this::onAddFilterClick)
|
new ListItem<Void>(R.string.settings_add_filter, 0, R.drawable.ic_fluent_add_24_regular, this::onAddFilterClick)
|
||||||
)));
|
)));
|
||||||
return adapter;
|
return adapter;
|
||||||
}
|
}
|
||||||
@@ -67,16 +67,14 @@ public class SettingsFiltersFragment extends BaseSettingsFragment<Filter>{
|
|||||||
Nav.go(getActivity(), EditFilterFragment.class, args);
|
Nav.go(getActivity(), EditFilterFragment.class, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onAddFilterClick(){
|
private void onAddFilterClick(ListItem<?> item){
|
||||||
Bundle args=new Bundle();
|
Bundle args=new Bundle();
|
||||||
args.putString("account", accountID);
|
args.putString("account", accountID);
|
||||||
Nav.go(getActivity(), EditFilterFragment.class, args);
|
Nav.go(getActivity(), EditFilterFragment.class, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ListItem<Filter> makeListItem(Filter f){
|
private ListItem<Filter> makeListItem(Filter f){
|
||||||
ListItem<Filter> item=new ListItem<>(f.title, getString(f.isActive() ? R.string.filter_active : R.string.filter_inactive), null, f);
|
ListItem<Filter> item=new ListItem<>(f.title, getString(f.isActive() ? R.string.filter_active : R.string.filter_inactive), this::onFilterClick, f);
|
||||||
item.onClick=()->onFilterClick(item);
|
|
||||||
item.isEnabled=true;
|
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import org.joinmastodon.android.ui.utils.UiUtils;
|
|||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.IntStream;
|
import java.util.stream.IntStream;
|
||||||
|
|
||||||
import me.grishka.appkit.Nav;
|
import me.grishka.appkit.Nav;
|
||||||
@@ -36,15 +37,15 @@ public class SettingsInstanceFragment extends BaseSettingsFragment<Void> impleme
|
|||||||
lp=s.getLocalPreferences();
|
lp=s.getLocalPreferences();
|
||||||
onDataLoaded(List.of(
|
onDataLoaded(List.of(
|
||||||
new ListItem<>(AccountSessionManager.get(accountID).domain, getString(R.string.settings_server_explanation), R.drawable.ic_fluent_server_24_regular, this::onServerClick),
|
new ListItem<>(AccountSessionManager.get(accountID).domain, getString(R.string.settings_server_explanation), R.drawable.ic_fluent_server_24_regular, this::onServerClick),
|
||||||
new ListItem<>(R.string.sk_settings_profile, 0, R.drawable.ic_fluent_open_24_regular, ()->UiUtils.launchWebBrowser(getActivity(), "https://"+s.domain+"/settings/profile")),
|
new ListItem<>(R.string.sk_settings_profile, 0, R.drawable.ic_fluent_open_24_regular, i->UiUtils.launchWebBrowser(getActivity(), "https://"+s.domain+"/settings/profile")),
|
||||||
new ListItem<>(R.string.sk_settings_posting, 0, R.drawable.ic_fluent_open_24_regular, ()->UiUtils.launchWebBrowser(getActivity(), "https://"+s.domain+"/settings/preferences/other")),
|
new ListItem<>(R.string.sk_settings_posting, 0, R.drawable.ic_fluent_open_24_regular, i->UiUtils.launchWebBrowser(getActivity(), "https://"+s.domain+"/settings/preferences/other")),
|
||||||
new ListItem<>(R.string.sk_settings_auth, 0, R.drawable.ic_fluent_open_24_regular, ()->UiUtils.launchWebBrowser(getActivity(), "https://"+s.domain+"/auth/edit"), 0, true),
|
new ListItem<>(R.string.sk_settings_auth, 0, R.drawable.ic_fluent_open_24_regular, i->UiUtils.launchWebBrowser(getActivity(), "https://"+s.domain+"/auth/edit"), 0, true),
|
||||||
contentTypesItem=new CheckableListItem<>(R.string.sk_settings_content_types, R.string.sk_settings_content_types_explanation, CheckableListItem.Style.SWITCH, lp.contentTypesEnabled, R.drawable.ic_fluent_text_edit_style_24_regular, this::onContentTypeClick),
|
contentTypesItem=new CheckableListItem<>(R.string.sk_settings_content_types, R.string.sk_settings_content_types_explanation, CheckableListItem.Style.SWITCH, lp.contentTypesEnabled, R.drawable.ic_fluent_text_edit_style_24_regular, i->onContentTypeClick()),
|
||||||
defaultContentTypeItem=new ListItem<>(R.string.sk_settings_default_content_type, lp.defaultContentType.getName(), R.drawable.ic_fluent_text_bold_24_regular, this::onDefaultContentTypeClick, 0, true),
|
defaultContentTypeItem=new ListItem<>(R.string.sk_settings_default_content_type, lp.defaultContentType.getName(), R.drawable.ic_fluent_text_bold_24_regular, this::onDefaultContentTypeClick, 0, true),
|
||||||
emojiReactionsItem=new CheckableListItem<>(R.string.sk_settings_emoji_reactions, R.string.sk_settings_emoji_reactions_explanation, CheckableListItem.Style.SWITCH, lp.emojiReactionsEnabled, R.drawable.ic_fluent_emoji_laugh_24_regular, this::onEmojiReactionsClick),
|
emojiReactionsItem=new CheckableListItem<>(R.string.sk_settings_emoji_reactions, R.string.sk_settings_emoji_reactions_explanation, CheckableListItem.Style.SWITCH, lp.emojiReactionsEnabled, R.drawable.ic_fluent_emoji_laugh_24_regular, i->onEmojiReactionsClick()),
|
||||||
showEmojiReactionsItem=new ListItem<>(R.string.sk_settings_show_emoji_reactions, getShowEmojiReactionsString(), R.drawable.ic_fluent_emoji_24_regular, this::onShowEmojiReactionsClick, 0, true),
|
showEmojiReactionsItem=new ListItem<>(R.string.sk_settings_show_emoji_reactions, getShowEmojiReactionsString(), R.drawable.ic_fluent_emoji_24_regular, this::onShowEmojiReactionsClick, 0, true),
|
||||||
localOnlyItem=new CheckableListItem<>(R.string.sk_settings_support_local_only, R.string.sk_settings_local_only_explanation, CheckableListItem.Style.SWITCH, lp.localOnlySupported, R.drawable.ic_fluent_eye_24_regular, this::onLocalOnlyClick),
|
localOnlyItem=new CheckableListItem<>(R.string.sk_settings_support_local_only, R.string.sk_settings_local_only_explanation, CheckableListItem.Style.SWITCH, lp.localOnlySupported, R.drawable.ic_fluent_eye_24_regular, i->onLocalOnlyClick()),
|
||||||
glitchModeItem=new CheckableListItem<>(R.string.sk_settings_glitch_instance, R.string.sk_settings_glitch_mode_explanation, CheckableListItem.Style.SWITCH, lp.glitchInstance, R.drawable.ic_fluent_eye_24_filled, ()->toggleCheckableItem(glitchModeItem))
|
glitchModeItem=new CheckableListItem<>(R.string.sk_settings_glitch_instance, R.string.sk_settings_glitch_mode_explanation, CheckableListItem.Style.SWITCH, lp.glitchInstance, R.drawable.ic_fluent_eye_24_filled, i->toggleCheckableItem(glitchModeItem))
|
||||||
));
|
));
|
||||||
contentTypesItem.checkedChangeListener=checked->onContentTypeClick();
|
contentTypesItem.checkedChangeListener=checked->onContentTypeClick();
|
||||||
defaultContentTypeItem.isEnabled=contentTypesItem.checked;
|
defaultContentTypeItem.isEnabled=contentTypesItem.checked;
|
||||||
@@ -68,7 +69,7 @@ public class SettingsInstanceFragment extends BaseSettingsFragment<Void> impleme
|
|||||||
E.post(new StatusDisplaySettingsChangedEvent(accountID));
|
E.post(new StatusDisplaySettingsChangedEvent(accountID));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onServerClick(){
|
private void onServerClick(ListItem<?> item){
|
||||||
Bundle args=new Bundle();
|
Bundle args=new Bundle();
|
||||||
args.putString("account", accountID);
|
args.putString("account", accountID);
|
||||||
Nav.go(getActivity(), SettingsServerFragment.class, args);
|
Nav.go(getActivity(), SettingsServerFragment.class, args);
|
||||||
@@ -87,23 +88,23 @@ public class SettingsInstanceFragment extends BaseSettingsFragment<Void> impleme
|
|||||||
defaultContentTypeItem.subtitleRes=lp.defaultContentType.getName();
|
defaultContentTypeItem.subtitleRes=lp.defaultContentType.getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onDefaultContentTypeClick(){
|
private void onDefaultContentTypeClick(ListItem<?> item_){
|
||||||
int selected=lp.defaultContentType.ordinal();
|
List<ContentType> supportedContentTypes=Arrays.stream(ContentType.values())
|
||||||
int[] newSelected={selected};
|
|
||||||
ContentType[] supportedContentTypes=Arrays.stream(ContentType.values())
|
|
||||||
.filter(t->t.supportedByInstance(getInstance().orElse(null)))
|
.filter(t->t.supportedByInstance(getInstance().orElse(null)))
|
||||||
.toArray(ContentType[]::new);
|
.collect(Collectors.toList());
|
||||||
String[] names=Arrays.stream(supportedContentTypes)
|
int selected=supportedContentTypes.indexOf(lp.defaultContentType);
|
||||||
|
int[] newSelected={selected};
|
||||||
|
String[] names=supportedContentTypes.stream()
|
||||||
.map(ContentType::getName)
|
.map(ContentType::getName)
|
||||||
.map(this::getString)
|
.map(this::getString)
|
||||||
.toArray(String[]::new);
|
.toArray(String[]::new);
|
||||||
|
|
||||||
new M3AlertDialogBuilder(getActivity())
|
new M3AlertDialogBuilder(getActivity())
|
||||||
.setTitle(R.string.settings_theme)
|
.setTitle(R.string.sk_settings_default_content_type)
|
||||||
.setSingleChoiceItems(names,
|
.setSingleChoiceItems(names,
|
||||||
selected, (dlg, item)->newSelected[0]=item)
|
selected, (dlg, item)->newSelected[0]=item)
|
||||||
.setPositiveButton(R.string.ok, (dlg, item)->{
|
.setPositiveButton(R.string.ok, (dlg, item)->{
|
||||||
ContentType type=supportedContentTypes[newSelected[0]];
|
ContentType type=supportedContentTypes.get(newSelected[0]);
|
||||||
lp.defaultContentType=type;
|
lp.defaultContentType=type;
|
||||||
defaultContentTypeItem.subtitleRes=type.getName();
|
defaultContentTypeItem.subtitleRes=type.getName();
|
||||||
rebindItem(defaultContentTypeItem);
|
rebindItem(defaultContentTypeItem);
|
||||||
@@ -112,7 +113,7 @@ public class SettingsInstanceFragment extends BaseSettingsFragment<Void> impleme
|
|||||||
.show();
|
.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onShowEmojiReactionsClick(){
|
private void onShowEmojiReactionsClick(ListItem<?> item_){
|
||||||
int selected=lp.showEmojiReactions.ordinal();
|
int selected=lp.showEmojiReactions.ordinal();
|
||||||
int[] newSelected={selected};
|
int[] newSelected={selected};
|
||||||
new M3AlertDialogBuilder(getActivity())
|
new M3AlertDialogBuilder(getActivity())
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import org.joinmastodon.android.api.session.AccountSessionManager;
|
|||||||
import org.joinmastodon.android.events.SelfUpdateStateChangedEvent;
|
import org.joinmastodon.android.events.SelfUpdateStateChangedEvent;
|
||||||
import org.joinmastodon.android.model.Instance;
|
import org.joinmastodon.android.model.Instance;
|
||||||
import org.joinmastodon.android.model.viewmodel.ListItem;
|
import org.joinmastodon.android.model.viewmodel.ListItem;
|
||||||
|
import org.joinmastodon.android.ui.AccountSwitcherSheet;
|
||||||
import org.joinmastodon.android.ui.M3AlertDialogBuilder;
|
import org.joinmastodon.android.ui.M3AlertDialogBuilder;
|
||||||
import org.joinmastodon.android.ui.utils.HideableSingleViewRecyclerAdapter;
|
import org.joinmastodon.android.ui.utils.HideableSingleViewRecyclerAdapter;
|
||||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||||
@@ -49,26 +50,27 @@ public class SettingsMainFragment extends BaseSettingsFragment<Void>{
|
|||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState){
|
public void onCreate(Bundle savedInstanceState){
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
account = AccountSessionManager.get(accountID);
|
account=AccountSessionManager.get(accountID);
|
||||||
setTitle(R.string.settings);
|
setTitle(R.string.settings);
|
||||||
setSubtitle(account.getFullUsername());
|
setSubtitle(account.getFullUsername());
|
||||||
onDataLoaded(List.of(
|
onDataLoaded(List.of(
|
||||||
new ListItem<>(R.string.settings_behavior, 0, R.drawable.ic_fluent_settings_24_regular, this::onBehaviorClick),
|
new ListItem<>(R.string.settings_behavior, 0, R.drawable.ic_fluent_settings_24_regular, this::onBehaviorClick),
|
||||||
new ListItem<>(R.string.settings_display, 0, R.drawable.ic_fluent_color_24_regular, this::onDisplayClick),
|
new ListItem<>(R.string.settings_display, 0, R.drawable.ic_fluent_color_24_regular, this::onDisplayClick),
|
||||||
new ListItem<>(R.string.settings_privacy, 0, R.drawable.ic_privacy_tip_24px, this::onPrivacyClick),
|
new ListItem<>(R.string.settings_privacy, 0, R.drawable.ic_fluent_shield_24_regular, this::onPrivacyClick),
|
||||||
new ListItem<>(R.string.settings_filters, 0, R.drawable.ic_filter_alt_24px, this::onFiltersClick),
|
|
||||||
new ListItem<>(R.string.settings_notifications, 0, R.drawable.ic_fluent_alert_24_regular, this::onNotificationsClick),
|
new ListItem<>(R.string.settings_notifications, 0, R.drawable.ic_fluent_alert_24_regular, this::onNotificationsClick),
|
||||||
new ListItem<>(R.string.sk_settings_instance, 0, R.drawable.ic_fluent_server_24_regular, this::onInstanceClick),
|
new ListItem<>(R.string.sk_settings_instance, 0, R.drawable.ic_fluent_server_24_regular, this::onInstanceClick),
|
||||||
new ListItem<>(getString(R.string.about_app, getString(R.string.sk_app_name)), null, R.drawable.ic_fluent_info_24_regular, this::onAboutClick, null, 0, true),
|
new ListItem<>(getString(R.string.about_app, getString(R.string.sk_app_name)), null, R.drawable.ic_fluent_info_24_regular, this::onAboutClick, null, 0, true),
|
||||||
|
new ListItem<>(R.string.manage_accounts, 0, R.drawable.ic_fluent_person_swap_24_regular, this::onManageAccountsClick),
|
||||||
new ListItem<>(R.string.log_out, 0, R.drawable.ic_fluent_sign_out_24_regular, this::onLogOutClick, R.attr.colorM3Error, false)
|
new ListItem<>(R.string.log_out, 0, R.drawable.ic_fluent_sign_out_24_regular, this::onLogOutClick, R.attr.colorM3Error, false)
|
||||||
));
|
));
|
||||||
|
|
||||||
Instance instance = AccountSessionManager.getInstance().getInstanceInfo(account.domain);
|
Instance instance=AccountSessionManager.getInstance().getInstanceInfo(account.domain);
|
||||||
if (!instance.isAkkoma())
|
if(!instance.isAkkoma()){
|
||||||
data.add(2, new ListItem<>(R.string.settings_filters, 0, R.drawable.ic_fluent_filter_24_regular, this::onFiltersClick));
|
data.add(3, new ListItem<>(R.string.settings_filters, 0, R.drawable.ic_fluent_filter_24_regular, this::onFiltersClick));
|
||||||
|
}
|
||||||
|
|
||||||
if(BuildConfig.DEBUG || BuildConfig.BUILD_TYPE.equals("appcenterPrivateBeta")){
|
if(BuildConfig.DEBUG || BuildConfig.BUILD_TYPE.equals("appcenterPrivateBeta")){
|
||||||
data.add(0, new ListItem<>("Debug settings", null, R.drawable.ic_fluent_wrench_screwdriver_24_regular, ()->Nav.go(getActivity(), SettingsDebugFragment.class, makeFragmentArgs()), null, 0, true));
|
data.add(0, new ListItem<>("Debug settings", null, R.drawable.ic_fluent_wrench_screwdriver_24_regular, i->Nav.go(getActivity(), SettingsDebugFragment.class, makeFragmentArgs()), null, 0, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
AccountSession session=AccountSessionManager.get(accountID);
|
AccountSession session=AccountSessionManager.get(accountID);
|
||||||
@@ -129,35 +131,39 @@ public class SettingsMainFragment extends BaseSettingsFragment<Void>{
|
|||||||
return args;
|
return args;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onBehaviorClick(){
|
private void onBehaviorClick(ListItem<?> item_){
|
||||||
Nav.go(getActivity(), SettingsBehaviorFragment.class, makeFragmentArgs());
|
Nav.go(getActivity(), SettingsBehaviorFragment.class, makeFragmentArgs());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onDisplayClick(){
|
private void onDisplayClick(ListItem<?> item_){
|
||||||
Nav.go(getActivity(), SettingsDisplayFragment.class, makeFragmentArgs());
|
Nav.go(getActivity(), SettingsDisplayFragment.class, makeFragmentArgs());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onPrivacyClick(){
|
private void onPrivacyClick(ListItem<?> item_){
|
||||||
Nav.go(getActivity(), SettingsPrivacyFragment.class, makeFragmentArgs());
|
Nav.go(getActivity(), SettingsPrivacyFragment.class, makeFragmentArgs());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onFiltersClick(){
|
private void onFiltersClick(ListItem<?> item_){
|
||||||
Nav.go(getActivity(), SettingsFiltersFragment.class, makeFragmentArgs());
|
Nav.go(getActivity(), SettingsFiltersFragment.class, makeFragmentArgs());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onNotificationsClick(){
|
private void onNotificationsClick(ListItem<?> item_){
|
||||||
Nav.go(getActivity(), SettingsNotificationsFragment.class, makeFragmentArgs());
|
Nav.go(getActivity(), SettingsNotificationsFragment.class, makeFragmentArgs());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onInstanceClick(){
|
private void onInstanceClick(ListItem<?> item_){
|
||||||
Nav.go(getActivity(), SettingsInstanceFragment.class, makeFragmentArgs());
|
Nav.go(getActivity(), SettingsInstanceFragment.class, makeFragmentArgs());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onAboutClick(){
|
private void onAboutClick(ListItem<?> item_){
|
||||||
Nav.go(getActivity(), SettingsAboutAppFragment.class, makeFragmentArgs());
|
Nav.go(getActivity(), SettingsAboutAppFragment.class, makeFragmentArgs());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onLogOutClick(){
|
private void onManageAccountsClick(ListItem<?> item){
|
||||||
|
new AccountSwitcherSheet(getActivity(), null).show();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onLogOutClick(ListItem<?> item_){
|
||||||
AccountSession session=AccountSessionManager.getInstance().getAccount(accountID);
|
AccountSession session=AccountSessionManager.getInstance().getAccount(accountID);
|
||||||
new M3AlertDialogBuilder(getActivity())
|
new M3AlertDialogBuilder(getActivity())
|
||||||
.setMessage(getString(R.string.confirm_log_out, session.getFullUsername()))
|
.setMessage(getString(R.string.confirm_log_out, session.getFullUsername()))
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ import org.joinmastodon.android.model.viewmodel.ListItem;
|
|||||||
import org.joinmastodon.android.ui.M3AlertDialogBuilder;
|
import org.joinmastodon.android.ui.M3AlertDialogBuilder;
|
||||||
import org.joinmastodon.android.ui.utils.HideableSingleViewRecyclerAdapter;
|
import org.joinmastodon.android.ui.utils.HideableSingleViewRecyclerAdapter;
|
||||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||||
import org.unifiedpush.android.connector.RegistrationDialogContent;
|
|
||||||
import org.unifiedpush.android.connector.UnifiedPush;
|
import org.unifiedpush.android.connector.UnifiedPush;
|
||||||
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
@@ -73,21 +72,21 @@ public class SettingsNotificationsFragment extends BaseSettingsFragment<Void>{
|
|||||||
useUnifiedPush=!getDistributor(getContext()).isEmpty();
|
useUnifiedPush=!getDistributor(getContext()).isEmpty();
|
||||||
|
|
||||||
onDataLoaded(List.of(
|
onDataLoaded(List.of(
|
||||||
pauseItem=new CheckableListItem<>(getString(R.string.pause_all_notifications), getPauseItemSubtitle(), CheckableListItem.Style.SWITCH, false, R.drawable.ic_fluent_alert_snooze_24_regular, ()->onPauseNotificationsClick(false)),
|
pauseItem=new CheckableListItem<>(getString(R.string.pause_all_notifications), getPauseItemSubtitle(), CheckableListItem.Style.SWITCH, false, R.drawable.ic_fluent_alert_snooze_24_regular, i->onPauseNotificationsClick(false)),
|
||||||
policyItem=new ListItem<>(R.string.settings_notifications_policy, 0, R.drawable.ic_fluent_people_24_regular, this::onNotificationsPolicyClick, 0, true),
|
policyItem=new ListItem<>(R.string.settings_notifications_policy, 0, R.drawable.ic_fluent_people_24_regular, this::onNotificationsPolicyClick, 0, true),
|
||||||
|
|
||||||
mentionsItem=new CheckableListItem<>(R.string.notification_type_mentions_and_replies, 0, CheckableListItem.Style.CHECKBOX, pushSubscription.alerts.mention, R.drawable.ic_fluent_mention_24_regular, ()->toggleCheckableItem(mentionsItem)),
|
mentionsItem=new CheckableListItem<>(R.string.notification_type_mentions_and_replies, 0, CheckableListItem.Style.CHECKBOX, pushSubscription.alerts.mention, R.drawable.ic_fluent_mention_24_regular, i->toggleCheckableItem(mentionsItem)),
|
||||||
boostsItem=new CheckableListItem<>(R.string.notification_type_reblog, 0, CheckableListItem.Style.CHECKBOX, pushSubscription.alerts.reblog, R.drawable.ic_fluent_arrow_repeat_all_24_regular, ()->toggleCheckableItem(boostsItem)),
|
boostsItem=new CheckableListItem<>(R.string.notification_type_reblog, 0, CheckableListItem.Style.CHECKBOX, pushSubscription.alerts.reblog, R.drawable.ic_fluent_arrow_repeat_all_24_regular, i->toggleCheckableItem(boostsItem)),
|
||||||
favoritesItem=new CheckableListItem<>(R.string.notification_type_favorite, 0, CheckableListItem.Style.CHECKBOX, pushSubscription.alerts.favourite, R.drawable.ic_fluent_star_24_regular, ()->toggleCheckableItem(favoritesItem)),
|
favoritesItem=new CheckableListItem<>(R.string.notification_type_favorite, 0, CheckableListItem.Style.CHECKBOX, pushSubscription.alerts.favourite, R.drawable.ic_fluent_star_24_regular, i->toggleCheckableItem(favoritesItem)),
|
||||||
followersItem=new CheckableListItem<>(R.string.notification_type_follow, 0, CheckableListItem.Style.CHECKBOX, pushSubscription.alerts.follow, R.drawable.ic_fluent_person_add_24_regular, ()->toggleCheckableItem(followersItem)),
|
followersItem=new CheckableListItem<>(R.string.notification_type_follow, 0, CheckableListItem.Style.CHECKBOX, pushSubscription.alerts.follow, R.drawable.ic_fluent_person_add_24_regular, i->toggleCheckableItem(followersItem)),
|
||||||
pollsItem=new CheckableListItem<>(R.string.notification_type_poll, 0, CheckableListItem.Style.CHECKBOX, pushSubscription.alerts.poll, R.drawable.ic_fluent_poll_24_regular, ()->toggleCheckableItem(pollsItem)),
|
pollsItem=new CheckableListItem<>(R.string.notification_type_poll, 0, CheckableListItem.Style.CHECKBOX, pushSubscription.alerts.poll, R.drawable.ic_fluent_poll_24_regular, i->toggleCheckableItem(pollsItem)),
|
||||||
updateItem=new CheckableListItem<>(R.string.sk_notification_type_update, 0, CheckableListItem.Style.CHECKBOX, pushSubscription.alerts.update, R.drawable.ic_fluent_history_24_regular, ()->toggleCheckableItem(updateItem)),
|
updateItem=new CheckableListItem<>(R.string.sk_notification_type_update, 0, CheckableListItem.Style.CHECKBOX, pushSubscription.alerts.update, R.drawable.ic_fluent_history_24_regular, i->toggleCheckableItem(updateItem)),
|
||||||
postsItem=new CheckableListItem<>(R.string.sk_notification_type_posts, 0, CheckableListItem.Style.CHECKBOX, pushSubscription.alerts.status, R.drawable.ic_fluent_chat_24_regular, ()->toggleCheckableItem(postsItem), true),
|
postsItem=new CheckableListItem<>(R.string.sk_notification_type_posts, 0, CheckableListItem.Style.CHECKBOX, pushSubscription.alerts.status, R.drawable.ic_fluent_chat_24_regular, i->toggleCheckableItem(postsItem), true),
|
||||||
|
|
||||||
uniformIconItem=new CheckableListItem<>(R.string.sk_settings_uniform_icon_for_notifications, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.uniformNotificationIcon, R.drawable.ic_ntf_logo, ()->toggleCheckableItem(uniformIconItem)),
|
uniformIconItem=new CheckableListItem<>(R.string.sk_settings_uniform_icon_for_notifications, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.uniformNotificationIcon, R.drawable.ic_ntf_logo, i->toggleCheckableItem(uniformIconItem)),
|
||||||
deleteItem=new CheckableListItem<>(R.string.sk_settings_enable_delete_notifications, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.enableDeleteNotifications, R.drawable.ic_fluent_mail_inbox_dismiss_24_regular, ()->toggleCheckableItem(deleteItem)),
|
deleteItem=new CheckableListItem<>(R.string.sk_settings_enable_delete_notifications, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.enableDeleteNotifications, R.drawable.ic_fluent_mail_inbox_dismiss_24_regular, i->toggleCheckableItem(deleteItem)),
|
||||||
onlyLatestItem=new CheckableListItem<>(R.string.sk_settings_single_notification, 0, CheckableListItem.Style.SWITCH, lp.keepOnlyLatestNotification, R.drawable.ic_fluent_convert_range_24_regular, ()->toggleCheckableItem(onlyLatestItem), true),
|
onlyLatestItem=new CheckableListItem<>(R.string.sk_settings_single_notification, 0, CheckableListItem.Style.SWITCH, lp.keepOnlyLatestNotification, R.drawable.ic_fluent_convert_range_24_regular, i->toggleCheckableItem(onlyLatestItem), true),
|
||||||
unifiedPushItem=new CheckableListItem<>(R.string.sk_settings_unifiedpush, 0, CheckableListItem.Style.SWITCH, useUnifiedPush, R.drawable.ic_fluent_alert_arrow_up_24_regular, this::onUnifiedPush, true)
|
unifiedPushItem=new CheckableListItem<>(R.string.sk_settings_unifiedpush, 0, CheckableListItem.Style.SWITCH, useUnifiedPush, R.drawable.ic_fluent_alert_arrow_up_24_regular, i->onUnifiedPushClick(), true)
|
||||||
));
|
));
|
||||||
|
|
||||||
//only enable when distributors, who can receive notifications, are available
|
//only enable when distributors, who can receive notifications, are available
|
||||||
@@ -98,7 +97,7 @@ public class SettingsNotificationsFragment extends BaseSettingsFragment<Void>{
|
|||||||
|
|
||||||
typeItems=List.of(mentionsItem, boostsItem, favoritesItem, followersItem, pollsItem, updateItem, postsItem);
|
typeItems=List.of(mentionsItem, boostsItem, favoritesItem, followersItem, pollsItem, updateItem, postsItem);
|
||||||
pauseItem.checkedChangeListener=checked->onPauseNotificationsClick(true);
|
pauseItem.checkedChangeListener=checked->onPauseNotificationsClick(true);
|
||||||
unifiedPushItem.checkedChangeListener=checked->onUnifiedPush();
|
unifiedPushItem.checkedChangeListener=checked->onUnifiedPushClick();
|
||||||
updatePolicyItem(null);
|
updatePolicyItem(null);
|
||||||
updatePauseItem();
|
updatePauseItem();
|
||||||
}
|
}
|
||||||
@@ -254,7 +253,7 @@ public class SettingsNotificationsFragment extends BaseSettingsFragment<Void>{
|
|||||||
alert.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false);
|
alert.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onNotificationsPolicyClick(){
|
private void onNotificationsPolicyClick(ListItem<?> item_){
|
||||||
String[] items=Stream.of(
|
String[] items=Stream.of(
|
||||||
R.string.notifications_policy_anyone,
|
R.string.notifications_policy_anyone,
|
||||||
R.string.notifications_policy_followed,
|
R.string.notifications_policy_followed,
|
||||||
@@ -328,7 +327,7 @@ public class SettingsNotificationsFragment extends BaseSettingsFragment<Void>{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onUnifiedPush(){
|
private void onUnifiedPushClick(){
|
||||||
if(getDistributor(getContext()).isEmpty()){
|
if(getDistributor(getContext()).isEmpty()){
|
||||||
List<String> distributors = UnifiedPush.getDistributors(getContext(), new ArrayList<>());
|
List<String> distributors = UnifiedPush.getDistributors(getContext(), new ArrayList<>());
|
||||||
showUnifiedPushRegisterDialog(distributors);
|
showUnifiedPushRegisterDialog(distributors);
|
||||||
|
|||||||
@@ -2,40 +2,98 @@ package org.joinmastodon.android.fragments.settings;
|
|||||||
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
|
||||||
|
import androidx.annotation.StringRes;
|
||||||
|
|
||||||
import org.joinmastodon.android.R;
|
import org.joinmastodon.android.R;
|
||||||
|
import org.joinmastodon.android.api.session.AccountSession;
|
||||||
import org.joinmastodon.android.api.session.AccountSessionManager;
|
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||||
import org.joinmastodon.android.model.Account;
|
import org.joinmastodon.android.model.Account;
|
||||||
|
import org.joinmastodon.android.model.Instance;
|
||||||
|
import org.joinmastodon.android.model.StatusPrivacy;
|
||||||
import org.joinmastodon.android.model.viewmodel.CheckableListItem;
|
import org.joinmastodon.android.model.viewmodel.CheckableListItem;
|
||||||
|
import org.joinmastodon.android.model.viewmodel.ListItem;
|
||||||
|
import org.joinmastodon.android.ui.M3AlertDialogBuilder;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class SettingsPrivacyFragment extends BaseSettingsFragment<Void>{
|
public class SettingsPrivacyFragment extends BaseSettingsFragment<Void>{
|
||||||
private CheckableListItem<Void> discoverableItem, indexableItem;
|
private CheckableListItem<Void> discoverableItem, indexableItem, lockedItem;
|
||||||
|
private ListItem<Void> privacyItem;
|
||||||
|
private StatusPrivacy privacy=null;
|
||||||
|
private Instance instance;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState){
|
public void onCreate(Bundle savedInstanceState){
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
setTitle(R.string.settings_privacy);
|
setTitle(R.string.settings_privacy);
|
||||||
Account self=AccountSessionManager.get(accountID).self;
|
AccountSession session=AccountSessionManager.get(accountID);
|
||||||
|
Account self=session.self;
|
||||||
|
instance=AccountSessionManager.getInstance().getInstanceInfo(session.domain);
|
||||||
|
privacy=self.source.privacy;
|
||||||
onDataLoaded(List.of(
|
onDataLoaded(List.of(
|
||||||
discoverableItem=new CheckableListItem<>(R.string.settings_discoverable, 0, CheckableListItem.Style.SWITCH, self.discoverable, R.drawable.ic_thumbs_up_down_24px, ()->toggleCheckableItem(discoverableItem)),
|
privacyItem=new ListItem<>(R.string.sk_settings_default_visibility, getPrivacyString(privacy), R.drawable.ic_fluent_eye_24_regular, this::onPrivacyClick, 0, true),
|
||||||
indexableItem=new CheckableListItem<>(R.string.settings_indexable, 0, CheckableListItem.Style.SWITCH, self.source.indexable!=null ? self.source.indexable : true, R.drawable.ic_search_24px, ()->toggleCheckableItem(indexableItem))
|
lockedItem=new CheckableListItem<>(R.string.sk_settings_lock_account, 0, CheckableListItem.Style.SWITCH, self.locked, R.drawable.ic_fluent_person_available_24_regular, i->toggleCheckableItem(lockedItem))
|
||||||
));
|
));
|
||||||
if(self.source.indexable==null)
|
|
||||||
indexableItem.isEnabled=false;
|
if(!instance.isAkkoma()){
|
||||||
|
data.addAll(List.of(
|
||||||
|
discoverableItem=new CheckableListItem<>(R.string.settings_discoverable, 0, CheckableListItem.Style.SWITCH, self.discoverable, R.drawable.ic_fluent_thumb_like_dislike_24_regular, i->toggleCheckableItem(discoverableItem)),
|
||||||
|
indexableItem=new CheckableListItem<>(R.string.settings_indexable, 0, CheckableListItem.Style.SWITCH, self.source.indexable!=null ? self.source.indexable : true, R.drawable.ic_fluent_search_24_regular, i->toggleCheckableItem(indexableItem))
|
||||||
|
));
|
||||||
|
if(self.source.indexable==null)
|
||||||
|
indexableItem.isEnabled=false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doLoadData(int offset, int count){}
|
protected void doLoadData(int offset, int count){}
|
||||||
|
|
||||||
|
private @StringRes int getPrivacyString(StatusPrivacy p){
|
||||||
|
if(p==null) return R.string.visibility_public;
|
||||||
|
return switch(p){
|
||||||
|
case PUBLIC -> R.string.visibility_public;
|
||||||
|
case UNLISTED -> R.string.sk_visibility_unlisted;
|
||||||
|
case PRIVATE -> R.string.visibility_followers_only;
|
||||||
|
case DIRECT -> R.string.visibility_private;
|
||||||
|
case LOCAL -> R.string.sk_local_only;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onPrivacyClick(ListItem<?> item_){
|
||||||
|
Account self=AccountSessionManager.get(accountID).self;
|
||||||
|
List<StatusPrivacy> options=new ArrayList<>(List.of(StatusPrivacy.PUBLIC, StatusPrivacy.UNLISTED, StatusPrivacy.PRIVATE, StatusPrivacy.DIRECT));
|
||||||
|
if(instance.isAkkoma()) options.add(StatusPrivacy.LOCAL);
|
||||||
|
int selected=options.indexOf(self.source.privacy);
|
||||||
|
int[] newSelected={selected};
|
||||||
|
new M3AlertDialogBuilder(getActivity())
|
||||||
|
.setTitle(R.string.sk_settings_default_visibility)
|
||||||
|
.setSingleChoiceItems(options.stream().map(this::getPrivacyString).map(this::getString).toArray(String[]::new),
|
||||||
|
selected, (dlg, item)->newSelected[0]=item)
|
||||||
|
.setPositiveButton(R.string.ok, (dlg, item)->{
|
||||||
|
privacy=options.get(newSelected[0]);
|
||||||
|
privacyItem.subtitleRes=getPrivacyString(privacy);
|
||||||
|
rebindItem(privacyItem);
|
||||||
|
})
|
||||||
|
.setNegativeButton(R.string.cancel, null)
|
||||||
|
.show();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPause(){
|
public void onPause(){
|
||||||
super.onPause();
|
super.onPause();
|
||||||
Account self=AccountSessionManager.get(accountID).self;
|
AccountSession s=AccountSessionManager.get(accountID);
|
||||||
if(self.discoverable!=discoverableItem.checked || (self.source.indexable!=null && self.source.indexable!=indexableItem.checked)){
|
Account self=s.self;
|
||||||
self.discoverable=discoverableItem.checked;
|
boolean savePlease=self.locked!=lockedItem.checked
|
||||||
self.source.indexable=indexableItem.checked;
|
|| self.source.privacy!=privacy
|
||||||
AccountSessionManager.get(accountID).savePreferencesLater();
|
|| (discoverableItem!=null && self.discoverable!=discoverableItem.checked)
|
||||||
|
|| (indexableItem!=null && self.source.indexable!=null && self.source.indexable!=indexableItem.checked);
|
||||||
|
if(savePlease){
|
||||||
|
if(discoverableItem!=null) self.discoverable=discoverableItem.checked;
|
||||||
|
if(indexableItem!=null) self.source.indexable=indexableItem.checked;
|
||||||
|
self.locked=lockedItem.checked;
|
||||||
|
s.preferences.postingDefaultVisibility=privacy;
|
||||||
|
s.savePreferencesLater();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -145,7 +145,7 @@ public class SettingsServerAboutFragment extends LoaderFragment{
|
|||||||
if(!TextUtils.isEmpty(instance.email)){
|
if(!TextUtils.isEmpty(instance.email)){
|
||||||
needDivider=true;
|
needDivider=true;
|
||||||
SimpleListItemViewHolder holder=new SimpleListItemViewHolder(getActivity(), scrollingLayout);
|
SimpleListItemViewHolder holder=new SimpleListItemViewHolder(getActivity(), scrollingLayout);
|
||||||
ListItem<Void> item=new ListItem<>(R.string.send_email_to_server_admin, 0, R.drawable.ic_fluent_mail_24_regular, ()->{});
|
ListItem<Void> item=new ListItem<>(R.string.send_email_to_server_admin, 0, R.drawable.ic_fluent_mail_24_regular, i->{});
|
||||||
holder.bind(item);
|
holder.bind(item);
|
||||||
holder.itemView.setBackground(UiUtils.getThemeDrawable(getActivity(), android.R.attr.selectableItemBackground));
|
holder.itemView.setBackground(UiUtils.getThemeDrawable(getActivity(), android.R.attr.selectableItemBackground));
|
||||||
holder.itemView.setOnClickListener(v->openAdminEmail());
|
holder.itemView.setOnClickListener(v->openAdminEmail());
|
||||||
|
|||||||
@@ -6,8 +6,6 @@ import android.text.TextUtils;
|
|||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
import org.joinmastodon.android.api.ObjectValidationException;
|
import org.joinmastodon.android.api.ObjectValidationException;
|
||||||
import org.joinmastodon.android.api.RequiredField;
|
|
||||||
import org.joinmastodon.android.api.requests.instance.GetInstance;
|
|
||||||
import org.parceler.Parcel;
|
import org.parceler.Parcel;
|
||||||
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
@@ -15,9 +13,6 @@ import java.time.LocalDate;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import me.grishka.appkit.api.Callback;
|
|
||||||
import me.grishka.appkit.api.ErrorResponse;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a user of Mastodon and their associated profile.
|
* Represents a user of Mastodon and their associated profile.
|
||||||
*/
|
*/
|
||||||
@@ -163,26 +158,26 @@ public class Account extends BaseModel implements Searchable{
|
|||||||
if(fields!=null){
|
if(fields!=null){
|
||||||
for(AccountField f:fields)
|
for(AccountField f:fields)
|
||||||
f.postprocess();
|
f.postprocess();
|
||||||
} else {
|
}else{
|
||||||
fields = Collections.emptyList();
|
fields=Collections.emptyList();
|
||||||
}
|
}
|
||||||
if(emojis!=null){
|
if(emojis!=null){
|
||||||
for(Emoji e:emojis)
|
for(Emoji e:emojis)
|
||||||
e.postprocess();
|
e.postprocess();
|
||||||
} else {
|
}else{
|
||||||
emojis = Collections.emptyList();
|
emojis=Collections.emptyList();
|
||||||
}
|
}
|
||||||
if(moved!=null)
|
if(moved!=null)
|
||||||
moved.postprocess();
|
moved.postprocess();
|
||||||
if(fqn == null) fqn = getFullyQualifiedName();
|
if(fqn==null) fqn=getFullyQualifiedName();
|
||||||
if(id == null) id = "";
|
if(id==null) id="";
|
||||||
if(username == null) username = "";
|
if(username==null) username="";
|
||||||
if(TextUtils.isEmpty(displayName))
|
if(TextUtils.isEmpty(displayName))
|
||||||
displayName = !TextUtils.isEmpty(username) ? username : "";
|
displayName=!TextUtils.isEmpty(username) ? username : "";
|
||||||
if(acct == null) acct = "";
|
if(acct==null) acct="";
|
||||||
if(url == null) url = "";
|
if(url==null) url="";
|
||||||
if(note == null) note = "";
|
if(note==null) note="";
|
||||||
if(avatar == null) avatar = "";
|
if(avatar==null) avatar="";
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isLocal(){
|
public boolean isLocal(){
|
||||||
@@ -212,6 +207,10 @@ public class Account extends BaseModel implements Searchable{
|
|||||||
return fqn != null ? fqn : acct.split("@")[0] + "@" + getDomainFromURL();
|
return fqn != null ? fqn : acct.split("@")[0] + "@" + getDomainFromURL();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getDisplayName(){
|
||||||
|
return '\u2068'+displayName+'\u2069';
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString(){
|
public String toString(){
|
||||||
return "Account{"+
|
return "Account{"+
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ public class Announcement extends BaseModel implements DisplayItemsParent {
|
|||||||
|
|
||||||
public Status toStatus() {
|
public Status toStatus() {
|
||||||
Status s=Status.ofFake(id, content, publishedAt);
|
Status s=Status.ofFake(id, content, publishedAt);
|
||||||
s.createdAt=startsAt != null ? startsAt : publishedAt;
|
s.createdAt=startsAt != null ? startsAt : publishedAt;
|
||||||
s.reactions=reactions;
|
s.reactions=reactions;
|
||||||
if(updatedAt != null) s.editedAt=updatedAt;
|
if(updatedAt != null) s.editedAt=updatedAt;
|
||||||
return s;
|
return s;
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import org.joinmastodon.android.model.Poll.Option;
|
|||||||
import org.parceler.Parcel;
|
import org.parceler.Parcel;
|
||||||
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
import java.time.temporal.ChronoUnit;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@@ -27,10 +28,10 @@ public class ScheduledStatus extends BaseModel implements DisplayItemsParent{
|
|||||||
@Override
|
@Override
|
||||||
public void postprocess() throws ObjectValidationException {
|
public void postprocess() throws ObjectValidationException {
|
||||||
super.postprocess();
|
super.postprocess();
|
||||||
if (mediaAttachments == null) mediaAttachments = List.of();
|
if(mediaAttachments==null) mediaAttachments=List.of();
|
||||||
for(Attachment a:mediaAttachments)
|
for(Attachment a:mediaAttachments)
|
||||||
a.postprocess();
|
a.postprocess();
|
||||||
if (params != null) params.postprocess();
|
if(params!=null) params.postprocess();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Parcel
|
@Parcel
|
||||||
@@ -53,7 +54,7 @@ public class ScheduledStatus extends BaseModel implements DisplayItemsParent{
|
|||||||
@Override
|
@Override
|
||||||
public void postprocess() throws ObjectValidationException {
|
public void postprocess() throws ObjectValidationException {
|
||||||
super.postprocess();
|
super.postprocess();
|
||||||
if (poll != null) poll.postprocess();
|
if(poll!=null) poll.postprocess();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,25 +68,26 @@ public class ScheduledStatus extends BaseModel implements DisplayItemsParent{
|
|||||||
public boolean hideTotals;
|
public boolean hideTotals;
|
||||||
|
|
||||||
public Poll toPoll() {
|
public Poll toPoll() {
|
||||||
Poll p = new Poll();
|
Poll p=new Poll();
|
||||||
p.voted = true;
|
p.voted=true;
|
||||||
p.emojis = List.of();
|
p.emojis=List.of();
|
||||||
p.ownVotes = List.of();
|
p.ownVotes=List.of();
|
||||||
p.multiple = multiple;
|
p.multiple=multiple;
|
||||||
p.options = options.stream().map(Option::new).collect(Collectors.toList());
|
p.options=options.stream().map(Option::new).collect(Collectors.toList());
|
||||||
|
p.expiresAt=Instant.now().plus(Integer.parseInt(expiresIn)+1, ChronoUnit.SECONDS);
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Status toStatus() {
|
public Status toStatus() {
|
||||||
Status s = Status.ofFake(id, params.text, scheduledAt);
|
Status s=Status.ofFake(id, params.text, scheduledAt);
|
||||||
s.mediaAttachments = mediaAttachments;
|
s.mediaAttachments=mediaAttachments;
|
||||||
s.inReplyToId = params.inReplyToId > 0 ? "" + params.inReplyToId : null;
|
s.inReplyToId=params.inReplyToId>0 ? ""+params.inReplyToId : null;
|
||||||
s.spoilerText = params.spoilerText;
|
s.spoilerText=params.spoilerText;
|
||||||
s.visibility = params.visibility;
|
s.visibility=params.visibility;
|
||||||
s.language = params.language;
|
s.language=params.language;
|
||||||
s.sensitive = params.sensitive;
|
s.sensitive=params.sensitive;
|
||||||
if (params.poll != null) s.poll = params.poll.toPoll();
|
if(params.poll!=null) s.poll=params.poll.toPoll();
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,22 +26,13 @@ import com.google.gson.JsonElement;
|
|||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
import com.google.gson.JsonParseException;
|
import com.google.gson.JsonParseException;
|
||||||
|
|
||||||
import org.joinmastodon.android.api.ObjectValidationException;
|
|
||||||
import org.joinmastodon.android.api.RequiredField;
|
|
||||||
import org.joinmastodon.android.api.session.AccountSession;
|
import org.joinmastodon.android.api.session.AccountSession;
|
||||||
import org.joinmastodon.android.api.session.AccountSessionManager;
|
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||||
import org.joinmastodon.android.events.EmojiReactionsUpdatedEvent;
|
import org.joinmastodon.android.events.EmojiReactionsUpdatedEvent;
|
||||||
import org.joinmastodon.android.events.StatusCountersUpdatedEvent;
|
|
||||||
import org.joinmastodon.android.ui.text.HtmlParser;
|
|
||||||
import org.joinmastodon.android.utils.StatusTextEncoder;
|
import org.joinmastodon.android.utils.StatusTextEncoder;
|
||||||
import org.parceler.Parcel;
|
|
||||||
|
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
import java.time.Instant;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
@Parcel
|
@Parcel
|
||||||
@@ -100,10 +91,11 @@ public class Status extends BaseModel implements DisplayItemsParent, Searchable{
|
|||||||
public transient boolean spoilerRevealed;
|
public transient boolean spoilerRevealed;
|
||||||
public transient boolean sensitiveRevealed;
|
public transient boolean sensitiveRevealed;
|
||||||
public transient boolean textExpanded, textExpandable;
|
public transient boolean textExpanded, textExpandable;
|
||||||
public transient boolean hasGapAfter;
|
public transient String hasGapAfter;
|
||||||
private transient String strippedText;
|
private transient String strippedText;
|
||||||
public transient TranslationState translationState=TranslationState.HIDDEN;
|
public transient TranslationState translationState=TranslationState.HIDDEN;
|
||||||
public transient Translation translation;
|
public transient Translation translation;
|
||||||
|
public transient boolean fromStatusCreated;
|
||||||
|
|
||||||
public Status(){}
|
public Status(){}
|
||||||
|
|
||||||
@@ -203,6 +195,10 @@ public class Status extends BaseModel implements DisplayItemsParent, Searchable{
|
|||||||
return reblog!=null ? reblog : this;
|
return reblog!=null ? reblog : this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getContentStatusID(){
|
||||||
|
return getContentStatus().id;
|
||||||
|
}
|
||||||
|
|
||||||
public String getStrippedText(){
|
public String getStrippedText(){
|
||||||
if(strippedText==null)
|
if(strippedText==null)
|
||||||
strippedText=HtmlParser.strip(content);
|
strippedText=HtmlParser.strip(content);
|
||||||
|
|||||||
@@ -33,9 +33,9 @@ public class AccountViewModel{
|
|||||||
V.dp(50), V.dp(50));
|
V.dp(50), V.dp(50));
|
||||||
emojiHelper=new CustomEmojiHelper();
|
emojiHelper=new CustomEmojiHelper();
|
||||||
if(session.getLocalPreferences().customEmojiInNames)
|
if(session.getLocalPreferences().customEmojiInNames)
|
||||||
parsedName=HtmlParser.parseCustomEmoji(account.displayName, account.emojis);
|
parsedName=HtmlParser.parseCustomEmoji(account.getDisplayName(), account.emojis);
|
||||||
else
|
else
|
||||||
parsedName=account.displayName;
|
parsedName=account.getDisplayName();
|
||||||
parsedBio=HtmlParser.parse(account.note, account.emojis, Collections.emptyList(), Collections.emptyList(), accountID);
|
parsedBio=HtmlParser.parse(account.note, account.emojis, Collections.emptyList(), Collections.emptyList(), accountID);
|
||||||
SpannableStringBuilder ssb=new SpannableStringBuilder(parsedName);
|
SpannableStringBuilder ssb=new SpannableStringBuilder(parsedName);
|
||||||
ssb.append(parsedBio);
|
ssb.append(parsedBio);
|
||||||
|
|||||||
@@ -9,42 +9,42 @@ public class CheckableListItem<T> extends ListItem<T>{
|
|||||||
public boolean checked;
|
public boolean checked;
|
||||||
public Consumer<Boolean> checkedChangeListener;
|
public Consumer<Boolean> checkedChangeListener;
|
||||||
|
|
||||||
public CheckableListItem(String title, String subtitle, Style style, boolean checked, int iconRes, Runnable onClick, T parentObject, boolean dividerAfter){
|
public CheckableListItem(String title, String subtitle, Style style, boolean checked, int iconRes, Consumer<CheckableListItem<T>> onClick, T parentObject, boolean dividerAfter){
|
||||||
super(title, subtitle, iconRes, onClick, parentObject, 0, dividerAfter);
|
super(title, subtitle, iconRes, (Consumer<ListItem<T>>)(Object)onClick, parentObject, 0, dividerAfter);
|
||||||
this.style=style;
|
this.style=style;
|
||||||
this.checked=checked;
|
this.checked=checked;
|
||||||
}
|
}
|
||||||
|
|
||||||
public CheckableListItem(String title, String subtitle, Style style, boolean checked, Runnable onClick){
|
public CheckableListItem(String title, String subtitle, Style style, boolean checked, Consumer<CheckableListItem<T>> onClick){
|
||||||
this(title, subtitle, style, checked, 0, onClick, null, false);
|
this(title, subtitle, style, checked, 0, onClick, null, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public CheckableListItem(String title, String subtitle, Style style, boolean checked, Runnable onClick, T parentObject){
|
public CheckableListItem(String title, String subtitle, Style style, boolean checked, Consumer<CheckableListItem<T>> onClick, T parentObject){
|
||||||
this(title, subtitle, style, checked, 0, onClick, parentObject, false);
|
this(title, subtitle, style, checked, 0, onClick, parentObject, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public CheckableListItem(String title, String subtitle, Style style, boolean checked, int iconRes, Runnable onClick){
|
public CheckableListItem(String title, String subtitle, Style style, boolean checked, int iconRes, Consumer<CheckableListItem<T>> onClick){
|
||||||
this(title, subtitle, style, checked, iconRes, onClick, null, false);
|
this(title, subtitle, style, checked, iconRes, onClick, null, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public CheckableListItem(String title, String subtitle, Style style, boolean checked, int iconRes, Runnable onClick, T parentObject){
|
public CheckableListItem(String title, String subtitle, Style style, boolean checked, int iconRes, Consumer<CheckableListItem<T>> onClick, T parentObject){
|
||||||
this(title, subtitle, style, checked, iconRes, onClick, parentObject, false);
|
this(title, subtitle, style, checked, iconRes, onClick, parentObject, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public CheckableListItem(int titleRes, int subtitleRes, Style style, boolean checked, Runnable onClick){
|
public CheckableListItem(int titleRes, int subtitleRes, Style style, boolean checked, Consumer<CheckableListItem<T>> onClick){
|
||||||
this(titleRes, subtitleRes, style, checked, 0, onClick, false);
|
this(titleRes, subtitleRes, style, checked, 0, onClick, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public CheckableListItem(int titleRes, int subtitleRes, Style style, boolean checked, Runnable onClick, boolean dividerAfter){
|
public CheckableListItem(int titleRes, int subtitleRes, Style style, boolean checked, Consumer<CheckableListItem<T>> onClick, boolean dividerAfter){
|
||||||
this(titleRes, subtitleRes, style, checked, 0, onClick, dividerAfter);
|
this(titleRes, subtitleRes, style, checked, 0, onClick, dividerAfter);
|
||||||
}
|
}
|
||||||
|
|
||||||
public CheckableListItem(int titleRes, int subtitleRes, Style style, boolean checked, int iconRes, Runnable onClick){
|
public CheckableListItem(int titleRes, int subtitleRes, Style style, boolean checked, int iconRes, Consumer<CheckableListItem<T>> onClick){
|
||||||
this(titleRes, subtitleRes, style, checked, iconRes, onClick, false);
|
this(titleRes, subtitleRes, style, checked, iconRes, onClick, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public CheckableListItem(int titleRes, int subtitleRes, Style style, boolean checked, int iconRes, Runnable onClick, boolean dividerAfter){
|
public CheckableListItem(int titleRes, int subtitleRes, Style style, boolean checked, int iconRes, Consumer<CheckableListItem<T>> onClick, boolean dividerAfter){
|
||||||
super(titleRes, subtitleRes, iconRes, onClick, 0, dividerAfter);
|
super(titleRes, subtitleRes, iconRes, (Consumer<ListItem<T>>)(Object)onClick, 0, dividerAfter);
|
||||||
this.style=style;
|
this.style=style;
|
||||||
this.checked=checked;
|
this.checked=checked;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ package org.joinmastodon.android.model.viewmodel;
|
|||||||
|
|
||||||
import org.joinmastodon.android.R;
|
import org.joinmastodon.android.R;
|
||||||
|
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
import androidx.annotation.DrawableRes;
|
import androidx.annotation.DrawableRes;
|
||||||
import androidx.annotation.StringRes;
|
import androidx.annotation.StringRes;
|
||||||
|
|
||||||
@@ -16,11 +18,11 @@ public class ListItem<T>{
|
|||||||
public int iconRes;
|
public int iconRes;
|
||||||
public int colorOverrideAttr;
|
public int colorOverrideAttr;
|
||||||
public boolean dividerAfter;
|
public boolean dividerAfter;
|
||||||
public Runnable onClick;
|
private Consumer<ListItem<T>> onClick;
|
||||||
public boolean isEnabled=true;
|
public boolean isEnabled=true;
|
||||||
public T parentObject;
|
public T parentObject;
|
||||||
|
|
||||||
public ListItem(String title, String subtitle, int iconRes, Runnable onClick, T parentObject, int colorOverrideAttr, boolean dividerAfter){
|
public ListItem(String title, String subtitle, int iconRes, Consumer<ListItem<T>> onClick, T parentObject, int colorOverrideAttr, boolean dividerAfter){
|
||||||
this.title=title;
|
this.title=title;
|
||||||
this.subtitle=subtitle;
|
this.subtitle=subtitle;
|
||||||
this.iconRes=iconRes;
|
this.iconRes=iconRes;
|
||||||
@@ -32,45 +34,41 @@ public class ListItem<T>{
|
|||||||
isEnabled=false;
|
isEnabled=false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ListItem(String title, String subtitle, Runnable onClick){
|
public ListItem(String title, String subtitle, Consumer<ListItem<T>> onClick){
|
||||||
this(title, subtitle, 0, onClick, null, 0, false);
|
this(title, subtitle, 0, onClick, null, 0, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ListItem(String title, String subtitle, Runnable onClick, T parentObject){
|
public ListItem(String title, String subtitle, Consumer<ListItem<T>> onClick, T parentObject){
|
||||||
this(title, subtitle, 0, onClick, parentObject, 0, false);
|
this(title, subtitle, 0, onClick, parentObject, 0, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ListItem(String title, String subtitle, @DrawableRes int iconRes, Runnable onClick){
|
public ListItem(String title, String subtitle, @DrawableRes int iconRes, Consumer<ListItem<T>> onClick){
|
||||||
this(title, subtitle, iconRes, onClick, null, 0, false);
|
this(title, subtitle, iconRes, onClick, null, 0, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ListItem(String title, String subtitle, @DrawableRes int iconRes, Runnable onClick, boolean dividerAfter){
|
public ListItem(String title, String subtitle, @DrawableRes int iconRes, Consumer<ListItem<T>> onClick, T parentObject){
|
||||||
this(title, subtitle, iconRes, onClick, null, 0, dividerAfter);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ListItem(String title, String subtitle, @DrawableRes int iconRes, Runnable onClick, T parentObject){
|
|
||||||
this(title, subtitle, iconRes, onClick, parentObject, 0, false);
|
this(title, subtitle, iconRes, onClick, parentObject, 0, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ListItem(@StringRes int titleRes, @StringRes int subtitleRes, Runnable onClick){
|
public ListItem(@StringRes int titleRes, @StringRes int subtitleRes, Consumer<ListItem<T>> onClick){
|
||||||
this(null, null, 0, onClick, null, 0, false);
|
this(null, null, 0, onClick, null, 0, false);
|
||||||
this.titleRes=titleRes;
|
this.titleRes=titleRes;
|
||||||
this.subtitleRes=subtitleRes;
|
this.subtitleRes=subtitleRes;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ListItem(@StringRes int titleRes, @StringRes int subtitleRes, Runnable onClick, int colorOverrideAttr, boolean dividerAfter){
|
public ListItem(@StringRes int titleRes, @StringRes int subtitleRes, Consumer<ListItem<T>> onClick, int colorOverrideAttr, boolean dividerAfter){
|
||||||
this(null, null, 0, onClick, null, colorOverrideAttr, dividerAfter);
|
this(null, null, 0, onClick, null, colorOverrideAttr, dividerAfter);
|
||||||
this.titleRes=titleRes;
|
this.titleRes=titleRes;
|
||||||
this.subtitleRes=subtitleRes;
|
this.subtitleRes=subtitleRes;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ListItem(@StringRes int titleRes, @StringRes int subtitleRes, @DrawableRes int iconRes, Runnable onClick){
|
public ListItem(@StringRes int titleRes, @StringRes int subtitleRes, @DrawableRes int iconRes, Consumer<ListItem<T>> onClick){
|
||||||
this(null, null, iconRes, onClick, null, 0, false);
|
this(null, null, iconRes, onClick, null, 0, false);
|
||||||
this.titleRes=titleRes;
|
this.titleRes=titleRes;
|
||||||
this.subtitleRes=subtitleRes;
|
this.subtitleRes=subtitleRes;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ListItem(@StringRes int titleRes, @StringRes int subtitleRes, @DrawableRes int iconRes, Runnable onClick, int colorOverrideAttr, boolean dividerAfter){
|
public ListItem(@StringRes int titleRes, @StringRes int subtitleRes, @DrawableRes int iconRes, Consumer<ListItem<T>> onClick, int colorOverrideAttr, boolean dividerAfter){
|
||||||
this(null, null, iconRes, onClick, null, colorOverrideAttr, dividerAfter);
|
this(null, null, iconRes, onClick, null, colorOverrideAttr, dividerAfter);
|
||||||
this.titleRes=titleRes;
|
this.titleRes=titleRes;
|
||||||
this.subtitleRes=subtitleRes;
|
this.subtitleRes=subtitleRes;
|
||||||
@@ -79,4 +77,13 @@ public class ListItem<T>{
|
|||||||
public int getItemViewType(){
|
public int getItemViewType(){
|
||||||
return colorOverrideAttr==0 ? R.id.list_item_simple : R.id.list_item_simple_tinted;
|
return colorOverrideAttr==0 ? R.id.list_item_simple : R.id.list_item_simple_tinted;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void performClick(){
|
||||||
|
if(onClick!=null)
|
||||||
|
onClick.accept(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public <I extends ListItem<T>> void setOnClick(Consumer<I> onClick){
|
||||||
|
this.onClick=(Consumer<ListItem<T>>) onClick;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import android.graphics.drawable.Animatable;
|
|||||||
import android.graphics.drawable.ColorDrawable;
|
import android.graphics.drawable.ColorDrawable;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.text.SpannableStringBuilder;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.view.WindowInsets;
|
import android.view.WindowInsets;
|
||||||
@@ -27,6 +27,8 @@ import org.joinmastodon.android.api.session.AccountSessionManager;
|
|||||||
import org.joinmastodon.android.fragments.HomeFragment;
|
import org.joinmastodon.android.fragments.HomeFragment;
|
||||||
import org.joinmastodon.android.fragments.SplashFragment;
|
import org.joinmastodon.android.fragments.SplashFragment;
|
||||||
import org.joinmastodon.android.fragments.onboarding.CustomWelcomeFragment;
|
import org.joinmastodon.android.fragments.onboarding.CustomWelcomeFragment;
|
||||||
|
import org.joinmastodon.android.ui.text.HtmlParser;
|
||||||
|
import org.joinmastodon.android.ui.utils.CustomEmojiHelper;
|
||||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||||
import org.joinmastodon.android.ui.views.CheckableRelativeLayout;
|
import org.joinmastodon.android.ui.views.CheckableRelativeLayout;
|
||||||
|
|
||||||
@@ -40,7 +42,6 @@ import androidx.annotation.NonNull;
|
|||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.annotation.StringRes;
|
import androidx.annotation.StringRes;
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
import me.grishka.appkit.FragmentStackActivity;
|
|
||||||
import me.grishka.appkit.Nav;
|
import me.grishka.appkit.Nav;
|
||||||
import me.grishka.appkit.api.Callback;
|
import me.grishka.appkit.api.Callback;
|
||||||
import me.grishka.appkit.api.ErrorResponse;
|
import me.grishka.appkit.api.ErrorResponse;
|
||||||
@@ -282,7 +283,7 @@ public class AccountSwitcherSheet extends BottomSheet{
|
|||||||
@SuppressLint("SetTextI18n")
|
@SuppressLint("SetTextI18n")
|
||||||
@Override
|
@Override
|
||||||
public void onBind(AccountSession item){
|
public void onBind(AccountSession item){
|
||||||
name.setText(item.self.displayName);
|
HtmlParser.setTextWithCustomEmoji(name, item.self.getDisplayName(), item.self.emojis);
|
||||||
username.setText(item.getFullUsername());
|
username.setText(item.getFullUsername());
|
||||||
radioButton.setVisibility(externalShare ? View.GONE : View.VISIBLE);
|
radioButton.setVisibility(externalShare ? View.GONE : View.VISIBLE);
|
||||||
extraBtnWrap.setVisibility(externalShare && openInApp ? View.VISIBLE : View.GONE);
|
extraBtnWrap.setVisibility(externalShare && openInApp ? View.VISIBLE : View.GONE);
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ public class SearchViewHelper{
|
|||||||
searchLayout.addView(searchEdit, new LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.MATCH_PARENT, 1f));
|
searchLayout.addView(searchEdit, new LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.MATCH_PARENT, 1f));
|
||||||
|
|
||||||
clearSearchButton=new ImageButton(context);
|
clearSearchButton=new ImageButton(context);
|
||||||
clearSearchButton.setImageResource(R.drawable.ic_baseline_close_24);
|
clearSearchButton.setImageResource(R.drawable.ic_fluent_dismiss_24_regular);
|
||||||
clearSearchButton.setContentDescription(context.getString(R.string.clear));
|
clearSearchButton.setContentDescription(context.getString(R.string.clear));
|
||||||
clearSearchButton.setImageTintList(ColorStateList.valueOf(UiUtils.getThemeColor(context, R.attr.colorM3OnSurfaceVariant)));
|
clearSearchButton.setImageTintList(ColorStateList.valueOf(UiUtils.getThemeColor(context, R.attr.colorM3OnSurfaceVariant)));
|
||||||
clearSearchButton.setBackground(UiUtils.getThemeDrawable(toolbarContext, android.R.attr.actionBarItemBackground));
|
clearSearchButton.setBackground(UiUtils.getThemeDrawable(toolbarContext, android.R.attr.actionBarItemBackground));
|
||||||
|
|||||||
@@ -26,9 +26,7 @@ import org.joinmastodon.android.ui.utils.CustomEmojiHelper;
|
|||||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||||
import org.joinmastodon.android.ui.views.ProgressBarButton;
|
import org.joinmastodon.android.ui.views.ProgressBarButton;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import me.grishka.appkit.imageloader.ImageLoaderViewHolder;
|
import me.grishka.appkit.imageloader.ImageLoaderViewHolder;
|
||||||
import me.grishka.appkit.imageloader.requests.ImageLoaderRequest;
|
import me.grishka.appkit.imageloader.requests.ImageLoaderRequest;
|
||||||
@@ -53,9 +51,9 @@ public class AccountCardStatusDisplayItem extends StatusDisplayItem{
|
|||||||
coverRequest=new UrlImageLoaderRequest(account.header, 1000, 1000);
|
coverRequest=new UrlImageLoaderRequest(account.header, 1000, 1000);
|
||||||
parsedBio=HtmlParser.parse(account.note, account.emojis, Collections.emptyList(), Collections.emptyList(), parentFragment.getAccountID());
|
parsedBio=HtmlParser.parse(account.note, account.emojis, Collections.emptyList(), Collections.emptyList(), parentFragment.getAccountID());
|
||||||
if(account.emojis.isEmpty()){
|
if(account.emojis.isEmpty()){
|
||||||
parsedName=account.displayName;
|
parsedName=account.getDisplayName();
|
||||||
}else{
|
}else{
|
||||||
parsedName=HtmlParser.parseCustomEmoji(account.displayName, account.emojis);
|
parsedName=HtmlParser.parseCustomEmoji(account.getDisplayName(), account.emojis);
|
||||||
emojiHelper.setText(new SpannableStringBuilder(parsedName).append(parsedBio));
|
emojiHelper.setText(new SpannableStringBuilder(parsedName).append(parsedBio));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -149,7 +147,7 @@ public class AccountCardStatusDisplayItem extends StatusDisplayItem{
|
|||||||
followingCount.setVisibility(item.account.followingCount < 0 ? View.GONE : View.VISIBLE);
|
followingCount.setVisibility(item.account.followingCount < 0 ? View.GONE : View.VISIBLE);
|
||||||
followingLabel.setVisibility(item.account.followingCount < 0 ? View.GONE : View.VISIBLE);
|
followingLabel.setVisibility(item.account.followingCount < 0 ? View.GONE : View.VISIBLE);
|
||||||
relationship=item.parentFragment.getRelationship(item.account.id);
|
relationship=item.parentFragment.getRelationship(item.account.id);
|
||||||
UiUtils.setExtraTextInfo(item.parentFragment.getContext(), null, findViewById(R.id.pronouns), true, false, false, item.account);
|
UiUtils.setExtraTextInfo(item.parentFragment.getContext(), null,true, false, false, item.account);
|
||||||
|
|
||||||
if(item.notification.type==Notification.Type.FOLLOW_REQUEST && (relationship==null || !relationship.followedBy)){
|
if(item.notification.type==Notification.Type.FOLLOW_REQUEST && (relationship==null || !relationship.followedBy)){
|
||||||
actionWrap.setVisibility(View.GONE);
|
actionWrap.setVisibility(View.GONE);
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import android.widget.Button;
|
|||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import org.joinmastodon.android.GlobalUserPreferences;
|
||||||
import org.joinmastodon.android.R;
|
import org.joinmastodon.android.R;
|
||||||
import org.joinmastodon.android.api.session.AccountSession;
|
import org.joinmastodon.android.api.session.AccountSession;
|
||||||
import org.joinmastodon.android.api.session.AccountSessionManager;
|
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||||
@@ -76,9 +77,7 @@ public class ExtendedFooterStatusDisplayItem extends StatusDisplayItem{
|
|||||||
@Override
|
@Override
|
||||||
public void onBind(ExtendedFooterStatusDisplayItem item){
|
public void onBind(ExtendedFooterStatusDisplayItem item){
|
||||||
Status s=item.status;
|
Status s=item.status;
|
||||||
AccountSession session=AccountSessionManager.get(item.accountID);
|
favorites.setCompoundDrawablesRelativeWithIntrinsicBounds(GlobalUserPreferences.likeIcon ? R.drawable.ic_fluent_heart_20_regular : R.drawable.ic_fluent_star_20_regular, 0, 0, 0);
|
||||||
boolean like=session!=null && session.getLocalPreferences().likeIcon;
|
|
||||||
favorites.setCompoundDrawablesRelativeWithIntrinsicBounds(like ? R.drawable.ic_fluent_heart_20_regular : R.drawable.ic_fluent_star_20_regular, 0, 0, 0);
|
|
||||||
favorites.setText(context.getResources().getQuantityString(R.plurals.x_favorites, (int)(s.favouritesCount%1000), s.favouritesCount));
|
favorites.setText(context.getResources().getQuantityString(R.plurals.x_favorites, (int)(s.favouritesCount%1000), s.favouritesCount));
|
||||||
reblogs.setText(context.getResources().getQuantityString(R.plurals.x_reblogs, (int) (s.reblogsCount % 1000), s.reblogsCount));
|
reblogs.setText(context.getResources().getQuantityString(R.plurals.x_reblogs, (int) (s.reblogsCount % 1000), s.reblogsCount));
|
||||||
reblogs.setVisibility(s.visibility != StatusPrivacy.DIRECT ? View.VISIBLE : View.GONE);
|
reblogs.setVisibility(s.visibility != StatusPrivacy.DIRECT ? View.VISIBLE : View.GONE);
|
||||||
|
|||||||
@@ -1,24 +1,17 @@
|
|||||||
package org.joinmastodon.android.ui.displayitems;
|
package org.joinmastodon.android.ui.displayitems;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.drawable.Drawable;
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.ImageView;
|
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import org.joinmastodon.android.R;
|
import org.joinmastodon.android.R;
|
||||||
import org.joinmastodon.android.fragments.BaseStatusListFragment;
|
import org.joinmastodon.android.fragments.BaseStatusListFragment;
|
||||||
import org.joinmastodon.android.model.Attachment;
|
import org.joinmastodon.android.model.Attachment;
|
||||||
import org.joinmastodon.android.model.Card;
|
|
||||||
import org.joinmastodon.android.model.Status;
|
|
||||||
import org.joinmastodon.android.ui.drawables.BlurhashCrossfadeDrawable;
|
|
||||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||||
|
|
||||||
import me.grishka.appkit.imageloader.ImageLoaderViewHolder;
|
|
||||||
|
|
||||||
public class FileStatusDisplayItem extends StatusDisplayItem{
|
public class FileStatusDisplayItem extends StatusDisplayItem{
|
||||||
private final Attachment attachment;
|
private final Attachment attachment;
|
||||||
|
|
||||||
|
|||||||
@@ -133,13 +133,10 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
|
|||||||
boolean condenseBottom = !item.isMainStatus && item.hasDescendantNeighbor &&
|
boolean condenseBottom = !item.isMainStatus && item.hasDescendantNeighbor &&
|
||||||
!nextIsWarning;
|
!nextIsWarning;
|
||||||
|
|
||||||
|
|
||||||
AccountSession session=AccountSessionManager.get(item.accountID);
|
|
||||||
boolean like=session!=null && session.getLocalPreferences().likeIcon;
|
|
||||||
ColorStateList color=item.parentFragment.getResources().getColorStateList(
|
ColorStateList color=item.parentFragment.getResources().getColorStateList(
|
||||||
like ? R.color.like_icon : R.color.favorite_icon, item.parentFragment.getContext().getTheme()
|
GlobalUserPreferences.likeIcon ? R.color.like_icon : R.color.favorite_icon, item.parentFragment.getContext().getTheme()
|
||||||
);
|
);
|
||||||
favIcon.setImageResource(like ? R.drawable.ic_fluent_heart_24_selector : R.drawable.ic_fluent_star_24_selector);
|
favIcon.setImageResource(GlobalUserPreferences.likeIcon ? R.drawable.ic_fluent_heart_24_selector : R.drawable.ic_fluent_star_24_selector);
|
||||||
favIcon.setImageTintList(color);
|
favIcon.setImageTintList(color);
|
||||||
favorites.setTextColor(color);
|
favorites.setTextColor(color);
|
||||||
|
|
||||||
@@ -175,7 +172,6 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
|
|||||||
} else if (action == MotionEvent.ACTION_DOWN) {
|
} else if (action == MotionEvent.ACTION_DOWN) {
|
||||||
longClickPerformed = false;
|
longClickPerformed = false;
|
||||||
touchingView = v;
|
touchingView = v;
|
||||||
v.setPivotX(V.sp(28));
|
|
||||||
v.animate().scaleX(0.85f).scaleY(0.85f).setInterpolator(CubicBezierInterpolator.DEFAULT).setDuration(75).start();
|
v.animate().scaleX(0.85f).scaleY(0.85f).setInterpolator(CubicBezierInterpolator.DEFAULT).setDuration(75).start();
|
||||||
if (disabled) return true;
|
if (disabled) return true;
|
||||||
v.postDelayed(longClickRunnable, ViewConfiguration.getLongPressTimeout());
|
v.postDelayed(longClickRunnable, ViewConfiguration.getLongPressTimeout());
|
||||||
@@ -321,7 +317,7 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
|
|||||||
R.string.sk_favorite_as,
|
R.string.sk_favorite_as,
|
||||||
R.string.sk_favorited_as,
|
R.string.sk_favorited_as,
|
||||||
R.string.sk_already_favorited,
|
R.string.sk_already_favorited,
|
||||||
R.drawable.ic_fluent_star_28_regular
|
GlobalUserPreferences.likeIcon ? R.drawable.ic_fluent_heart_28_regular : R.drawable.ic_fluent_star_28_regular
|
||||||
);
|
);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import android.widget.TextView;
|
|||||||
|
|
||||||
import org.joinmastodon.android.R;
|
import org.joinmastodon.android.R;
|
||||||
import org.joinmastodon.android.fragments.BaseStatusListFragment;
|
import org.joinmastodon.android.fragments.BaseStatusListFragment;
|
||||||
|
import org.joinmastodon.android.fragments.StatusListFragment;
|
||||||
import org.joinmastodon.android.model.Status;
|
import org.joinmastodon.android.model.Status;
|
||||||
import org.joinmastodon.android.ui.drawables.SawtoothTearDrawable;
|
import org.joinmastodon.android.ui.drawables.SawtoothTearDrawable;
|
||||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||||
@@ -18,13 +19,17 @@ import me.grishka.appkit.utils.V;
|
|||||||
|
|
||||||
public class GapStatusDisplayItem extends StatusDisplayItem{
|
public class GapStatusDisplayItem extends StatusDisplayItem{
|
||||||
public boolean loading;
|
public boolean loading;
|
||||||
private Status status;
|
private final Status status;
|
||||||
|
|
||||||
public GapStatusDisplayItem(String parentID, BaseStatusListFragment<?> parentFragment, Status status){
|
public GapStatusDisplayItem(String parentID, BaseStatusListFragment<?> parentFragment, Status status){
|
||||||
super(parentID, parentFragment);
|
super(parentID, parentFragment);
|
||||||
this.status=status;
|
this.status=status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getMaxID(){
|
||||||
|
return status.hasGapAfter;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Type getType(){
|
public Type getType(){
|
||||||
return Type.GAP;
|
return Type.GAP;
|
||||||
@@ -54,13 +59,19 @@ public class GapStatusDisplayItem extends StatusDisplayItem{
|
|||||||
if(!item.loading){
|
if(!item.loading){
|
||||||
progressBottom.setVisibility(View.GONE);
|
progressBottom.setVisibility(View.GONE);
|
||||||
progressTop.setVisibility(View.GONE);
|
progressTop.setVisibility(View.GONE);
|
||||||
|
textTop.setAlpha(1);
|
||||||
|
textBottom.setAlpha(1);
|
||||||
}
|
}
|
||||||
top.setClickable(!item.loading);
|
top.setClickable(!item.loading);
|
||||||
bottom.setClickable(!item.loading);
|
bottom.setClickable(!item.loading);
|
||||||
StatusDisplayItem next=getNextVisibleDisplayItem().orElse(null);
|
Status next=!(item.parentFragment instanceof StatusListFragment) ? null : getNextVisibleDisplayItem(i->{
|
||||||
Instant dateBelow=next instanceof HeaderStatusDisplayItem h ? h.status.createdAt
|
Status s=((StatusListFragment) item.parentFragment).getStatusByID(i.parentID);
|
||||||
: next instanceof ReblogOrReplyLineStatusDisplayItem l ? l.status.createdAt
|
return s!=null && !s.fromStatusCreated;
|
||||||
: null;
|
})
|
||||||
|
.map(i->((StatusListFragment) item.parentFragment).getStatusByID(i.parentID))
|
||||||
|
.orElse(null);
|
||||||
|
bottom.setVisibility(next==null ? View.GONE : View.VISIBLE);
|
||||||
|
Instant dateBelow=next!=null ? next.createdAt : null;
|
||||||
String text=dateBelow!=null && item.status.createdAt!=null && dateBelow.isBefore(item.status.createdAt)
|
String text=dateBelow!=null && item.status.createdAt!=null && dateBelow.isBefore(item.status.createdAt)
|
||||||
? UiUtils.formatPeriodBetween(item.parentFragment.getContext(), dateBelow, item.status.createdAt)
|
? UiUtils.formatPeriodBetween(item.parentFragment.getContext(), dateBelow, item.status.createdAt)
|
||||||
: null;
|
: null;
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
|
|||||||
GlobalUserPreferences.playGifs ? user.avatar : user.avatarStatic,
|
GlobalUserPreferences.playGifs ? user.avatar : user.avatarStatic,
|
||||||
V.dp(50), V.dp(50));
|
V.dp(50), V.dp(50));
|
||||||
this.accountID=accountID;
|
this.accountID=accountID;
|
||||||
parsedName=new SpannableStringBuilder(user.displayName);
|
parsedName=new SpannableStringBuilder(user.getDisplayName());
|
||||||
this.status=status;
|
this.status=status;
|
||||||
this.notification=notification;
|
this.notification=notification;
|
||||||
this.scheduledStatus=scheduledStatus;
|
this.scheduledStatus=scheduledStatus;
|
||||||
@@ -137,7 +137,7 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static class Holder extends StatusDisplayItem.Holder<HeaderStatusDisplayItem> implements ImageLoaderViewHolder{
|
public static class Holder extends StatusDisplayItem.Holder<HeaderStatusDisplayItem> implements ImageLoaderViewHolder{
|
||||||
private final TextView name, time, username, extraText, pronouns;
|
private final TextView name, time, username, extraText;
|
||||||
private final View collapseBtn, timeUsernameSeparator;
|
private final View collapseBtn, timeUsernameSeparator;
|
||||||
private final ImageView avatar, more, visibility, deleteNotification, unreadIndicator, markAsRead, collapseBtnIcon, botIcon;
|
private final ImageView avatar, more, visibility, deleteNotification, unreadIndicator, markAsRead, collapseBtnIcon, botIcon;
|
||||||
private final PopupMenu optionsMenu;
|
private final PopupMenu optionsMenu;
|
||||||
@@ -164,7 +164,6 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
|
|||||||
collapseBtn=findViewById(R.id.collapse_btn);
|
collapseBtn=findViewById(R.id.collapse_btn);
|
||||||
collapseBtnIcon=findViewById(R.id.collapse_btn_icon);
|
collapseBtnIcon=findViewById(R.id.collapse_btn_icon);
|
||||||
extraText=findViewById(R.id.extra_text);
|
extraText=findViewById(R.id.extra_text);
|
||||||
pronouns=findViewById(R.id.pronouns);
|
|
||||||
avatar.setOnClickListener(this::onAvaClick);
|
avatar.setOnClickListener(this::onAvaClick);
|
||||||
avatar.setOutlineProvider(OutlineProviders.roundedRect(12));
|
avatar.setOutlineProvider(OutlineProviders.roundedRect(12));
|
||||||
avatar.setClipToOutline(true);
|
avatar.setClipToOutline(true);
|
||||||
@@ -209,7 +208,6 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
|
|||||||
}else if(item.scheduledStatus!=null){
|
}else if(item.scheduledStatus!=null){
|
||||||
args.putString("sourceText", item.status.text);
|
args.putString("sourceText", item.status.text);
|
||||||
args.putString("sourceSpoiler", item.status.spoilerText);
|
args.putString("sourceSpoiler", item.status.spoilerText);
|
||||||
args.putBoolean("redraftStatus", true);
|
|
||||||
args.putParcelable("scheduledStatus", Parcels.wrap(item.scheduledStatus));
|
args.putParcelable("scheduledStatus", Parcels.wrap(item.scheduledStatus));
|
||||||
Nav.go(item.parentFragment.getActivity(), ComposeFragment.class, args);
|
Nav.go(item.parentFragment.getActivity(), ComposeFragment.class, args);
|
||||||
}else{
|
}else{
|
||||||
@@ -219,14 +217,14 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
|
|||||||
public void onSuccess(GetStatusSourceText.Response result){
|
public void onSuccess(GetStatusSourceText.Response result){
|
||||||
args.putString("sourceText", result.text);
|
args.putString("sourceText", result.text);
|
||||||
args.putString("sourceSpoiler", result.spoilerText);
|
args.putString("sourceSpoiler", result.spoilerText);
|
||||||
if (result.contentType != null) {
|
if(result.contentType!=null){
|
||||||
args.putString("sourceContentType", result.contentType.name());
|
args.putString("sourceContentType", result.contentType.name());
|
||||||
}
|
}
|
||||||
if (redraft) {
|
if(redraft){
|
||||||
UiUtils.confirmDeletePost(item.parentFragment.getActivity(), item.parentFragment.getAccountID(), item.status, s->{
|
UiUtils.confirmDeletePost(item.parentFragment.getActivity(), item.parentFragment.getAccountID(), item.status, s->{
|
||||||
Nav.go(item.parentFragment.getActivity(), ComposeFragment.class, args);
|
Nav.go(item.parentFragment.getActivity(), ComposeFragment.class, args);
|
||||||
}, true);
|
}, true);
|
||||||
} else {
|
}else{
|
||||||
Nav.go(item.parentFragment.getActivity(), ComposeFragment.class, args);
|
Nav.go(item.parentFragment.getActivity(), ComposeFragment.class, args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -243,7 +241,7 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
|
|||||||
if (item.scheduledStatus != null) {
|
if (item.scheduledStatus != null) {
|
||||||
UiUtils.confirmDeleteScheduledPost(item.parentFragment.getActivity(), item.parentFragment.getAccountID(), item.scheduledStatus, ()->{});
|
UiUtils.confirmDeleteScheduledPost(item.parentFragment.getActivity(), item.parentFragment.getAccountID(), item.scheduledStatus, ()->{});
|
||||||
} else {
|
} else {
|
||||||
UiUtils.confirmDeletePost(item.parentFragment.getActivity(), item.parentFragment.getAccountID(), item.status, s->{});
|
UiUtils.confirmDeletePost(item.parentFragment.getActivity(), item.parentFragment.getAccountID(), item.status, s->{}, false);
|
||||||
}
|
}
|
||||||
}else if(id==R.id.pin || id==R.id.unpin) {
|
}else if(id==R.id.pin || id==R.id.unpin) {
|
||||||
UiUtils.confirmPinPost(item.parentFragment.getActivity(), item.parentFragment.getAccountID(), item.status, !item.status.pinned, s->{});
|
UiUtils.confirmPinPost(item.parentFragment.getActivity(), item.parentFragment.getAccountID(), item.status, !item.status.pinned, s->{});
|
||||||
@@ -333,7 +331,7 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
|
|||||||
if(TextUtils.isEmpty(item.extraText)){
|
if(TextUtils.isEmpty(item.extraText)){
|
||||||
if (item.status != null) {
|
if (item.status != null) {
|
||||||
boolean displayPronouns=item.parentFragment instanceof ThreadFragment ? GlobalUserPreferences.displayPronounsInThreads : GlobalUserPreferences.displayPronounsInTimelines;
|
boolean displayPronouns=item.parentFragment instanceof ThreadFragment ? GlobalUserPreferences.displayPronounsInThreads : GlobalUserPreferences.displayPronounsInTimelines;
|
||||||
UiUtils.setExtraTextInfo(item.parentFragment.getContext(), extraText, pronouns, displayPronouns, item.status.visibility==StatusPrivacy.DIRECT, item.status.localOnly || item.status.visibility==StatusPrivacy.LOCAL, item.status.account);
|
UiUtils.setExtraTextInfo(item.parentFragment.getContext(), extraText, displayPronouns, item.status.visibility==StatusPrivacy.DIRECT, item.status.localOnly || item.status.visibility==StatusPrivacy.LOCAL, item.status.account);
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
extraText.setVisibility(View.VISIBLE);
|
extraText.setVisibility(View.VISIBLE);
|
||||||
@@ -377,21 +375,32 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
|
|||||||
markAsRead.setVisibility(View.GONE);
|
markAsRead.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item.status == null || !item.status.textExpandable) {
|
bindCollapseButton();
|
||||||
collapseBtn.setVisibility(View.GONE);
|
|
||||||
} else {
|
|
||||||
String collapseText = item.parentFragment.getString(item.status.textExpanded ? R.string.sk_collapse : R.string.sk_expand);
|
|
||||||
collapseBtn.setVisibility(item.status.textExpandable ? View.VISIBLE : View.GONE);
|
|
||||||
collapseBtn.setContentDescription(collapseText);
|
|
||||||
if (GlobalUserPreferences.reduceMotion) collapseBtnIcon.setScaleY(item.status.textExpanded ? -1 : 1);
|
|
||||||
else collapseBtnIcon.animate().scaleY(item.status.textExpanded ? -1 : 1).start();
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) collapseBtn.setTooltipText(collapseText);
|
|
||||||
}
|
|
||||||
|
|
||||||
itemView.setPaddingRelative(itemView.getPaddingStart(), itemView.getPaddingTop(),
|
itemView.setPaddingRelative(itemView.getPaddingStart(), itemView.getPaddingTop(),
|
||||||
item.inset ? V.dp(10) : V.dp(4), itemView.getPaddingBottom());
|
item.inset ? V.dp(10) : V.dp(4), itemView.getPaddingBottom());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void bindCollapseButton(){
|
||||||
|
boolean expandable=item.status!=null && item.status.textExpandable;
|
||||||
|
collapseBtn.setVisibility(expandable ? View.VISIBLE : View.GONE);
|
||||||
|
if(expandable) {
|
||||||
|
bindCollapseButtonText();
|
||||||
|
collapseBtnIcon.setScaleY(item.status.textExpanded ? -1 : 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void bindCollapseButtonText(){
|
||||||
|
String collapseText = item.parentFragment.getString(item.status.textExpanded ? R.string.sk_collapse : R.string.sk_expand);
|
||||||
|
collapseBtn.setContentDescription(collapseText);
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) collapseBtn.setTooltipText(collapseText);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void animateExpandToggle(){
|
||||||
|
bindCollapseButtonText();
|
||||||
|
collapseBtnIcon.animate().scaleY(item.status.textExpanded ? -1 : 1).start();
|
||||||
|
}
|
||||||
|
|
||||||
public void animateVisibilityToggle(boolean visible){
|
public void animateVisibilityToggle(boolean visible){
|
||||||
visibility.animate()
|
visibility.animate()
|
||||||
.alpha(visible ? 1 : 0)
|
.alpha(visible ? 1 : 0)
|
||||||
@@ -537,7 +546,8 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
|
|||||||
follow.setIcon(following ? R.drawable.ic_fluent_person_delete_24_regular : R.drawable.ic_fluent_person_add_24_regular);
|
follow.setIcon(following ? R.drawable.ic_fluent_person_delete_24_regular : R.drawable.ic_fluent_person_add_24_regular);
|
||||||
manageUserLists.setVisible(relationship != null && relationship.following);
|
manageUserLists.setVisible(relationship != null && relationship.following);
|
||||||
manageUserLists.setTitle(item.parentFragment.getString(R.string.sk_lists_with_user, username));
|
manageUserLists.setTitle(item.parentFragment.getString(R.string.sk_lists_with_user, username));
|
||||||
UiUtils.insetPopupMenuIcon(item.parentFragment.getContext(), follow);
|
// ic_fluent_person_add_24_regular actually has a width of 25dp -.-
|
||||||
|
UiUtils.insetPopupMenuIcon(item.parentFragment.getContext(), follow, following ? 0 : V.dp(-1));
|
||||||
}
|
}
|
||||||
|
|
||||||
workaroundChangingMenuItemWidths(menu, username);
|
workaroundChangingMenuItemWidths(menu, username);
|
||||||
|
|||||||
@@ -382,7 +382,7 @@ public class MediaGridStatusDisplayItem extends StatusDisplayItem{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public MediaAttachmentViewController getViewController(int index){
|
public MediaAttachmentViewController getViewController(int index){
|
||||||
return controllers.get(index);
|
return index<controllers.size() ? controllers.get(index) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setClipChildren(boolean clip){
|
public void setClipChildren(boolean clip){
|
||||||
|
|||||||
@@ -1,15 +1,14 @@
|
|||||||
package org.joinmastodon.android.ui.displayitems;
|
package org.joinmastodon.android.ui.displayitems;
|
||||||
|
|
||||||
import static org.joinmastodon.android.MastodonApp.context;
|
import static org.joinmastodon.android.MastodonApp.context;
|
||||||
import static org.joinmastodon.android.model.Notification.Type.PLEROMA_EMOJI_REACTION;
|
|
||||||
import static org.joinmastodon.android.ui.utils.UiUtils.generateFormattedString;
|
import static org.joinmastodon.android.ui.utils.UiUtils.generateFormattedString;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.res.ColorStateList;
|
import android.content.res.ColorStateList;
|
||||||
|
import android.graphics.drawable.Animatable;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.text.Html;
|
|
||||||
import android.text.SpannableStringBuilder;
|
import android.text.SpannableStringBuilder;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.TypedValue;
|
import android.util.TypedValue;
|
||||||
@@ -23,6 +22,7 @@ import org.joinmastodon.android.R;
|
|||||||
import org.joinmastodon.android.api.session.AccountSession;
|
import org.joinmastodon.android.api.session.AccountSession;
|
||||||
import org.joinmastodon.android.api.session.AccountSessionManager;
|
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||||
import org.joinmastodon.android.fragments.BaseStatusListFragment;
|
import org.joinmastodon.android.fragments.BaseStatusListFragment;
|
||||||
|
import org.joinmastodon.android.fragments.NotificationsListFragment;
|
||||||
import org.joinmastodon.android.fragments.ProfileFragment;
|
import org.joinmastodon.android.fragments.ProfileFragment;
|
||||||
import org.joinmastodon.android.model.Emoji;
|
import org.joinmastodon.android.model.Emoji;
|
||||||
import org.joinmastodon.android.model.Notification;
|
import org.joinmastodon.android.model.Notification;
|
||||||
@@ -62,7 +62,7 @@ public class NotificationHeaderStatusDisplayItem extends StatusDisplayItem{
|
|||||||
TextUtils.isEmpty(notification.account.avatar) ? session.getDefaultAvatarUrl() :
|
TextUtils.isEmpty(notification.account.avatar) ? session.getDefaultAvatarUrl() :
|
||||||
GlobalUserPreferences.playGifs ? notification.account.avatar : notification.account.avatarStatic,
|
GlobalUserPreferences.playGifs ? notification.account.avatar : notification.account.avatarStatic,
|
||||||
V.dp(50), V.dp(50));
|
V.dp(50), V.dp(50));
|
||||||
SpannableStringBuilder parsedName=new SpannableStringBuilder(notification.account.displayName);
|
SpannableStringBuilder parsedName=new SpannableStringBuilder(notification.account.getDisplayName());
|
||||||
HtmlParser.parseCustomEmoji(parsedName, notification.account.emojis);
|
HtmlParser.parseCustomEmoji(parsedName, notification.account.emojis);
|
||||||
String str = parentFragment.getString(switch(notification.type){
|
String str = parentFragment.getString(switch(notification.type){
|
||||||
case FOLLOW -> R.string.user_followed_you;
|
case FOLLOW -> R.string.user_followed_you;
|
||||||
@@ -113,7 +113,7 @@ public class NotificationHeaderStatusDisplayItem extends StatusDisplayItem{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static class Holder extends StatusDisplayItem.Holder<NotificationHeaderStatusDisplayItem> implements ImageLoaderViewHolder{
|
public static class Holder extends StatusDisplayItem.Holder<NotificationHeaderStatusDisplayItem> implements ImageLoaderViewHolder{
|
||||||
private final ImageView icon, avatar;
|
private final ImageView icon, avatar, deleteNotification;
|
||||||
private final TextView text, timestamp;
|
private final TextView text, timestamp;
|
||||||
private final int selectableItemBackground;
|
private final int selectableItemBackground;
|
||||||
|
|
||||||
@@ -123,9 +123,15 @@ public class NotificationHeaderStatusDisplayItem extends StatusDisplayItem{
|
|||||||
avatar=findViewById(R.id.avatar);
|
avatar=findViewById(R.id.avatar);
|
||||||
text=findViewById(R.id.text);
|
text=findViewById(R.id.text);
|
||||||
timestamp=findViewById(R.id.timestamp);
|
timestamp=findViewById(R.id.timestamp);
|
||||||
|
deleteNotification=findViewById(R.id.delete_notification);
|
||||||
|
|
||||||
avatar.setOutlineProvider(OutlineProviders.roundedRect(8));
|
avatar.setOutlineProvider(OutlineProviders.roundedRect(8));
|
||||||
avatar.setClipToOutline(true);
|
avatar.setClipToOutline(true);
|
||||||
|
deleteNotification.setOnClickListener(v->UiUtils.confirmDeleteNotification(activity, item.parentFragment.getAccountID(), item.notification, ()->{
|
||||||
|
if (item.parentFragment instanceof NotificationsListFragment fragment) {
|
||||||
|
fragment.removeNotification(item.notification);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
itemView.setOnClickListener(this::onItemClick);
|
itemView.setOnClickListener(this::onItemClick);
|
||||||
TypedValue outValue = new TypedValue();
|
TypedValue outValue = new TypedValue();
|
||||||
@@ -141,6 +147,8 @@ public class NotificationHeaderStatusDisplayItem extends StatusDisplayItem{
|
|||||||
item.emojiHelper.setImageDrawable(index-1, image);
|
item.emojiHelper.setImageDrawable(index-1, image);
|
||||||
text.invalidate();
|
text.invalidate();
|
||||||
}
|
}
|
||||||
|
if(image instanceof Animatable)
|
||||||
|
((Animatable) image).start();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -158,7 +166,7 @@ public class NotificationHeaderStatusDisplayItem extends StatusDisplayItem{
|
|||||||
timestamp.setText(item.timestamp);
|
timestamp.setText(item.timestamp);
|
||||||
avatar.setVisibility(item.notification.type==Notification.Type.POLL ? View.GONE : View.VISIBLE);
|
avatar.setVisibility(item.notification.type==Notification.Type.POLL ? View.GONE : View.VISIBLE);
|
||||||
icon.setImageResource(switch(item.notification.type){
|
icon.setImageResource(switch(item.notification.type){
|
||||||
case FAVORITE -> R.drawable.ic_fluent_star_24_filled;
|
case FAVORITE -> GlobalUserPreferences.likeIcon ? R.drawable.ic_fluent_heart_24_filled : R.drawable.ic_fluent_star_24_filled;
|
||||||
case REBLOG -> R.drawable.ic_fluent_arrow_repeat_all_24_filled;
|
case REBLOG -> R.drawable.ic_fluent_arrow_repeat_all_24_filled;
|
||||||
case FOLLOW, FOLLOW_REQUEST -> R.drawable.ic_fluent_person_add_24_filled;
|
case FOLLOW, FOLLOW_REQUEST -> R.drawable.ic_fluent_person_add_24_filled;
|
||||||
case POLL -> R.drawable.ic_fluent_poll_24_filled;
|
case POLL -> R.drawable.ic_fluent_poll_24_filled;
|
||||||
@@ -169,15 +177,18 @@ public class NotificationHeaderStatusDisplayItem extends StatusDisplayItem{
|
|||||||
default -> throw new IllegalStateException("Unexpected value: "+item.notification.type);
|
default -> throw new IllegalStateException("Unexpected value: "+item.notification.type);
|
||||||
});
|
});
|
||||||
icon.setImageTintList(ColorStateList.valueOf(UiUtils.getThemeColor(item.parentFragment.getActivity(), switch(item.notification.type){
|
icon.setImageTintList(ColorStateList.valueOf(UiUtils.getThemeColor(item.parentFragment.getActivity(), switch(item.notification.type){
|
||||||
case FAVORITE -> R.attr.colorFavorite;
|
case FAVORITE -> GlobalUserPreferences.likeIcon ? R.attr.colorLike : R.attr.colorFavorite;
|
||||||
case REBLOG -> R.attr.colorBoost;
|
case REBLOG -> R.attr.colorBoost;
|
||||||
case POLL -> R.attr.colorPoll;
|
case POLL -> R.attr.colorPoll;
|
||||||
default -> android.R.attr.colorAccent;
|
default -> android.R.attr.colorAccent;
|
||||||
})));
|
})));
|
||||||
|
deleteNotification.setVisibility(GlobalUserPreferences.enableDeleteNotifications && item.notification != null ? View.VISIBLE : View.GONE);
|
||||||
itemView.setBackgroundResource(item.notification.type != Notification.Type.POLL
|
itemView.setBackgroundResource(item.notification.type != Notification.Type.POLL
|
||||||
&& item.notification.type != Notification.Type.REPORT ?
|
&& item.notification.type != Notification.Type.REPORT ?
|
||||||
selectableItemBackground : 0);
|
selectableItemBackground : 0);
|
||||||
itemView.setClickable(item.notification.type != Notification.Type.POLL);
|
itemView.setClickable(item.notification.type != Notification.Type.POLL);
|
||||||
|
itemView.setPaddingRelative(itemView.getPaddingStart(), itemView.getPaddingTop(),
|
||||||
|
GlobalUserPreferences.enableDeleteNotifications ? V.dp(4) : V.dp(16), itemView.getPaddingBottom());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onItemClick(View v) {
|
public void onItemClick(View v) {
|
||||||
|
|||||||
@@ -10,10 +10,8 @@ import android.text.SpannableStringBuilder;
|
|||||||
import android.util.TypedValue;
|
import android.util.TypedValue;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.LinearLayout;
|
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import org.joinmastodon.android.GlobalUserPreferences;
|
|
||||||
import org.joinmastodon.android.R;
|
import org.joinmastodon.android.R;
|
||||||
import org.joinmastodon.android.api.session.AccountSessionManager;
|
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||||
import org.joinmastodon.android.fragments.BaseStatusListFragment;
|
import org.joinmastodon.android.fragments.BaseStatusListFragment;
|
||||||
@@ -40,7 +38,7 @@ public class ReblogOrReplyLineStatusDisplayItem extends StatusDisplayItem{
|
|||||||
private StatusPrivacy visibility;
|
private StatusPrivacy visibility;
|
||||||
@DrawableRes
|
@DrawableRes
|
||||||
private int iconEnd;
|
private int iconEnd;
|
||||||
private CustomEmojiHelper emojiHelper=new CustomEmojiHelper(), fullTextEmojiHelper;
|
private CustomEmojiHelper emojiHelper=new CustomEmojiHelper();
|
||||||
private View.OnClickListener handleClick;
|
private View.OnClickListener handleClick;
|
||||||
public boolean needBottomPadding;
|
public boolean needBottomPadding;
|
||||||
ReblogOrReplyLineStatusDisplayItem extra;
|
ReblogOrReplyLineStatusDisplayItem extra;
|
||||||
@@ -58,21 +56,13 @@ public class ReblogOrReplyLineStatusDisplayItem extends StatusDisplayItem{
|
|||||||
HtmlParser.parseCustomEmoji(ssb, emojis);
|
HtmlParser.parseCustomEmoji(ssb, emojis);
|
||||||
this.text=ssb;
|
this.text=ssb;
|
||||||
emojiHelper.setText(ssb);
|
emojiHelper.setText(ssb);
|
||||||
|
this.fullText=fullText;
|
||||||
this.icon=icon;
|
this.icon=icon;
|
||||||
this.status=status;
|
this.status=status;
|
||||||
this.handleClick=handleClick;
|
this.handleClick=handleClick;
|
||||||
TypedValue outValue = new TypedValue();
|
TypedValue outValue = new TypedValue();
|
||||||
context.getTheme().resolveAttribute(android.R.attr.selectableItemBackground, outValue, true);
|
context.getTheme().resolveAttribute(android.R.attr.selectableItemBackground, outValue, true);
|
||||||
updateVisibility(visibility);
|
updateVisibility(visibility);
|
||||||
|
|
||||||
if (fullText != null) {
|
|
||||||
fullTextEmojiHelper = new CustomEmojiHelper();
|
|
||||||
SpannableStringBuilder fullTextSsb = new SpannableStringBuilder(fullText);
|
|
||||||
HtmlParser.parseCustomEmoji(fullTextSsb, emojis);
|
|
||||||
this.fullText=fullTextSsb;
|
|
||||||
fullTextEmojiHelper.setText(fullTextSsb);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateVisibility(StatusPrivacy visibility) {
|
public void updateVisibility(StatusPrivacy visibility) {
|
||||||
@@ -92,34 +82,28 @@ public class ReblogOrReplyLineStatusDisplayItem extends StatusDisplayItem{
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getImageCount(){
|
public int getImageCount(){
|
||||||
return emojiHelper.getImageCount();
|
return emojiHelper.getImageCount() + (extra!=null ? extra.emojiHelper.getImageCount() : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ImageLoaderRequest getImageRequest(int index){
|
public ImageLoaderRequest getImageRequest(int index){
|
||||||
return emojiHelper.getImageRequest(index);
|
int firstHelperCount=emojiHelper.getImageCount();
|
||||||
|
CustomEmojiHelper helper=index<firstHelperCount ? emojiHelper : extra.emojiHelper;
|
||||||
|
return helper.getImageRequest(firstHelperCount>0 ? index%firstHelperCount : index);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Holder extends StatusDisplayItem.Holder<ReblogOrReplyLineStatusDisplayItem> implements ImageLoaderViewHolder{
|
public static class Holder extends StatusDisplayItem.Holder<ReblogOrReplyLineStatusDisplayItem> implements ImageLoaderViewHolder{
|
||||||
private final TextView text, extraText;
|
private final TextView text, extraText;
|
||||||
private final View separator;
|
private final View separator;
|
||||||
private final ViewGroup parent;
|
|
||||||
|
|
||||||
public Holder(Activity activity, ViewGroup parent){
|
public Holder(Activity activity, ViewGroup parent){
|
||||||
super(activity, R.layout.display_item_reblog_or_reply_line, parent);
|
super(activity, R.layout.display_item_reblog_or_reply_line, parent);
|
||||||
this.parent = parent;
|
|
||||||
text=findViewById(R.id.text);
|
text=findViewById(R.id.text);
|
||||||
extraText=findViewById(R.id.extra_text);
|
extraText=findViewById(R.id.extra_text);
|
||||||
separator=findViewById(R.id.separator);
|
separator=findViewById(R.id.separator);
|
||||||
if (GlobalUserPreferences.compactReblogReplyLine) {
|
|
||||||
parent.addOnLayoutChangeListener((v, l, t, right, b, ol, ot, oldRight, ob) -> {
|
|
||||||
if (right != oldRight) layoutLine();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void bindLine(ReblogOrReplyLineStatusDisplayItem item, TextView text) {
|
private void bindLine(ReblogOrReplyLineStatusDisplayItem item, TextView text) {
|
||||||
if (item.fullText != null) text.setContentDescription(item.fullText);
|
|
||||||
text.setText(item.text);
|
text.setText(item.text);
|
||||||
text.setCompoundDrawablesRelativeWithIntrinsicBounds(item.icon, 0, item.iconEnd, 0);
|
text.setCompoundDrawablesRelativeWithIntrinsicBounds(item.icon, 0, item.iconEnd, 0);
|
||||||
text.setOnClickListener(item.handleClick);
|
text.setOnClickListener(item.handleClick);
|
||||||
@@ -133,7 +117,10 @@ public class ReblogOrReplyLineStatusDisplayItem extends StatusDisplayItem{
|
|||||||
case LOCAL -> R.string.sk_local_only;
|
case LOCAL -> R.string.sk_local_only;
|
||||||
default -> 0;
|
default -> 0;
|
||||||
} : 0;
|
} : 0;
|
||||||
if (visibilityText != 0) text.setContentDescription(item.text + " (" + ctx.getString(visibilityText) + ")");
|
String visibilityDescription=visibilityText!=0 ? " (" + ctx.getString(visibilityText) + ")" : null;
|
||||||
|
text.setContentDescription(item.fullText==null && visibilityDescription==null ? null :
|
||||||
|
(item.fullText!=null ? item.fullText : item.text)
|
||||||
|
+ (visibilityDescription!=null ? visibilityDescription : ""));
|
||||||
if(Build.VERSION.SDK_INT<Build.VERSION_CODES.N)
|
if(Build.VERSION.SDK_INT<Build.VERSION_CODES.N)
|
||||||
UiUtils.fixCompoundDrawableTintOnAndroid6(text);
|
UiUtils.fixCompoundDrawableTintOnAndroid6(text);
|
||||||
text.setCompoundDrawableTintList(text.getTextColors());
|
text.setCompoundDrawableTintList(text.getTextColors());
|
||||||
@@ -146,31 +133,15 @@ public class ReblogOrReplyLineStatusDisplayItem extends StatusDisplayItem{
|
|||||||
extraText.setVisibility(item.extra == null ? View.GONE : View.VISIBLE);
|
extraText.setVisibility(item.extra == null ? View.GONE : View.VISIBLE);
|
||||||
separator.setVisibility(item.extra == null ? View.GONE : View.VISIBLE);
|
separator.setVisibility(item.extra == null ? View.GONE : View.VISIBLE);
|
||||||
itemView.setPadding(itemView.getPaddingLeft(), itemView.getPaddingTop(), itemView.getPaddingRight(), item.needBottomPadding ? V.dp(16) : 0);
|
itemView.setPadding(itemView.getPaddingLeft(), itemView.getPaddingTop(), itemView.getPaddingRight(), item.needBottomPadding ? V.dp(16) : 0);
|
||||||
layoutLine();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void layoutLine() {
|
|
||||||
// layout line only if above header, compact and has extra
|
|
||||||
if (!GlobalUserPreferences.compactReblogReplyLine || item.extra == null) return;
|
|
||||||
itemView.measure(
|
|
||||||
View.MeasureSpec.makeMeasureSpec(parent.getWidth(), View.MeasureSpec.EXACTLY),
|
|
||||||
View.MeasureSpec.UNSPECIFIED);
|
|
||||||
boolean isVertical = ((LinearLayout) itemView).getOrientation() == LinearLayout.VERTICAL;
|
|
||||||
extraText.setPaddingRelative(extraText.getPaddingStart(), item.extra != null && isVertical ? 0 : V.dp(16), extraText.getPaddingEnd(), extraText.getPaddingBottom());
|
|
||||||
separator.setVisibility(item.extra != null && !isVertical ? View.VISIBLE : View.GONE);
|
|
||||||
((LinearLayout) itemView).removeView(extraText);
|
|
||||||
if (isVertical) ((LinearLayout) itemView).addView(extraText);
|
|
||||||
else ((LinearLayout) itemView).addView(extraText, 0);
|
|
||||||
text.setText(isVertical ? item.fullText : item.text);
|
|
||||||
if (item.extra != null) {
|
|
||||||
extraText.setText(isVertical ? item.extra.fullText : item.extra.text);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setImage(int index, Drawable image){
|
public void setImage(int index, Drawable image){
|
||||||
item.emojiHelper.setImageDrawable(index, image);
|
int firstHelperCount=item.emojiHelper.getImageCount();
|
||||||
|
CustomEmojiHelper helper=index<firstHelperCount ? item.emojiHelper : item.extra.emojiHelper;
|
||||||
|
helper.setImageDrawable(firstHelperCount>0 ? index%firstHelperCount : index, image);
|
||||||
text.invalidate();
|
text.invalidate();
|
||||||
|
extraText.invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -13,7 +13,8 @@ import android.text.TextUtils;
|
|||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
import org.joinmastodon.android.GlobalUserPreferences;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import org.joinmastodon.android.R;
|
import org.joinmastodon.android.R;
|
||||||
import org.joinmastodon.android.api.session.AccountLocalPreferences;
|
import org.joinmastodon.android.api.session.AccountLocalPreferences;
|
||||||
import org.joinmastodon.android.api.session.AccountSessionManager;
|
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||||
@@ -22,14 +23,16 @@ import org.joinmastodon.android.fragments.HashtagTimelineFragment;
|
|||||||
import org.joinmastodon.android.fragments.HomeTabFragment;
|
import org.joinmastodon.android.fragments.HomeTabFragment;
|
||||||
import org.joinmastodon.android.fragments.ListTimelineFragment;
|
import org.joinmastodon.android.fragments.ListTimelineFragment;
|
||||||
import org.joinmastodon.android.fragments.ProfileFragment;
|
import org.joinmastodon.android.fragments.ProfileFragment;
|
||||||
|
import org.joinmastodon.android.fragments.StatusListFragment;
|
||||||
import org.joinmastodon.android.fragments.ThreadFragment;
|
import org.joinmastodon.android.fragments.ThreadFragment;
|
||||||
import org.joinmastodon.android.model.Account;
|
import org.joinmastodon.android.model.Account;
|
||||||
import org.joinmastodon.android.model.Attachment;
|
import org.joinmastodon.android.model.Attachment;
|
||||||
import org.joinmastodon.android.model.DisplayItemsParent;
|
import org.joinmastodon.android.model.DisplayItemsParent;
|
||||||
import org.joinmastodon.android.model.LegacyFilter;
|
|
||||||
import org.joinmastodon.android.model.FilterAction;
|
import org.joinmastodon.android.model.FilterAction;
|
||||||
|
import org.joinmastodon.android.model.LegacyFilter;
|
||||||
import org.joinmastodon.android.model.FilterContext;
|
import org.joinmastodon.android.model.FilterContext;
|
||||||
import org.joinmastodon.android.model.FilterResult;
|
import org.joinmastodon.android.model.FilterResult;
|
||||||
|
import org.joinmastodon.android.model.Notification;
|
||||||
import org.joinmastodon.android.model.Poll;
|
import org.joinmastodon.android.model.Poll;
|
||||||
import org.joinmastodon.android.model.ScheduledStatus;
|
import org.joinmastodon.android.model.ScheduledStatus;
|
||||||
import org.joinmastodon.android.model.Status;
|
import org.joinmastodon.android.model.Status;
|
||||||
@@ -37,13 +40,14 @@ import org.joinmastodon.android.ui.PhotoLayoutHelper;
|
|||||||
import org.joinmastodon.android.ui.text.HtmlParser;
|
import org.joinmastodon.android.ui.text.HtmlParser;
|
||||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||||
import org.joinmastodon.android.ui.viewholders.AccountViewHolder;
|
import org.joinmastodon.android.ui.viewholders.AccountViewHolder;
|
||||||
import org.joinmastodon.android.utils.StatusFilterPredicate;
|
|
||||||
import org.parceler.Parcels;
|
import org.parceler.Parcels;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.function.Predicate;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import me.grishka.appkit.Nav;
|
import me.grishka.appkit.Nav;
|
||||||
@@ -57,10 +61,10 @@ public abstract class StatusDisplayItem{
|
|||||||
public boolean inset;
|
public boolean inset;
|
||||||
public int index;
|
public int index;
|
||||||
public boolean
|
public boolean
|
||||||
hasDescendantNeighbor = false,
|
hasDescendantNeighbor=false,
|
||||||
hasAncestoringNeighbor = false,
|
hasAncestoringNeighbor=false,
|
||||||
isMainStatus = true,
|
isMainStatus=true,
|
||||||
isDirectDescendant = false;
|
isDirectDescendant=false;
|
||||||
|
|
||||||
public static final int FLAG_INSET=1;
|
public static final int FLAG_INSET=1;
|
||||||
public static final int FLAG_NO_FOOTER=1 << 1;
|
public static final int FLAG_NO_FOOTER=1 << 1;
|
||||||
@@ -87,6 +91,16 @@ public abstract class StatusDisplayItem{
|
|||||||
this.parentFragment=parentFragment;
|
this.parentFragment=parentFragment;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public String getContentStatusID(){
|
||||||
|
if(parentFragment instanceof StatusListFragment slf){
|
||||||
|
Status s=slf.getContentStatusByID(parentID);
|
||||||
|
return s!=null ? s.id : parentID;
|
||||||
|
}else{
|
||||||
|
return parentID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public abstract Type getType();
|
public abstract Type getType();
|
||||||
|
|
||||||
public int getImageCount(){
|
public int getImageCount(){
|
||||||
@@ -128,11 +142,11 @@ public abstract class StatusDisplayItem{
|
|||||||
String parentID = parent.getID();
|
String parentID = parent.getID();
|
||||||
String text = threadReply ? fragment.getString(R.string.sk_show_thread)
|
String text = threadReply ? fragment.getString(R.string.sk_show_thread)
|
||||||
: account == null ? fragment.getString(R.string.sk_in_reply)
|
: account == null ? fragment.getString(R.string.sk_in_reply)
|
||||||
: GlobalUserPreferences.compactReblogReplyLine && status.reblog != null ? account.displayName
|
: status.reblog != null ? account.getDisplayName()
|
||||||
: fragment.getString(R.string.in_reply_to, account.displayName);
|
: fragment.getString(R.string.in_reply_to, account.getDisplayName());
|
||||||
String fullText = threadReply ? fragment.getString(R.string.sk_show_thread)
|
String fullText = threadReply ? fragment.getString(R.string.sk_show_thread)
|
||||||
: account == null ? fragment.getString(R.string.sk_in_reply)
|
: account == null ? fragment.getString(R.string.sk_in_reply)
|
||||||
: fragment.getString(R.string.in_reply_to, account.displayName);
|
: fragment.getString(R.string.in_reply_to, account.getDisplayName());
|
||||||
return new ReblogOrReplyLineStatusDisplayItem(
|
return new ReblogOrReplyLineStatusDisplayItem(
|
||||||
parentID, fragment, text, account == null ? List.of() : account.emojis,
|
parentID, fragment, text, account == null ? List.of() : account.emojis,
|
||||||
R.drawable.ic_fluent_arrow_reply_20sp_filled, null, null, fullText, status
|
R.drawable.ic_fluent_arrow_reply_20sp_filled, null, null, fullText, status
|
||||||
@@ -145,7 +159,7 @@ public abstract class StatusDisplayItem{
|
|||||||
Status statusForContent=status.getContentStatus();
|
Status statusForContent=status.getContentStatus();
|
||||||
Bundle args=new Bundle();
|
Bundle args=new Bundle();
|
||||||
args.putString("account", accountID);
|
args.putString("account", accountID);
|
||||||
ScheduledStatus scheduledStatus = parentObject instanceof ScheduledStatus ? (ScheduledStatus) parentObject : null;
|
ScheduledStatus scheduledStatus = parentObject instanceof ScheduledStatus s ? s : null;
|
||||||
|
|
||||||
HeaderStatusDisplayItem header=null;
|
HeaderStatusDisplayItem header=null;
|
||||||
boolean hideCounts=!AccountSessionManager.get(accountID).getLocalPreferences().showInteractionCounts;
|
boolean hideCounts=!AccountSessionManager.get(accountID).getLocalPreferences().showInteractionCounts;
|
||||||
@@ -162,12 +176,11 @@ public abstract class StatusDisplayItem{
|
|||||||
|
|
||||||
if(status.reblog!=null){
|
if(status.reblog!=null){
|
||||||
boolean isOwnPost = AccountSessionManager.getInstance().isSelf(fragment.getAccountID(), status.account);
|
boolean isOwnPost = AccountSessionManager.getInstance().isSelf(fragment.getAccountID(), status.account);
|
||||||
String fullText = fragment.getString(R.string.user_boosted, status.account.displayName);
|
String text=fragment.getString(R.string.user_boosted, status.account.getDisplayName());
|
||||||
String text = GlobalUserPreferences.compactReblogReplyLine && replyLine != null ? status.account.displayName : fullText;
|
|
||||||
items.add(new ReblogOrReplyLineStatusDisplayItem(parentID, fragment, text, status.account.emojis, R.drawable.ic_fluent_arrow_repeat_all_20sp_filled, isOwnPost ? status.visibility : null, i->{
|
items.add(new ReblogOrReplyLineStatusDisplayItem(parentID, fragment, text, status.account.emojis, R.drawable.ic_fluent_arrow_repeat_all_20sp_filled, isOwnPost ? status.visibility : null, i->{
|
||||||
args.putParcelable("profileAccount", Parcels.wrap(status.account));
|
args.putParcelable("profileAccount", Parcels.wrap(status.account));
|
||||||
Nav.go(fragment.getActivity(), ProfileFragment.class, args);
|
Nav.go(fragment.getActivity(), ProfileFragment.class, args);
|
||||||
}, fullText, status));
|
}, null, status));
|
||||||
} else if (!(status.tags.isEmpty() ||
|
} else if (!(status.tags.isEmpty() ||
|
||||||
fragment instanceof HashtagTimelineFragment ||
|
fragment instanceof HashtagTimelineFragment ||
|
||||||
fragment instanceof ListTimelineFragment
|
fragment instanceof ListTimelineFragment
|
||||||
@@ -191,7 +204,7 @@ public abstract class StatusDisplayItem{
|
|||||||
.map(ReblogOrReplyLineStatusDisplayItem.class::cast)
|
.map(ReblogOrReplyLineStatusDisplayItem.class::cast)
|
||||||
.findFirst();
|
.findFirst();
|
||||||
|
|
||||||
if (primaryLine.isPresent() && GlobalUserPreferences.compactReblogReplyLine) {
|
if (primaryLine.isPresent()) {
|
||||||
primaryLine.get().extra = replyLine;
|
primaryLine.get().extra = replyLine;
|
||||||
} else {
|
} else {
|
||||||
items.add(replyLine);
|
items.add(replyLine);
|
||||||
@@ -201,7 +214,7 @@ public abstract class StatusDisplayItem{
|
|||||||
if((flags & FLAG_CHECKABLE)!=0)
|
if((flags & FLAG_CHECKABLE)!=0)
|
||||||
items.add(header=new CheckableHeaderStatusDisplayItem(parentID, statusForContent.account, statusForContent.createdAt, fragment, accountID, statusForContent, null));
|
items.add(header=new CheckableHeaderStatusDisplayItem(parentID, statusForContent.account, statusForContent.createdAt, fragment, accountID, statusForContent, null));
|
||||||
else
|
else
|
||||||
items.add(header=new HeaderStatusDisplayItem(parentID, statusForContent.account, statusForContent.createdAt, fragment, accountID, statusForContent, null, null, scheduledStatus));
|
items.add(header=new HeaderStatusDisplayItem(parentID, statusForContent.account, statusForContent.createdAt, fragment, accountID, statusForContent, null, parentObject instanceof Notification n ? n : null, scheduledStatus));
|
||||||
}
|
}
|
||||||
|
|
||||||
LegacyFilter applyingFilter=null;
|
LegacyFilter applyingFilter=null;
|
||||||
@@ -292,10 +305,7 @@ public abstract class StatusDisplayItem{
|
|||||||
footer=new FooterStatusDisplayItem(parentID, fragment, statusForContent, accountID);
|
footer=new FooterStatusDisplayItem(parentID, fragment, statusForContent, accountID);
|
||||||
footer.hideCounts=hideCounts;
|
footer.hideCounts=hideCounts;
|
||||||
items.add(footer);
|
items.add(footer);
|
||||||
if(status.hasGapAfter && !(fragment instanceof ThreadFragment))
|
|
||||||
items.add(new GapStatusDisplayItem(parentID, fragment, status));
|
|
||||||
}
|
}
|
||||||
int i=1;
|
|
||||||
boolean inset=(flags & FLAG_INSET)!=0;
|
boolean inset=(flags & FLAG_INSET)!=0;
|
||||||
// add inset dummy so last content item doesn't clip out of inset bounds
|
// add inset dummy so last content item doesn't clip out of inset bounds
|
||||||
if((inset || footer==null) && (flags & FLAG_CHECKABLE)==0){
|
if((inset || footer==null) && (flags & FLAG_CHECKABLE)==0){
|
||||||
@@ -305,6 +315,10 @@ public abstract class StatusDisplayItem{
|
|||||||
// !contentItems.isEmpty() && contentItems
|
// !contentItems.isEmpty() && contentItems
|
||||||
// .get(contentItems.size() - 1) instanceof MediaGridStatusDisplayItem));
|
// .get(contentItems.size() - 1) instanceof MediaGridStatusDisplayItem));
|
||||||
}
|
}
|
||||||
|
GapStatusDisplayItem gap=null;
|
||||||
|
if((flags & FLAG_NO_FOOTER)==0 && status.hasGapAfter!=null && !(fragment instanceof ThreadFragment))
|
||||||
|
items.add(gap=new GapStatusDisplayItem(parentID, fragment, status));
|
||||||
|
int i=1;
|
||||||
for(StatusDisplayItem item:items){
|
for(StatusDisplayItem item:items){
|
||||||
item.inset=inset;
|
item.inset=inset;
|
||||||
item.index=i++;
|
item.index=i++;
|
||||||
@@ -316,8 +330,13 @@ public abstract class StatusDisplayItem{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return applyingFilter==null ? items :
|
List<StatusDisplayItem> nonGapItems=gap!=null ? items.subList(0, items.size()-1) : items;
|
||||||
new ArrayList<>(List.of(new WarningFilteredStatusDisplayItem(parentID, fragment, statusForContent, items, applyingFilter)));
|
WarningFilteredStatusDisplayItem warning=applyingFilter==null ? null :
|
||||||
|
new WarningFilteredStatusDisplayItem(parentID, fragment, statusForContent, nonGapItems, applyingFilter);
|
||||||
|
return applyingFilter==null ? items : new ArrayList<>(gap!=null
|
||||||
|
? List.of(warning, gap)
|
||||||
|
: Collections.singletonList(warning)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void buildPollItems(String parentID, BaseStatusListFragment fragment, Poll poll, List<StatusDisplayItem> items){
|
public static void buildPollItems(String parentID, BaseStatusListFragment fragment, Poll poll, List<StatusDisplayItem> items){
|
||||||
@@ -374,12 +393,14 @@ public abstract class StatusDisplayItem{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Optional<StatusDisplayItem> getNextVisibleDisplayItem(){
|
public Optional<StatusDisplayItem> getNextVisibleDisplayItem(){
|
||||||
|
return getNextVisibleDisplayItem(null);
|
||||||
|
}
|
||||||
|
public Optional<StatusDisplayItem> getNextVisibleDisplayItem(Predicate<StatusDisplayItem> predicate){
|
||||||
Optional<StatusDisplayItem> next=getNextDisplayItem();
|
Optional<StatusDisplayItem> next=getNextDisplayItem();
|
||||||
for(int offset=1; next.isPresent(); next=getDisplayItemOffset(++offset)){
|
for(int offset=1; next.isPresent(); next=getDisplayItemOffset(++offset)){
|
||||||
if(!next.map(n->
|
boolean isHidden=next.map(n->(n instanceof EmojiReactionsStatusDisplayItem e && e.isHidden())
|
||||||
(n instanceof EmojiReactionsStatusDisplayItem e && e.isHidden()) ||
|
|| (n instanceof DummyStatusDisplayItem)).orElse(false);
|
||||||
(n instanceof DummyStatusDisplayItem)
|
if(!isHidden && (predicate==null || predicate.test(next.get()))) return next;
|
||||||
).orElse(false)) return next;
|
|
||||||
}
|
}
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -210,9 +210,10 @@ public class TextStatusDisplayItem extends StatusDisplayItem{
|
|||||||
Translation existingTrans=item.status.getContentStatus().translation;
|
Translation existingTrans=item.status.getContentStatus().translation;
|
||||||
String existingTransLang=existingTrans!=null ? existingTrans.detectedSourceLanguage : null;
|
String existingTransLang=existingTrans!=null ? existingTrans.detectedSourceLanguage : null;
|
||||||
String lang=existingTransLang!=null ? existingTransLang : item.status.getContentStatus().language;
|
String lang=existingTransLang!=null ? existingTransLang : item.status.getContentStatus().language;
|
||||||
String displayLang=Locale.forLanguageTag(lang != null ? lang
|
Locale locale=lang!=null ? Locale.forLanguageTag(lang) : null;
|
||||||
: AccountSessionManager.get(item.parentFragment.getAccountID()).preferences.postingDefaultLanguage).getDisplayLanguage();
|
translationButton.setText(locale!=null
|
||||||
translationButton.setText(item.parentFragment.getString(R.string.translate_post, !displayLang.isBlank() ? displayLang : lang));
|
? item.parentFragment.getString(R.string.translate_post, locale.getDisplayLanguage())
|
||||||
|
: item.parentFragment.getString(R.string.sk_translate_post));
|
||||||
translationButton.setClickable(true);
|
translationButton.setClickable(true);
|
||||||
translationButton.animate().alpha(1).setDuration(100).start();
|
translationButton.animate().alpha(1).setDuration(100).start();
|
||||||
translationInfo.setVisibility(View.GONE);
|
translationInfo.setVisibility(View.GONE);
|
||||||
|
|||||||
@@ -564,7 +564,7 @@ public class PhotoViewer implements ZoomPanView.Listener{
|
|||||||
if(player==null || !player.isPlaying())
|
if(player==null || !player.isPlaying())
|
||||||
return;
|
return;
|
||||||
player.pause();
|
player.pause();
|
||||||
videoPlayPauseButton.setImageResource(R.drawable.ic_play_24);
|
videoPlayPauseButton.setImageResource(R.drawable.ic_fluent_play_24_filled);
|
||||||
videoPlayPauseButton.setContentDescription(activity.getString(R.string.play));
|
videoPlayPauseButton.setContentDescription(activity.getString(R.string.play));
|
||||||
stopUpdatingVideoPosition();
|
stopUpdatingVideoPosition();
|
||||||
windowView.removeCallbacks(uiAutoHider);
|
windowView.removeCallbacks(uiAutoHider);
|
||||||
@@ -575,7 +575,7 @@ public class PhotoViewer implements ZoomPanView.Listener{
|
|||||||
if(player==null || player.isPlaying())
|
if(player==null || player.isPlaying())
|
||||||
return;
|
return;
|
||||||
player.start();
|
player.start();
|
||||||
videoPlayPauseButton.setImageResource(R.drawable.ic_pause_24);
|
videoPlayPauseButton.setImageResource(R.drawable.ic_fluent_pause_24_filled);
|
||||||
videoPlayPauseButton.setContentDescription(activity.getString(R.string.pause));
|
videoPlayPauseButton.setContentDescription(activity.getString(R.string.pause));
|
||||||
startUpdatingVideoPosition(player);
|
startUpdatingVideoPosition(player);
|
||||||
}
|
}
|
||||||
@@ -940,7 +940,7 @@ public class PhotoViewer implements ZoomPanView.Listener{
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCompletion(MediaPlayer mp){
|
public void onCompletion(MediaPlayer mp){
|
||||||
videoPlayPauseButton.setImageResource(R.drawable.ic_play_24);
|
videoPlayPauseButton.setImageResource(R.drawable.ic_fluent_play_24_filled);
|
||||||
videoPlayPauseButton.setContentDescription(activity.getString(R.string.play));
|
videoPlayPauseButton.setContentDescription(activity.getString(R.string.play));
|
||||||
stopUpdatingVideoPosition();
|
stopUpdatingVideoPosition();
|
||||||
if(!uiVisible)
|
if(!uiVisible)
|
||||||
|
|||||||
@@ -210,6 +210,7 @@ public class HtmlParser{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void parseCustomEmoji(SpannableStringBuilder ssb, List<Emoji> emojis){
|
public static void parseCustomEmoji(SpannableStringBuilder ssb, List<Emoji> emojis){
|
||||||
|
if(emojis==null) return;
|
||||||
Map<String, Emoji> emojiByCode =
|
Map<String, Emoji> emojiByCode =
|
||||||
emojis.stream()
|
emojis.stream()
|
||||||
.collect(
|
.collect(
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import android.text.TextPaint;
|
|||||||
import android.text.style.CharacterStyle;
|
import android.text.style.CharacterStyle;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
|
import org.joinmastodon.android.GlobalUserPreferences;
|
||||||
import org.joinmastodon.android.model.Hashtag;
|
import org.joinmastodon.android.model.Hashtag;
|
||||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||||
|
|
||||||
@@ -34,7 +35,7 @@ public class LinkSpan extends CharacterStyle {
|
|||||||
@Override
|
@Override
|
||||||
public void updateDrawState(TextPaint tp) {
|
public void updateDrawState(TextPaint tp) {
|
||||||
tp.setColor(color=tp.linkColor);
|
tp.setColor(color=tp.linkColor);
|
||||||
tp.setUnderlineText(true);
|
tp.setUnderlineText(GlobalUserPreferences.underlinedLinks);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onClick(Context context){
|
public void onClick(Context context){
|
||||||
@@ -45,7 +46,7 @@ public class LinkSpan extends CharacterStyle {
|
|||||||
if(linkObject instanceof Hashtag ht)
|
if(linkObject instanceof Hashtag ht)
|
||||||
UiUtils.openHashtagTimeline(context, accountID, ht);
|
UiUtils.openHashtagTimeline(context, accountID, ht);
|
||||||
else
|
else
|
||||||
UiUtils.openHashtagTimeline(context, accountID, text);
|
UiUtils.openHashtagTimeline(context, accountID, link);
|
||||||
}
|
}
|
||||||
case CUSTOM -> listener.onLinkClick(this);
|
case CUSTOM -> listener.onLinkClick(this);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,88 @@
|
|||||||
|
package org.joinmastodon.android.ui.utils;
|
||||||
|
|
||||||
|
import android.animation.Animator;
|
||||||
|
import android.animation.AnimatorListenerAdapter;
|
||||||
|
import android.animation.IntEvaluator;
|
||||||
|
import android.animation.ObjectAnimator;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.view.ActionMode;
|
||||||
|
import android.view.Menu;
|
||||||
|
import android.view.MenuItem;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
import org.joinmastodon.android.R;
|
||||||
|
|
||||||
|
import java.util.function.IntSupplier;
|
||||||
|
|
||||||
|
import me.grishka.appkit.FragmentStackActivity;
|
||||||
|
import me.grishka.appkit.fragments.AppKitFragment;
|
||||||
|
|
||||||
|
public class ActionModeHelper{
|
||||||
|
public static ActionMode startActionMode(AppKitFragment fragment, IntSupplier statusBarColorSupplier, ActionMode.Callback callback){
|
||||||
|
FragmentStackActivity activity=(FragmentStackActivity) fragment.getActivity();
|
||||||
|
return activity.startActionMode(new ActionMode.Callback(){
|
||||||
|
@Override
|
||||||
|
public boolean onCreateActionMode(ActionMode mode, Menu menu){
|
||||||
|
if(!callback.onCreateActionMode(mode, menu))
|
||||||
|
return false;
|
||||||
|
ObjectAnimator anim=ObjectAnimator.ofInt(activity.getWindow(), "statusBarColor", statusBarColorSupplier.getAsInt(), UiUtils.getThemeColor(activity, R.attr.colorM3Primary));
|
||||||
|
anim.setEvaluator(new IntEvaluator(){
|
||||||
|
@Override
|
||||||
|
public Integer evaluate(float fraction, Integer startValue, Integer endValue){
|
||||||
|
return UiUtils.alphaBlendColors(startValue, endValue, fraction);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
anim.start();
|
||||||
|
activity.invalidateSystemBarColors(fragment);
|
||||||
|
View fakeView=new View(activity);
|
||||||
|
// mode.setCustomView(fakeView);
|
||||||
|
// int buttonID=activity.getResources().getIdentifier("action_mode_close_button", "id", "android");
|
||||||
|
// View btn=activity.getWindow().getDecorView().findViewById(buttonID);
|
||||||
|
// if(btn!=null){
|
||||||
|
// ((ViewGroup.MarginLayoutParams)btn.getLayoutParams()).setMarginEnd(0);
|
||||||
|
// }
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onPrepareActionMode(ActionMode mode, Menu menu){
|
||||||
|
if(!callback.onPrepareActionMode(mode, menu))
|
||||||
|
return false;
|
||||||
|
for(int i=0;i<menu.size();i++){
|
||||||
|
Drawable icon=menu.getItem(i).getIcon();
|
||||||
|
if(icon!=null){
|
||||||
|
icon=icon.mutate();
|
||||||
|
icon.setTint(UiUtils.getThemeColor(activity, R.attr.colorM3OnPrimary));
|
||||||
|
menu.getItem(i).setIcon(icon);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onActionItemClicked(ActionMode mode, MenuItem item){
|
||||||
|
return callback.onActionItemClicked(mode, item);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDestroyActionMode(ActionMode mode){
|
||||||
|
ObjectAnimator anim=ObjectAnimator.ofInt(activity.getWindow(), "statusBarColor", UiUtils.getThemeColor(activity, R.attr.colorM3Primary), statusBarColorSupplier.getAsInt());
|
||||||
|
anim.setEvaluator(new IntEvaluator(){
|
||||||
|
@Override
|
||||||
|
public Integer evaluate(float fraction, Integer startValue, Integer endValue){
|
||||||
|
return UiUtils.alphaBlendColors(startValue, endValue, fraction);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
anim.addListener(new AnimatorListenerAdapter(){
|
||||||
|
@Override
|
||||||
|
public void onAnimationEnd(Animator animation){
|
||||||
|
activity.getWindow().setStatusBarColor(0);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
anim.start();
|
||||||
|
activity.invalidateSystemBarColors(fragment);
|
||||||
|
callback.onDestroyActionMode(mode);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -68,6 +68,7 @@ import org.joinmastodon.android.E;
|
|||||||
import org.joinmastodon.android.GlobalUserPreferences;
|
import org.joinmastodon.android.GlobalUserPreferences;
|
||||||
import org.joinmastodon.android.MastodonApp;
|
import org.joinmastodon.android.MastodonApp;
|
||||||
import org.joinmastodon.android.R;
|
import org.joinmastodon.android.R;
|
||||||
|
import org.joinmastodon.android.api.CacheController;
|
||||||
import org.joinmastodon.android.api.MastodonAPIRequest;
|
import org.joinmastodon.android.api.MastodonAPIRequest;
|
||||||
import org.joinmastodon.android.api.MastodonErrorResponse;
|
import org.joinmastodon.android.api.MastodonErrorResponse;
|
||||||
import org.joinmastodon.android.api.StatusInteractionController;
|
import org.joinmastodon.android.api.StatusInteractionController;
|
||||||
@@ -479,7 +480,7 @@ public class UiUtils {
|
|||||||
|
|
||||||
public static void confirmToggleBlockUser(Activity activity, String accountID, Account account, boolean currentlyBlocked, Consumer<Relationship> resultCallback) {
|
public static void confirmToggleBlockUser(Activity activity, String accountID, Account account, boolean currentlyBlocked, Consumer<Relationship> resultCallback) {
|
||||||
showConfirmationAlert(activity, activity.getString(currentlyBlocked ? R.string.confirm_unblock_title : R.string.confirm_block_title),
|
showConfirmationAlert(activity, activity.getString(currentlyBlocked ? R.string.confirm_unblock_title : R.string.confirm_block_title),
|
||||||
activity.getString(currentlyBlocked ? R.string.confirm_unblock : R.string.confirm_block, account.displayName),
|
activity.getString(currentlyBlocked ? R.string.confirm_unblock : R.string.confirm_block, account.getDisplayName()),
|
||||||
activity.getString(currentlyBlocked ? R.string.do_unblock : R.string.do_block),
|
activity.getString(currentlyBlocked ? R.string.do_unblock : R.string.do_block),
|
||||||
R.drawable.ic_fluent_person_prohibited_28_regular,
|
R.drawable.ic_fluent_person_prohibited_28_regular,
|
||||||
() -> {
|
() -> {
|
||||||
@@ -507,7 +508,7 @@ public class UiUtils {
|
|||||||
public static void confirmSoftBlockUser(Activity activity, String accountID, Account account, Consumer<Relationship> resultCallback) {
|
public static void confirmSoftBlockUser(Activity activity, String accountID, Account account, Consumer<Relationship> resultCallback) {
|
||||||
showConfirmationAlert(activity,
|
showConfirmationAlert(activity,
|
||||||
activity.getString(R.string.sk_remove_follower),
|
activity.getString(R.string.sk_remove_follower),
|
||||||
activity.getString(R.string.sk_remove_follower_confirm, account.displayName),
|
activity.getString(R.string.sk_remove_follower_confirm, account.getDisplayName()),
|
||||||
activity.getString(R.string.sk_do_remove_follower),
|
activity.getString(R.string.sk_do_remove_follower),
|
||||||
R.drawable.ic_fluent_person_delete_24_regular,
|
R.drawable.ic_fluent_person_delete_24_regular,
|
||||||
() -> new SetAccountBlocked(account.id, true).setCallback(new Callback<>() {
|
() -> new SetAccountBlocked(account.id, true).setCallback(new Callback<>() {
|
||||||
@@ -565,7 +566,7 @@ public class UiUtils {
|
|||||||
params.setMargins(0, V.dp(-12), 0, 0);
|
params.setMargins(0, V.dp(-12), 0, 0);
|
||||||
durationView.setLayoutParams(params);
|
durationView.setLayoutParams(params);
|
||||||
Button button=durationView.findViewById(R.id.button);
|
Button button=durationView.findViewById(R.id.button);
|
||||||
((TextView) durationView.findViewById(R.id.message)).setText(context.getString(R.string.confirm_mute, account.displayName));
|
((TextView) durationView.findViewById(R.id.message)).setText(context.getString(R.string.confirm_mute, account.getDisplayName()));
|
||||||
|
|
||||||
AtomicReference<Duration> muteDuration=new AtomicReference<>(Duration.ZERO);
|
AtomicReference<Duration> muteDuration=new AtomicReference<>(Duration.ZERO);
|
||||||
|
|
||||||
@@ -599,7 +600,7 @@ public class UiUtils {
|
|||||||
|
|
||||||
new M3AlertDialogBuilder(context)
|
new M3AlertDialogBuilder(context)
|
||||||
.setTitle(context.getString(currentlyMuted ? R.string.confirm_unmute_title : R.string.confirm_mute_title))
|
.setTitle(context.getString(currentlyMuted ? R.string.confirm_unmute_title : R.string.confirm_mute_title))
|
||||||
.setMessage(currentlyMuted ? context.getString(R.string.confirm_unmute, account.displayName) : null)
|
.setMessage(currentlyMuted ? context.getString(R.string.confirm_unmute, account.getDisplayName()) : null)
|
||||||
.setView(currentlyMuted ? null : durationView)
|
.setView(currentlyMuted ? null : durationView)
|
||||||
.setPositiveButton(context.getString(currentlyMuted ? R.string.do_unmute : R.string.do_mute), (dlg, i)->{
|
.setPositiveButton(context.getString(currentlyMuted ? R.string.do_unmute : R.string.do_mute), (dlg, i)->{
|
||||||
new SetAccountMuted(account.id, !currentlyMuted, muteDuration.get().getSeconds())
|
new SetAccountMuted(account.id, !currentlyMuted, muteDuration.get().getSeconds())
|
||||||
@@ -625,23 +626,22 @@ public class UiUtils {
|
|||||||
.show();
|
.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void confirmDeletePost(Activity activity, String accountID, Status status, Consumer<Status> resultCallback) {
|
|
||||||
confirmDeletePost(activity, accountID, status, resultCallback, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void confirmDeletePost(Activity activity, String accountID, Status status, Consumer<Status> resultCallback, boolean forRedraft) {
|
public static void confirmDeletePost(Activity activity, String accountID, Status status, Consumer<Status> resultCallback, boolean forRedraft) {
|
||||||
|
Status s=status.getContentStatus();
|
||||||
showConfirmationAlert(activity,
|
showConfirmationAlert(activity,
|
||||||
forRedraft ? R.string.sk_confirm_delete_and_redraft_title : R.string.confirm_delete_title,
|
forRedraft ? R.string.sk_confirm_delete_and_redraft_title : R.string.confirm_delete_title,
|
||||||
forRedraft ? R.string.sk_confirm_delete_and_redraft : R.string.confirm_delete,
|
forRedraft ? R.string.sk_confirm_delete_and_redraft : R.string.confirm_delete,
|
||||||
forRedraft ? R.string.sk_delete_and_redraft : R.string.delete,
|
forRedraft ? R.string.sk_delete_and_redraft : R.string.delete,
|
||||||
forRedraft ? R.drawable.ic_fluent_arrow_clockwise_28_regular : R.drawable.ic_fluent_delete_28_regular,
|
forRedraft ? R.drawable.ic_fluent_arrow_clockwise_28_regular : R.drawable.ic_fluent_delete_28_regular,
|
||||||
() -> new DeleteStatus(status.id)
|
() -> new DeleteStatus(s.id)
|
||||||
.setCallback(new Callback<>() {
|
.setCallback(new Callback<>() {
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(Status result) {
|
public void onSuccess(Status result) {
|
||||||
resultCallback.accept(result);
|
resultCallback.accept(result);
|
||||||
AccountSessionManager.getInstance().getAccount(accountID).getCacheController().deleteStatus(status.id);
|
E.post(new StatusDeletedEvent(s.id, accountID));
|
||||||
E.post(new StatusDeletedEvent(status.id, accountID));
|
if(status!=s){
|
||||||
|
E.post(new StatusDeletedEvent(status.id, accountID));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -779,8 +779,8 @@ public class UiUtils {
|
|||||||
button.setText(relationship.followedBy ? R.string.follow_back : R.string.button_follow);
|
button.setText(relationship.followedBy ? R.string.follow_back : R.string.button_follow);
|
||||||
styleRes=R.style.Widget_Mastodon_M3_Button_Filled;
|
styleRes=R.style.Widget_Mastodon_M3_Button_Filled;
|
||||||
}else{
|
}else{
|
||||||
button.setText(R.string.button_following);
|
button.setText(relationship.followedBy ? R.string.sk_button_mutuals : R.string.button_following);
|
||||||
styleRes=R.style.Widget_Mastodon_M3_Button_Tonal;
|
styleRes=relationship.followedBy ? R.style.Widget_Mastodon_M3_Button_Tonal_Outlined : R.style.Widget_Mastodon_M3_Button_Tonal;
|
||||||
}
|
}
|
||||||
|
|
||||||
TypedArray ta=button.getContext().obtainStyledAttributes(styleRes, new int[]{android.R.attr.background});
|
TypedArray ta=button.getContext().obtainStyledAttributes(styleRes, new int[]{android.R.attr.background});
|
||||||
@@ -797,25 +797,32 @@ public class UiUtils {
|
|||||||
} else if (relationship.muting) {
|
} else if (relationship.muting) {
|
||||||
confirmToggleMuteUser(activity, accountID, account, true, resultCallback);
|
confirmToggleMuteUser(activity, accountID, account, true, resultCallback);
|
||||||
} else {
|
} else {
|
||||||
progressCallback.accept(true);
|
Runnable action=()->{
|
||||||
new SetAccountFollowed(account.id, !relationship.following && !relationship.requested, true, false)
|
progressCallback.accept(true);
|
||||||
.setCallback(new Callback<>() {
|
new SetAccountFollowed(account.id, !relationship.following && !relationship.requested, true)
|
||||||
@Override
|
.setCallback(new Callback<>(){
|
||||||
public void onSuccess(Relationship result) {
|
@Override
|
||||||
resultCallback.accept(result);
|
public void onSuccess(Relationship result){
|
||||||
progressCallback.accept(false);
|
resultCallback.accept(result);
|
||||||
if(!result.following && !result.requested){
|
progressCallback.accept(false);
|
||||||
E.post(new RemoveAccountPostsEvent(accountID, account.id, true));
|
if(!result.following && !result.requested){
|
||||||
|
E.post(new RemoveAccountPostsEvent(accountID, account.id, true));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onError(ErrorResponse error) {
|
public void onError(ErrorResponse error){
|
||||||
error.showToast(activity);
|
error.showToast(activity);
|
||||||
progressCallback.accept(false);
|
progressCallback.accept(false);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.exec(accountID);
|
.exec(accountID);
|
||||||
|
};
|
||||||
|
if(relationship.following && GlobalUserPreferences.confirmUnfollow){
|
||||||
|
showConfirmationAlert(activity, null, activity.getString(R.string.unfollow_confirmation, account.getDisplayUsername()), activity.getString(R.string.unfollow), R.drawable.ic_fluent_person_delete_24_regular, action);
|
||||||
|
}else{
|
||||||
|
action.run();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -899,17 +906,26 @@ public class UiUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void insetPopupMenuIcon(Context context, MenuItem item) {
|
public static void insetPopupMenuIcon(Context context, MenuItem item) {
|
||||||
ColorStateList iconTint = ColorStateList.valueOf(UiUtils.getThemeColor(context, android.R.attr.textColorSecondary));
|
insetPopupMenuIcon(context, item, 0);
|
||||||
insetPopupMenuIcon(item, iconTint);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void insetPopupMenuIcon(MenuItem item, ColorStateList iconTint) {
|
public static void insetPopupMenuIcon(Context context, MenuItem item, int addWidth) {
|
||||||
Drawable icon = item.getIcon().mutate();
|
ColorStateList iconTint = ColorStateList.valueOf(UiUtils.getThemeColor(context, android.R.attr.textColorSecondary));
|
||||||
if (Build.VERSION.SDK_INT >= 26) item.setIconTintList(iconTint);
|
insetPopupMenuIcon(item, iconTint, addWidth);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param addWidth set if icon is too wide/narrow. if icon is 25dp in width, set to -1dp
|
||||||
|
*/
|
||||||
|
public static void insetPopupMenuIcon(MenuItem item, ColorStateList iconTint, int addWidth) {
|
||||||
|
Drawable icon=item.getIcon().mutate();
|
||||||
|
if(Build.VERSION.SDK_INT>=26) item.setIconTintList(iconTint);
|
||||||
else icon.setTintList(iconTint);
|
else icon.setTintList(iconTint);
|
||||||
icon = new InsetDrawable(icon, V.dp(8), 0, V.dp(8), 0);
|
int pad=V.dp(8);
|
||||||
|
boolean rtl=icon.getLayoutDirection()==View.LAYOUT_DIRECTION_RTL;
|
||||||
|
icon=new InsetDrawable(icon, rtl ? pad+addWidth : pad, 0, rtl ? pad : addWidth+pad, 0);
|
||||||
item.setIcon(icon);
|
item.setIcon(icon);
|
||||||
SpannableStringBuilder ssb = new SpannableStringBuilder(item.getTitle());
|
SpannableStringBuilder ssb = new SpannableStringBuilder(item.getTitle());
|
||||||
item.setTitle(ssb);
|
item.setTitle(ssb);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -943,7 +959,7 @@ public class UiUtils {
|
|||||||
if (subMenu != null) enableMenuIcons(context, subMenu, exclude);
|
if (subMenu != null) enableMenuIcons(context, subMenu, exclude);
|
||||||
if (item.getIcon() == null || Arrays.stream(exclude).anyMatch(id -> id == item.getItemId()))
|
if (item.getIcon() == null || Arrays.stream(exclude).anyMatch(id -> id == item.getItemId()))
|
||||||
continue;
|
continue;
|
||||||
insetPopupMenuIcon(item, iconTint);
|
insetPopupMenuIcon(item, iconTint, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -973,8 +989,8 @@ public class UiUtils {
|
|||||||
default -> R.style.Theme_Mastodon_AutoLightDark;
|
default -> R.style.Theme_Mastodon_AutoLightDark;
|
||||||
});
|
});
|
||||||
|
|
||||||
AccountLocalPreferences prefs=session != null ? session.getLocalPreferences() : null;
|
AccountLocalPreferences prefs=session!=null ? session.getLocalPreferences() : null;
|
||||||
AccountLocalPreferences.ColorPreference color=prefs != null ? prefs.color : AccountLocalPreferences.ColorPreference.MATERIAL3;
|
AccountLocalPreferences.ColorPreference color=prefs!=null ? prefs.getCurrentColor() : AccountLocalPreferences.ColorPreference.MATERIAL3;
|
||||||
ColorPalette palette = ColorPalette.palettes.get(color);
|
ColorPalette palette = ColorPalette.palettes.get(color);
|
||||||
if (palette != null) palette.apply(context, theme);
|
if (palette != null) palette.apply(context, theme);
|
||||||
|
|
||||||
@@ -1100,23 +1116,21 @@ public class UiUtils {
|
|||||||
return back;
|
return back;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean setExtraTextInfo(Context ctx, @Nullable TextView extraText, @Nullable TextView pronouns, boolean displayPronouns, boolean mentionedOnly, boolean localOnly, @Nullable Account account) {
|
public static boolean setExtraTextInfo(Context ctx, @Nullable TextView extraText, boolean displayPronouns, boolean mentionedOnly, boolean localOnly, @Nullable Account account) {
|
||||||
List<String> extraParts = extraText!=null && (localOnly || mentionedOnly) ? new ArrayList<>() : null;
|
List<String> extraParts=new ArrayList<>();
|
||||||
Optional<String> p=pronouns==null || !displayPronouns ? Optional.empty() : extractPronouns(ctx, account);
|
Optional<String> p=!displayPronouns ? Optional.empty() : extractPronouns(ctx, account);
|
||||||
if(p.isPresent()) {
|
|
||||||
HtmlParser.setTextWithCustomEmoji(pronouns, p.get(), account.emojis);
|
|
||||||
pronouns.setVisibility(View.VISIBLE);
|
|
||||||
}else if(pronouns!=null){
|
|
||||||
pronouns.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
if(localOnly)
|
if(localOnly)
|
||||||
extraParts.add(ctx.getString(R.string.sk_inline_local_only));
|
extraParts.add(ctx.getString(R.string.sk_inline_local_only));
|
||||||
if(mentionedOnly)
|
if(mentionedOnly)
|
||||||
extraParts.add(ctx.getString(R.string.sk_inline_direct));
|
extraParts.add(ctx.getString(R.string.sk_inline_direct));
|
||||||
if(extraText!=null && extraParts!=null && !extraParts.isEmpty()) {
|
if(p.isPresent() && extraParts.isEmpty())
|
||||||
String sepp = ctx.getString(R.string.sk_separator);
|
extraParts.add(p.get());
|
||||||
String text = String.join(" " + sepp + " ", extraParts);
|
|
||||||
if(account == null) extraText.setText(text);
|
if(extraText!=null && !extraParts.isEmpty()) {
|
||||||
|
String sepp=ctx.getString(R.string.sk_separator);
|
||||||
|
String text=String.join(" " + sepp + " ", extraParts);
|
||||||
|
if(account==null) extraText.setText(text);
|
||||||
else HtmlParser.setTextWithCustomEmoji(extraText, text, account.emojis);
|
else HtmlParser.setTextWithCustomEmoji(extraText, text, account.emojis);
|
||||||
extraText.setVisibility(View.VISIBLE);
|
extraText.setVisibility(View.VISIBLE);
|
||||||
return true;
|
return true;
|
||||||
@@ -1692,14 +1706,17 @@ public class UiUtils {
|
|||||||
|
|
||||||
Matcher matcher=trimPronouns.matcher(text);
|
Matcher matcher=trimPronouns.matcher(text);
|
||||||
if(!matcher.find()) return null;
|
if(!matcher.find()) return null;
|
||||||
String matched=matcher.group(1);
|
String pronouns=matcher.group(1);
|
||||||
// crude fix to allow for pronouns like "it(/she)"
|
// crude fix to allow for pronouns like "it(/she)"
|
||||||
int missingClosingParens=0;
|
int missingClosingParens=0;
|
||||||
for(char c : matched.toCharArray()){
|
for(char c : pronouns.toCharArray()){
|
||||||
if(c=='(') missingClosingParens++;
|
if(c=='(') missingClosingParens++;
|
||||||
if(c==')') missingClosingParens--;
|
if(c==')') missingClosingParens--;
|
||||||
}
|
}
|
||||||
return matched+")".repeat(Math.max(0, missingClosingParens));
|
pronouns+=")".repeat(Math.max(0, missingClosingParens));
|
||||||
|
// if ends with an un-closed custom emoji
|
||||||
|
if(pronouns.matches("^.*\\s+:[a-zA-Z_]+$")) pronouns+=':';
|
||||||
|
return pronouns;
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://stackoverflow.com/questions/9475589/how-to-get-string-from-different-locales-in-android
|
// https://stackoverflow.com/questions/9475589/how-to-get-string-from-different-locales-in-android
|
||||||
@@ -1711,7 +1728,7 @@ public class UiUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static Optional<String> extractPronouns(Context context, @Nullable Account account) {
|
public static Optional<String> extractPronouns(Context context, @Nullable Account account) {
|
||||||
if (account == null) return Optional.empty();
|
if (account==null || account.fields==null) return Optional.empty();
|
||||||
String localizedPronouns=context.getString(R.string.sk_pronouns_label).toLowerCase();
|
String localizedPronouns=context.getString(R.string.sk_pronouns_label).toLowerCase();
|
||||||
|
|
||||||
// higher = worse. the lowest number wins. also i'm sorry for writing this
|
// higher = worse. the lowest number wins. also i'm sorry for writing this
|
||||||
|
|||||||
@@ -4,11 +4,12 @@ import android.animation.Animator;
|
|||||||
import android.animation.AnimatorListenerAdapter;
|
import android.animation.AnimatorListenerAdapter;
|
||||||
import android.animation.AnimatorSet;
|
import android.animation.AnimatorSet;
|
||||||
import android.animation.ObjectAnimator;
|
import android.animation.ObjectAnimator;
|
||||||
|
import android.animation.ValueAnimator;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.drawable.ColorDrawable;
|
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.graphics.drawable.GradientDrawable;
|
||||||
import android.media.MediaMetadataRetriever;
|
import android.media.MediaMetadataRetriever;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
@@ -19,6 +20,7 @@ import android.text.TextUtils;
|
|||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
import android.view.ViewOutlineProvider;
|
||||||
import android.widget.HorizontalScrollView;
|
import android.widget.HorizontalScrollView;
|
||||||
import android.widget.ImageButton;
|
import android.widget.ImageButton;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
@@ -27,8 +29,8 @@ import android.widget.ProgressBar;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.DrawableRes;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.StringRes;
|
||||||
|
|
||||||
import org.joinmastodon.android.MastodonApp;
|
import org.joinmastodon.android.MastodonApp;
|
||||||
import org.joinmastodon.android.R;
|
import org.joinmastodon.android.R;
|
||||||
@@ -51,11 +53,8 @@ import org.parceler.Parcel;
|
|||||||
import org.parceler.Parcels;
|
import org.parceler.Parcels;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.ListIterator;
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
@@ -204,6 +203,15 @@ public class ComposeMediaViewController{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateButton(ImageButton btn, @DrawableRes int drawableId, @StringRes int labelId){
|
||||||
|
btn.setImageResource(drawableId);
|
||||||
|
String label=fragment.getContext().getString(labelId);
|
||||||
|
btn.setContentDescription(label);
|
||||||
|
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
|
||||||
|
btn.setTooltipText(label);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private View createMediaAttachmentView(DraftMediaAttachment draft){
|
private View createMediaAttachmentView(DraftMediaAttachment draft){
|
||||||
View thumb=fragment.getActivity().getLayoutInflater().inflate(R.layout.compose_media_thumb, attachmentsView, false);
|
View thumb=fragment.getActivity().getLayoutInflater().inflate(R.layout.compose_media_thumb, attachmentsView, false);
|
||||||
ImageView img=thumb.findViewById(R.id.thumb);
|
ImageView img=thumb.findViewById(R.id.thumb);
|
||||||
@@ -231,12 +239,11 @@ public class ComposeMediaViewController{
|
|||||||
draft.removeButton.setOnClickListener(this::onRemoveMediaAttachmentClick);
|
draft.removeButton.setOnClickListener(this::onRemoveMediaAttachmentClick);
|
||||||
draft.editButton.setTag(draft);
|
draft.editButton.setTag(draft);
|
||||||
|
|
||||||
thumb.setOutlineProvider(OutlineProviders.roundedRect(12));
|
thumb.setOutlineProvider(ViewOutlineProvider.BACKGROUND);
|
||||||
thumb.setClipToOutline(true);
|
thumb.setClipToOutline(true);
|
||||||
img.setOutlineProvider(OutlineProviders.roundedRect(12));
|
img.setOutlineProvider(OutlineProviders.roundedRect(12));
|
||||||
img.setClipToOutline(true);
|
img.setClipToOutline(true);
|
||||||
|
|
||||||
thumb.setBackgroundColor(UiUtils.getThemeColor(fragment.getActivity(), R.attr.colorM3Surface));
|
|
||||||
thumb.setOnLongClickListener(v->{
|
thumb.setOnLongClickListener(v->{
|
||||||
if(!v.hasTransientState() && attachments.size()>1){
|
if(!v.hasTransientState() && attachments.size()>1){
|
||||||
attachmentsView.startDragging(v);
|
attachmentsView.startDragging(v);
|
||||||
@@ -266,11 +273,11 @@ public class ComposeMediaViewController{
|
|||||||
draft.subtitleView.setText(subtitleRes);
|
draft.subtitleView.setText(subtitleRes);
|
||||||
}
|
}
|
||||||
draft.titleView.setText(fragment.getString(R.string.attachment_x_percent_uploaded, 0));
|
draft.titleView.setText(fragment.getString(R.string.attachment_x_percent_uploaded, 0));
|
||||||
draft.removeButton.setImageResource(R.drawable.ic_baseline_close_24);
|
updateButton(draft.removeButton, R.drawable.ic_fluent_dismiss_24_regular, R.string.delete);
|
||||||
|
|
||||||
if(draft.state==AttachmentUploadState.ERROR){
|
if(draft.state==AttachmentUploadState.ERROR){
|
||||||
draft.titleView.setText(R.string.upload_failed);
|
draft.titleView.setText(R.string.upload_failed);
|
||||||
draft.editButton.setImageResource(R.drawable.ic_fluent_arrow_counterclockwise_24_regular);
|
updateButton(draft.removeButton, R.drawable.ic_fluent_arrow_counterclockwise_24_regular, R.string.retry);
|
||||||
draft.editButton.setOnClickListener(this::onRetryOrCancelMediaUploadClick);
|
draft.editButton.setOnClickListener(this::onRetryOrCancelMediaUploadClick);
|
||||||
draft.progressBar.setVisibility(View.GONE);
|
draft.progressBar.setVisibility(View.GONE);
|
||||||
draft.setUseErrorColors(true);
|
draft.setUseErrorColors(true);
|
||||||
@@ -280,7 +287,7 @@ public class ComposeMediaViewController{
|
|||||||
draft.editButton.setOnClickListener(this::onEditMediaDescriptionClick);
|
draft.editButton.setOnClickListener(this::onEditMediaDescriptionClick);
|
||||||
}else{
|
}else{
|
||||||
draft.editButton.setVisibility(View.GONE);
|
draft.editButton.setVisibility(View.GONE);
|
||||||
draft.removeButton.setImageResource(R.drawable.ic_baseline_close_24);
|
updateButton(draft.removeButton, R.drawable.ic_fluent_dismiss_24_regular, R.string.delete);
|
||||||
if(draft.state==AttachmentUploadState.PROCESSING){
|
if(draft.state==AttachmentUploadState.PROCESSING){
|
||||||
draft.titleView.setText(R.string.upload_processing);
|
draft.titleView.setText(R.string.upload_processing);
|
||||||
}else{
|
}else{
|
||||||
@@ -374,7 +381,7 @@ public class ComposeMediaViewController{
|
|||||||
// attachment.retryButton.setContentDescription(fragment.getString(R.string.retry_upload));
|
// attachment.retryButton.setContentDescription(fragment.getString(R.string.retry_upload));
|
||||||
|
|
||||||
V.setVisibilityAnimated(attachment.editButton, View.VISIBLE);
|
V.setVisibilityAnimated(attachment.editButton, View.VISIBLE);
|
||||||
attachment.editButton.setImageResource(R.drawable.ic_fluent_arrow_counterclockwise_24_regular);
|
updateButton(attachment.editButton, R.drawable.ic_fluent_arrow_counterclockwise_24_regular, R.string.retry);
|
||||||
attachment.editButton.setOnClickListener(ComposeMediaViewController.this::onRetryOrCancelMediaUploadClick);
|
attachment.editButton.setOnClickListener(ComposeMediaViewController.this::onRetryOrCancelMediaUploadClick);
|
||||||
attachment.setUseErrorColors(true);
|
attachment.setUseErrorColors(true);
|
||||||
V.setVisibilityAnimated(attachment.progressBar, View.GONE);
|
V.setVisibilityAnimated(attachment.progressBar, View.GONE);
|
||||||
@@ -478,8 +485,8 @@ public class ComposeMediaViewController{
|
|||||||
throw new IllegalStateException("Unexpected state "+attachment.state);
|
throw new IllegalStateException("Unexpected state "+attachment.state);
|
||||||
attachment.uploadRequest=null;
|
attachment.uploadRequest=null;
|
||||||
attachment.state=AttachmentUploadState.DONE;
|
attachment.state=AttachmentUploadState.DONE;
|
||||||
attachment.editButton.setImageResource(R.drawable.ic_fluent_edit_24_regular);
|
updateButton(attachment.editButton, R.drawable.ic_fluent_edit_24_regular, R.string.sk_edit_alt_text);
|
||||||
attachment.removeButton.setImageResource(R.drawable.ic_fluent_delete_24_regular);
|
updateButton(attachment.removeButton, R.drawable.ic_fluent_dismiss_24_regular, R.string.delete);
|
||||||
attachment.editButton.setOnClickListener(this::onEditMediaDescriptionClick);
|
attachment.editButton.setOnClickListener(this::onEditMediaDescriptionClick);
|
||||||
V.setVisibilityAnimated(attachment.progressBar, View.GONE);
|
V.setVisibilityAnimated(attachment.progressBar, View.GONE);
|
||||||
V.setVisibilityAnimated(attachment.editButton, View.VISIBLE);
|
V.setVisibilityAnimated(attachment.editButton, View.VISIBLE);
|
||||||
@@ -708,18 +715,21 @@ public class ComposeMediaViewController{
|
|||||||
if(errorTransitionAnimator!=null)
|
if(errorTransitionAnimator!=null)
|
||||||
errorTransitionAnimator.cancel();
|
errorTransitionAnimator.cancel();
|
||||||
AnimatorSet set=new AnimatorSet();
|
AnimatorSet set=new AnimatorSet();
|
||||||
int color1, color2, color3;
|
int defaultBg=UiUtils.getThemeColor(view.getContext(), R.attr.colorM3Surface);
|
||||||
|
int errorBg=UiUtils.getThemeColor(view.getContext(), R.attr.colorM3ErrorContainer);
|
||||||
|
int color2, color3;
|
||||||
if(use){
|
if(use){
|
||||||
color1=UiUtils.getThemeColor(view.getContext(), R.attr.colorM3ErrorContainer);
|
|
||||||
color2=UiUtils.getThemeColor(view.getContext(), R.attr.colorM3Error);
|
color2=UiUtils.getThemeColor(view.getContext(), R.attr.colorM3Error);
|
||||||
color3=UiUtils.getThemeColor(view.getContext(), R.attr.colorM3OnErrorContainer);
|
color3=UiUtils.getThemeColor(view.getContext(), R.attr.colorM3OnErrorContainer);
|
||||||
}else{
|
}else{
|
||||||
color1=UiUtils.getThemeColor(view.getContext(), R.attr.colorM3Surface);
|
|
||||||
color2=UiUtils.getThemeColor(view.getContext(), R.attr.colorM3OnSurface);
|
color2=UiUtils.getThemeColor(view.getContext(), R.attr.colorM3OnSurface);
|
||||||
color3=UiUtils.getThemeColor(view.getContext(), R.attr.colorM3OnSurfaceVariant);
|
color3=UiUtils.getThemeColor(view.getContext(), R.attr.colorM3OnSurfaceVariant);
|
||||||
}
|
}
|
||||||
|
GradientDrawable bg=(GradientDrawable) view.getBackground().mutate();
|
||||||
|
ValueAnimator bgAnim=ValueAnimator.ofArgb(use ? defaultBg : errorBg, use ? errorBg : defaultBg);
|
||||||
|
bgAnim.addUpdateListener(anim->bg.setColor((Integer) anim.getAnimatedValue()));
|
||||||
set.playTogether(
|
set.playTogether(
|
||||||
ObjectAnimator.ofArgb(view, "backgroundColor", ((ColorDrawable)view.getBackground()).getColor(), color1),
|
bgAnim,
|
||||||
ObjectAnimator.ofArgb(titleView, "textColor", titleView.getCurrentTextColor(), color2),
|
ObjectAnimator.ofArgb(titleView, "textColor", titleView.getCurrentTextColor(), color2),
|
||||||
ObjectAnimator.ofArgb(subtitleView, "textColor", subtitleView.getCurrentTextColor(), color3),
|
ObjectAnimator.ofArgb(subtitleView, "textColor", subtitleView.getCurrentTextColor(), color3),
|
||||||
ObjectAnimator.ofArgb(removeButton.getDrawable(), "tint", subtitleView.getCurrentTextColor(), color3)
|
ObjectAnimator.ofArgb(removeButton.getDrawable(), "tint", subtitleView.getCurrentTextColor(), color3)
|
||||||
|
|||||||
@@ -134,7 +134,10 @@ public class ComposePollViewController{
|
|||||||
DraftPollOption opt=createDraftPollOption(false);
|
DraftPollOption opt=createDraftPollOption(false);
|
||||||
opt.edit.setText(eopt.title);
|
opt.edit.setText(eopt.title);
|
||||||
}
|
}
|
||||||
pollDuration=(int)fragment.editingStatus.poll.expiresAt.minus(fragment.editingStatus.createdAt.toEpochMilli(), ChronoUnit.MILLIS).getEpochSecond();
|
if(fragment.scheduledStatus!=null && fragment.scheduledStatus.params.poll!=null)
|
||||||
|
pollDuration=Integer.parseInt(fragment.scheduledStatus.params.poll.expiresIn);
|
||||||
|
else if(fragment.editingStatus.poll.expiresAt!=null)
|
||||||
|
pollDuration=(int)fragment.editingStatus.poll.expiresAt.minus(fragment.editingStatus.createdAt.toEpochMilli(), ChronoUnit.MILLIS).getEpochSecond();
|
||||||
updatePollOptionHints();
|
updatePollOptionHints();
|
||||||
pollDurationValue.setText(UiUtils.formatDuration(fragment.getContext(), pollDuration));
|
pollDurationValue.setText(UiUtils.formatDuration(fragment.getContext(), pollDuration));
|
||||||
pollIsMultipleChoice=fragment.editingStatus.poll.multiple;
|
pollIsMultipleChoice=fragment.editingStatus.poll.multiple;
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import android.app.Fragment;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.graphics.drawable.Animatable;
|
import android.graphics.drawable.Animatable;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.text.SpannableStringBuilder;
|
import android.text.SpannableStringBuilder;
|
||||||
import android.text.style.TypefaceSpan;
|
import android.text.style.TypefaceSpan;
|
||||||
@@ -25,6 +26,7 @@ import org.joinmastodon.android.GlobalUserPreferences;
|
|||||||
import org.joinmastodon.android.R;
|
import org.joinmastodon.android.R;
|
||||||
import org.joinmastodon.android.api.requests.accounts.SetAccountFollowed;
|
import org.joinmastodon.android.api.requests.accounts.SetAccountFollowed;
|
||||||
import org.joinmastodon.android.api.session.AccountSessionManager;
|
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||||
|
import org.joinmastodon.android.fragments.ListsFragment;
|
||||||
import org.joinmastodon.android.fragments.ProfileFragment;
|
import org.joinmastodon.android.fragments.ProfileFragment;
|
||||||
import org.joinmastodon.android.fragments.report.ReportReasonChoiceFragment;
|
import org.joinmastodon.android.fragments.report.ReportReasonChoiceFragment;
|
||||||
import org.joinmastodon.android.model.Account;
|
import org.joinmastodon.android.model.Account;
|
||||||
@@ -98,6 +100,9 @@ public class AccountViewHolder extends BindableViewHolder<AccountViewModel> impl
|
|||||||
contextMenu=new PopupMenu(fragment.getActivity(), menuAnchor);
|
contextMenu=new PopupMenu(fragment.getActivity(), menuAnchor);
|
||||||
contextMenu.inflate(R.menu.profile);
|
contextMenu.inflate(R.menu.profile);
|
||||||
contextMenu.setOnMenuItemClickListener(this::onContextMenuItemSelected);
|
contextMenu.setOnMenuItemClickListener(this::onContextMenuItemSelected);
|
||||||
|
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.P && !UiUtils.isEMUI())
|
||||||
|
contextMenu.getMenu().setGroupDividerEnabled(true);
|
||||||
|
UiUtils.enablePopupMenuIcons(fragment.getContext(), contextMenu);
|
||||||
|
|
||||||
setStyle(AccessoryType.BUTTON, false);
|
setStyle(AccessoryType.BUTTON, false);
|
||||||
}
|
}
|
||||||
@@ -212,14 +217,20 @@ public class AccountViewHolder extends BindableViewHolder<AccountViewModel> impl
|
|||||||
Menu menu=contextMenu.getMenu();
|
Menu menu=contextMenu.getMenu();
|
||||||
Account account=item.account;
|
Account account=item.account;
|
||||||
|
|
||||||
menu.findItem(R.id.share).setTitle(fragment.getString(R.string.share_user, account.getDisplayUsername()));
|
|
||||||
menu.findItem(R.id.manage_user_lists).setTitle(fragment.getString(R.string.sk_lists_with_user, account.getShortUsername()));
|
menu.findItem(R.id.manage_user_lists).setTitle(fragment.getString(R.string.sk_lists_with_user, account.getShortUsername()));
|
||||||
menu.findItem(R.id.mute).setTitle(fragment.getString(relationship.muting ? R.string.unmute_user : R.string.mute_user, account.getDisplayUsername()));
|
MenuItem mute=menu.findItem(R.id.mute);
|
||||||
menu.findItem(R.id.block).setTitle(fragment.getString(relationship.blocking ? R.string.unblock_user : R.string.block_user, account.getDisplayUsername()));
|
mute.setTitle(fragment.getString(relationship.muting ? R.string.unmute_user : R.string.mute_user, account.getShortUsername()));
|
||||||
menu.findItem(R.id.report).setTitle(fragment.getString(R.string.report_user, account.getDisplayUsername()));
|
mute.setIcon(relationship.muting ? R.drawable.ic_fluent_speaker_0_24_regular : R.drawable.ic_fluent_speaker_off_24_regular);
|
||||||
|
UiUtils.insetPopupMenuIcon(fragment.getContext(), mute);
|
||||||
|
menu.findItem(R.id.block).setTitle(fragment.getString(relationship.blocking ? R.string.unblock_user : R.string.block_user, account.getShortUsername()));
|
||||||
|
menu.findItem(R.id.report).setTitle(fragment.getString(R.string.report_user, account.getShortUsername()));
|
||||||
|
menu.findItem(R.id.manage_user_lists).setVisible(relationship.following);
|
||||||
|
menu.findItem(R.id.soft_block).setVisible(relationship.followedBy && !relationship.following);
|
||||||
MenuItem hideBoosts=menu.findItem(R.id.hide_boosts);
|
MenuItem hideBoosts=menu.findItem(R.id.hide_boosts);
|
||||||
if(relationship.following){
|
if(relationship.following){
|
||||||
hideBoosts.setTitle(fragment.getString(relationship.showingReblogs ? R.string.hide_boosts_from_user : R.string.show_boosts_from_user, account.getDisplayUsername()));
|
hideBoosts.setTitle(fragment.getString(relationship.showingReblogs ? R.string.hide_boosts_from_user : R.string.show_boosts_from_user, account.getShortUsername()));
|
||||||
|
hideBoosts.setIcon(relationship.showingReblogs ? R.drawable.ic_fluent_arrow_repeat_all_off_24_regular : R.drawable.ic_fluent_arrow_repeat_all_24_regular);
|
||||||
|
UiUtils.insetPopupMenuIcon(fragment.getContext(), hideBoosts);
|
||||||
hideBoosts.setVisible(true);
|
hideBoosts.setVisible(true);
|
||||||
}else{
|
}else{
|
||||||
hideBoosts.setVisible(false);
|
hideBoosts.setVisible(false);
|
||||||
@@ -274,6 +285,8 @@ public class AccountViewHolder extends BindableViewHolder<AccountViewModel> impl
|
|||||||
UiUtils.confirmToggleMuteUser(fragment.getActivity(), accountID, account, relationship.muting, this::updateRelationship);
|
UiUtils.confirmToggleMuteUser(fragment.getActivity(), accountID, account, relationship.muting, this::updateRelationship);
|
||||||
}else if(id==R.id.block){
|
}else if(id==R.id.block){
|
||||||
UiUtils.confirmToggleBlockUser(fragment.getActivity(), accountID, account, relationship.blocking, this::updateRelationship);
|
UiUtils.confirmToggleBlockUser(fragment.getActivity(), accountID, account, relationship.blocking, this::updateRelationship);
|
||||||
|
}else if(id==R.id.soft_block){
|
||||||
|
UiUtils.confirmSoftBlockUser(fragment.getActivity(), accountID, account, this::updateRelationship);
|
||||||
}else if(id==R.id.report){
|
}else if(id==R.id.report){
|
||||||
Bundle args=new Bundle();
|
Bundle args=new Bundle();
|
||||||
args.putString("account", accountID);
|
args.putString("account", accountID);
|
||||||
@@ -303,6 +316,12 @@ public class AccountViewHolder extends BindableViewHolder<AccountViewModel> impl
|
|||||||
})
|
})
|
||||||
.wrapProgress(fragment.getActivity(), R.string.loading, false)
|
.wrapProgress(fragment.getActivity(), R.string.loading, false)
|
||||||
.exec(accountID);
|
.exec(accountID);
|
||||||
|
}else if(id==R.id.manage_user_lists){
|
||||||
|
final Bundle args=new Bundle();
|
||||||
|
args.putString("account", accountID);
|
||||||
|
args.putString("profileAccount", account.id);
|
||||||
|
args.putString("profileDisplayUsername", account.getDisplayUsername());
|
||||||
|
Nav.go(fragment.getActivity(), ListsFragment.class, args);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,6 +73,6 @@ public abstract class ListItemViewHolder<T extends ListItem<?>> extends Bindable
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onClick(){
|
public void onClick(){
|
||||||
item.onClick.run();
|
item.performClick();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,33 +1,40 @@
|
|||||||
package org.joinmastodon.android.ui.views;
|
package org.joinmastodon.android.ui.views;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.res.TypedArray;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import me.grishka.appkit.utils.V;
|
import org.joinmastodon.android.R;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A LinearLayout for TextViews. First child TextView will get truncated if it doesn't fit, remaining will always wrap content.
|
* A LinearLayout for TextViews. First child TextView will get truncated if it doesn't fit, remaining will always wrap content.
|
||||||
*/
|
*/
|
||||||
public class HeaderSubtitleLinearLayout extends LinearLayout{
|
public class HeaderSubtitleLinearLayout extends LinearLayout{
|
||||||
|
private float firstFraction;
|
||||||
|
|
||||||
public HeaderSubtitleLinearLayout(Context context){
|
public HeaderSubtitleLinearLayout(Context context){
|
||||||
super(context);
|
this(context, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public HeaderSubtitleLinearLayout(Context context, AttributeSet attrs){
|
public HeaderSubtitleLinearLayout(Context context, AttributeSet attrs){
|
||||||
super(context, attrs);
|
this(context, attrs, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public HeaderSubtitleLinearLayout(Context context, AttributeSet attrs, int defStyleAttr){
|
public HeaderSubtitleLinearLayout(Context context, AttributeSet attrs, int defStyleAttr){
|
||||||
super(context, attrs, defStyleAttr);
|
super(context, attrs, defStyleAttr);
|
||||||
|
TypedArray ta=context.obtainStyledAttributes(attrs, R.styleable.HeaderSubtitleLinearLayout);
|
||||||
|
firstFraction=ta.getFraction(R.styleable.HeaderSubtitleLinearLayout_firstFraction, 1, 1, 0.5f);
|
||||||
|
ta.recycle();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
|
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
|
||||||
if(getLayoutChildCount()>1){
|
if(getLayoutChildCount()>1){
|
||||||
int remainingWidth=MeasureSpec.getSize(widthMeasureSpec);
|
int fullWidth=MeasureSpec.getSize(widthMeasureSpec);
|
||||||
|
int remainingWidth=fullWidth;
|
||||||
for(int i=1;i<getChildCount();i++){
|
for(int i=1;i<getChildCount();i++){
|
||||||
View v=getChildAt(i);
|
View v=getChildAt(i);
|
||||||
if(v.getVisibility()==GONE)
|
if(v.getVisibility()==GONE)
|
||||||
@@ -38,8 +45,7 @@ public class HeaderSubtitleLinearLayout extends LinearLayout{
|
|||||||
}
|
}
|
||||||
View first=getChildAt(0);
|
View first=getChildAt(0);
|
||||||
if(first instanceof TextView){
|
if(first instanceof TextView){
|
||||||
// guaranteeing at least 64dp of width for the display name
|
((TextView) first).setMaxWidth(Math.max(remainingWidth, (int)(firstFraction*fullWidth)));
|
||||||
((TextView) first).setMaxWidth(Math.max(remainingWidth, V.dp(64)));
|
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
View first=getChildAt(0);
|
View first=getChildAt(0);
|
||||||
@@ -58,4 +64,12 @@ public class HeaderSubtitleLinearLayout extends LinearLayout{
|
|||||||
}
|
}
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setFirstFraction(float firstFraction){
|
||||||
|
this.firstFraction=firstFraction;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getFirstFraction(){
|
||||||
|
return firstFraction;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
package org.joinmastodon.android.ui.views;
|
package org.joinmastodon.android.ui.views;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.graphics.Typeface;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
import java.util.function.IntConsumer;
|
import java.util.function.IntConsumer;
|
||||||
import java.util.function.IntPredicate;
|
import java.util.function.IntPredicate;
|
||||||
@@ -45,9 +47,7 @@ public class TabBar extends LinearLayout{
|
|||||||
listener.accept(v.getId());
|
listener.accept(v.getId());
|
||||||
if(v.getId()==selectedTabID)
|
if(v.getId()==selectedTabID)
|
||||||
return;
|
return;
|
||||||
findViewById(selectedTabID).setSelected(false);
|
selectTab(v.getId());
|
||||||
v.setSelected(true);
|
|
||||||
selectedTabID=v.getId();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean onChildLongClick(View v){
|
private boolean onChildLongClick(View v){
|
||||||
@@ -60,8 +60,17 @@ public class TabBar extends LinearLayout{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void selectTab(int id){
|
public void selectTab(int id){
|
||||||
findViewById(selectedTabID).setSelected(false);
|
toggleSelected(selectedTabID, false);
|
||||||
selectedTabID=id;
|
selectedTabID=id;
|
||||||
findViewById(selectedTabID).setSelected(true);
|
toggleSelected(id, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void toggleSelected(int selectedTabID, boolean selected){
|
||||||
|
LinearLayout tab=findViewById(selectedTabID);
|
||||||
|
tab.setSelected(selected);
|
||||||
|
View v=tab.findViewWithTag("label");
|
||||||
|
if(v instanceof TextView text){
|
||||||
|
text.setTypeface(Typeface.create(text.getTypeface(), selected ? Typeface.BOLD : Typeface.NORMAL));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user