Compare commits
242 Commits
v2.1.4+for
...
v2.1.6+for
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
0cc8cddfc3 | ||
|
|
4428ef7ac2 | ||
|
|
44912b7982 | ||
|
|
c930db6068 | ||
|
|
d96d4dd581 | ||
|
|
67e3a5bb47 | ||
|
|
b0a5aa93e1 | ||
|
|
0bc1459898 | ||
|
|
fae25e93a5 | ||
|
|
c0c121050c | ||
|
|
afe572ca7f | ||
|
|
8cb4db5fcf | ||
|
|
de235ec7cc | ||
|
|
140c2a7b9d | ||
|
|
c833513344 | ||
|
|
1e95536208 | ||
|
|
b58fda9795 | ||
|
|
3135aef398 | ||
|
|
c83dc51322 | ||
|
|
9cfaed89e6 | ||
|
|
5374ac766c | ||
|
|
98596e77f2 | ||
|
|
54aa89c7f8 | ||
|
|
f59157b160 | ||
|
|
6b38db9607 | ||
|
|
53afc120f3 | ||
|
|
c10cdfd795 | ||
|
|
c2184e7bd8 | ||
|
|
baf756e163 | ||
|
|
efc67fd7e8 | ||
|
|
43e737425a | ||
|
|
b5b3cb42a1 | ||
|
|
f72f7cb831 | ||
|
|
f86d60be23 | ||
|
|
7c8624bd53 | ||
|
|
a75ce70615 | ||
|
|
331548b38d | ||
|
|
8b8f192dfa | ||
|
|
061b2ee3de | ||
|
|
5ea2864bd5 | ||
|
|
ee2b4b6a1f | ||
|
|
697f801c1a | ||
|
|
ebb49c44fe | ||
|
|
bc4619e6b1 | ||
|
|
4a3b948760 | ||
|
|
f81283c892 | ||
|
|
7eae879037 | ||
|
|
1b0ce5d893 | ||
|
|
5d26ea85e9 | ||
|
|
6efe263dd8 | ||
|
|
0379347f2d | ||
|
|
1299b2ad42 | ||
|
|
f3b3bcaa0a | ||
|
|
b1bec870c5 | ||
|
|
36e05a6d14 | ||
|
|
2e11f78e9d | ||
|
|
9fcfbe5593 | ||
|
|
c17745368d | ||
|
|
e78b518654 | ||
|
|
55a8634be2 | ||
|
|
ac891eea53 | ||
|
|
74fa2a3081 | ||
|
|
6c1c5b7759 | ||
|
|
1f4152b588 | ||
|
|
70386ea1b2 | ||
|
|
cbce90c461 | ||
|
|
74ae3bf706 | ||
|
|
1feccdc26d | ||
|
|
c38c2a425b | ||
|
|
f43352b790 | ||
|
|
c5b52b2781 | ||
|
|
b91840fb95 | ||
|
|
1988849b26 | ||
|
|
fc10fbffb0 | ||
|
|
e40841c128 |
@@ -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 105
|
||||||
versionName "2.1.4+fork.100"
|
versionName "2.1.6+fork.105"
|
||||||
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']
|
||||||
}
|
}
|
||||||
@@ -70,7 +70,7 @@ dependencies {
|
|||||||
implementation 'me.grishka.litex:viewpager:1.0.0'
|
implementation 'me.grishka.litex:viewpager:1.0.0'
|
||||||
implementation 'me.grishka.litex:viewpager2:1.0.0'
|
implementation 'me.grishka.litex:viewpager2:1.0.0'
|
||||||
implementation 'me.grishka.litex:palette:1.0.0'
|
implementation 'me.grishka.litex:palette:1.0.0'
|
||||||
implementation 'me.grishka.appkit:appkit:1.2.9'
|
implementation 'me.grishka.appkit:appkit:1.2.14'
|
||||||
implementation 'com.google.code.gson:gson:2.9.0'
|
implementation 'com.google.code.gson:gson:2.9.0'
|
||||||
implementation 'org.jsoup:jsoup:1.14.3'
|
implementation 'org.jsoup:jsoup:1.14.3'
|
||||||
implementation 'com.squareup:otto:1.3.8'
|
implementation 'com.squareup:otto:1.3.8'
|
||||||
|
|||||||
@@ -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
|
|
||||||
|
|||||||
@@ -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());
|
||||||
|
|||||||
@@ -32,7 +32,6 @@ public class ExternalShareActivity extends FragmentStackActivity{
|
|||||||
UiUtils.setUserPreferredTheme(this);
|
UiUtils.setUserPreferredTheme(this);
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
if(savedInstanceState==null){
|
if(savedInstanceState==null){
|
||||||
|
|
||||||
Optional<String> text = Optional.ofNullable(getIntent().getStringExtra(Intent.EXTRA_TEXT));
|
Optional<String> text = Optional.ofNullable(getIntent().getStringExtra(Intent.EXTRA_TEXT));
|
||||||
Optional<Pair<String, Optional<String>>> fediHandle = text.flatMap(UiUtils::parseFediverseHandle);
|
Optional<Pair<String, Optional<String>>> fediHandle = text.flatMap(UiUtils::parseFediverseHandle);
|
||||||
boolean isFediUrl = text.map(UiUtils::looksLikeFediverseUrl).orElse(false);
|
boolean isFediUrl = text.map(UiUtils::looksLikeFediverseUrl).orElse(false);
|
||||||
|
|||||||
@@ -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,16 +51,17 @@ 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;
|
||||||
public static ColorPreference color;
|
|
||||||
public static boolean disableM3PillActiveIndicator;
|
public static boolean disableM3PillActiveIndicator;
|
||||||
public static boolean showNavigationLabels;
|
public static boolean showNavigationLabels;
|
||||||
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);
|
||||||
@@ -112,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);
|
||||||
@@ -123,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)
|
||||||
@@ -133,14 +134,11 @@ public class GlobalUserPreferences{
|
|||||||
.apply();
|
.apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
int migrationLevel=prefs.getInt("migrationLevel", BuildConfig.VERSION_CODE);
|
||||||
color=ColorPreference.valueOf(prefs.getString("color", ColorPreference.PINK.name()));
|
if(migrationLevel < 61)
|
||||||
} catch (IllegalArgumentException|ClassCastException ignored) {
|
migrateToUpstreamVersion61();
|
||||||
// invalid color name or color was previously saved as integer
|
if(migrationLevel < BuildConfig.VERSION_CODE)
|
||||||
color=ColorPreference.PINK;
|
prefs.edit().putInt("migrationLevel", BuildConfig.VERSION_CODE).apply();
|
||||||
}
|
|
||||||
|
|
||||||
if(prefs.getInt("migrationLevel", 0) < 61) migrateToUpstreamVersion61();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void save(){
|
public static void save(){
|
||||||
@@ -170,8 +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)
|
|
||||||
.putString("color", color.name())
|
|
||||||
.putBoolean("allowRemoteLoading", allowRemoteLoading)
|
.putBoolean("allowRemoteLoading", allowRemoteLoading)
|
||||||
.putString("autoRevealEqualSpoilers", autoRevealEqualSpoilers.name())
|
.putString("autoRevealEqualSpoilers", autoRevealEqualSpoilers.name())
|
||||||
.putBoolean("forwardReportDefault", forwardReportDefault)
|
.putBoolean("forwardReportDefault", forwardReportDefault)
|
||||||
@@ -182,9 +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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum ThemePreference{
|
||||||
|
AUTO,
|
||||||
|
LIGHT,
|
||||||
|
DARK
|
||||||
|
}
|
||||||
|
|
||||||
|
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!!");
|
||||||
|
|
||||||
@@ -231,49 +251,8 @@ public class GlobalUserPreferences{
|
|||||||
|
|
||||||
localPrefs.save();
|
localPrefs.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
prefs.edit().putInt("migrationLevel", 61).apply();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum ColorPreference{
|
//endregion
|
||||||
MATERIAL3,
|
|
||||||
PINK,
|
|
||||||
PURPLE,
|
|
||||||
GREEN,
|
|
||||||
BLUE,
|
|
||||||
BROWN,
|
|
||||||
RED,
|
|
||||||
YELLOW;
|
|
||||||
|
|
||||||
public @StringRes int getName() {
|
|
||||||
return switch(this){
|
|
||||||
case MATERIAL3 -> R.string.sk_color_palette_material3;
|
|
||||||
case PINK -> R.string.sk_color_palette_pink;
|
|
||||||
case PURPLE -> R.string.sk_color_palette_purple;
|
|
||||||
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;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum ThemePreference{
|
|
||||||
AUTO,
|
|
||||||
LIGHT,
|
|
||||||
DARK
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum AutoRevealMode {
|
|
||||||
NEVER,
|
|
||||||
THREADS,
|
|
||||||
DISCUSSIONS
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum PrefixRepliesMode {
|
|
||||||
NEVER,
|
|
||||||
ALWAYS,
|
|
||||||
TO_OTHERS
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,54 +39,12 @@ import me.grishka.appkit.api.ErrorResponse;
|
|||||||
public class MainActivity extends FragmentStackActivity implements ProvidesAssistContent {
|
public class MainActivity extends FragmentStackActivity implements ProvidesAssistContent {
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(@Nullable Bundle savedInstanceState){
|
protected void onCreate(@Nullable Bundle savedInstanceState){
|
||||||
UiUtils.setUserPreferredTheme(this);
|
AccountSession session=getCurrentSession();
|
||||||
|
UiUtils.setUserPreferredTheme(this, session);
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
if(savedInstanceState==null){
|
if(savedInstanceState==null){
|
||||||
if(AccountSessionManager.getInstance().getLoggedInAccounts().isEmpty()){
|
restartHomeFragment();
|
||||||
showFragmentClearingBackStack(new CustomWelcomeFragment());
|
|
||||||
}else{
|
|
||||||
AccountSession session;
|
|
||||||
Bundle args=new Bundle();
|
|
||||||
Intent intent=getIntent();
|
|
||||||
if(intent.hasExtra("fromExternalShare")) {
|
|
||||||
AccountSessionManager.getInstance()
|
|
||||||
.setLastActiveAccountID(intent.getStringExtra("account"));
|
|
||||||
AccountSessionManager.getInstance().maybeUpdateLocalInfo(
|
|
||||||
AccountSessionManager.getInstance().getLastActiveAccount());
|
|
||||||
showFragmentForExternalShare(intent.getExtras());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean fromNotification = intent.getBooleanExtra("fromNotification", false);
|
|
||||||
boolean hasNotification = intent.hasExtra("notification");
|
|
||||||
if(fromNotification){
|
|
||||||
String accountID=intent.getStringExtra("accountID");
|
|
||||||
try{
|
|
||||||
session=AccountSessionManager.getInstance().getAccount(accountID);
|
|
||||||
if(!hasNotification) args.putString("tab", "notifications");
|
|
||||||
}catch(IllegalStateException x){
|
|
||||||
session=AccountSessionManager.getInstance().getLastActiveAccount();
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
session=AccountSessionManager.getInstance().getLastActiveAccount();
|
|
||||||
}
|
|
||||||
AccountSessionManager.getInstance().maybeUpdateLocalInfo(session);
|
|
||||||
args.putString("account", session.getID());
|
|
||||||
Fragment fragment=session.activated ? new HomeFragment() : new AccountActivationFragment();
|
|
||||||
fragment.setArguments(args);
|
|
||||||
if(fromNotification && hasNotification){
|
|
||||||
Notification notification=Parcels.unwrap(intent.getParcelableExtra("notification"));
|
|
||||||
showFragmentForNotification(notification, session.getID());
|
|
||||||
} else if (intent.getBooleanExtra("compose", false)){
|
|
||||||
showCompose();
|
|
||||||
} else if (Intent.ACTION_VIEW.equals(intent.getAction())){
|
|
||||||
handleURL(intent.getData(), null);
|
|
||||||
} else {
|
|
||||||
showFragmentClearingBackStack(fragment);
|
|
||||||
maybeRequestNotificationsPermission();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(GithubSelfUpdater.needSelfUpdating()){
|
if(GithubSelfUpdater.needSelfUpdating()){
|
||||||
@@ -259,4 +217,81 @@ public class MainActivity extends FragmentStackActivity implements ProvidesAssis
|
|||||||
Fragment fragment = getCurrentFragment();
|
Fragment fragment = getCurrentFragment();
|
||||||
if (fragment != null) callFragmentToProvideAssistContent(fragment, assistContent);
|
if (fragment != null) callFragmentToProvideAssistContent(fragment, assistContent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public AccountSession getCurrentSession(){
|
||||||
|
AccountSession session;
|
||||||
|
Bundle args=new Bundle();
|
||||||
|
Intent intent=getIntent();
|
||||||
|
if(intent.hasExtra("fromExternalShare")) {
|
||||||
|
return AccountSessionManager.getInstance()
|
||||||
|
.getAccount(intent.getStringExtra("account"));
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean fromNotification = intent.getBooleanExtra("fromNotification", false);
|
||||||
|
boolean hasNotification = intent.hasExtra("notification");
|
||||||
|
if(fromNotification){
|
||||||
|
String accountID=intent.getStringExtra("accountID");
|
||||||
|
try{
|
||||||
|
session=AccountSessionManager.getInstance().getAccount(accountID);
|
||||||
|
if(!hasNotification) args.putString("tab", "notifications");
|
||||||
|
}catch(IllegalStateException x){
|
||||||
|
session=AccountSessionManager.getInstance().getLastActiveAccount();
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
session=AccountSessionManager.getInstance().getLastActiveAccount();
|
||||||
|
}
|
||||||
|
return session;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void restartActivity(){
|
||||||
|
finish();
|
||||||
|
startActivity(new Intent(this, MainActivity.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void restartHomeFragment(){
|
||||||
|
if(AccountSessionManager.getInstance().getLoggedInAccounts().isEmpty()){
|
||||||
|
showFragmentClearingBackStack(new CustomWelcomeFragment());
|
||||||
|
}else{
|
||||||
|
AccountSession session;
|
||||||
|
Bundle args=new Bundle();
|
||||||
|
Intent intent=getIntent();
|
||||||
|
if(intent.hasExtra("fromExternalShare")) {
|
||||||
|
AccountSessionManager.getInstance()
|
||||||
|
.setLastActiveAccountID(intent.getStringExtra("account"));
|
||||||
|
AccountSessionManager.getInstance().maybeUpdateLocalInfo(
|
||||||
|
AccountSessionManager.getInstance().getLastActiveAccount());
|
||||||
|
showFragmentForExternalShare(intent.getExtras());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean fromNotification = intent.getBooleanExtra("fromNotification", false);
|
||||||
|
boolean hasNotification = intent.hasExtra("notification");
|
||||||
|
if(fromNotification){
|
||||||
|
String accountID=intent.getStringExtra("accountID");
|
||||||
|
try{
|
||||||
|
session=AccountSessionManager.getInstance().getAccount(accountID);
|
||||||
|
if(!hasNotification) args.putString("tab", "notifications");
|
||||||
|
}catch(IllegalStateException x){
|
||||||
|
session=AccountSessionManager.getInstance().getLastActiveAccount();
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
session=AccountSessionManager.getInstance().getLastActiveAccount();
|
||||||
|
}
|
||||||
|
AccountSessionManager.getInstance().maybeUpdateLocalInfo(session);
|
||||||
|
args.putString("account", session.getID());
|
||||||
|
Fragment fragment=session.activated ? new HomeFragment() : new AccountActivationFragment();
|
||||||
|
fragment.setArguments(args);
|
||||||
|
if(fromNotification && hasNotification){
|
||||||
|
Notification notification=Parcels.unwrap(intent.getParcelableExtra("notification"));
|
||||||
|
showFragmentForNotification(notification, session.getID());
|
||||||
|
} else if (intent.getBooleanExtra("compose", false)){
|
||||||
|
showCompose();
|
||||||
|
} else if (Intent.ACTION_VIEW.equals(intent.getAction())){
|
||||||
|
handleURL(intent.getData(), null);
|
||||||
|
} else {
|
||||||
|
showFragmentClearingBackStack(fragment);
|
||||||
|
maybeRequestNotificationsPermission();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,12 +70,11 @@ 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());
|
||||||
String _newMaxID=newMaxID;
|
String _newMaxID=newMaxID;
|
||||||
AccountSessionManager.get(accountID).filterStatuses(result, FilterContext.HOME);
|
|
||||||
uiHandler.post(()->callback.onSuccess(new CacheablePaginatedResponse<>(result, _newMaxID, true)));
|
uiHandler.post(()->callback.onSuccess(new CacheablePaginatedResponse<>(result, _newMaxID, true)));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -86,9 +86,7 @@ public class CacheController{
|
|||||||
.setCallback(new Callback<>(){
|
.setCallback(new Callback<>(){
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(List<Status> result){
|
public void onSuccess(List<Status> result){
|
||||||
ArrayList<Status> filtered=new ArrayList<>(result);
|
callback.onSuccess(new CacheablePaginatedResponse<>(result, result.isEmpty() ? null : result.get(result.size()-1).id, false));
|
||||||
AccountSessionManager.get(accountID).filterStatuses(filtered, FilterContext.HOME);
|
|
||||||
callback.onSuccess(new CacheablePaginatedResponse<>(filtered, result.isEmpty() ? null : result.get(result.size()-1).id, false));
|
|
||||||
putHomeTimeline(result, maxID==null);
|
putHomeTimeline(result, maxID==null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,7 +114,7 @@ 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());
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
@@ -82,7 +85,11 @@ public class StatusInteractionController{
|
|||||||
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
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -6,9 +6,14 @@ import static org.joinmastodon.android.api.MastodonAPIController.gson;
|
|||||||
|
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
|
|
||||||
|
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.model.ContentType;
|
import org.joinmastodon.android.model.ContentType;
|
||||||
|
import org.joinmastodon.android.model.Emoji;
|
||||||
import org.joinmastodon.android.model.TimelineDefinition;
|
import org.joinmastodon.android.model.TimelineDefinition;
|
||||||
|
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
@@ -36,12 +41,14 @@ public class AccountLocalPreferences{
|
|||||||
public String publishButtonText;
|
public String publishButtonText;
|
||||||
public String timelineReplyVisibility; // akkoma-only
|
public String timelineReplyVisibility; // akkoma-only
|
||||||
public boolean keepOnlyLatestNotification;
|
public boolean keepOnlyLatestNotification;
|
||||||
|
|
||||||
public boolean emojiReactionsEnabled;
|
public boolean emojiReactionsEnabled;
|
||||||
public ShowEmojiReactions showEmojiReactions;
|
public ShowEmojiReactions showEmojiReactions;
|
||||||
|
public ColorPreference color;
|
||||||
|
public ArrayList<Emoji> recentCustomEmoji;
|
||||||
|
|
||||||
private final static Type recentLanguagesType=new TypeToken<ArrayList<String>>() {}.getType();
|
private final static Type recentLanguagesType=new TypeToken<ArrayList<String>>() {}.getType();
|
||||||
private final static Type timelinesType=new TypeToken<ArrayList<TimelineDefinition>>() {}.getType();
|
private final static Type timelinesType=new TypeToken<ArrayList<TimelineDefinition>>() {}.getType();
|
||||||
|
private final static Type recentCustomEmojiType=new TypeToken<ArrayList<Emoji>>() {}.getType();
|
||||||
|
|
||||||
public AccountLocalPreferences(SharedPreferences prefs, AccountSession session){
|
public AccountLocalPreferences(SharedPreferences prefs, AccountSession session){
|
||||||
this.prefs=prefs;
|
this.prefs=prefs;
|
||||||
@@ -66,6 +73,8 @@ 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=prefs.contains("color") ? ColorPreference.valueOf(prefs.getString("color", null)) : null;
|
||||||
|
recentCustomEmoji=fromJson(prefs.getString("recentCustomEmoji", null), recentCustomEmojiType, new ArrayList<>());
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getNotificationsPauseEndTime(){
|
public long getNotificationsPauseEndTime(){
|
||||||
@@ -76,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)
|
||||||
@@ -99,9 +112,35 @@ 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!=null ? color.name() : null)
|
||||||
|
.putString("recentCustomEmoji", gson.toJson(recentCustomEmoji))
|
||||||
.apply();
|
.apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum ColorPreference{
|
||||||
|
MATERIAL3,
|
||||||
|
PINK,
|
||||||
|
PURPLE,
|
||||||
|
GREEN,
|
||||||
|
BLUE,
|
||||||
|
BROWN,
|
||||||
|
RED,
|
||||||
|
YELLOW;
|
||||||
|
|
||||||
|
public @StringRes int getName() {
|
||||||
|
return switch(this){
|
||||||
|
case MATERIAL3 -> R.string.sk_color_palette_material3;
|
||||||
|
case PINK -> R.string.sk_color_palette_pink;
|
||||||
|
case PURPLE -> R.string.sk_color_palette_purple;
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public enum ShowEmojiReactions{
|
public enum ShowEmojiReactions{
|
||||||
HIDE_EMPTY,
|
HIDE_EMPTY,
|
||||||
ONLY_OPENED,
|
ONLY_OPENED,
|
||||||
|
|||||||
@@ -40,7 +40,6 @@ import java.util.Objects;
|
|||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.function.Predicate;
|
|
||||||
|
|
||||||
import me.grishka.appkit.api.Callback;
|
import me.grishka.appkit.api.Callback;
|
||||||
import me.grishka.appkit.api.ErrorResponse;
|
import me.grishka.appkit.api.ErrorResponse;
|
||||||
@@ -255,52 +254,71 @@ public class AccountSession{
|
|||||||
filterStatusContainingObjects(objects, extractor, context, null);
|
filterStatusContainingObjects(objects, extractor, context, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T> void filterStatusContainingObjects(List<T> objects, Function<T, Status> extractor, FilterContext context, Account profile){
|
private boolean statusIsOnOwnProfile(Status s, Account profile){
|
||||||
Predicate<Status> statusIsOnOwnProfile = (s) -> self != null && profile != null && s.account != null
|
return self != null && profile != null && s.account != null
|
||||||
&& Objects.equals(self.id, profile.id) && Objects.equals(self.id, s.account.id);
|
&& Objects.equals(self.id, profile.id) && Objects.equals(self.id, s.account.id);
|
||||||
|
}
|
||||||
|
|
||||||
if(getLocalPreferences().serverSideFiltersSupported){
|
private boolean isFilteredType(Status s){
|
||||||
// Even with server-side filters, clients are expected to remove statuses that match a filter that hides them
|
return (!localPreferences.showReplies && s.inReplyToId != null)
|
||||||
objects.removeIf(o->{
|
|| (!localPreferences.showBoosts && s.reblog != null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> void filterStatusContainingObjects(List<T> objects, Function<T, Status> extractor, FilterContext context, Account profile){
|
||||||
|
if(!localPreferences.serverSideFiltersSupported) for(T obj:objects){
|
||||||
|
Status s=extractor.apply(obj);
|
||||||
|
if(s!=null && s.filtered!=null){
|
||||||
|
localPreferences.serverSideFiltersSupported=true;
|
||||||
|
localPreferences.save();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<T> removeUs=new ArrayList<>();
|
||||||
|
for(int i=0; i<objects.size(); i++){
|
||||||
|
T o=objects.get(i);
|
||||||
|
if(filterStatusContainingObject(o, extractor, context, profile)){
|
||||||
Status s=extractor.apply(o);
|
Status s=extractor.apply(o);
|
||||||
|
removeUs.add(o);
|
||||||
|
if(s!=null && s.hasGapAfter!=null && i>0){
|
||||||
|
// oops, we're about to remove an item that has a gap after...
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
objects.removeAll(removeUs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> boolean filterStatusContainingObject(T object, Function<T, Status> extractor, FilterContext context, Account profile){
|
||||||
|
Status s=extractor.apply(object);
|
||||||
if(s==null)
|
if(s==null)
|
||||||
return false;
|
return false;
|
||||||
if(s.filtered==null)
|
|
||||||
return false;
|
|
||||||
// don't hide own posts in own profile
|
// don't hide own posts in own profile
|
||||||
if (statusIsOnOwnProfile.test(s))
|
if(statusIsOnOwnProfile(s, profile))
|
||||||
return false;
|
return false;
|
||||||
|
if(isFilteredType(s) && (context == FilterContext.HOME || context == FilterContext.PUBLIC))
|
||||||
|
return true;
|
||||||
|
// Even with server-side filters, clients are expected to remove statuses that match a filter that hides them
|
||||||
|
if(localPreferences.serverSideFiltersSupported){
|
||||||
for(FilterResult filter : s.filtered){
|
for(FilterResult filter : s.filtered){
|
||||||
if(filter.filter.isActive() && filter.filter.filterAction==FilterAction.HIDE)
|
if(filter.filter.isActive() && filter.filter.filterAction==FilterAction.HIDE)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
}else if(wordFilters!=null){
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(wordFilters==null)
|
|
||||||
return;
|
|
||||||
for(T obj:objects){
|
|
||||||
Status s=extractor.apply(obj);
|
|
||||||
if(s!=null && s.filtered!=null){
|
|
||||||
getLocalPreferences().serverSideFiltersSupported=true;
|
|
||||||
getLocalPreferences().save();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
objects.removeIf(o->{
|
|
||||||
Status s=extractor.apply(o);
|
|
||||||
if(s==null)
|
|
||||||
return false;
|
|
||||||
// don't hide own posts in own profile
|
|
||||||
if (statusIsOnOwnProfile.test(s))
|
|
||||||
return false;
|
|
||||||
for(LegacyFilter filter : wordFilters){
|
for(LegacyFilter filter : wordFilters){
|
||||||
if(filter.context.contains(context) && filter.matches(s) && filter.isActive())
|
if(filter.context.contains(context) && filter.matches(s) && filter.isActive())
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateAccountInfo(){
|
public void updateAccountInfo(){
|
||||||
|
|||||||
@@ -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,19 +9,16 @@ import org.joinmastodon.android.R;
|
|||||||
import org.joinmastodon.android.api.requests.accounts.GetAccountStatuses;
|
import org.joinmastodon.android.api.requests.accounts.GetAccountStatuses;
|
||||||
import org.joinmastodon.android.api.session.AccountSessionManager;
|
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||||
import org.joinmastodon.android.events.RemoveAccountPostsEvent;
|
import org.joinmastodon.android.events.RemoveAccountPostsEvent;
|
||||||
import org.joinmastodon.android.events.StatusCreatedEvent;
|
|
||||||
import org.joinmastodon.android.events.StatusUnpinnedEvent;
|
import org.joinmastodon.android.events.StatusUnpinnedEvent;
|
||||||
import org.joinmastodon.android.model.Account;
|
import org.joinmastodon.android.model.Account;
|
||||||
import org.joinmastodon.android.model.FilterContext;
|
import org.joinmastodon.android.model.FilterContext;
|
||||||
import org.joinmastodon.android.model.Status;
|
import org.joinmastodon.android.model.Status;
|
||||||
import org.joinmastodon.android.ui.displayitems.HeaderStatusDisplayItem;
|
import org.joinmastodon.android.ui.displayitems.HeaderStatusDisplayItem;
|
||||||
import org.joinmastodon.android.utils.StatusFilterPredicate;
|
|
||||||
import org.parceler.Parcels;
|
import org.parceler.Parcels;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import me.grishka.appkit.api.SimpleCallback;
|
import me.grishka.appkit.api.SimpleCallback;
|
||||||
|
|
||||||
@@ -55,15 +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;
|
||||||
AccountSessionManager asm = AccountSessionManager.getInstance();
|
boolean more=applyMaxID(result);
|
||||||
boolean empty=result.isEmpty();
|
|
||||||
AccountSessionManager.get(accountID).filterStatuses(result, getFilterContext(), user);
|
AccountSessionManager.get(accountID).filterStatuses(result, getFilterContext(), user);
|
||||||
onDataLoaded(result, !empty);
|
onDataLoaded(result, more);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.exec(accountID);
|
.exec(accountID);
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import android.graphics.Rect;
|
|||||||
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.util.Log;
|
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.view.WindowInsets;
|
import android.view.WindowInsets;
|
||||||
@@ -34,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;
|
||||||
@@ -90,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);
|
||||||
@@ -156,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())
|
||||||
@@ -164,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);
|
||||||
|
|
||||||
@@ -550,21 +557,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;
|
||||||
|
if(holder.getItem().hasVisibilityToggle) holder.animateVisibilityToggle(false);
|
||||||
MediaGridStatusDisplayItem.Holder mediaGrid=findHolderOfType(holder.getItemID(), MediaGridStatusDisplayItem.Holder.class);
|
MediaGridStatusDisplayItem.Holder mediaGrid=findHolderOfType(holder.getItemID(), MediaGridStatusDisplayItem.Holder.class);
|
||||||
if(mediaGrid!=null){
|
if(mediaGrid!=null){
|
||||||
if(!status.sensitiveRevealed) mediaGrid.revealSensitive();
|
if(!status.sensitiveRevealed) mediaGrid.revealSensitive();
|
||||||
else mediaGrid.hideSensitive();
|
else mediaGrid.hideSensitive();
|
||||||
}else{
|
}else{
|
||||||
// media grid's methods normally change the status' state - we still want to be able
|
status.sensitiveRevealed=false;
|
||||||
// to do this if the media grid is not bound, tho - so, doing it ourselves here
|
notifyItemChangedAfter(holder.getItem(), MediaGridStatusDisplayItem.class);
|
||||||
status.sensitiveRevealed = !status.sensitiveRevealed;
|
|
||||||
}
|
}
|
||||||
holder.rebind();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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.rebind();
|
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){
|
||||||
@@ -573,8 +580,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);
|
||||||
@@ -586,39 +593,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) {
|
||||||
|
s.textExpandable=expandable;
|
||||||
HeaderStatusDisplayItem.Holder header=findHolderOfType(holder.getItemID(), HeaderStatusDisplayItem.Holder.class);
|
HeaderStatusDisplayItem.Holder header=findHolderOfType(holder.getItemID(), HeaderStatusDisplayItem.Holder.class);
|
||||||
if (header != null) header.rebind();
|
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){}
|
||||||
@@ -677,6 +674,58 @@ 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++){
|
||||||
@@ -801,6 +850,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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -812,6 +863,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)
|
||||||
@@ -828,6 +881,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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -846,7 +901,7 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
|||||||
if(getContext()==null) return;
|
if(getContext()==null) return;
|
||||||
super.onDataLoaded(d, more);
|
super.onDataLoaded(d, more);
|
||||||
// more available, but the page isn't even full yet? seems wrong, let's load some more
|
// more available, but the page isn't even full yet? seems wrong, let's load some more
|
||||||
if(more && d.size() < itemsPerPage){
|
if(more && data.size() < itemsPerPage){
|
||||||
preloader.onScrolledToLastItem();
|
preloader.onScrolledToLastItem();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
@@ -162,7 +161,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
|||||||
private int charCount, charLimit, trimmedCharCount;
|
private int charCount, charLimit, trimmedCharCount;
|
||||||
|
|
||||||
private Button publishButton, languageButton, scheduleTimeBtn;
|
private Button publishButton, languageButton, scheduleTimeBtn;
|
||||||
private PopupMenu languagePopup, contentTypePopup, visibilityPopup, draftOptionsPopup;
|
private PopupMenu contentTypePopup, visibilityPopup, draftOptionsPopup;
|
||||||
private ImageButton mediaBtn, pollBtn, emojiBtn, spoilerBtn, draftsBtn, scheduleDraftDismiss, contentTypeBtn;
|
private ImageButton mediaBtn, pollBtn, emojiBtn, spoilerBtn, draftsBtn, scheduleDraftDismiss, contentTypeBtn;
|
||||||
private View sensitiveBtn;
|
private View sensitiveBtn;
|
||||||
private TextView replyText;
|
private TextView replyText;
|
||||||
@@ -294,7 +293,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
|||||||
@Override
|
@Override
|
||||||
public View onCreateContentView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
|
public View onCreateContentView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
|
||||||
creatingView=true;
|
creatingView=true;
|
||||||
emojiKeyboard=new CustomEmojiPopupKeyboard(getActivity(), customEmojis, instanceDomain);
|
emojiKeyboard=new CustomEmojiPopupKeyboard(getActivity(), accountID, customEmojis, instanceDomain);
|
||||||
emojiKeyboard.setListener(new CustomEmojiPopupKeyboard.Listener(){
|
emojiKeyboard.setListener(new CustomEmojiPopupKeyboard.Listener(){
|
||||||
@Override
|
@Override
|
||||||
public void onEmojiSelected(Emoji emoji){
|
public void onEmojiSelected(Emoji emoji){
|
||||||
@@ -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());
|
||||||
@@ -853,7 +868,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
|||||||
: 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,9 +1068,6 @@ 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)){
|
||||||
@@ -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;
|
||||||
}
|
}
|
||||||
@@ -1290,7 +1289,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
|||||||
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())
|
||||||
|
|||||||
@@ -26,12 +26,12 @@ import android.widget.ImageView;
|
|||||||
import org.joinmastodon.android.GlobalUserPreferences;
|
import org.joinmastodon.android.GlobalUserPreferences;
|
||||||
import org.joinmastodon.android.R;
|
import org.joinmastodon.android.R;
|
||||||
import org.joinmastodon.android.api.MastodonAPIController;
|
import org.joinmastodon.android.api.MastodonAPIController;
|
||||||
|
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||||
import org.joinmastodon.android.model.Attachment;
|
import org.joinmastodon.android.model.Attachment;
|
||||||
import org.joinmastodon.android.ui.M3AlertDialogBuilder;
|
import org.joinmastodon.android.ui.M3AlertDialogBuilder;
|
||||||
import org.joinmastodon.android.ui.photoviewer.PhotoViewer;
|
import org.joinmastodon.android.ui.photoviewer.PhotoViewer;
|
||||||
import org.joinmastodon.android.ui.utils.ColorPalette;
|
import org.joinmastodon.android.ui.utils.ColorPalette;
|
||||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||||
import org.joinmastodon.android.ui.views.FixedAspectRatioImageView;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
|
||||||
@@ -54,16 +54,17 @@ public class ComposeImageDescriptionFragment extends MastodonToolbarFragment imp
|
|||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState){
|
public void onCreate(Bundle savedInstanceState){
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
accountID=getArguments().getString("account");
|
|
||||||
attachmentID=getArguments().getString("attachment");
|
|
||||||
setHasOptionsMenu(true);
|
setHasOptionsMenu(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onAttach(Activity activity){
|
public void onAttach(Activity activity){
|
||||||
super.onAttach(activity);
|
super.onAttach(activity);
|
||||||
|
accountID=getArguments().getString("account");
|
||||||
|
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(GlobalUserPreferences.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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import org.joinmastodon.android.api.MastodonErrorResponse;
|
|||||||
import org.joinmastodon.android.api.requests.tags.GetTag;
|
import org.joinmastodon.android.api.requests.tags.GetTag;
|
||||||
import org.joinmastodon.android.api.requests.tags.SetTagFollowed;
|
import org.joinmastodon.android.api.requests.tags.SetTagFollowed;
|
||||||
import org.joinmastodon.android.api.requests.timelines.GetHashtagTimeline;
|
import org.joinmastodon.android.api.requests.timelines.GetHashtagTimeline;
|
||||||
|
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||||
import org.joinmastodon.android.model.FilterContext;
|
import org.joinmastodon.android.model.FilterContext;
|
||||||
import org.joinmastodon.android.model.Hashtag;
|
import org.joinmastodon.android.model.Hashtag;
|
||||||
import org.joinmastodon.android.model.Status;
|
import org.joinmastodon.android.model.Status;
|
||||||
@@ -85,16 +86,19 @@ public class HashtagTimelineFragment extends PinnableStatusListFragment{
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected TimelineDefinition makeTimelineDefinition() {
|
protected TimelineDefinition makeTimelineDefinition() {
|
||||||
return TimelineDefinition.ofHashtag(hashtag);
|
return TimelineDefinition.ofHashtag(hashtagName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@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){
|
||||||
onDataLoaded(result, !result.isEmpty());
|
if(getActivity()==null) return;
|
||||||
|
boolean more=applyMaxID(result);
|
||||||
|
AccountSessionManager.get(accountID).filterStatuses(result, getFilterContext());
|
||||||
|
onDataLoaded(result, more);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.exec(accountID);
|
.exec(accountID);
|
||||||
@@ -217,8 +221,6 @@ public class HashtagTimelineFragment extends PinnableStatusListFragment{
|
|||||||
followMenuItem=optionsMenu.findItem(R.id.follow_hashtag);
|
followMenuItem=optionsMenu.findItem(R.id.follow_hashtag);
|
||||||
pinMenuItem=optionsMenu.findItem(R.id.pin);
|
pinMenuItem=optionsMenu.findItem(R.id.pin);
|
||||||
followMenuItem.setVisible(toolbarContentVisible);
|
followMenuItem.setVisible(toolbarContentVisible);
|
||||||
followMenuItem.setTitle(getString(hashtag.following ? R.string.unfollow_user : R.string.follow_user, "#"+hashtagName));
|
|
||||||
followMenuItem.setIcon(hashtag.following ? R.drawable.ic_fluent_person_delete_24_filled : R.drawable.ic_fluent_person_add_24_regular);
|
|
||||||
pinMenuItem.setShowAsAction(toolbarContentVisible ? MenuItem.SHOW_AS_ACTION_NEVER : MenuItem.SHOW_AS_ACTION_ALWAYS);
|
pinMenuItem.setShowAsAction(toolbarContentVisible ? MenuItem.SHOW_AS_ACTION_NEVER : MenuItem.SHOW_AS_ACTION_ALWAYS);
|
||||||
super.updatePinButton(pinMenuItem);
|
super.updatePinButton(pinMenuItem);
|
||||||
if(toolbarContentVisible){
|
if(toolbarContentVisible){
|
||||||
@@ -260,7 +262,7 @@ public class HashtagTimelineFragment extends PinnableStatusListFragment{
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void updateHeader(){
|
private void updateHeader(){
|
||||||
if(hashtag==null)
|
if(hashtag==null || getActivity()==null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if(hashtag.history!=null && !hashtag.history.isEmpty()){
|
if(hashtag.history!=null && !hashtag.history.isEmpty()){
|
||||||
|
|||||||
@@ -400,10 +400,9 @@ 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
|
||||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater){
|
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater){
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import androidx.recyclerview.widget.RecyclerView;
|
|||||||
import org.joinmastodon.android.GlobalUserPreferences;
|
import org.joinmastodon.android.GlobalUserPreferences;
|
||||||
import org.joinmastodon.android.api.requests.markers.SaveMarkers;
|
import org.joinmastodon.android.api.requests.markers.SaveMarkers;
|
||||||
import org.joinmastodon.android.api.requests.timelines.GetHomeTimeline;
|
import org.joinmastodon.android.api.requests.timelines.GetHomeTimeline;
|
||||||
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.model.CacheablePaginatedResponse;
|
import org.joinmastodon.android.model.CacheablePaginatedResponse;
|
||||||
import org.joinmastodon.android.model.FilterContext;
|
import org.joinmastodon.android.model.FilterContext;
|
||||||
@@ -20,6 +19,7 @@ import org.joinmastodon.android.model.TimelineMarkers;
|
|||||||
import org.joinmastodon.android.ui.displayitems.GapStatusDisplayItem;
|
import org.joinmastodon.android.ui.displayitems.GapStatusDisplayItem;
|
||||||
import org.joinmastodon.android.ui.displayitems.StatusDisplayItem;
|
import org.joinmastodon.android.ui.displayitems.StatusDisplayItem;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -49,16 +49,6 @@ public class HomeTimelineFragment extends StatusListFragment {
|
|||||||
loadData();
|
loadData();
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean typeFilterPredicate(Status s) {
|
|
||||||
AccountLocalPreferences lp=getLocalPrefs();
|
|
||||||
return (lp.showReplies || s.inReplyToId == null) &&
|
|
||||||
(lp.showBoosts || s.reblog == null);
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<Status> filterPosts(List<Status> items) {
|
|
||||||
return items.stream().filter(this::typeFilterPredicate).collect(Collectors.toList());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doLoadData(int offset, int count){
|
protected void doLoadData(int offset, int count){
|
||||||
AccountSessionManager.getInstance()
|
AccountSessionManager.getInstance()
|
||||||
@@ -67,9 +57,10 @@ public class HomeTimelineFragment extends StatusListFragment {
|
|||||||
@Override
|
@Override
|
||||||
public void onSuccess(CacheablePaginatedResponse<List<Status>> result){
|
public void onSuccess(CacheablePaginatedResponse<List<Status>> result){
|
||||||
if(getActivity()==null) return;
|
if(getActivity()==null) return;
|
||||||
List<Status> filteredItems = filterPosts(result.items);
|
boolean empty=result.items.isEmpty();
|
||||||
maxID=result.maxID;
|
maxID=result.maxID;
|
||||||
onDataLoaded(filteredItems, !result.items.isEmpty());
|
AccountSessionManager.get(accountID).filterStatuses(result.items, getFilterContext());
|
||||||
|
onDataLoaded(result.items, !empty);
|
||||||
if(result.isFromCache())
|
if(result.isFromCache())
|
||||||
loadNewPosts();
|
loadNewPosts();
|
||||||
}
|
}
|
||||||
@@ -142,23 +133,26 @@ public class HomeTimelineFragment extends StatusListFragment {
|
|||||||
public void onSuccess(List<Status> result){
|
public void onSuccess(List<Status> result){
|
||||||
currentRequest=null;
|
currentRequest=null;
|
||||||
dataLoading=false;
|
dataLoading=false;
|
||||||
result = filterPosts(result);
|
|
||||||
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(!data.isEmpty() && last.id.equals(data.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<String> existingIds=data.stream().map(Status::getID).collect(Collectors.toList());
|
||||||
|
toAdd.removeIf(s->existingIds.contains(s.getID()));
|
||||||
|
List<Status> toAddUnfiltered=new ArrayList<>(toAdd);
|
||||||
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();
|
||||||
AccountSessionManager.getInstance().getAccount(accountID).getCacheController().putHomeTimeline(toAdd, false);
|
|
||||||
}
|
}
|
||||||
|
if(toAddUnfiltered.isEmpty())
|
||||||
|
AccountSessionManager.getInstance().getAccount(accountID).getCacheController().putHomeTimeline(toAddUnfiltered, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -185,7 +179,7 @@ public class HomeTimelineFragment extends StatusListFragment {
|
|||||||
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);
|
||||||
@@ -202,12 +196,13 @@ 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{
|
||||||
@@ -220,7 +215,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++;
|
||||||
@@ -233,7 +228,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);
|
||||||
}
|
}
|
||||||
@@ -278,7 +274,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();
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import org.joinmastodon.android.R;
|
|||||||
import org.joinmastodon.android.api.requests.lists.GetList;
|
import org.joinmastodon.android.api.requests.lists.GetList;
|
||||||
import org.joinmastodon.android.api.requests.lists.UpdateList;
|
import org.joinmastodon.android.api.requests.lists.UpdateList;
|
||||||
import org.joinmastodon.android.api.requests.timelines.GetListTimeline;
|
import org.joinmastodon.android.api.requests.timelines.GetListTimeline;
|
||||||
|
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||||
import org.joinmastodon.android.events.ListDeletedEvent;
|
import org.joinmastodon.android.events.ListDeletedEvent;
|
||||||
import org.joinmastodon.android.events.ListUpdatedCreatedEvent;
|
import org.joinmastodon.android.events.ListUpdatedCreatedEvent;
|
||||||
import org.joinmastodon.android.model.FilterContext;
|
import org.joinmastodon.android.model.FilterContext;
|
||||||
@@ -25,10 +26,8 @@ import org.joinmastodon.android.model.TimelineDefinition;
|
|||||||
import org.joinmastodon.android.ui.M3AlertDialogBuilder;
|
import org.joinmastodon.android.ui.M3AlertDialogBuilder;
|
||||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||||
import org.joinmastodon.android.ui.views.ListEditor;
|
import org.joinmastodon.android.ui.views.ListEditor;
|
||||||
import org.joinmastodon.android.utils.StatusFilterPredicate;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
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;
|
||||||
@@ -134,13 +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;
|
||||||
result=result.stream().filter(new StatusFilterPredicate(accountID, getFilterContext())).collect(Collectors.toList());
|
boolean more=applyMaxID(result);
|
||||||
onDataLoaded(result, !result.isEmpty());
|
AccountSessionManager.get(accountID).filterStatuses(result, getFilterContext());
|
||||||
|
onDataLoaded(result, more);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.exec(accountID);
|
.exec(accountID);
|
||||||
|
|||||||
@@ -134,6 +134,7 @@ public class NotificationsListFragment extends BaseStatusListFragment<Notificati
|
|||||||
return;
|
return;
|
||||||
maxID=result.maxID;
|
maxID=result.maxID;
|
||||||
onDataLoaded(result.items.stream().filter(n->n.type!=null).collect(Collectors.toList()), !result.items.isEmpty());
|
onDataLoaded(result.items.stream().filter(n->n.type!=null).collect(Collectors.toList()), !result.items.isEmpty());
|
||||||
|
if(bannerHelper!=null) bannerHelper.onBannerBecameVisible();
|
||||||
reloadingFromCache=false;
|
reloadingFromCache=false;
|
||||||
if (getParentFragment() instanceof NotificationsFragment nf) {
|
if (getParentFragment() instanceof NotificationsFragment nf) {
|
||||||
nf.updateMarkAllReadButton();
|
nf.updateMarkAllReadButton();
|
||||||
@@ -237,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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import android.os.Bundle;
|
|||||||
|
|
||||||
import org.joinmastodon.android.R;
|
import org.joinmastodon.android.R;
|
||||||
import org.joinmastodon.android.api.requests.accounts.GetAccountStatuses;
|
import org.joinmastodon.android.api.requests.accounts.GetAccountStatuses;
|
||||||
|
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||||
import org.joinmastodon.android.model.Account;
|
import org.joinmastodon.android.model.Account;
|
||||||
import org.joinmastodon.android.model.FilterContext;
|
import org.joinmastodon.android.model.FilterContext;
|
||||||
import org.joinmastodon.android.model.Status;
|
import org.joinmastodon.android.model.Status;
|
||||||
@@ -35,6 +36,8 @@ public class PinnedPostsListFragment extends StatusListFragment{
|
|||||||
.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;
|
||||||
|
AccountSessionManager.get(accountID).filterStatuses(result, getFilterContext());
|
||||||
onDataLoaded(result, false);
|
onDataLoaded(result, false);
|
||||||
}
|
}
|
||||||
}).exec(accountID);
|
}).exec(accountID);
|
||||||
|
|||||||
@@ -133,6 +133,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
|||||||
private ImageView avatar;
|
private ImageView avatar;
|
||||||
private CoverImageView cover;
|
private CoverImageView cover;
|
||||||
private View avatarBorder;
|
private View avatarBorder;
|
||||||
|
private View usernameWrap;
|
||||||
private TextView name, username, bio, followersCount, followersLabel, followingCount, followingLabel;
|
private TextView name, username, bio, followersCount, followersLabel, followingCount, followingLabel;
|
||||||
private ImageView lockIcon, botIcon;
|
private ImageView lockIcon, botIcon;
|
||||||
private ProgressBarButton actionButton, notifyButton;
|
private ProgressBarButton actionButton, notifyButton;
|
||||||
@@ -233,6 +234,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
|||||||
cover=content.findViewById(R.id.cover);
|
cover=content.findViewById(R.id.cover);
|
||||||
avatarBorder=content.findViewById(R.id.avatar_border);
|
avatarBorder=content.findViewById(R.id.avatar_border);
|
||||||
name=content.findViewById(R.id.name);
|
name=content.findViewById(R.id.name);
|
||||||
|
usernameWrap=content.findViewById(R.id.username_wrap);
|
||||||
username=content.findViewById(R.id.username);
|
username=content.findViewById(R.id.username);
|
||||||
lockIcon=content.findViewById(R.id.lock_icon);
|
lockIcon=content.findViewById(R.id.lock_icon);
|
||||||
botIcon=content.findViewById(R.id.bot_icon);
|
botIcon=content.findViewById(R.id.bot_icon);
|
||||||
@@ -760,12 +762,13 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
|||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
menu.findItem(R.id.manage_user_lists).setTitle(getString(R.string.sk_lists_with_user, account.getShortUsername()));
|
||||||
MenuItem mute=menu.findItem(R.id.mute);
|
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);
|
||||||
@@ -774,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);
|
||||||
if (relationship.following) {
|
|
||||||
MenuItem hideBoosts=menu.findItem(R.id.hide_boosts);
|
MenuItem hideBoosts=menu.findItem(R.id.hide_boosts);
|
||||||
|
if (relationship.following) {
|
||||||
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
|
||||||
@@ -798,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);
|
||||||
@@ -1099,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);
|
||||||
@@ -1114,7 +1120,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
|||||||
|
|
||||||
name.setVisibility(View.GONE);
|
name.setVisibility(View.GONE);
|
||||||
rolesView.setVisibility(View.GONE);
|
rolesView.setVisibility(View.GONE);
|
||||||
username.setVisibility(View.GONE);
|
usernameWrap.setVisibility(View.GONE);
|
||||||
bio.setVisibility(View.GONE);
|
bio.setVisibility(View.GONE);
|
||||||
countersLayout.setVisibility(View.GONE);
|
countersLayout.setVisibility(View.GONE);
|
||||||
|
|
||||||
@@ -1163,7 +1169,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
|||||||
bioEditWrap.setVisibility(View.GONE);
|
bioEditWrap.setVisibility(View.GONE);
|
||||||
name.setVisibility(View.VISIBLE);
|
name.setVisibility(View.VISIBLE);
|
||||||
rolesView.setVisibility(View.VISIBLE);
|
rolesView.setVisibility(View.VISIBLE);
|
||||||
username.setVisibility(View.VISIBLE);
|
usernameWrap.setVisibility(View.VISIBLE);
|
||||||
bio.setVisibility(View.VISIBLE);
|
bio.setVisibility(View.VISIBLE);
|
||||||
countersLayout.setVisibility(View.VISIBLE);
|
countersLayout.setVisibility(View.VISIBLE);
|
||||||
refreshLayout.setEnabled(true);
|
refreshLayout.setEnabled(true);
|
||||||
@@ -1175,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(){
|
||||||
@@ -1204,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)
|
||||||
|
|||||||
@@ -47,13 +47,12 @@ public class SplashFragment extends AppKitFragment{
|
|||||||
private ProgressBarButton defaultServerButton;
|
private ProgressBarButton defaultServerButton;
|
||||||
private ProgressBar defaultServerProgress;
|
private ProgressBar defaultServerProgress;
|
||||||
private String chosenDefaultServer=DEFAULT_SERVER;
|
private String chosenDefaultServer=DEFAULT_SERVER;
|
||||||
private boolean loadingDefaultServer;
|
private boolean loadingDefaultServer, loadedDefaultServer;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState){
|
public void onCreate(Bundle savedInstanceState){
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
motionEffect=new InterpolatingMotionEffect(MastodonApp.context);
|
motionEffect=new InterpolatingMotionEffect(MastodonApp.context);
|
||||||
loadAndChooseDefaultServer();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@@ -101,6 +100,8 @@ public class SplashFragment extends AppKitFragment{
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
if(!loadedDefaultServer && !loadingDefaultServer)
|
||||||
|
loadAndChooseDefaultServer();
|
||||||
|
|
||||||
return contentView;
|
return contentView;
|
||||||
}
|
}
|
||||||
@@ -239,6 +240,7 @@ public class SplashFragment extends AppKitFragment{
|
|||||||
private void setChosenDefaultServer(String domain){
|
private void setChosenDefaultServer(String domain){
|
||||||
chosenDefaultServer=domain;
|
chosenDefaultServer=domain;
|
||||||
loadingDefaultServer=false;
|
loadingDefaultServer=false;
|
||||||
|
loadedDefaultServer=true;
|
||||||
if(defaultServerButton!=null && getActivity()!=null){
|
if(defaultServerButton!=null && getActivity()!=null){
|
||||||
defaultServerButton.setTextVisible(true);
|
defaultServerButton.setTextVisible(true);
|
||||||
defaultServerProgress.setVisibility(View.GONE);
|
defaultServerProgress.setVisibility(View.GONE);
|
||||||
|
|||||||
@@ -48,8 +48,8 @@ public class StatusEditHistoryFragment extends StatusListFragment{
|
|||||||
.setCallback(new SimpleCallback<>(this){
|
.setCallback(new SimpleCallback<>(this){
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(List<Status> result){
|
public void onSuccess(List<Status> result){
|
||||||
Collections.sort(result, Comparator.comparing((Status s)->s.createdAt).reversed());
|
|
||||||
if(getActivity()==null) return;
|
if(getActivity()==null) return;
|
||||||
|
Collections.sort(result, Comparator.comparing((Status s)->s.createdAt).reversed());
|
||||||
onDataLoaded(result, false);
|
onDataLoaded(result, false);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ 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;
|
||||||
@@ -28,6 +29,7 @@ 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.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
@@ -46,6 +48,8 @@ public abstract class StatusListFragment extends BaseStatusListFragment<Status>
|
|||||||
flags |= StatusDisplayItem.FLAG_NO_FOOTER;
|
flags |= StatusDisplayItem.FLAG_NO_FOOTER;
|
||||||
if(!lp.emojiReactionsEnabled || lp.showEmojiReactions==ONLY_OPENED)
|
if(!lp.emojiReactionsEnabled || lp.showEmojiReactions==ONLY_OPENED)
|
||||||
flags |= StatusDisplayItem.FLAG_NO_EMOJI_REACTIONS;
|
flags |= StatusDisplayItem.FLAG_NO_EMOJI_REACTIONS;
|
||||||
|
if(GlobalUserPreferences.translateButtonOpenedOnly)
|
||||||
|
flags |= StatusDisplayItem.FLAG_NO_TRANSLATE;
|
||||||
return StatusDisplayItem.buildItems(this, s, accountID, s, knownAccounts, getFilterContext(), isMainThreadStatus ? 0 : flags);
|
return StatusDisplayItem.buildItems(this, s, accountID, s, knownAccounts, getFilterContext(), isMainThreadStatus ? 0 : flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -140,12 +144,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;
|
||||||
@@ -172,43 +176,58 @@ public abstract class StatusListFragment extends BaseStatusListFragment<Status>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void removeStatus(Status status){
|
private void iterateRemoveStatus(List<Status> l, String id){
|
||||||
data.remove(status);
|
Iterator<Status> it=l.iterator();
|
||||||
preloadedData.remove(status);
|
while(it.hasNext()){
|
||||||
int index=-1, ancestorFirstIndex = -1, ancestorLastIndex = -1;
|
if(it.next().getContentStatus().id.equals(id)){
|
||||||
for(int i=0;i<displayItems.size();i++){
|
it.remove();
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void removeStatusDisplayItems(Status status, int index, int ancestorFirstIndex, int ancestorLastIndex, boolean deleteContent){
|
||||||
// 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==index-1){
|
||||||
for(int i=ancestorFirstIndex; i<=ancestorLastIndex; i++){
|
for(int i=ancestorFirstIndex; i<=ancestorLastIndex; i++){
|
||||||
StatusDisplayItem item=displayItems.get(i);
|
StatusDisplayItem item=displayItems.get(i);
|
||||||
|
String id=deleteContent ? item.getContentID() : item.parentID;
|
||||||
// update ancestor to have no descendant anymore
|
// update ancestor to have no descendant anymore
|
||||||
if (item.parentID.equals(status.inReplyToId)) item.hasDescendantNeighbor = false;
|
if(id.equals(status.inReplyToId)) item.hasDescendantNeighbor=false;
|
||||||
}
|
}
|
||||||
adapter.notifyItemRangeChanged(ancestorFirstIndex, ancestorLastIndex-ancestorFirstIndex+1);
|
adapter.notifyItemRangeChanged(ancestorFirstIndex, ancestorLastIndex-ancestorFirstIndex+1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(index==-1)
|
if(index==-1) return;
|
||||||
return;
|
|
||||||
int lastIndex;
|
int lastIndex;
|
||||||
for(lastIndex=index;lastIndex<displayItems.size();lastIndex++){
|
for(lastIndex=index;lastIndex<displayItems.size();lastIndex++){
|
||||||
if(!displayItems.get(lastIndex).parentID.equals(status.id))
|
StatusDisplayItem item=displayItems.get(lastIndex);
|
||||||
break;
|
String id=deleteContent ? item.getContentID() : item.parentID;
|
||||||
|
if(!id.equals(status.id)) break;
|
||||||
}
|
}
|
||||||
displayItems.subList(index, lastIndex).clear();
|
displayItems.subList(index, lastIndex).clear();
|
||||||
adapter.notifyItemRangeRemoved(index, lastIndex-index);
|
adapter.notifyItemRangeRemoved(index, lastIndex-index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void removeStatus(Status status){
|
||||||
|
boolean deleteContent=status==status.getContentStatus();
|
||||||
|
int ancestorFirstIndex=-1, ancestorLastIndex=-1;
|
||||||
|
for(int i=0;i<displayItems.size();i++){
|
||||||
|
StatusDisplayItem item=displayItems.get(i);
|
||||||
|
String id=deleteContent ? item.getContentID() : item.parentID;
|
||||||
|
if(id.equals(status.id)){
|
||||||
|
removeStatusDisplayItems(status, i, ancestorFirstIndex, ancestorLastIndex, deleteContent);
|
||||||
|
ancestorFirstIndex=ancestorLastIndex=-1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(id.equals(status.inReplyToId)){
|
||||||
|
if(ancestorFirstIndex==-1) ancestorFirstIndex=i;
|
||||||
|
ancestorLastIndex=i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
iterateRemoveStatus(data, status.id);
|
||||||
|
iterateRemoveStatus(preloadedData, status.id);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onConfigurationChanged(Configuration newConfig) {
|
public void onConfigurationChanged(Configuration newConfig) {
|
||||||
super.onConfigurationChanged(newConfig);
|
super.onConfigurationChanged(newConfig);
|
||||||
@@ -275,6 +294,18 @@ public abstract class StatusListFragment extends BaseStatusListFragment<Status>
|
|||||||
removeStatus(status);
|
removeStatus(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
public void onReblogDeleted(ReblogDeletedEvent ev){
|
||||||
|
if(!ev.accountID.equals(accountID))
|
||||||
|
return;
|
||||||
|
for(Status item : data){
|
||||||
|
if(item.getContentStatus().id.equals(ev.statusID) && item.reblog!=null){
|
||||||
|
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))
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ import org.joinmastodon.android.GlobalUserPreferences.AutoRevealMode;
|
|||||||
import org.joinmastodon.android.R;
|
import org.joinmastodon.android.R;
|
||||||
import org.joinmastodon.android.api.requests.statuses.GetStatusByID;
|
import org.joinmastodon.android.api.requests.statuses.GetStatusByID;
|
||||||
import org.joinmastodon.android.api.requests.statuses.GetStatusContext;
|
import org.joinmastodon.android.api.requests.statuses.GetStatusContext;
|
||||||
|
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||||
import org.joinmastodon.android.events.StatusCountersUpdatedEvent;
|
import org.joinmastodon.android.events.StatusCountersUpdatedEvent;
|
||||||
import org.joinmastodon.android.events.StatusCreatedEvent;
|
|
||||||
import org.joinmastodon.android.events.StatusUpdatedEvent;
|
import org.joinmastodon.android.events.StatusUpdatedEvent;
|
||||||
import org.joinmastodon.android.model.Account;
|
import org.joinmastodon.android.model.Account;
|
||||||
import org.joinmastodon.android.model.FilterContext;
|
import org.joinmastodon.android.model.FilterContext;
|
||||||
@@ -31,7 +31,6 @@ import org.joinmastodon.android.ui.displayitems.WarningFilteredStatusDisplayItem
|
|||||||
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.utils.ProvidesAssistContent;
|
import org.joinmastodon.android.utils.ProvidesAssistContent;
|
||||||
import org.joinmastodon.android.utils.StatusFilterPredicate;
|
|
||||||
import org.parceler.Parcels;
|
import org.parceler.Parcels;
|
||||||
|
|
||||||
import java.util.ArrayDeque;
|
import java.util.ArrayDeque;
|
||||||
@@ -195,8 +194,8 @@ public class ThreadFragment extends StatusListFragment implements ProvidesAssist
|
|||||||
// TODO: figure out how this code works
|
// TODO: figure out how this code works
|
||||||
if (isInstanceAkkoma()) sortStatusContext(mainStatus, result);
|
if (isInstanceAkkoma()) sortStatusContext(mainStatus, result);
|
||||||
|
|
||||||
result.descendants=filterStatuses(result.descendants);
|
filterStatuses(result.descendants);
|
||||||
result.ancestors=filterStatuses(result.ancestors);
|
filterStatuses(result.ancestors);
|
||||||
restoreStatusStates(result.descendants, oldData);
|
restoreStatusStates(result.descendants, oldData);
|
||||||
restoreStatusStates(result.ancestors, oldData);
|
restoreStatusStates(result.ancestors, oldData);
|
||||||
|
|
||||||
@@ -332,11 +331,8 @@ public class ThreadFragment extends StatusListFragment implements ProvidesAssist
|
|||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Status> filterStatuses(List<Status> statuses){
|
private void filterStatuses(List<Status> statuses){
|
||||||
StatusFilterPredicate statusFilterPredicate=new StatusFilterPredicate(accountID,getFilterContext());
|
AccountSessionManager.get(accountID).filterStatuses(statuses, getFilterContext());
|
||||||
return statuses.stream()
|
|
||||||
.filter(statusFilterPredicate)
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -6,21 +6,19 @@ import android.os.Bundle;
|
|||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
import org.joinmastodon.android.api.requests.timelines.GetBubbleTimeline;
|
import org.joinmastodon.android.api.requests.timelines.GetBubbleTimeline;
|
||||||
|
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||||
import org.joinmastodon.android.fragments.StatusListFragment;
|
import org.joinmastodon.android.fragments.StatusListFragment;
|
||||||
import org.joinmastodon.android.model.FilterContext;
|
import org.joinmastodon.android.model.FilterContext;
|
||||||
import org.joinmastodon.android.model.Status;
|
import org.joinmastodon.android.model.Status;
|
||||||
import org.joinmastodon.android.ui.utils.DiscoverInfoBannerHelper;
|
import org.joinmastodon.android.ui.utils.DiscoverInfoBannerHelper;
|
||||||
import org.joinmastodon.android.utils.StatusFilterPredicate;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import me.grishka.appkit.api.SimpleCallback;
|
import me.grishka.appkit.api.SimpleCallback;
|
||||||
import me.grishka.appkit.utils.MergeRecyclerAdapter;
|
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){
|
||||||
@@ -36,15 +34,15 @@ 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(!result.isEmpty())
|
|
||||||
maxID=result.get(result.size()-1).id;
|
|
||||||
if(getActivity()==null) return;
|
if(getActivity()==null) return;
|
||||||
result=result.stream().filter(new StatusFilterPredicate(accountID, getFilterContext())).collect(Collectors.toList());
|
boolean more=applyMaxID(result);
|
||||||
onDataLoaded(result, !result.isEmpty());
|
AccountSessionManager.get(accountID).filterStatuses(result, getFilterContext());
|
||||||
|
onDataLoaded(result, more);
|
||||||
|
bannerHelper.onBannerBecameVisible();
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.exec(accountID);
|
.exec(accountID);
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -96,8 +96,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())
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import android.net.Uri;
|
|||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
|
||||||
import org.joinmastodon.android.api.requests.trends.GetTrendingStatuses;
|
import org.joinmastodon.android.api.requests.trends.GetTrendingStatuses;
|
||||||
|
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||||
import org.joinmastodon.android.fragments.StatusListFragment;
|
import org.joinmastodon.android.fragments.StatusListFragment;
|
||||||
import org.joinmastodon.android.model.FilterContext;
|
import org.joinmastodon.android.model.FilterContext;
|
||||||
import org.joinmastodon.android.model.Status;
|
import org.joinmastodon.android.model.Status;
|
||||||
@@ -17,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){
|
||||||
@@ -25,12 +27,17 @@ 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){
|
||||||
onDataLoaded(result, !result.isEmpty());
|
if(getActivity()==null) return;
|
||||||
|
boolean empty=result.isEmpty();
|
||||||
|
offset+=result.size();
|
||||||
|
AccountSessionManager.get(accountID).filterStatuses(result, getFilterContext());
|
||||||
|
onDataLoaded(result, !empty);
|
||||||
bannerHelper.onBannerBecameVisible();
|
bannerHelper.onBannerBecameVisible();
|
||||||
}
|
}
|
||||||
}).exec(accountID);
|
}).exec(accountID);
|
||||||
|
|||||||
@@ -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(!result.isEmpty())
|
if(getActivity()==null) return;
|
||||||
maxID=result.get(result.size()-1).id;
|
boolean more=applyMaxID(result);
|
||||||
boolean empty=result.isEmpty();
|
AccountSessionManager.get(accountID).filterStatuses(result, getFilterContext());
|
||||||
AccountSessionManager.get(accountID).filterStatuses(result, FilterContext.PUBLIC);
|
onDataLoaded(result, more);
|
||||||
onDataLoaded(result, !empty);
|
|
||||||
bannerHelper.onBannerBecameVisible();
|
bannerHelper.onBannerBecameVisible();
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package org.joinmastodon.android.fragments.discover;
|
|||||||
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.View;
|
|
||||||
|
|
||||||
import org.joinmastodon.android.api.requests.timelines.GetPublicTimeline;
|
import org.joinmastodon.android.api.requests.timelines.GetPublicTimeline;
|
||||||
import org.joinmastodon.android.api.session.AccountSessionManager;
|
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||||
@@ -30,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(!result.isEmpty())
|
if(getActivity()==null) return;
|
||||||
maxID=result.get(result.size()-1).id;
|
boolean more=applyMaxID(result);
|
||||||
boolean empty=result.isEmpty();
|
AccountSessionManager.get(accountID).filterStatuses(result, getFilterContext());
|
||||||
AccountSessionManager.get(accountID).filterStatuses(result, FilterContext.PUBLIC);
|
onDataLoaded(result, more);
|
||||||
onDataLoaded(result, !empty);
|
|
||||||
bannerHelper.onBannerBecameVisible();
|
bannerHelper.onBannerBecameVisible();
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -165,9 +165,7 @@ public class AccountActivationFragment extends ToolbarFragment{
|
|||||||
private void tryGetAccount(){
|
private void tryGetAccount(){
|
||||||
if(AccountSessionManager.getInstance().tryGetAccount(accountID)==null){
|
if(AccountSessionManager.getInstance().tryGetAccount(accountID)==null){
|
||||||
uiHandler.removeCallbacks(pollRunnable);
|
uiHandler.removeCallbacks(pollRunnable);
|
||||||
getActivity().finish();
|
((MainActivity)getActivity()).restartHomeFragment();
|
||||||
Intent intent=new Intent(getActivity(), MainActivity.class);
|
|
||||||
startActivity(intent);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
currentRequest=new GetOwnAccount()
|
currentRequest=new GetOwnAccount()
|
||||||
|
|||||||
@@ -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){
|
||||||
|
|||||||
@@ -83,10 +83,11 @@ 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){
|
||||||
|
if(getActivity()==null) return;
|
||||||
for(Status s:result){
|
for(Status s:result){
|
||||||
s.sensitive=true;
|
s.sensitive=true;
|
||||||
}
|
}
|
||||||
@@ -103,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
|
||||||
|
|||||||
@@ -227,7 +227,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
|
||||||
|
|||||||
@@ -97,7 +97,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());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
@@ -17,6 +18,7 @@ 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.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.events.StatusDisplaySettingsChangedEvent;
|
import org.joinmastodon.android.events.StatusDisplaySettingsChangedEvent;
|
||||||
@@ -27,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;
|
||||||
@@ -37,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;
|
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;
|
||||||
|
|
||||||
@@ -51,7 +55,7 @@ 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, this::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),
|
||||||
@@ -68,6 +72,8 @@ public class SettingsDisplayFragment extends BaseSettingsFragment<Void>{
|
|||||||
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, ()->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, ()->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, ()->toggleCheckableItem(translateOpenedItem)),
|
||||||
|
likeIconItem=new CheckableListItem<>(R.string.sk_settings_like_icon, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.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, ()->toggleCheckableItem(underlinedLinksItem)),
|
||||||
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)),
|
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)),
|
||||||
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),
|
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),
|
||||||
pronounsInTimelinesItem=new CheckableListItem<>(R.string.sk_settings_display_pronouns_in_timelines, 0, CheckableListItem.Style.CHECKBOX, GlobalUserPreferences.displayPronounsInTimelines, 0, ()->toggleCheckableItem(pronounsInTimelinesItem)),
|
pronounsInTimelinesItem=new CheckableListItem<>(R.string.sk_settings_display_pronouns_in_timelines, 0, CheckableListItem.Style.CHECKBOX, GlobalUserPreferences.displayPronounsInTimelines, 0, ()->toggleCheckableItem(pronounsInTimelinesItem)),
|
||||||
@@ -94,9 +100,9 @@ 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.revealCWs=revealCWsItem.checked;
|
lp.revealCWs=revealCWsItem.checked;
|
||||||
lp.hideSensitiveMedia=hideSensitiveMediaItem.checked;
|
lp.hideSensitiveMedia=hideSensitiveMediaItem.checked;
|
||||||
@@ -112,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;
|
||||||
@@ -130,17 +138,11 @@ public class SettingsDisplayFragment extends BaseSettingsFragment<Void>{
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private @StringRes int getColorPaletteValue(){
|
private String getColorPaletteValue(){
|
||||||
return switch(GlobalUserPreferences.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() {
|
||||||
@@ -196,26 +198,40 @@ public class SettingsDisplayFragment extends BaseSettingsFragment<Void>{
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void onColorClick(){
|
private void onColorClick(){
|
||||||
int selected=GlobalUserPreferences.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(GlobalUserPreferences.ColorPreference.values()).map(GlobalUserPreferences.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)
|
||||||
.setTitle(R.string.settings_theme)
|
items.add(0, getString(R.string.sk_settings_color_palette_default, items.get(GlobalUserPreferences.color.ordinal())));
|
||||||
.setSingleChoiceItems(names,
|
|
||||||
selected, (dlg, item)->newSelected[0]=item)
|
Consumer<Boolean> save=(asDefault)->{
|
||||||
.setPositiveButton(R.string.ok, (dlg, item)->{
|
boolean defaultSelected=multiple && newSelected[0]==0;
|
||||||
GlobalUserPreferences.ColorPreference pref=GlobalUserPreferences.ColorPreference.values()[newSelected[0]];
|
ColorPreference pref=defaultSelected ? null : ColorPreference.values()[newSelected[0]-indexOffset];
|
||||||
if(pref!=GlobalUserPreferences.color){
|
if(pref!=lp.color){
|
||||||
GlobalUserPreferences.ColorPreference prev=GlobalUserPreferences.color;
|
ColorPreference prev=lp.color;
|
||||||
|
lp.color=asDefault ? null : pref;
|
||||||
|
lp.save();
|
||||||
|
if((asDefault || !multiple) && pref!=null){
|
||||||
GlobalUserPreferences.color=pref;
|
GlobalUserPreferences.color=pref;
|
||||||
GlobalUserPreferences.save();
|
GlobalUserPreferences.save();
|
||||||
colorItem.subtitleRes=getColorPaletteValue();
|
|
||||||
rebindItem(colorItem);
|
|
||||||
maybeApplyNewThemeRightNow(null, prev, null);
|
|
||||||
}
|
}
|
||||||
})
|
colorItem.subtitle=getColorPaletteValue();
|
||||||
.setNegativeButton(R.string.cancel, null)
|
rebindItem(colorItem);
|
||||||
.show();
|
if(prev==null && pref!=null) restartActivityToApplyNewTheme();
|
||||||
|
else maybeApplyNewThemeRightNow(null, prev, null);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
AlertDialog.Builder alert=new M3AlertDialogBuilder(getActivity())
|
||||||
|
.setTitle(R.string.sk_settings_color_palette)
|
||||||
|
.setSingleChoiceItems(items.toArray(String[]::new),
|
||||||
|
selected, (dlg, item)->newSelected[0]=item)
|
||||||
|
.setPositiveButton(R.string.ok, (dlg, item)->save.accept(false))
|
||||||
|
.setNegativeButton(R.string.cancel, null);
|
||||||
|
if(multiple) alert.setNeutralButton(R.string.sk_set_as_default, (dlg, item)->save.accept(true));
|
||||||
|
alert.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onPublishTextClick(){
|
private void onPublishTextClick(){
|
||||||
@@ -257,17 +273,17 @@ public class SettingsDisplayFragment extends BaseSettingsFragment<Void>{
|
|||||||
.show();
|
.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void maybeApplyNewThemeRightNow(GlobalUserPreferences.ThemePreference prevTheme, GlobalUserPreferences.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=GlobalUserPreferences.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!=GlobalUserPreferences.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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,8 +55,7 @@ public class SettingsMainFragment extends BaseSettingsFragment<Void>{
|
|||||||
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),
|
||||||
@@ -65,7 +64,7 @@ public class SettingsMainFragment extends BaseSettingsFragment<Void>{
|
|||||||
|
|
||||||
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, ()->Nav.go(getActivity(), SettingsDebugFragment.class, makeFragmentArgs()), null, 0, true));
|
||||||
@@ -163,9 +162,7 @@ public class SettingsMainFragment extends BaseSettingsFragment<Void>{
|
|||||||
.setMessage(getString(R.string.confirm_log_out, session.getFullUsername()))
|
.setMessage(getString(R.string.confirm_log_out, session.getFullUsername()))
|
||||||
.setPositiveButton(R.string.log_out, (dialog, which)->account.logOut(getActivity(), ()->{
|
.setPositiveButton(R.string.log_out, (dialog, which)->account.logOut(getActivity(), ()->{
|
||||||
loggedOut=true;
|
loggedOut=true;
|
||||||
getActivity().finish();
|
((MainActivity)getActivity()).restartActivity();
|
||||||
Intent intent=new Intent(getActivity(), MainActivity.class);
|
|
||||||
startActivity(intent);
|
|
||||||
}))
|
}))
|
||||||
.setNegativeButton(R.string.cancel, null)
|
.setNegativeButton(R.string.cancel, null)
|
||||||
.show();
|
.show();
|
||||||
|
|||||||
@@ -18,8 +18,8 @@ public class SettingsPrivacyFragment extends BaseSettingsFragment<Void>{
|
|||||||
setTitle(R.string.settings_privacy);
|
setTitle(R.string.settings_privacy);
|
||||||
Account self=AccountSessionManager.get(accountID).self;
|
Account self=AccountSessionManager.get(accountID).self;
|
||||||
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)),
|
discoverableItem=new CheckableListItem<>(R.string.settings_discoverable, 0, CheckableListItem.Style.SWITCH, self.discoverable, R.drawable.ic_fluent_thumb_like_dislike_24_regular, ()->toggleCheckableItem(discoverableItem)),
|
||||||
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))
|
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, ()->toggleCheckableItem(indexableItem))
|
||||||
));
|
));
|
||||||
if(self.source.indexable==null)
|
if(self.source.indexable==null)
|
||||||
indexableItem.isEnabled=false;
|
indexableItem.isEnabled=false;
|
||||||
|
|||||||
@@ -68,6 +68,14 @@ public class Attachment extends BaseModel{
|
|||||||
return 1080;
|
return 1080;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean hasKnownDimensions(){
|
||||||
|
return meta!=null && (
|
||||||
|
(meta.height>0 && meta.width>0)
|
||||||
|
|| (meta.original!=null && meta.original.height>0 && meta.original.width>0)
|
||||||
|
|| (meta.small!=null && meta.small.height>0 && meta.small.width>0)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public double getDuration(){
|
public double getDuration(){
|
||||||
if(meta==null)
|
if(meta==null)
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ 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;
|
||||||
|
|||||||
@@ -8,6 +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.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.view.WindowInsets;
|
import android.view.WindowInsets;
|
||||||
@@ -39,6 +40,7 @@ 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;
|
||||||
@@ -144,21 +146,9 @@ public class AccountSwitcherSheet extends BottomSheet{
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void logOut(String accountID){
|
private void logOut(String accountID){
|
||||||
AccountSession session=AccountSessionManager.getInstance().getAccount(accountID);
|
AccountSessionManager.get(accountID).logOut(activity, ()->{
|
||||||
new RevokeOauthToken(session.app.clientId, session.app.clientSecret, session.token.accessToken)
|
((MainActivity)activity).restartActivity();
|
||||||
.setCallback(new Callback<>(){
|
});
|
||||||
@Override
|
|
||||||
public void onSuccess(Object result){
|
|
||||||
onLoggedOut(accountID);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onError(ErrorResponse error){
|
|
||||||
onLoggedOut(accountID);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.wrapProgress(activity, R.string.loading, false)
|
|
||||||
.exec(accountID);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void logOutAll(){
|
private void logOutAll(){
|
||||||
@@ -331,10 +321,10 @@ public class AccountSwitcherSheet extends BottomSheet{
|
|||||||
onClick.accept(item.getID(), false);
|
onClick.accept(item.getID(), false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(AccountSessionManager.getInstance().tryGetAccount(item.getID())!=null)
|
if(AccountSessionManager.getInstance().tryGetAccount(item.getID())!=null){
|
||||||
AccountSessionManager.getInstance().setLastActiveAccountID(item.getID());
|
AccountSessionManager.getInstance().setLastActiveAccountID(item.getID());
|
||||||
activity.finish();
|
((MainActivity)activity).restartActivity();
|
||||||
activity.startActivity(new Intent(activity, MainActivity.class));
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -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));
|
||||||
|
|||||||
@@ -170,12 +170,14 @@ public class EmojiReactionsStatusDisplayItem extends StatusDisplayItem {
|
|||||||
@Override
|
@Override
|
||||||
public void onBind(EmojiReactionsStatusDisplayItem item) {
|
public void onBind(EmojiReactionsStatusDisplayItem item) {
|
||||||
if(emojiKeyboard != null) root.removeView(emojiKeyboard.getView());
|
if(emojiKeyboard != null) root.removeView(emojiKeyboard.getView());
|
||||||
|
addButton.setSelected(false);
|
||||||
AccountSession session=item.parentFragment.getSession();
|
AccountSession session=item.parentFragment.getSession();
|
||||||
item.status.reactions.forEach(r->r.request=r.getUrl(item.playGifs)!=null
|
item.status.reactions.forEach(r->r.request=r.getUrl(item.playGifs)!=null
|
||||||
? new UrlImageLoaderRequest(r.getUrl(item.playGifs), V.sp(24), V.sp(24))
|
? new UrlImageLoaderRequest(r.getUrl(item.playGifs), V.sp(24), V.sp(24))
|
||||||
: null);
|
: null);
|
||||||
emojiKeyboard=new CustomEmojiPopupKeyboard(
|
emojiKeyboard=new CustomEmojiPopupKeyboard(
|
||||||
(Activity) item.parentFragment.getContext(),
|
(Activity) item.parentFragment.getContext(),
|
||||||
|
item.accountID,
|
||||||
AccountSessionManager.getInstance().getCustomEmojis(session.domain),
|
AccountSessionManager.getInstance().getCustomEmojis(session.domain),
|
||||||
session.domain, true);
|
session.domain, true);
|
||||||
emojiKeyboard.setListener(this);
|
emojiKeyboard.setListener(this);
|
||||||
|
|||||||
@@ -13,7 +13,10 @@ 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.AccountSessionManager;
|
||||||
import org.joinmastodon.android.fragments.BaseStatusListFragment;
|
import org.joinmastodon.android.fragments.BaseStatusListFragment;
|
||||||
import org.joinmastodon.android.fragments.StatusEditHistoryFragment;
|
import org.joinmastodon.android.fragments.StatusEditHistoryFragment;
|
||||||
import org.joinmastodon.android.fragments.account_list.StatusFavoritesListFragment;
|
import org.joinmastodon.android.fragments.account_list.StatusFavoritesListFragment;
|
||||||
@@ -74,6 +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;
|
||||||
|
favorites.setCompoundDrawablesRelativeWithIntrinsicBounds(GlobalUserPreferences.likeIcon ? 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;
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,10 @@
|
|||||||
package org.joinmastodon.android.ui.displayitems;
|
package org.joinmastodon.android.ui.displayitems;
|
||||||
|
|
||||||
import static org.joinmastodon.android.ui.utils.UiUtils.opacityIn;
|
|
||||||
import static org.joinmastodon.android.ui.utils.UiUtils.opacityOut;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.content.res.ColorStateList;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
@@ -17,6 +15,7 @@ import android.view.ViewGroup;
|
|||||||
import android.view.accessibility.AccessibilityNodeInfo;
|
import android.view.accessibility.AccessibilityNodeInfo;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
import android.widget.FrameLayout;
|
import android.widget.FrameLayout;
|
||||||
|
import android.widget.ImageView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import org.joinmastodon.android.GlobalUserPreferences;
|
import org.joinmastodon.android.GlobalUserPreferences;
|
||||||
@@ -57,13 +56,14 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
|
|||||||
public static class Holder extends StatusDisplayItem.Holder<FooterStatusDisplayItem>{
|
public static class Holder extends StatusDisplayItem.Holder<FooterStatusDisplayItem>{
|
||||||
private final TextView replies, boosts, favorites;
|
private final TextView replies, boosts, favorites;
|
||||||
private final View reply, boost, favorite, share, bookmark;
|
private final View reply, boost, favorite, share, bookmark;
|
||||||
|
private final ImageView favIcon;
|
||||||
|
|
||||||
private View touchingView = null;
|
private View touchingView = null;
|
||||||
private boolean longClickPerformed = false;
|
private boolean longClickPerformed = false;
|
||||||
private final Runnable longClickRunnable = () -> {
|
private final Runnable longClickRunnable = () -> {
|
||||||
longClickPerformed = touchingView != null && touchingView.performLongClick();
|
longClickPerformed = touchingView != null && touchingView.performLongClick();
|
||||||
if (longClickPerformed && touchingView != null) {
|
if (longClickPerformed && touchingView != null) {
|
||||||
touchingView.startAnimation(opacityIn);
|
UiUtils.opacityIn(touchingView);
|
||||||
touchingView.animate().scaleX(1).scaleY(1).setInterpolator(CubicBezierInterpolator.DEFAULT).setDuration(150).start();
|
touchingView.animate().scaleX(1).scaleY(1).setInterpolator(CubicBezierInterpolator.DEFAULT).setDuration(150).start();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -89,6 +89,7 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
|
|||||||
favorite=findViewById(R.id.favorite_btn);
|
favorite=findViewById(R.id.favorite_btn);
|
||||||
share=findViewById(R.id.share_btn);
|
share=findViewById(R.id.share_btn);
|
||||||
bookmark=findViewById(R.id.bookmark_btn);
|
bookmark=findViewById(R.id.bookmark_btn);
|
||||||
|
favIcon=findViewById(R.id.favorite_icon);
|
||||||
|
|
||||||
reply.setOnTouchListener(this::onButtonTouch);
|
reply.setOnTouchListener(this::onButtonTouch);
|
||||||
reply.setOnClickListener(this::onReplyClick);
|
reply.setOnClickListener(this::onReplyClick);
|
||||||
@@ -132,6 +133,13 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
|
|||||||
boolean condenseBottom = !item.isMainStatus && item.hasDescendantNeighbor &&
|
boolean condenseBottom = !item.isMainStatus && item.hasDescendantNeighbor &&
|
||||||
!nextIsWarning;
|
!nextIsWarning;
|
||||||
|
|
||||||
|
ColorStateList color=item.parentFragment.getResources().getColorStateList(
|
||||||
|
GlobalUserPreferences.likeIcon ? R.color.like_icon : R.color.favorite_icon, item.parentFragment.getContext().getTheme()
|
||||||
|
);
|
||||||
|
favIcon.setImageResource(GlobalUserPreferences.likeIcon ? R.drawable.ic_fluent_heart_24_selector : R.drawable.ic_fluent_star_24_selector);
|
||||||
|
favIcon.setImageTintList(color);
|
||||||
|
favorites.setTextColor(color);
|
||||||
|
|
||||||
ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) itemView.getLayoutParams();
|
ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) itemView.getLayoutParams();
|
||||||
params.setMargins(params.leftMargin, params.topMargin, params.rightMargin,
|
params.setMargins(params.leftMargin, params.topMargin, params.rightMargin,
|
||||||
condenseBottom ? V.dp(-5) : 0);
|
condenseBottom ? V.dp(-5) : 0);
|
||||||
@@ -160,21 +168,20 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
|
|||||||
if (!longClickPerformed) v.animate().scaleX(1).scaleY(1).setInterpolator(CubicBezierInterpolator.DEFAULT).setDuration(150).start();
|
if (!longClickPerformed) v.animate().scaleX(1).scaleY(1).setInterpolator(CubicBezierInterpolator.DEFAULT).setDuration(150).start();
|
||||||
if (disabled) return true;
|
if (disabled) return true;
|
||||||
if (action == MotionEvent.ACTION_UP && !longClickPerformed) v.performClick();
|
if (action == MotionEvent.ACTION_UP && !longClickPerformed) v.performClick();
|
||||||
else if (!longClickPerformed) v.startAnimation(opacityIn);
|
else if (!longClickPerformed) UiUtils.opacityIn(v);
|
||||||
} 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());
|
||||||
v.startAnimation(opacityOut);
|
UiUtils.opacityOut(v);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onReplyClick(View v){
|
private void onReplyClick(View v){
|
||||||
v.startAnimation(opacityIn);
|
UiUtils.opacityIn(v);
|
||||||
Bundle args=new Bundle();
|
Bundle args=new Bundle();
|
||||||
args.putString("account", item.accountID);
|
args.putString("account", item.accountID);
|
||||||
args.putParcelable("replyTo", Parcels.wrap(item.status));
|
args.putParcelable("replyTo", Parcels.wrap(item.status));
|
||||||
@@ -198,7 +205,7 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
|
|||||||
|
|
||||||
private void onBoostClick(View v){
|
private void onBoostClick(View v){
|
||||||
if (GlobalUserPreferences.confirmBoost) {
|
if (GlobalUserPreferences.confirmBoost) {
|
||||||
v.startAnimation(opacityIn);
|
UiUtils.opacityIn(v);
|
||||||
onBoostLongClick(v);
|
onBoostLongClick(v);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -207,7 +214,7 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void boostConsumer(View v, Status r) {
|
private void boostConsumer(View v, Status r) {
|
||||||
v.startAnimation(opacityIn);
|
UiUtils.opacityIn(v);
|
||||||
bindText(boosts, r.reblogsCount);
|
bindText(boosts, r.reblogsCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -218,7 +225,7 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
|
|||||||
AccountSession session = AccountSessionManager.getInstance().getAccount(item.accountID);
|
AccountSession session = AccountSessionManager.getInstance().getAccount(item.accountID);
|
||||||
|
|
||||||
Consumer<StatusPrivacy> doReblog = (visibility) -> {
|
Consumer<StatusPrivacy> doReblog = (visibility) -> {
|
||||||
v.startAnimation(opacityOut);
|
UiUtils.opacityOut(v);
|
||||||
session.getStatusInteractionController()
|
session.getStatusInteractionController()
|
||||||
.setReblogged(item.status, !item.status.reblogged, visibility, r->boostConsumer(v, r));
|
.setReblogged(item.status, !item.status.reblogged, visibility, r->boostConsumer(v, r));
|
||||||
dialog.dismiss();
|
dialog.dismiss();
|
||||||
@@ -271,7 +278,7 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
|
|||||||
|
|
||||||
menu.findViewById(R.id.quote).setOnClickListener(c->{
|
menu.findViewById(R.id.quote).setOnClickListener(c->{
|
||||||
dialog.dismiss();
|
dialog.dismiss();
|
||||||
v.startAnimation(opacityIn);
|
UiUtils.opacityIn(v);
|
||||||
Bundle args=new Bundle();
|
Bundle args=new Bundle();
|
||||||
args.putString("account", item.accountID);
|
args.putString("account", item.accountID);
|
||||||
AccountSession accountSession=AccountSessionManager.getInstance().getAccount(item.accountID);
|
AccountSession accountSession=AccountSessionManager.getInstance().getAccount(item.accountID);
|
||||||
@@ -296,7 +303,7 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
|
|||||||
private void onFavoriteClick(View v){
|
private void onFavoriteClick(View v){
|
||||||
favorite.setSelected(!item.status.favourited);
|
favorite.setSelected(!item.status.favourited);
|
||||||
AccountSessionManager.getInstance().getAccount(item.accountID).getStatusInteractionController().setFavorited(item.status, !item.status.favourited, r->{
|
AccountSessionManager.getInstance().getAccount(item.accountID).getStatusInteractionController().setFavorited(item.status, !item.status.favourited, r->{
|
||||||
v.startAnimation(opacityIn);
|
UiUtils.opacityIn(v);
|
||||||
bindText(favorites, r.favouritesCount);
|
bindText(favorites, r.favouritesCount);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -310,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;
|
||||||
}
|
}
|
||||||
@@ -318,7 +325,7 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
|
|||||||
private void onBookmarkClick(View v){
|
private void onBookmarkClick(View v){
|
||||||
bookmark.setSelected(!item.status.bookmarked);
|
bookmark.setSelected(!item.status.bookmarked);
|
||||||
AccountSessionManager.getInstance().getAccount(item.accountID).getStatusInteractionController().setBookmarked(item.status, !item.status.bookmarked, r->{
|
AccountSessionManager.getInstance().getAccount(item.accountID).getStatusInteractionController().setBookmarked(item.status, !item.status.bookmarked, r->{
|
||||||
v.startAnimation(opacityIn);
|
UiUtils.opacityIn(v);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -337,7 +344,7 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void onShareClick(View v){
|
private void onShareClick(View v){
|
||||||
v.startAnimation(opacityIn);
|
UiUtils.opacityIn(v);
|
||||||
Intent intent=new Intent(Intent.ACTION_SEND);
|
Intent intent=new Intent(Intent.ACTION_SEND);
|
||||||
intent.setType("text/plain");
|
intent.setType("text/plain");
|
||||||
intent.putExtra(Intent.EXTRA_TEXT, item.status.url);
|
intent.putExtra(Intent.EXTRA_TEXT, item.status.url);
|
||||||
|
|||||||
@@ -18,13 +18,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,6 +58,8 @@ 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);
|
||||||
@@ -72,7 +78,7 @@ public class GapStatusDisplayItem extends StatusDisplayItem{
|
|||||||
private void onViewClick(View v){
|
private void onViewClick(View v){
|
||||||
if(item.loading) return;
|
if(item.loading) return;
|
||||||
boolean isTop=v==top;
|
boolean isTop=v==top;
|
||||||
(isTop ? textTop : textBottom).startAnimation(UiUtils.opacityOut);
|
UiUtils.opacityOut(isTop ? textTop : textBottom);
|
||||||
V.setVisibilityAnimated((isTop ? progressTop : progressBottom), View.VISIBLE);
|
V.setVisibilityAnimated((isTop ? progressTop : progressBottom), View.VISIBLE);
|
||||||
item.parentFragment.onGapClick(this, isTop);
|
item.parentFragment.onGapClick(this, isTop);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ import me.grishka.appkit.api.ErrorResponse;
|
|||||||
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;
|
||||||
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 HeaderStatusDisplayItem extends StatusDisplayItem{
|
public class HeaderStatusDisplayItem extends StatusDisplayItem{
|
||||||
@@ -76,7 +77,7 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
|
|||||||
private CustomEmojiHelper emojiHelper=new CustomEmojiHelper();
|
private CustomEmojiHelper emojiHelper=new CustomEmojiHelper();
|
||||||
private SpannableStringBuilder parsedName;
|
private SpannableStringBuilder parsedName;
|
||||||
public final Status status;
|
public final Status status;
|
||||||
private boolean hasVisibilityToggle;
|
public boolean hasVisibilityToggle;
|
||||||
boolean needBottomPadding;
|
boolean needBottomPadding;
|
||||||
private CharSequence extraText;
|
private CharSequence extraText;
|
||||||
private Notification notification;
|
private Notification notification;
|
||||||
@@ -208,7 +209,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{
|
||||||
@@ -242,7 +242,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->{});
|
||||||
@@ -294,17 +294,6 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
|
|||||||
UiUtils.enablePopupMenuIcons(activity, optionsMenu);
|
UiUtils.enablePopupMenuIcons(activity, optionsMenu);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void populateAccountsMenu(Menu menu) {
|
|
||||||
List<AccountSession> sessions=AccountSessionManager.getInstance().getLoggedInAccounts();
|
|
||||||
sessions.stream().filter(s -> !s.getID().equals(item.accountID)).forEach(s -> {
|
|
||||||
String username = "@"+s.self.username+"@"+s.domain;
|
|
||||||
menu.add(username).setOnMenuItemClickListener(c->{
|
|
||||||
UiUtils.openURL(item.parentFragment.getActivity(), s.getID(), item.status.url, false);
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressLint("SetTextI18n")
|
@SuppressLint("SetTextI18n")
|
||||||
@Override
|
@Override
|
||||||
public void onBind(HeaderStatusDisplayItem item){
|
public void onBind(HeaderStatusDisplayItem item){
|
||||||
@@ -331,23 +320,13 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
|
|||||||
botIcon.setColorFilter(username.getCurrentTextColor());
|
botIcon.setColorFilter(username.getCurrentTextColor());
|
||||||
|
|
||||||
deleteNotification.setVisibility(GlobalUserPreferences.enableDeleteNotifications && item.notification!=null && !item.inset ? View.VISIBLE : View.GONE);
|
deleteNotification.setVisibility(GlobalUserPreferences.enableDeleteNotifications && item.notification!=null && !item.inset ? View.VISIBLE : View.GONE);
|
||||||
|
visibility.setVisibility(item.hasVisibilityToggle ? View.VISIBLE : View.GONE);
|
||||||
if (item.hasVisibilityToggle){
|
if (item.hasVisibilityToggle){
|
||||||
boolean hidden = !item.status.sensitiveRevealed || (item.status.hasSpoiler() && !item.status.spoilerRevealed);
|
boolean visible = item.status.sensitiveRevealed && (!item.status.hasSpoiler() || item.status.spoilerRevealed);
|
||||||
|
visibility.setAlpha(visible ? 1 : 0f);
|
||||||
// doing this because V.setVisibilityAnimated ignores changes between INVISIBLE and GONE
|
visibility.setScaleY(visible ? 1 : 0.8f);
|
||||||
int newVis=hidden ? View.INVISIBLE : View.VISIBLE;
|
visibility.setScaleX(visible ? 1 : 0.8f);
|
||||||
if(newVis==View.INVISIBLE && visibility.getVisibility()==View.GONE)
|
visibility.setEnabled(visible);
|
||||||
visibility.setVisibility(newVis);
|
|
||||||
else
|
|
||||||
V.setVisibilityAnimated(visibility, newVis);
|
|
||||||
|
|
||||||
visibility.setEnabled(!hidden);
|
|
||||||
visibility.setContentDescription(item.parentFragment.getString(item.status.sensitiveRevealed ? R.string.spoiler_hide : R.string.spoiler_show));
|
|
||||||
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.O){
|
|
||||||
visibility.setTooltipText(visibility.getContentDescription());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
visibility.setVisibility(View.GONE);
|
|
||||||
}
|
}
|
||||||
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);
|
||||||
if(TextUtils.isEmpty(item.extraText)){
|
if(TextUtils.isEmpty(item.extraText)){
|
||||||
@@ -397,21 +376,42 @@ 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){
|
||||||
|
visibility.animate()
|
||||||
|
.alpha(visible ? 1 : 0)
|
||||||
|
.scaleX(visible ? 1 : 0.8f)
|
||||||
|
.scaleY(visible ? 1 : 0.8f)
|
||||||
|
.setInterpolator(CubicBezierInterpolator.DEFAULT)
|
||||||
|
.start();
|
||||||
|
visibility.setEnabled(visible);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setImage(int index, Drawable drawable){
|
public void setImage(int index, Drawable drawable){
|
||||||
if(index>0){
|
if(index>0){
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
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;
|
||||||
@@ -9,7 +8,6 @@ import android.app.Activity;
|
|||||||
import android.content.res.ColorStateList;
|
import android.content.res.ColorStateList;
|
||||||
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;
|
||||||
@@ -20,9 +18,11 @@ import android.widget.TextView;
|
|||||||
|
|
||||||
import org.joinmastodon.android.GlobalUserPreferences;
|
import org.joinmastodon.android.GlobalUserPreferences;
|
||||||
import org.joinmastodon.android.R;
|
import org.joinmastodon.android.R;
|
||||||
|
import org.joinmastodon.android.api.session.AccountLocalPreferences;
|
||||||
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;
|
||||||
@@ -46,11 +46,13 @@ public class NotificationHeaderStatusDisplayItem extends StatusDisplayItem{
|
|||||||
private final String accountID;
|
private final String accountID;
|
||||||
private final CustomEmojiHelper emojiHelper=new CustomEmojiHelper();
|
private final CustomEmojiHelper emojiHelper=new CustomEmojiHelper();
|
||||||
private final CharSequence text;
|
private final CharSequence text;
|
||||||
|
private final CharSequence timestamp;
|
||||||
|
|
||||||
public NotificationHeaderStatusDisplayItem(String parentID, BaseStatusListFragment parentFragment, Notification notification, String accountID){
|
public NotificationHeaderStatusDisplayItem(String parentID, BaseStatusListFragment parentFragment, Notification notification, String accountID){
|
||||||
super(parentID, parentFragment);
|
super(parentID, parentFragment);
|
||||||
this.notification=notification;
|
this.notification=notification;
|
||||||
this.accountID=accountID;
|
this.accountID=accountID;
|
||||||
|
this.timestamp=notification.createdAt==null ? null : UiUtils.formatRelativeTimestamp(context, notification.createdAt);
|
||||||
|
|
||||||
if(notification.type==Notification.Type.POLL){
|
if(notification.type==Notification.Type.POLL){
|
||||||
text=parentFragment.getString(R.string.poll_ended);
|
text=parentFragment.getString(R.string.poll_ended);
|
||||||
@@ -111,8 +113,8 @@ 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;
|
private final TextView text, timestamp;
|
||||||
private final int selectableItemBackground;
|
private final int selectableItemBackground;
|
||||||
|
|
||||||
public Holder(Activity activity, ViewGroup parent){
|
public Holder(Activity activity, ViewGroup parent){
|
||||||
@@ -120,9 +122,16 @@ public class NotificationHeaderStatusDisplayItem extends StatusDisplayItem{
|
|||||||
icon=findViewById(R.id.icon);
|
icon=findViewById(R.id.icon);
|
||||||
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);
|
||||||
|
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();
|
||||||
@@ -152,9 +161,10 @@ public class NotificationHeaderStatusDisplayItem extends StatusDisplayItem{
|
|||||||
@Override
|
@Override
|
||||||
public void onBind(NotificationHeaderStatusDisplayItem item){
|
public void onBind(NotificationHeaderStatusDisplayItem item){
|
||||||
text.setText(item.text);
|
text.setText(item.text);
|
||||||
|
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;
|
||||||
@@ -165,15 +175,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) {
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ public class PollOptionStatusDisplayItem extends StatusDisplayItem{
|
|||||||
private final TextView text, percent;
|
private final TextView text, percent;
|
||||||
private final View button;
|
private final View button;
|
||||||
private final ImageView icon;
|
private final ImageView icon;
|
||||||
private final Drawable progressBg, progressBgInset;
|
private final Drawable progressBg;
|
||||||
|
|
||||||
public Holder(Activity activity, ViewGroup parent){
|
public Holder(Activity activity, ViewGroup parent){
|
||||||
super(activity, R.layout.display_item_poll_option, parent);
|
super(activity, R.layout.display_item_poll_option, parent);
|
||||||
@@ -77,7 +77,6 @@ public class PollOptionStatusDisplayItem extends StatusDisplayItem{
|
|||||||
icon=findViewById(R.id.icon);
|
icon=findViewById(R.id.icon);
|
||||||
button=findViewById(R.id.button);
|
button=findViewById(R.id.button);
|
||||||
progressBg=activity.getResources().getDrawable(R.drawable.bg_poll_option_voted, activity.getTheme()).mutate();
|
progressBg=activity.getResources().getDrawable(R.drawable.bg_poll_option_voted, activity.getTheme()).mutate();
|
||||||
progressBgInset=activity.getResources().getDrawable(R.drawable.bg_poll_option_voted_inset, activity.getTheme()).mutate();
|
|
||||||
itemView.setOnClickListener(this::onButtonClick);
|
itemView.setOnClickListener(this::onButtonClick);
|
||||||
button.setOutlineProvider(OutlineProviders.roundedRect(20));
|
button.setOutlineProvider(OutlineProviders.roundedRect(20));
|
||||||
button.setClipToOutline(true);
|
button.setClipToOutline(true);
|
||||||
@@ -93,23 +92,18 @@ public class PollOptionStatusDisplayItem extends StatusDisplayItem{
|
|||||||
item.showResults ? R.drawable.ic_poll_option_button : R.drawable.ic_fluent_radio_button_24_selector
|
item.showResults ? R.drawable.ic_poll_option_button : R.drawable.ic_fluent_radio_button_24_selector
|
||||||
));
|
));
|
||||||
if(item.showResults){
|
if(item.showResults){
|
||||||
Drawable bg=item.inset ? progressBgInset : progressBg;
|
Drawable bg=progressBg;
|
||||||
bg.setLevel(Math.round(10000f*item.votesFraction));
|
bg.setLevel(Math.round(10000f*item.votesFraction));
|
||||||
button.setBackground(bg);
|
button.setBackground(bg);
|
||||||
itemView.setSelected(item.poll.ownVotes!=null && item.poll.ownVotes.contains(item.optionIndex));
|
itemView.setSelected(item.poll.ownVotes!=null && item.poll.ownVotes.contains(item.optionIndex));
|
||||||
percent.setText(String.format(Locale.getDefault(), "%d%%", Math.round(item.votesFraction*100f)));
|
percent.setText(String.format(Locale.getDefault(), "%d%%", Math.round(item.votesFraction*100f)));
|
||||||
}else{
|
}else{
|
||||||
itemView.setSelected(item.poll.selectedOptions!=null && item.poll.selectedOptions.contains(item.option));
|
itemView.setSelected(item.poll.selectedOptions!=null && item.poll.selectedOptions.contains(item.option));
|
||||||
button.setBackgroundResource(item.inset ? R.drawable.bg_poll_option_clickable_inset : R.drawable.bg_poll_option_clickable);
|
button.setBackgroundResource(R.drawable.bg_poll_option_clickable);
|
||||||
}
|
}
|
||||||
if(item.inset){
|
|
||||||
text.setTextColor(itemView.getContext().getColorStateList(R.color.poll_option_text_inset));
|
|
||||||
percent.setTextColor(itemView.getContext().getColorStateList(R.color.poll_option_text_inset));
|
|
||||||
}else{
|
|
||||||
text.setTextColor(UiUtils.getThemeColor(itemView.getContext(), android.R.attr.textColorPrimary));
|
text.setTextColor(UiUtils.getThemeColor(itemView.getContext(), android.R.attr.textColorPrimary));
|
||||||
percent.setTextColor(UiUtils.getThemeColor(itemView.getContext(), R.attr.colorM3OnSecondaryContainer));
|
percent.setTextColor(UiUtils.getThemeColor(itemView.getContext(), R.attr.colorM3OnSecondaryContainer));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setImage(int index, Drawable image){
|
public void setImage(int index, Drawable image){
|
||||||
|
|||||||
@@ -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,27 @@ 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);
|
CustomEmojiHelper helper=index<emojiHelper.getImageCount() ? emojiHelper : extra.emojiHelper;
|
||||||
|
return helper.getImageRequest(index%emojiHelper.getImageCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
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 +116,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 +132,14 @@ 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);
|
CustomEmojiHelper helper=index<item.emojiHelper.getImageCount() ? item.emojiHelper : item.extra.emojiHelper;
|
||||||
|
helper.setImageDrawable(index%item.emojiHelper.getImageCount(), image);
|
||||||
text.invalidate();
|
text.invalidate();
|
||||||
|
extraText.invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ import android.text.TextUtils;
|
|||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import org.joinmastodon.android.GlobalUserPreferences;
|
import org.joinmastodon.android.GlobalUserPreferences;
|
||||||
import org.joinmastodon.android.R;
|
import org.joinmastodon.android.R;
|
||||||
import org.joinmastodon.android.api.session.AccountLocalPreferences;
|
import org.joinmastodon.android.api.session.AccountLocalPreferences;
|
||||||
@@ -22,6 +24,7 @@ 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;
|
||||||
@@ -30,6 +33,7 @@ import org.joinmastodon.android.model.LegacyFilter;
|
|||||||
import org.joinmastodon.android.model.FilterAction;
|
import org.joinmastodon.android.model.FilterAction;
|
||||||
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;
|
||||||
@@ -87,6 +91,16 @@ public abstract class StatusDisplayItem{
|
|||||||
this.parentFragment=parentFragment;
|
this.parentFragment=parentFragment;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public String getContentID(){
|
||||||
|
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,7 +142,7 @@ 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.displayName
|
||||||
: fragment.getString(R.string.in_reply_to, account.displayName);
|
: fragment.getString(R.string.in_reply_to, account.displayName);
|
||||||
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)
|
||||||
@@ -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;
|
||||||
@@ -163,7 +177,7 @@ 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 fullText = fragment.getString(R.string.user_boosted, status.account.displayName);
|
||||||
String text = GlobalUserPreferences.compactReblogReplyLine && replyLine != null ? status.account.displayName : fullText;
|
String text = 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);
|
||||||
@@ -191,7 +205,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,14 +215,15 @@ 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));
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean filtered=false;
|
LegacyFilter applyingFilter=null;
|
||||||
if(status.filtered!=null){
|
if(status.filtered!=null){
|
||||||
for(FilterResult filter:status.filtered){
|
for(FilterResult filter:status.filtered){
|
||||||
if(filter.filter.isActive()){
|
LegacyFilter f=filter.filter;
|
||||||
filtered=true;
|
if(f.isActive() && filterContext != null && f.context.contains(filterContext)){
|
||||||
|
applyingFilter=f;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -291,7 +306,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))
|
if(status.hasGapAfter!=null && !(fragment instanceof ThreadFragment))
|
||||||
items.add(new GapStatusDisplayItem(parentID, fragment, status));
|
items.add(new GapStatusDisplayItem(parentID, fragment, status));
|
||||||
}
|
}
|
||||||
int i=1;
|
int i=1;
|
||||||
@@ -315,14 +330,7 @@ public abstract class StatusDisplayItem{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LegacyFilter applyingFilter = null;
|
return applyingFilter==null ? items :
|
||||||
if (!statusForContent.filterRevealed) {
|
|
||||||
StatusFilterPredicate predicate = new StatusFilterPredicate(accountID, filterContext, FilterAction.WARN);
|
|
||||||
statusForContent.filterRevealed = predicate.test(status);
|
|
||||||
applyingFilter = predicate.getApplyingFilter();
|
|
||||||
}
|
|
||||||
|
|
||||||
return statusForContent.filterRevealed ? items :
|
|
||||||
new ArrayList<>(List.of(new WarningFilteredStatusDisplayItem(parentID, fragment, statusForContent, items, applyingFilter)));
|
new ArrayList<>(List.of(new WarningFilteredStatusDisplayItem(parentID, fragment, statusForContent, items, applyingFilter)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
package org.joinmastodon.android.ui.displayitems;
|
package org.joinmastodon.android.ui.displayitems;
|
||||||
|
|
||||||
import static org.joinmastodon.android.ui.utils.UiUtils.opacityIn;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.graphics.drawable.Animatable;
|
import android.graphics.drawable.Animatable;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
@@ -16,6 +14,7 @@ import android.widget.TextView;
|
|||||||
|
|
||||||
import org.joinmastodon.android.GlobalUserPreferences;
|
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.fragments.BaseStatusListFragment;
|
import org.joinmastodon.android.fragments.BaseStatusListFragment;
|
||||||
import org.joinmastodon.android.model.Status;
|
import org.joinmastodon.android.model.Status;
|
||||||
import org.joinmastodon.android.model.Translation;
|
import org.joinmastodon.android.model.Translation;
|
||||||
@@ -29,6 +28,7 @@ import java.util.Locale;
|
|||||||
import me.grishka.appkit.imageloader.ImageLoaderViewHolder;
|
import me.grishka.appkit.imageloader.ImageLoaderViewHolder;
|
||||||
import me.grishka.appkit.imageloader.MovieDrawable;
|
import me.grishka.appkit.imageloader.MovieDrawable;
|
||||||
import me.grishka.appkit.imageloader.requests.ImageLoaderRequest;
|
import me.grishka.appkit.imageloader.requests.ImageLoaderRequest;
|
||||||
|
import me.grishka.appkit.utils.CubicBezierInterpolator;
|
||||||
import me.grishka.appkit.utils.V;
|
import me.grishka.appkit.utils.V;
|
||||||
|
|
||||||
public class TextStatusDisplayItem extends StatusDisplayItem{
|
public class TextStatusDisplayItem extends StatusDisplayItem{
|
||||||
@@ -112,7 +112,8 @@ public class TextStatusDisplayItem extends StatusDisplayItem{
|
|||||||
}else{
|
}else{
|
||||||
text.setText(item.text);
|
text.setText(item.text);
|
||||||
}
|
}
|
||||||
text.setTextIsSelectable(item.textSelectable);
|
text.setTextIsSelectable(false);
|
||||||
|
if(item.textSelectable) itemView.post(() -> text.setTextIsSelectable(true));
|
||||||
text.setInvalidateOnEveryFrame(false);
|
text.setInvalidateOnEveryFrame(false);
|
||||||
itemView.setClickable(false);
|
itemView.setClickable(false);
|
||||||
itemView.setPadding(itemView.getPaddingLeft(), item.reduceTopPadding ? V.dp(6) : V.dp(12), itemView.getPaddingRight(), itemView.getPaddingBottom());
|
itemView.setPadding(itemView.getPaddingLeft(), item.reduceTopPadding ? V.dp(6) : V.dp(12), itemView.getPaddingRight(), itemView.getPaddingBottom());
|
||||||
@@ -200,17 +201,20 @@ public class TextStatusDisplayItem extends StatusDisplayItem{
|
|||||||
translationProgress=findViewById(R.id.translation_progress);
|
translationProgress=findViewById(R.id.translation_progress);
|
||||||
translationButton.setOnClickListener(v->item.parentFragment.togglePostTranslation(item.status, item.parentID));
|
translationButton.setOnClickListener(v->item.parentFragment.togglePostTranslation(item.status, item.parentID));
|
||||||
}
|
}
|
||||||
|
if(translationButton!=null) translationButton.animate().cancel();
|
||||||
if(item.status.translationState==Status.TranslationState.HIDDEN){
|
if(item.status.translationState==Status.TranslationState.HIDDEN){
|
||||||
if(updateText) text.setText(item.text);
|
if(updateText) text.setText(item.text);
|
||||||
if(translationFooter==null) return;
|
if(translationFooter==null) return;
|
||||||
translationFooter.setVisibility(translateEnabled ? View.VISIBLE : View.GONE);
|
translationFooter.setVisibility(translateEnabled ? View.VISIBLE : View.GONE);
|
||||||
translationProgress.setVisibility(View.GONE);
|
translationProgress.setVisibility(View.GONE);
|
||||||
Translation existingTrans=item.status.getContentStatus().translation;
|
Translation existingTrans=item.status.getContentStatus().translation;
|
||||||
String lang=existingTrans!=null ? existingTrans.detectedSourceLanguage : null;
|
String existingTransLang=existingTrans!=null ? existingTrans.detectedSourceLanguage : null;
|
||||||
String displayLang=Locale.forLanguageTag(lang!=null ? lang : item.status.getContentStatus().language).getDisplayLanguage();
|
String lang=existingTransLang!=null ? existingTransLang : item.status.getContentStatus().language;
|
||||||
|
String displayLang=Locale.forLanguageTag(lang != null ? lang
|
||||||
|
: AccountSessionManager.get(item.parentFragment.getAccountID()).preferences.postingDefaultLanguage).getDisplayLanguage();
|
||||||
translationButton.setText(item.parentFragment.getString(R.string.translate_post, !displayLang.isBlank() ? displayLang : lang));
|
translationButton.setText(item.parentFragment.getString(R.string.translate_post, !displayLang.isBlank() ? displayLang : lang));
|
||||||
translationButton.setEnabled(true);
|
translationButton.setClickable(true);
|
||||||
translationButton.setAlpha(1);
|
translationButton.animate().alpha(1).setDuration(100).start();
|
||||||
translationInfo.setVisibility(View.GONE);
|
translationInfo.setVisibility(View.GONE);
|
||||||
UiUtils.beginLayoutTransition((ViewGroup) translationButtonWrap);
|
UiUtils.beginLayoutTransition((ViewGroup) translationButtonWrap);
|
||||||
}else{
|
}else{
|
||||||
@@ -218,8 +222,8 @@ public class TextStatusDisplayItem extends StatusDisplayItem{
|
|||||||
if(item.status.translationState==Status.TranslationState.SHOWN){
|
if(item.status.translationState==Status.TranslationState.SHOWN){
|
||||||
translationProgress.setVisibility(View.GONE);
|
translationProgress.setVisibility(View.GONE);
|
||||||
translationButton.setText(R.string.translation_show_original);
|
translationButton.setText(R.string.translation_show_original);
|
||||||
translationButton.setEnabled(true);
|
translationButton.setClickable(true);
|
||||||
translationButton.setAlpha(1);
|
translationButton.animate().alpha(1).setDuration(200).start();
|
||||||
translationInfo.setVisibility(View.VISIBLE);
|
translationInfo.setVisibility(View.VISIBLE);
|
||||||
translationButton.setVisibility(View.VISIBLE);
|
translationButton.setVisibility(View.VISIBLE);
|
||||||
String displayLang=Locale.forLanguageTag(item.status.translation.detectedSourceLanguage).getDisplayLanguage();
|
String displayLang=Locale.forLanguageTag(item.status.translation.detectedSourceLanguage).getDisplayLanguage();
|
||||||
@@ -233,8 +237,8 @@ public class TextStatusDisplayItem extends StatusDisplayItem{
|
|||||||
}
|
}
|
||||||
}else{ // LOADING
|
}else{ // LOADING
|
||||||
translationProgress.setVisibility(View.VISIBLE);
|
translationProgress.setVisibility(View.VISIBLE);
|
||||||
translationButton.setEnabled(false);
|
translationButton.setClickable(false);
|
||||||
translationButton.startAnimation(opacityIn);
|
translationButton.animate().alpha(UiUtils.ALPHA_PRESSED).setStartDelay(50).setDuration(300).setInterpolator(CubicBezierInterpolator.DEFAULT).start();
|
||||||
translationInfo.setVisibility(View.INVISIBLE);
|
translationInfo.setVisibility(View.INVISIBLE);
|
||||||
UiUtils.beginLayoutTransition((ViewGroup) translationButton.getParent());
|
UiUtils.beginLayoutTransition((ViewGroup) translationButton.getParent());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,13 +31,11 @@ public class WarningFilteredStatusDisplayItem extends StatusDisplayItem{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static class Holder extends StatusDisplayItem.Holder<WarningFilteredStatusDisplayItem>{
|
public static class Holder extends StatusDisplayItem.Holder<WarningFilteredStatusDisplayItem>{
|
||||||
public final View warningWrap;
|
|
||||||
public final TextView text;
|
public final TextView text;
|
||||||
public List<StatusDisplayItem> filteredItems;
|
public List<StatusDisplayItem> filteredItems;
|
||||||
|
|
||||||
public Holder(Context context, ViewGroup parent) {
|
public Holder(Context context, ViewGroup parent) {
|
||||||
super(context, R.layout.display_item_filter_warning, parent);
|
super(context, R.layout.display_item_filter_warning, parent);
|
||||||
warningWrap=findViewById(R.id.warning_wrap);
|
|
||||||
text=findViewById(R.id.text);
|
text=findViewById(R.id.text);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,11 +43,7 @@ public class WarningFilteredStatusDisplayItem extends StatusDisplayItem{
|
|||||||
public void onBind(WarningFilteredStatusDisplayItem item) {
|
public void onBind(WarningFilteredStatusDisplayItem item) {
|
||||||
filteredItems = item.filteredItems;
|
filteredItems = item.filteredItems;
|
||||||
text.setText(item.parentFragment.getString(R.string.sk_filtered, item.applyingFilter.title));
|
text.setText(item.parentFragment.getString(R.string.sk_filtered, item.applyingFilter.title));
|
||||||
}
|
itemView.setOnClickListener(v->item.parentFragment.onWarningClick(this));
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onClick() {
|
|
||||||
item.parentFragment.onWarningClick(this);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,6 +66,10 @@ public class BlurhashCrossfadeDrawable extends Drawable{
|
|||||||
|
|
||||||
public void setImageDrawable(Drawable imageDrawable){
|
public void setImageDrawable(Drawable imageDrawable){
|
||||||
this.imageDrawable=imageDrawable;
|
this.imageDrawable=imageDrawable;
|
||||||
|
if(imageDrawable!=null){
|
||||||
|
width=imageDrawable.getIntrinsicWidth();
|
||||||
|
height=imageDrawable.getIntrinsicHeight();
|
||||||
|
}
|
||||||
invalidateSelf();
|
invalidateSelf();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,11 +103,15 @@ public class BlurhashCrossfadeDrawable extends Drawable{
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getIntrinsicWidth(){
|
public int getIntrinsicWidth(){
|
||||||
|
if(width==0)
|
||||||
|
return imageDrawable==null ? 1920 : imageDrawable.getIntrinsicWidth();
|
||||||
return width;
|
return width;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getIntrinsicHeight(){
|
public int getIntrinsicHeight(){
|
||||||
|
if(height==0)
|
||||||
|
return imageDrawable==null ? 1080 : imageDrawable.getIntrinsicHeight();
|
||||||
return height;
|
return height;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
@@ -734,9 +734,18 @@ public class PhotoViewer implements ZoomPanView.Listener{
|
|||||||
public void onBind(Attachment item){
|
public void onBind(Attachment item){
|
||||||
super.onBind(item);
|
super.onBind(item);
|
||||||
FrameLayout.LayoutParams params=(FrameLayout.LayoutParams) imageView.getLayoutParams();
|
FrameLayout.LayoutParams params=(FrameLayout.LayoutParams) imageView.getLayoutParams();
|
||||||
|
Drawable currentDrawable=listener.getPhotoViewCurrentDrawable(getAbsoluteAdapterPosition());
|
||||||
|
if(item.hasKnownDimensions()){
|
||||||
params.width=item.getWidth();
|
params.width=item.getWidth();
|
||||||
params.height=item.getHeight();
|
params.height=item.getHeight();
|
||||||
ViewImageLoader.load(this, listener.getPhotoViewCurrentDrawable(getAbsoluteAdapterPosition()), new UrlImageLoaderRequest(item.url), false);
|
}else if(currentDrawable!=null){
|
||||||
|
params.width=currentDrawable.getIntrinsicWidth();
|
||||||
|
params.height=currentDrawable.getIntrinsicHeight();
|
||||||
|
}else{
|
||||||
|
params.width=1920;
|
||||||
|
params.height=1080;
|
||||||
|
}
|
||||||
|
ViewImageLoader.load(this, currentDrawable, new UrlImageLoaderRequest(item.url), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -778,9 +787,18 @@ public class PhotoViewer implements ZoomPanView.Listener{
|
|||||||
super.onBind(item);
|
super.onBind(item);
|
||||||
playerReady=false;
|
playerReady=false;
|
||||||
FrameLayout.LayoutParams params=(FrameLayout.LayoutParams) wrap.getLayoutParams();
|
FrameLayout.LayoutParams params=(FrameLayout.LayoutParams) wrap.getLayoutParams();
|
||||||
|
Drawable currentDrawable=listener.getPhotoViewCurrentDrawable(getAbsoluteAdapterPosition());
|
||||||
|
if(item.hasKnownDimensions()){
|
||||||
params.width=item.getWidth();
|
params.width=item.getWidth();
|
||||||
params.height=item.getHeight();
|
params.height=item.getHeight();
|
||||||
wrap.setBackground(listener.getPhotoViewCurrentDrawable(getAbsoluteAdapterPosition()));
|
}else if(currentDrawable!=null){
|
||||||
|
params.width=currentDrawable.getIntrinsicWidth();
|
||||||
|
params.height=currentDrawable.getIntrinsicHeight();
|
||||||
|
}else{
|
||||||
|
params.width=1920;
|
||||||
|
params.height=1080;
|
||||||
|
}
|
||||||
|
wrap.setBackground(currentDrawable);
|
||||||
progressBar.setVisibility(item.type==Attachment.Type.VIDEO ? View.VISIBLE : View.GONE);
|
progressBar.setVisibility(item.type==Attachment.Type.VIDEO ? View.VISIBLE : View.GONE);
|
||||||
if(itemView.isAttachedToWindow()){
|
if(itemView.isAttachedToWindow()){
|
||||||
reset();
|
reset();
|
||||||
@@ -841,7 +859,9 @@ public class PhotoViewer implements ZoomPanView.Listener{
|
|||||||
@Override
|
@Override
|
||||||
public boolean onError(MediaPlayer mp, int what, int extra){
|
public boolean onError(MediaPlayer mp, int what, int extra){
|
||||||
Log.e(TAG, "video player onError() called with: mp = ["+mp+"], what = ["+what+"], extra = ["+extra+"]");
|
Log.e(TAG, "video player onError() called with: mp = ["+mp+"], what = ["+what+"], extra = ["+extra+"]");
|
||||||
return false;
|
Toast.makeText(activity, R.string.error_playing_video, Toast.LENGTH_SHORT).show();
|
||||||
|
onStartSwipeToDismissTransition(0f);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void prepareAndStartPlayer(){
|
public void prepareAndStartPlayer(){
|
||||||
@@ -862,6 +882,8 @@ public class PhotoViewer implements ZoomPanView.Listener{
|
|||||||
player.prepareAsync();
|
player.prepareAsync();
|
||||||
}catch(IOException x){
|
}catch(IOException x){
|
||||||
Log.w(TAG, "Error initializing gif player", x);
|
Log.w(TAG, "Error initializing gif player", x);
|
||||||
|
Toast.makeText(activity, R.string.error_playing_video, Toast.LENGTH_SHORT).show();
|
||||||
|
onStartSwipeToDismissTransition(0f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -918,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)
|
||||||
|
|||||||
@@ -119,8 +119,10 @@ public class ZoomPanView extends FrameLayout implements ScaleGestureDetector.OnS
|
|||||||
|
|
||||||
int width=right-left;
|
int width=right-left;
|
||||||
int height=bottom-top;
|
int height=bottom-top;
|
||||||
if(width==0 || height==0)
|
if(width==0 || height==0 || child.getWidth()==0 || child.getWidth()==0){
|
||||||
|
matrix.reset();
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
float scale=Math.min(width/(float)child.getWidth(), height/(float)child.getHeight());
|
float scale=Math.min(width/(float)child.getWidth(), height/(float)child.getHeight());
|
||||||
minScale=scale;
|
minScale=scale;
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
package org.joinmastodon.android.ui.utils;
|
package org.joinmastodon.android.ui.utils;
|
||||||
|
|
||||||
import static org.joinmastodon.android.GlobalUserPreferences.ColorPreference;
|
|
||||||
import static org.joinmastodon.android.GlobalUserPreferences.ThemePreference;
|
import static org.joinmastodon.android.GlobalUserPreferences.ThemePreference;
|
||||||
import static org.joinmastodon.android.GlobalUserPreferences.trueBlackTheme;
|
import static org.joinmastodon.android.GlobalUserPreferences.trueBlackTheme;
|
||||||
|
import static org.joinmastodon.android.api.session.AccountLocalPreferences.ColorPreference.*;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
@@ -11,20 +11,21 @@ import androidx.annotation.StyleRes;
|
|||||||
|
|
||||||
import org.joinmastodon.android.GlobalUserPreferences;
|
import org.joinmastodon.android.GlobalUserPreferences;
|
||||||
import org.joinmastodon.android.R;
|
import org.joinmastodon.android.R;
|
||||||
|
import org.joinmastodon.android.api.session.AccountLocalPreferences;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public class ColorPalette {
|
public class ColorPalette {
|
||||||
public static final Map<GlobalUserPreferences.ColorPreference, ColorPalette> palettes = Map.of(
|
public static final Map<AccountLocalPreferences.ColorPreference, ColorPalette> palettes = Map.of(
|
||||||
ColorPreference.MATERIAL3, new ColorPalette(R.style.ColorPalette_Material3)
|
MATERIAL3, new ColorPalette(R.style.ColorPalette_Material3)
|
||||||
.dark(R.style.ColorPalette_Material3_Dark, R.style.ColorPalette_Material3_AutoLightDark),
|
.dark(R.style.ColorPalette_Material3_Dark, R.style.ColorPalette_Material3_AutoLightDark),
|
||||||
ColorPreference.PINK, new ColorPalette(R.style.ColorPalette_Pink),
|
PINK, new ColorPalette(R.style.ColorPalette_Pink),
|
||||||
ColorPreference.PURPLE, new ColorPalette(R.style.ColorPalette_Purple),
|
PURPLE, new ColorPalette(R.style.ColorPalette_Purple),
|
||||||
ColorPreference.GREEN, new ColorPalette(R.style.ColorPalette_Green),
|
GREEN, new ColorPalette(R.style.ColorPalette_Green),
|
||||||
ColorPreference.BLUE, new ColorPalette(R.style.ColorPalette_Blue),
|
BLUE, new ColorPalette(R.style.ColorPalette_Blue),
|
||||||
ColorPreference.BROWN, new ColorPalette(R.style.ColorPalette_Brown),
|
BROWN, new ColorPalette(R.style.ColorPalette_Brown),
|
||||||
ColorPreference.RED, new ColorPalette(R.style.ColorPalette_Red),
|
RED, new ColorPalette(R.style.ColorPalette_Red),
|
||||||
ColorPreference.YELLOW, new ColorPalette(R.style.ColorPalette_Yellow)
|
YELLOW, new ColorPalette(R.style.ColorPalette_Yellow)
|
||||||
);
|
);
|
||||||
|
|
||||||
private @StyleRes int base;
|
private @StyleRes int base;
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ public class MediaAttachmentViewController{
|
|||||||
private final Context context;
|
private final Context context;
|
||||||
private boolean didClear;
|
private boolean didClear;
|
||||||
private Status status;
|
private Status status;
|
||||||
|
private Attachment attachment;
|
||||||
|
|
||||||
public MediaAttachmentViewController(Context context, MediaGridStatusDisplayItem.GridItemType type){
|
public MediaAttachmentViewController(Context context, MediaGridStatusDisplayItem.GridItemType type){
|
||||||
view=context.getSystemService(LayoutInflater.class).inflate(switch(type){
|
view=context.getSystemService(LayoutInflater.class).inflate(switch(type){
|
||||||
@@ -54,6 +55,7 @@ public class MediaAttachmentViewController{
|
|||||||
|
|
||||||
public void bind(Attachment attachment, Status status){
|
public void bind(Attachment attachment, Status status){
|
||||||
this.status=status;
|
this.status=status;
|
||||||
|
this.attachment=attachment;
|
||||||
crossfadeDrawable.setSize(attachment.getWidth(), attachment.getHeight());
|
crossfadeDrawable.setSize(attachment.getWidth(), attachment.getHeight());
|
||||||
crossfadeDrawable.setBlurhashDrawable(attachment.blurhashPlaceholder);
|
crossfadeDrawable.setBlurhashDrawable(attachment.blurhashPlaceholder);
|
||||||
crossfadeDrawable.setCrossfadeAlpha(0f);
|
crossfadeDrawable.setCrossfadeAlpha(0f);
|
||||||
@@ -76,6 +78,11 @@ public class MediaAttachmentViewController{
|
|||||||
crossfadeDrawable.setImageDrawable(drawable);
|
crossfadeDrawable.setImageDrawable(drawable);
|
||||||
if(didClear)
|
if(didClear)
|
||||||
crossfadeDrawable.animateAlpha(0f);
|
crossfadeDrawable.animateAlpha(0f);
|
||||||
|
// Make sure the image is not stretched if the server returned wrong dimensions
|
||||||
|
if(drawable!=null && (drawable.getIntrinsicWidth()!=attachment.getWidth() || drawable.getIntrinsicHeight()!=attachment.getHeight())){
|
||||||
|
photo.setImageDrawable(null);
|
||||||
|
photo.setImageDrawable(crossfadeDrawable);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clearImage(){
|
public void clearImage(){
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package org.joinmastodon.android.ui.utils;
|
package org.joinmastodon.android.ui.utils;
|
||||||
|
|
||||||
import static android.view.Menu.NONE;
|
import static android.view.Menu.NONE;
|
||||||
|
import static org.joinmastodon.android.GlobalUserPreferences.ThemePreference.*;
|
||||||
import static org.joinmastodon.android.GlobalUserPreferences.theme;
|
import static org.joinmastodon.android.GlobalUserPreferences.theme;
|
||||||
import static org.joinmastodon.android.GlobalUserPreferences.trueBlackTheme;
|
import static org.joinmastodon.android.GlobalUserPreferences.trueBlackTheme;
|
||||||
|
|
||||||
@@ -53,9 +54,8 @@ import android.view.MenuItem;
|
|||||||
import android.view.SubMenu;
|
import android.view.SubMenu;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
import android.view.ViewPropertyAnimator;
|
||||||
import android.view.WindowInsets;
|
import android.view.WindowInsets;
|
||||||
import android.view.animation.AlphaAnimation;
|
|
||||||
import android.view.animation.Animation;
|
|
||||||
import android.webkit.MimeTypeMap;
|
import android.webkit.MimeTypeMap;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
@@ -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;
|
||||||
@@ -85,6 +86,7 @@ import org.joinmastodon.android.api.requests.statuses.CreateStatus;
|
|||||||
import org.joinmastodon.android.api.requests.statuses.DeleteStatus;
|
import org.joinmastodon.android.api.requests.statuses.DeleteStatus;
|
||||||
import org.joinmastodon.android.api.requests.statuses.GetStatusByID;
|
import org.joinmastodon.android.api.requests.statuses.GetStatusByID;
|
||||||
import org.joinmastodon.android.api.requests.statuses.SetStatusPinned;
|
import org.joinmastodon.android.api.requests.statuses.SetStatusPinned;
|
||||||
|
import org.joinmastodon.android.api.session.AccountLocalPreferences;
|
||||||
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.ScheduledStatusDeletedEvent;
|
import org.joinmastodon.android.events.ScheduledStatusDeletedEvent;
|
||||||
@@ -176,17 +178,6 @@ public class UiUtils {
|
|||||||
public static int MAX_WIDTH, SCROLL_TO_TOP_DELTA;
|
public static int MAX_WIDTH, SCROLL_TO_TOP_DELTA;
|
||||||
|
|
||||||
public static final float ALPHA_PRESSED=0.55f;
|
public static final float ALPHA_PRESSED=0.55f;
|
||||||
public static final Animation opacityOut, opacityIn;
|
|
||||||
|
|
||||||
static {
|
|
||||||
opacityOut = new AlphaAnimation(1, ALPHA_PRESSED);
|
|
||||||
opacityOut.setDuration(300);
|
|
||||||
opacityOut.setInterpolator(CubicBezierInterpolator.DEFAULT);
|
|
||||||
opacityOut.setFillAfter(true);
|
|
||||||
opacityIn = new AlphaAnimation(ALPHA_PRESSED, 1);
|
|
||||||
opacityIn.setDuration(400);
|
|
||||||
opacityIn.setInterpolator(CubicBezierInterpolator.DEFAULT);
|
|
||||||
}
|
|
||||||
|
|
||||||
private UiUtils() {
|
private UiUtils() {
|
||||||
}
|
}
|
||||||
@@ -635,24 +626,26 @@ 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);
|
CacheController cache=AccountSessionManager.get(accountID).getCacheController();
|
||||||
|
cache.deleteStatus(s.id);
|
||||||
|
E.post(new StatusDeletedEvent(s.id, accountID));
|
||||||
|
if(status!=s){
|
||||||
|
cache.deleteStatus(status.id);
|
||||||
E.post(new StatusDeletedEvent(status.id, accountID));
|
E.post(new StatusDeletedEvent(status.id, accountID));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onError(ErrorResponse error) {
|
public void onError(ErrorResponse error) {
|
||||||
@@ -807,8 +800,9 @@ 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 {
|
||||||
|
Runnable action=()->{
|
||||||
progressCallback.accept(true);
|
progressCallback.accept(true);
|
||||||
new SetAccountFollowed(account.id, !relationship.following && !relationship.requested, true, false)
|
new SetAccountFollowed(account.id, !relationship.following && !relationship.requested, true)
|
||||||
.setCallback(new Callback<>(){
|
.setCallback(new Callback<>(){
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(Relationship result){
|
public void onSuccess(Relationship result){
|
||||||
@@ -826,6 +820,12 @@ public class UiUtils {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -973,14 +973,20 @@ public class UiUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void setUserPreferredTheme(Context context) {
|
public static void setUserPreferredTheme(Context context) {
|
||||||
|
setUserPreferredTheme(context, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setUserPreferredTheme(Context context, @Nullable AccountSession session) {
|
||||||
context.setTheme(switch(theme) {
|
context.setTheme(switch(theme) {
|
||||||
case LIGHT -> R.style.Theme_Mastodon_Light;
|
case LIGHT -> R.style.Theme_Mastodon_Light;
|
||||||
case DARK -> R.style.Theme_Mastodon_Dark;
|
case DARK -> R.style.Theme_Mastodon_Dark;
|
||||||
default -> R.style.Theme_Mastodon_AutoLightDark;
|
default -> R.style.Theme_Mastodon_AutoLightDark;
|
||||||
});
|
});
|
||||||
|
|
||||||
ColorPalette palette = ColorPalette.palettes.get(GlobalUserPreferences.color);
|
AccountLocalPreferences prefs=session!=null ? session.getLocalPreferences() : null;
|
||||||
if (palette != null) palette.apply(context);
|
AccountLocalPreferences.ColorPreference color=prefs!=null ? prefs.getCurrentColor() : AccountLocalPreferences.ColorPreference.MATERIAL3;
|
||||||
|
ColorPalette palette = ColorPalette.palettes.get(color);
|
||||||
|
if (palette != null) palette.apply(context, theme);
|
||||||
|
|
||||||
Resources res = context.getResources();
|
Resources res = context.getResources();
|
||||||
MAX_WIDTH = (int) res.getDimension(R.dimen.layout_max_width);
|
MAX_WIDTH = (int) res.getDimension(R.dimen.layout_max_width);
|
||||||
@@ -997,9 +1003,9 @@ public class UiUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isDarkTheme() {
|
public static boolean isDarkTheme() {
|
||||||
if (theme == GlobalUserPreferences.ThemePreference.AUTO)
|
if (theme == AUTO)
|
||||||
return (MastodonApp.context.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES;
|
return (MastodonApp.context.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES;
|
||||||
return theme == GlobalUserPreferences.ThemePreference.DARK;
|
return theme == DARK;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Optional<Pair<String, Optional<String>>> parseFediverseHandle(String maybeFediHandle) {
|
public static Optional<Pair<String, Optional<String>>> parseFediverseHandle(String maybeFediHandle) {
|
||||||
@@ -1715,7 +1721,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
|
||||||
@@ -1740,4 +1746,16 @@ public class UiUtils {
|
|||||||
.filter(Objects::nonNull)
|
.filter(Objects::nonNull)
|
||||||
.findFirst();
|
.findFirst();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void opacityIn(View v){
|
||||||
|
v.animate().alpha(1).setDuration(400).setInterpolator(CubicBezierInterpolator.DEFAULT).start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void opacityOut(View v){
|
||||||
|
opacityOut(v, ALPHA_PRESSED).start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ViewPropertyAnimator opacityOut(View v, float alpha){
|
||||||
|
return v.animate().alpha(alpha).setDuration(300).setInterpolator(CubicBezierInterpolator.DEFAULT);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import android.widget.TextView;
|
|||||||
import org.joinmastodon.android.GlobalUserPreferences;
|
import org.joinmastodon.android.GlobalUserPreferences;
|
||||||
import org.joinmastodon.android.R;
|
import org.joinmastodon.android.R;
|
||||||
import org.joinmastodon.android.api.MastodonAPIController;
|
import org.joinmastodon.android.api.MastodonAPIController;
|
||||||
|
import org.joinmastodon.android.api.session.AccountLocalPreferences;
|
||||||
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.ui.DividerItemDecoration;
|
import org.joinmastodon.android.ui.DividerItemDecoration;
|
||||||
@@ -91,9 +92,19 @@ public class ComposeLanguageAlertViewController{
|
|||||||
detectLanguage(detected, postText);
|
detectLanguage(detected, postText);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (session!=null && session.getLocalPreferences().bottomEncoding) {
|
AccountLocalPreferences lp=session==null ? null : session.getLocalPreferences();
|
||||||
|
if(lp!=null){
|
||||||
|
for(String tag : lp.recentLanguages){
|
||||||
|
if(specialLocales.stream().anyMatch(l->l.language!=null && l.language.languageTag!=null
|
||||||
|
&& l.language.languageTag.equals(tag))) continue;
|
||||||
|
resolver.from(tag).ifPresent(lang->specialLocales.add(new SpecialLocaleInfo(
|
||||||
|
lang, lang.getDisplayName(context), null
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
if(lp.bottomEncoding) {
|
||||||
specialLocales.add(new SpecialLocaleInfo(null, "\uD83E\uDD7A\uD83D\uDC49\uD83D\uDC48", "bottom"));
|
specialLocales.add(new SpecialLocaleInfo(null, "\uD83E\uDD7A\uD83D\uDC49\uD83D\uDC48", "bottom"));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(previouslySelected!=null){
|
if(previouslySelected!=null){
|
||||||
if(previouslySelected.index!=-1 && ((previouslySelected.index<specialLocales.size() && Objects.equals(previouslySelected.language, specialLocales.get(previouslySelected.index).language)) ||
|
if(previouslySelected.index!=-1 && ((previouslySelected.index<specialLocales.size() && Objects.equals(previouslySelected.language, specialLocales.get(previouslySelected.index).language)) ||
|
||||||
@@ -323,7 +334,7 @@ public class ComposeLanguageAlertViewController{
|
|||||||
public void onClick(){
|
public void onClick(){
|
||||||
selectItem(getAbsoluteAdapterPosition());
|
selectItem(getAbsoluteAdapterPosition());
|
||||||
selectedLocale=item.language;
|
selectedLocale=item.language;
|
||||||
selectedEncoding = item.title.equals("bottom") ? "bottom" : null;
|
selectedEncoding=item.title != null && item.title.equals("bottom") ? "bottom" : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
@@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<item android:color="@color/bookmark_selected" android:state_selected="true"/>
|
<item android:color="@color/bookmark_selected" android:state_selected="true"/>
|
||||||
<item android:color="?android:textColorSecondary"/>
|
<item android:color="?colorM3OnSurfaceVariant"/>
|
||||||
</selector>
|
</selector>
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<item android:color="?colorM3Primary" android:state_selected="true"/>
|
<item android:color="?colorM3Primary" android:state_selected="true"/>
|
||||||
<item android:color="?colorM3OnBackground" android:state_enabled="true"/>
|
<item android:color="?colorM3OnSurfaceVariant" android:state_enabled="true"/>
|
||||||
<item android:color="@color/m3_on_background_alpha38" />
|
<item android:color="@color/m3_on_background_alpha38" />
|
||||||
</selector>
|
</selector>
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<item android:color="@color/favorite_selected" android:state_selected="true"/>
|
<item android:color="@color/favorite_selected" android:state_selected="true"/>
|
||||||
<item android:color="?android:textColorSecondary"/>
|
<item android:color="?colorM3OnSurfaceVariant"/>
|
||||||
</selector>
|
</selector>
|
||||||
5
mastodon/src/main/res/color/like_icon.xml
Normal file
5
mastodon/src/main/res/color/like_icon.xml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item android:color="@color/like_selected" android:state_selected="true"/>
|
||||||
|
<item android:color="?android:textColorSecondary"/>
|
||||||
|
</selector>
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<item android:color="?colorM3TertiaryContainer" android:state_selected="true"/>
|
|
||||||
<item android:color="?colorM3SurfaceVariant"/>
|
|
||||||
</selector>
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<item android:color="?colorM3OnTertiaryContainer" android:state_selected="true"/>
|
|
||||||
<item android:color="?colorM3OnSurface"/>
|
|
||||||
</selector>
|
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<solid android:color="?colorM3Surface" />
|
||||||
<stroke android:color="?colorM3OutlineVariant" android:width="1dp"/>
|
<stroke android:color="?colorM3OutlineVariant" android:width="1dp"/>
|
||||||
<corners android:radius="11dp"/>
|
<corners android:radius="12dp"/>
|
||||||
</shape>
|
</shape>
|
||||||
7
mastodon/src/main/res/drawable/bg_filter_warning.xml
Normal file
7
mastodon/src/main/res/drawable/bg_filter_warning.xml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item>
|
||||||
|
<color android:color="?colorM3SurfaceVariant"/>
|
||||||
|
</item>
|
||||||
|
<item android:drawable="?android:selectableItemBackground"/>
|
||||||
|
</layer-list>
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<ripple xmlns:android="http://schemas.android.com/apk/res/android" android:color="?android:colorControlHighlight">
|
|
||||||
<item>
|
|
||||||
<shape>
|
|
||||||
<stroke android:width="1dp" android:color="?colorM3Outline"/>
|
|
||||||
<solid android:color="?colorM3Surface"/>
|
|
||||||
<corners android:radius="20dp"/>
|
|
||||||
</shape>
|
|
||||||
</item>
|
|
||||||
<item android:id="@android:id/mask">
|
|
||||||
<shape>
|
|
||||||
<solid android:color="#000"/>
|
|
||||||
<corners android:radius="20dp"/>
|
|
||||||
</shape>
|
|
||||||
</item>
|
|
||||||
</ripple>
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<item>
|
|
||||||
<shape>
|
|
||||||
<solid android:color="?colorM3Surface"/>
|
|
||||||
<corners android:radius="20dp"/>
|
|
||||||
</shape>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<scale android:scaleGravity="start|fill_vertical" android:scaleWidth="100%">
|
|
||||||
<shape>
|
|
||||||
<solid android:color="@color/poll_option_progress_inset"/>
|
|
||||||
<corners android:radius="20dp"/>
|
|
||||||
</shape>
|
|
||||||
</scale>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<shape>
|
|
||||||
<stroke android:width="1dp" android:color="?colorM3Outline"/>
|
|
||||||
<corners android:radius="20dp"/>
|
|
||||||
</shape>
|
|
||||||
</item>
|
|
||||||
</layer-list>
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
<vector android:height="24dp" android:tint="?colorM3OnPrimary"
|
|
||||||
android:viewportHeight="24" android:viewportWidth="24"
|
|
||||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<path android:fillColor="@android:color/white" android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z"/>
|
|
||||||
</vector>
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:width="24dp"
|
|
||||||
android:height="24dp"
|
|
||||||
android:viewportWidth="24"
|
|
||||||
android:viewportHeight="24">
|
|
||||||
<path
|
|
||||||
android:fillColor="@android:color/white"
|
|
||||||
android:pathData="M11,19V13H5V11H11V5H13V11H19V13H13V19Z"/>
|
|
||||||
</vector>
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:width="24dp"
|
|
||||||
android:height="24dp"
|
|
||||||
android:viewportWidth="24"
|
|
||||||
android:viewportHeight="24">
|
|
||||||
<path
|
|
||||||
android:fillColor="@android:color/white"
|
|
||||||
android:pathData="M14,3V5H5Q5,5 5,5Q5,5 5,5V19Q5,19 5,19Q5,19 5,19H19Q19,19 19,19Q19,19 19,19V10H21V19Q21,19.825 20.413,20.413Q19.825,21 19,21H5Q4.175,21 3.587,20.413Q3,19.825 3,19V5Q3,4.175 3.587,3.587Q4.175,3 5,3ZM19,3V5H21V7H19V9H17V7H15V5H17V3ZM6,17H18L14.25,12L11.25,16L9,13ZM5,5V8V10V19Q5,19 5,19Q5,19 5,19Q5,19 5,19Q5,19 5,19V5Q5,5 5,5Q5,5 5,5Z"/>
|
|
||||||
</vector>
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:width="48dp"
|
|
||||||
android:height="48dp"
|
|
||||||
android:viewportWidth="48"
|
|
||||||
android:viewportHeight="48">
|
|
||||||
<path
|
|
||||||
android:fillColor="@android:color/white"
|
|
||||||
android:pathData="M29.45,6V9H9Q9,9 9,9Q9,9 9,9V39Q9,39 9,39Q9,39 9,39H39Q39,39 39,39Q39,39 39,39V18.6H42V39Q42,40.2 41.1,41.1Q40.2,42 39,42H9Q7.8,42 6.9,41.1Q6,40.2 6,39V9Q6,7.8 6.9,6.9Q7.8,6 9,6ZM38,6V10.05H42.05V13.05H38V17.1H35V13.05H30.95V10.05H35V6ZM12,33.9H36L28.8,24.3L22.45,32.65L17.75,26.45ZM9,9V14.55V18.6V39Q9,39 9,39Q9,39 9,39Q9,39 9,39Q9,39 9,39V9Q9,9 9,9Q9,9 9,9Z"/>
|
|
||||||
</vector>
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:width="48dp"
|
|
||||||
android:height="48dp"
|
|
||||||
android:viewportWidth="48"
|
|
||||||
android:viewportHeight="48">
|
|
||||||
<path
|
|
||||||
android:fillColor="@color/m3_sys_dark_on_surface"
|
|
||||||
android:pathData="M29.45,6V9H9Q9,9 9,9Q9,9 9,9V39Q9,39 9,39Q9,39 9,39H39Q39,39 39,39Q39,39 39,39V18.6H42V39Q42,40.2 41.1,41.1Q40.2,42 39,42H9Q7.8,42 6.9,41.1Q6,40.2 6,39V9Q6,7.8 6.9,6.9Q7.8,6 9,6ZM38,6V10.05H42.05V13.05H38V17.1H35V13.05H30.95V10.05H35V6ZM12,33.9H36L28.8,24.3L22.45,32.65L17.75,26.45ZM9,9V14.55V18.6V39Q9,39 9,39Q9,39 9,39Q9,39 9,39Q9,39 9,39V9Q9,9 9,9Q9,9 9,9Z"/>
|
|
||||||
</vector>
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:width="24dp"
|
|
||||||
android:height="24dp"
|
|
||||||
android:viewportWidth="24"
|
|
||||||
android:viewportHeight="24">
|
|
||||||
<path
|
|
||||||
android:pathData="M3,16V10.167C3,9.836 3.11,9.564 3.33,9.35C3.57,9.117 3.86,9 4.2,9H7.8C8.14,9 8.42,9.117 8.64,9.35C8.88,9.564 9,9.836 9,10.167V16H7.2V14.25H4.8V16H3ZM4.8,12.5H7.2V10.75H4.8V12.5Z"
|
|
||||||
android:fillColor="#49454F"
|
|
||||||
android:fillType="evenOdd"/>
|
|
||||||
<path
|
|
||||||
android:pathData="M17.1,10.75V16H18.9V10.75H21V9H15V10.75H17.1Z"
|
|
||||||
android:fillColor="#49454F"/>
|
|
||||||
<path
|
|
||||||
android:pathData="M10.2,9V16H15V14.25H12V9H10.2Z"
|
|
||||||
android:fillColor="#49454F"/>
|
|
||||||
</vector>
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:width="20dp"
|
|
||||||
android:height="20dp"
|
|
||||||
android:viewportWidth="20"
|
|
||||||
android:viewportHeight="20">
|
|
||||||
<path
|
|
||||||
android:fillColor="@android:color/white"
|
|
||||||
android:pathData="M10,18.333Q8.271,18.333 6.75,17.677Q5.229,17.021 4.104,15.896Q2.979,14.771 2.323,13.25Q1.667,11.729 1.667,10Q1.667,8.271 2.323,6.75Q2.979,5.229 4.104,4.104Q5.229,2.979 6.75,2.323Q8.271,1.667 10,1.667Q11.729,1.667 13.25,2.323Q14.771,2.979 15.896,4.104Q17.021,5.229 17.677,6.75Q18.333,8.271 18.333,10V11.271Q18.333,12.5 17.49,13.354Q16.646,14.208 15.417,14.208Q14.688,14.208 14.042,13.906Q13.396,13.604 12.958,13.042Q12.375,13.625 11.604,13.927Q10.833,14.229 10,14.229Q8.229,14.229 7,13Q5.771,11.771 5.771,10Q5.771,8.229 7,7Q8.229,5.771 10,5.771Q11.771,5.771 13,7Q14.229,8.229 14.229,10V11.271Q14.229,11.75 14.583,12.104Q14.938,12.458 15.417,12.458Q15.896,12.458 16.24,12.104Q16.583,11.75 16.583,11.271V10Q16.583,7.25 14.667,5.333Q12.75,3.417 10,3.417Q7.25,3.417 5.333,5.333Q3.417,7.25 3.417,10Q3.417,12.75 5.333,14.667Q7.25,16.583 10,16.583H14.125V18.333ZM10,12.479Q11.042,12.479 11.76,11.76Q12.479,11.042 12.479,10Q12.479,8.958 11.76,8.24Q11.042,7.521 10,7.521Q8.958,7.521 8.24,8.24Q7.521,8.958 7.521,10Q7.521,11.042 8.24,11.76Q8.958,12.479 10,12.479Z"/>
|
|
||||||
</vector>
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:width="24dp"
|
|
||||||
android:height="24dp"
|
|
||||||
android:viewportWidth="24"
|
|
||||||
android:viewportHeight="24">
|
|
||||||
<path
|
|
||||||
android:fillColor="@android:color/white"
|
|
||||||
android:pathData="M9,22Q7.55,22 6.275,21.45Q5,20.9 4.05,19.95Q3.1,19 2.55,17.725Q2,16.45 2,15Q2,12.975 3.05,11.3Q4.1,9.625 5.8,8.75Q6.3,7.775 7.038,7.037Q7.775,6.3 8.75,5.8Q9.575,4.1 11.275,3.05Q12.975,2 15,2Q16.45,2 17.725,2.55Q19,3.1 19.95,4.05Q20.9,5 21.45,6.275Q22,7.55 22,9Q22,11.125 20.95,12.75Q19.9,14.375 18.2,15.25Q17.7,16.225 16.962,16.962Q16.225,17.7 15.25,18.2Q14.375,19.9 12.7,20.95Q11.025,22 9,22ZM9,20Q9.825,20 10.588,19.75Q11.35,19.5 12,19Q10.55,19 9.275,18.45Q8,17.9 7.05,16.95Q6.1,16 5.55,14.725Q5,13.45 5,12Q4.5,12.65 4.25,13.412Q4,14.175 4,15Q4,16.05 4.4,16.95Q4.8,17.85 5.475,18.525Q6.15,19.2 7.05,19.6Q7.95,20 9,20ZM12,17Q12.825,17 13.613,16.75Q14.4,16.5 15.05,16Q13.575,16 12.3,15.438Q11.025,14.875 10.075,13.925Q9.125,12.975 8.562,11.7Q8,10.425 8,8.95Q7.5,9.6 7.25,10.387Q7,11.175 7,12Q7,13.05 7.388,13.95Q7.775,14.85 8.475,15.525Q9.15,16.225 10.05,16.613Q10.95,17 12,17ZM15,14Q15.45,14 15.863,13.925Q16.275,13.85 16.7,13.7Q17.25,12.2 16.863,10.812Q16.475,9.425 15.525,8.475Q14.575,7.525 13.188,7.137Q11.8,6.75 10.3,7.3Q10.15,7.725 10.075,8.137Q10,8.55 10,9Q10,10.05 10.387,10.95Q10.775,11.85 11.475,12.525Q12.15,13.225 13.05,13.613Q13.95,14 15,14ZM19,12.05Q19.5,11.4 19.75,10.612Q20,9.825 20,9Q20,7.95 19.613,7.05Q19.225,6.15 18.525,5.475Q17.85,4.775 16.95,4.387Q16.05,4 15,4Q14.125,4 13.363,4.25Q12.6,4.5 11.95,5Q13.425,5 14.7,5.562Q15.975,6.125 16.925,7.075Q17.875,8.025 18.438,9.3Q19,10.575 19,12.05Z"/>
|
|
||||||
</vector>
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:width="24dp"
|
|
||||||
android:height="24dp"
|
|
||||||
android:viewportWidth="24"
|
|
||||||
android:viewportHeight="24">
|
|
||||||
<path
|
|
||||||
android:fillColor="@android:color/white"
|
|
||||||
android:pathData="M4,22Q3.175,22 2.588,21.413Q2,20.825 2,20V4Q2,3.175 2.588,2.587Q3.175,2 4,2H12L18,8V12.25H16V9H11V4H4Q4,4 4,4Q4,4 4,4V20Q4,20 4,20Q4,20 4,20H15V22ZM4,20V12.25V9V4Q4,4 4,4Q4,4 4,4V20Q4,20 4,20Q4,20 4,20ZM5,19Q5.1,17.775 5.75,16.75Q6.4,15.725 7.45,15.125L6.5,13.425Q6.5,13.4 6.6,13.05Q6.725,13 6.838,13Q6.95,13 7,13.125L7.975,14.875Q8.475,14.675 8.975,14.562Q9.475,14.45 10,14.45Q10.525,14.45 11.025,14.562Q11.525,14.675 12.025,14.875L13,13.125Q13,13.125 13.375,13.025Q13.5,13.075 13.525,13.2Q13.55,13.325 13.5,13.425L12.55,15.125Q13.6,15.725 14.25,16.75Q14.9,17.775 15,19ZM7.75,17.5Q7.95,17.5 8.1,17.35Q8.25,17.2 8.25,17Q8.25,16.8 8.1,16.65Q7.95,16.5 7.75,16.5Q7.55,16.5 7.4,16.65Q7.25,16.8 7.25,17Q7.25,17.2 7.4,17.35Q7.55,17.5 7.75,17.5ZM12.25,17.5Q12.45,17.5 12.6,17.35Q12.75,17.2 12.75,17Q12.75,16.8 12.6,16.65Q12.45,16.5 12.25,16.5Q12.05,16.5 11.9,16.65Q11.75,16.8 11.75,17Q11.75,17.2 11.9,17.35Q12.05,17.5 12.25,17.5ZM20,22 L16,18 17.4,16.575 19,18.15V14H21V18.15L22.6,16.575L24,18Z"/>
|
|
||||||
</vector>
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:width="24dp"
|
|
||||||
android:height="24dp"
|
|
||||||
android:viewportWidth="960"
|
|
||||||
android:viewportHeight="960">
|
|
||||||
<path
|
|
||||||
android:fillColor="@android:color/white"
|
|
||||||
android:pathData="M480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480ZM80,480Q80,397 111.5,324Q143,251 197,197Q251,143 324,111.5Q397,80 480,80Q507,80 533,83.5Q559,87 584,94Q568,109 555.5,127Q543,145 535,165Q521,163 507.5,161.5Q494,160 480,160Q346,160 253,253Q160,346 160,480Q160,614 253,707Q346,800 480,800Q614,800 707,707Q800,614 800,480Q800,466 798.5,452.5Q797,439 795,425Q815,417 833,404.5Q851,392 866,376Q873,401 876.5,427Q880,453 880,480Q880,563 848.5,636Q817,709 763,763Q709,817 636,848.5Q563,880 480,880Q397,880 324,848.5Q251,817 197,763Q143,709 111.5,636Q80,563 80,480ZM720,360Q670,360 635,325Q600,290 600,240Q600,190 635,155Q670,120 720,120Q770,120 805,155Q840,190 840,240Q840,290 805,325Q770,360 720,360Z"/>
|
|
||||||
</vector>
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user