Compare commits

...

108 Commits

Author SHA1 Message Date
sk
20039ec97e bump version 2023-10-20 13:33:02 +02:00
SomeTr
172d25eeb0 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (398 of 398 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/uk/
2023-10-20 11:32:21 +00:00
alextecplayz
fa04e00032 Translated using Weblate (Romanian)
Currently translated at 100.0% (398 of 398 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ro/
2023-10-20 11:32:21 +00:00
Linerly
3ff442894d Translated using Weblate (Indonesian)
Currently translated at 100.0% (398 of 398 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/id/
2023-10-20 11:32:21 +00:00
Choukajohn
edb0823bf9 Translated using Weblate (French)
Currently translated at 100.0% (398 of 398 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fr/
2023-10-20 11:32:21 +00:00
sk
9de83355e1 revert api timeout and increase for search
closes sk22#881
2023-10-20 13:31:27 +02:00
sk
183fb0e8c0 use fluent back button 2023-10-20 12:54:51 +02:00
sk
d624a04e18 fix see new posts button font size 2023-10-20 12:50:34 +02:00
sk
303461d803 take switcher width into account for button 2023-10-20 12:17:12 +02:00
sk
11c7816bb1 make show new posts button less disruptive 2023-10-20 11:43:35 +02:00
sk
b5eae13a16 introduce separate tonal selector backgrounds 2023-10-20 11:43:15 +02:00
sk
59026286a1 don't cache as many posts 2023-10-20 10:46:56 +02:00
sk
ef0fbb26a4 don't return before refreshDone 2023-10-20 10:33:45 +02:00
sk
387b31193f hopefully unfuck removing statuses and reblogs 2023-10-19 21:42:17 +02:00
sk22
95fa547f15 Translated using Weblate (German)
Currently translated at 100.0% (398 of 398 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/de/
2023-10-19 15:13:41 +00:00
sk22
3198c9adb1 Translated using Weblate (German)
Currently translated at 99.2% (395 of 398 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/de/
2023-10-19 15:07:29 +00:00
SomeTr
e1af6f4643 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (18 of 18 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/uk/
2023-10-19 15:07:29 +00:00
SomeTr
cc52e491b0 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (396 of 396 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/uk/
2023-10-19 15:07:29 +00:00
Choukajohn
b0db0d9f2e Translated using Weblate (French)
Currently translated at 100.0% (396 of 396 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fr/
2023-10-19 15:07:29 +00:00
sk
d699788a12 fix string 2023-10-19 17:07:18 +02:00
sk
bdbf441e1a Merge remote-tracking branch 'upstream/l10n_master' 2023-10-19 17:01:46 +02:00
sk
0deba2885b Merge remote-tracking branch 'weblate/main' 2023-10-19 17:01:13 +02:00
sk
48b39fd3bc boop version 2023-10-19 16:59:45 +02:00
sk
875b235e6d restart when show replies/boosts changes
closes sk22#879
2023-10-19 16:58:26 +02:00
sk
1711682322 don't display extra text if visibility == local 2023-10-19 16:54:23 +02:00
sk
70f5ec7500 update header layout 2023-10-19 16:54:07 +02:00
sk
d34c73c210 add options for locking account and default vis 2023-10-19 16:49:23 +02:00
sk
50a0586e8a fix content type index and title 2023-10-19 16:02:51 +02:00
Jacoco
1d2ca1e500 fix: hiding discovery on Akkoma + hiding privacy settings (#867)
* Hide privacy settings on Akkoma

* Fix Akkoma skipping discovery

* Make settings order more clear in the code
2023-10-19 15:42:29 +02:00
EndermanCo
34b7123a8d Translated using Weblate (Persian)
Currently translated at 100.0% (394 of 394 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fa/
2023-10-19 10:17:38 +00:00
butterflyoffire
ec718ff58e Translated using Weblate (Arabic)
Currently translated at 80.4% (317 of 394 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ar/
2023-10-19 10:17:38 +00:00
ihor_ck
20a442e27f Translated using Weblate (Ukrainian)
Currently translated at 100.0% (394 of 394 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/uk/
2023-10-19 10:17:38 +00:00
SomeTr
47cb74abc9 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (394 of 394 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/uk/
2023-10-19 10:17:37 +00:00
SomeTr
a11e53c89a Translated using Weblate (Ukrainian)
Currently translated at 100.0% (394 of 394 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/uk/
2023-10-19 10:17:37 +00:00
David Lapshin
d721e8ca46 Translated using Weblate (Russian)
Currently translated at 99.7% (393 of 394 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ru/
2023-10-19 10:17:37 +00:00
alextecplayz
23e5dcd030 Translated using Weblate (Romanian)
Currently translated at 100.0% (394 of 394 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ro/
2023-10-19 10:17:37 +00:00
Linerly
25dd2cfab8 Translated using Weblate (Indonesian)
Currently translated at 100.0% (394 of 394 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/id/
2023-10-19 10:17:37 +00:00
Choukajohn
8537c7a7ae Translated using Weblate (French)
Currently translated at 100.0% (394 of 394 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fr/
2023-10-19 10:17:37 +00:00
gallegonovato
ebd7f9c36c Translated using Weblate (Spanish)
Currently translated at 100.0% (394 of 394 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/es/
2023-10-19 10:17:37 +00:00
poesty
49cda3aeb2 Translated using Weblate (Chinese (Simplified))
Currently translated at 99.7% (393 of 394 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/zh_Hans/
2023-10-19 10:17:37 +00:00
sk
67cbc8aff2 don't load new posts every time we hit the top 2023-10-19 01:06:03 +02:00
sk
5db44cbf9d don't save bidi-safe string in account
also support custom emoji in account switcher
closes sk22#859
2023-10-19 01:01:53 +02:00
sk
95858e3280 remove debug println 2023-10-19 00:44:10 +02:00
sk
36846acbe5 fix null pointer when content language is null 2023-10-19 00:38:06 +02:00
sk
b95d944003 save own posts from timeline before removing them 2023-10-19 00:22:52 +02:00
sk
f52886af74 don't add own boosts to home
closes sk22#875
2023-10-19 00:09:09 +02:00
sk
6cbe406cef load new posts on reload 2023-10-19 00:04:54 +02:00
sk
3097bc7168 oops: put home timeline if result NOT empty 2023-10-18 23:28:44 +02:00
sk
5f7faa69e8 remove existing statuses to move them up 2023-10-18 22:07:10 +02:00
sk
ed24e89a96 don't compare newly fetched posts to created post
closes sk22#866
2023-10-18 21:48:11 +02:00
sk
8ea05c6ebd fix menu grouping 2023-10-18 21:24:59 +02:00
sk
a30fcbbe34 reorder profile menu
closes sk22#873
2023-10-18 21:23:58 +02:00
sk
39f76f9988 always show "boosted" text in reply/boost line
closes sk22#874
2023-10-18 21:21:03 +02:00
sk
5135653cd3 wow!! configurable first fraction 2023-10-18 21:11:48 +02:00
sk
2e4f04cd88 fix divide by zero error 2023-10-18 20:40:23 +02:00
Eugen Rochko
a44e0e036a New translations strings.xml (Persian) 2023-10-18 20:27:30 +02:00
Eugen Rochko
5d54c1bae4 New translations strings.xml (Spanish) 2023-10-18 20:27:29 +02:00
sk
09577074a9 merge settings changes 2023-10-18 20:26:20 +02:00
sk
53f0e2a933 change extra text size 2023-10-18 19:39:12 +02:00
sk
b8dccbbef1 now hopefully fixing header/subtitle extra sizing 2023-10-18 19:23:13 +02:00
Eugen Rochko
2ef17ba051 New translations strings.xml (Spanish) 2023-10-18 19:15:17 +02:00
Eugen Rochko
f63daf3a4e New translations strings.xml (Thai) 2023-10-18 19:15:16 +02:00
Eugen Rochko
52b079be2a New translations strings.xml (Thai) 2023-10-18 18:11:40 +02:00
Eugen Rochko
efeca17106 New translations strings.xml (Chinese Traditional) 2023-10-18 11:34:03 +02:00
Eugen Rochko
6827166c1d New translations strings.xml (Galician) 2023-10-18 08:51:11 +02:00
Eugen Rochko
04483e61e8 New translations strings.xml (Galician) 2023-10-18 07:49:15 +02:00
Eugen Rochko
22fe174922 New translations strings.xml (Icelandic) 2023-10-17 20:07:09 +02:00
Eugen Rochko
f143da3913 New translations strings.xml (Kabyle) 2023-10-17 04:25:08 +02:00
Eugen Rochko
7e9f41c74b New translations strings.xml (Scottish Gaelic) 2023-10-17 04:25:05 +02:00
Eugen Rochko
a1474d0d29 New translations strings.xml (Filipino) 2023-10-17 04:25:03 +02:00
Eugen Rochko
0dce936ad3 New translations strings.xml (Persian) 2023-10-17 04:24:58 +02:00
Eugen Rochko
6ebbbb4c6c New translations strings.xml (Indonesian) 2023-10-17 04:24:57 +02:00
Eugen Rochko
dc6ddbd0ee New translations strings.xml (Portuguese, Brazilian) 2023-10-17 04:24:56 +02:00
Eugen Rochko
86c81d6b53 New translations strings.xml (Galician) 2023-10-17 04:24:55 +02:00
Eugen Rochko
451a92aa36 New translations strings.xml (Vietnamese) 2023-10-17 04:24:53 +02:00
Eugen Rochko
5c42e67e73 New translations strings.xml (Chinese Simplified) 2023-10-17 04:24:52 +02:00
Eugen Rochko
d20d36d964 New translations strings.xml (Turkish) 2023-10-17 04:24:51 +02:00
Eugen Rochko
1a8d46c71e New translations strings.xml (Slovenian) 2023-10-17 04:24:50 +02:00
Eugen Rochko
91da10eca3 New translations strings.xml (Portuguese) 2023-10-17 04:24:49 +02:00
Eugen Rochko
3bb0dcee53 New translations strings.xml (Polish) 2023-10-17 04:24:48 +02:00
Eugen Rochko
d3fd4b200f New translations strings.xml (Norwegian) 2023-10-17 04:24:47 +02:00
Eugen Rochko
fed96864e1 New translations strings.xml (Dutch) 2023-10-17 04:24:46 +02:00
Eugen Rochko
3b351bea27 New translations strings.xml (Korean) 2023-10-17 04:24:45 +02:00
Eugen Rochko
254e01dca1 New translations strings.xml (Armenian) 2023-10-17 04:24:44 +02:00
Eugen Rochko
19158e1d48 New translations strings.xml (Hungarian) 2023-10-17 04:24:43 +02:00
Eugen Rochko
bffb78fccf New translations strings.xml (Basque) 2023-10-17 04:24:41 +02:00
Eugen Rochko
a3800592a2 New translations strings.xml (Greek) 2023-10-17 04:24:39 +02:00
Eugen Rochko
22a498dfc9 New translations strings.xml (German) 2023-10-17 04:24:38 +02:00
Eugen Rochko
9ea96e32bd New translations strings.xml (Danish) 2023-10-17 04:24:37 +02:00
Eugen Rochko
68f51a123e New translations strings.xml (Czech) 2023-10-17 04:24:36 +02:00
Eugen Rochko
43b1b63581 New translations strings.xml (Catalan) 2023-10-17 04:24:35 +02:00
Eugen Rochko
43b4a2c515 New translations strings.xml (Belarusian) 2023-10-17 04:24:34 +02:00
Eugen Rochko
5b9cfdb689 New translations strings.xml (Arabic) 2023-10-17 04:24:33 +02:00
Eugen Rochko
b43cd7103a New translations strings.xml (Spanish) 2023-10-17 04:24:32 +02:00
Eugen Rochko
30e4f6e0f5 New translations strings.xml (French) 2023-10-17 04:24:30 +02:00
Eugen Rochko
1d0ebf889b New translations strings.xml (Chinese Traditional) 2023-10-17 04:24:28 +02:00
Eugen Rochko
7c4f1da485 New translations strings.xml (Finnish) 2023-10-17 04:24:27 +02:00
Eugen Rochko
8163921014 New translations strings.xml (Russian) 2023-10-17 04:24:26 +02:00
Eugen Rochko
993393dd96 New translations strings.xml (Swedish) 2023-10-17 04:24:25 +02:00
Eugen Rochko
82aed43934 New translations strings.xml (Italian) 2023-10-17 04:24:24 +02:00
Eugen Rochko
fa65134c26 New translations strings.xml (Ukrainian) 2023-10-17 04:24:23 +02:00
Eugen Rochko
af4266c739 New translations strings.xml (Japanese) 2023-10-17 04:24:22 +02:00
Eugen Rochko
f72ea2e763 New translations strings.xml (Icelandic) 2023-10-17 04:24:21 +02:00
Eugen Rochko
c5540270a3 New translations strings.xml (Thai) 2023-10-17 04:24:20 +02:00
sk
5840c94395 isolate bi-directional text in display name 2023-10-17 01:03:06 +02:00
sk
92d7ae67ef don't break custom emoji in pronouns 2023-10-17 00:38:27 +02:00
sk
fc09514a4d the pronouns are stored in the balls (extra text)
also, improve max-width behavior
2023-10-17 00:28:00 +02:00
sk
300fa97781 remove comment 2023-10-16 19:36:30 +02:00
120 changed files with 953 additions and 559 deletions

View File

@@ -15,8 +15,8 @@ android {
applicationId "org.joinmastodon.android.sk" applicationId "org.joinmastodon.android.sk"
minSdk 23 minSdk 23
targetSdk 33 targetSdk 33
versionCode 105 versionCode 107
versionName "2.1.6+fork.105" versionName "2.1.6+fork.107"
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']
} }

View File

@@ -266,7 +266,7 @@ public class AudioPlayerService extends Service{
private void updateNotification(boolean dismissable, boolean removeNotification){ private void updateNotification(boolean dismissable, boolean removeNotification){
Notification.Builder bldr=new Notification.Builder(this) Notification.Builder bldr=new Notification.Builder(this)
.setSmallIcon(R.drawable.ic_ntf_logo) .setSmallIcon(R.drawable.ic_ntf_logo)
.setContentTitle(status.account.displayName) .setContentTitle(status.account.getDisplayName())
.setContentText(HtmlParser.strip(status.content)) .setContentText(HtmlParser.strip(status.content))
.setOngoing(!dismissable) .setOngoing(!dismissable)
.setShowWhen(false) .setShowWhen(false)

View File

@@ -120,6 +120,8 @@ public class CacheController{
values.put("time", s.createdAt.getEpochSecond()); values.put("time", s.createdAt.getEpochSecond());
db.insertWithOnConflict("home_timeline", null, values, SQLiteDatabase.CONFLICT_REPLACE); db.insertWithOnConflict("home_timeline", null, values, SQLiteDatabase.CONFLICT_REPLACE);
} }
if(!clear)
db.delete("home_timeline", "`id` NOT IN (SELECT `id` FROM `home_timeline` ORDER BY `time` DESC LIMIT ?)", new String[]{"100"});
}); });
} }

View File

@@ -53,9 +53,7 @@ public class MastodonAPIController{
.registerTypeAdapter(Status.class, new Status.StatusDeserializer()) .registerTypeAdapter(Status.class, new Status.StatusDeserializer())
.create(); .create();
private static WorkerThread thread=new WorkerThread("MastodonAPIController"); private static WorkerThread thread=new WorkerThread("MastodonAPIController");
private static OkHttpClient httpClient=new OkHttpClient.Builder() private static OkHttpClient httpClient=new OkHttpClient.Builder().build();
.readTimeout(5, TimeUnit.MINUTES)
.build();
private AccountSession session; private AccountSession session;
private static List<String> badDomains = new ArrayList<>(); private static List<String> badDomains = new ArrayList<>();
@@ -113,13 +111,13 @@ public class MastodonAPIController{
} }
Request hreq=builder.build(); Request hreq=builder.build();
Call call=httpClient.newCall(hreq); OkHttpClient client=req.timeout>0
? httpClient.newBuilder().readTimeout(req.timeout, TimeUnit.MILLISECONDS).build()
: httpClient;
Call call=client.newCall(hreq);
synchronized(req){ synchronized(req){
req.okhttpCall=call; req.okhttpCall=call;
} }
if(req.timeout>0){
call.timeout().timeout(req.timeout, TimeUnit.MILLISECONDS);
}
if(BuildConfig.DEBUG) if(BuildConfig.DEBUG)
Log.d(TAG, "["+(session==null ? "no-auth" : session.getID())+"] Sending request: "+hreq); Log.d(TAG, "["+(session==null ? "no-auth" : session.getID())+"] Sending request: "+hreq);

View File

@@ -153,8 +153,9 @@ public abstract class MastodonAPIRequest<T> extends APIRequest<T>{
headers.put(key, value); headers.put(key, value);
} }
protected void setTimeout(long timeout){ public MastodonAPIRequest<T> setTimeout(long timeout){
this.timeout=timeout; this.timeout=timeout;
return this;
} }
protected String getPathPrefix(){ protected String getPathPrefix(){

View File

@@ -218,7 +218,7 @@ public class AccountSession{
public void savePreferencesIfPending(){ public void savePreferencesIfPending(){
if(preferencesNeedSaving){ if(preferencesNeedSaving){
new UpdateAccountCredentialsPreferences(preferences, null, self.discoverable, self.source.indexable) new UpdateAccountCredentialsPreferences(preferences, self.locked, self.discoverable, self.source.indexable)
.setCallback(new Callback<>(){ .setCallback(new Callback<>(){
@Override @Override
public void onSuccess(Account result){ public void onSuccess(Account result){

View File

@@ -9,5 +9,6 @@ public class StatusCreatedEvent{
public StatusCreatedEvent(Status status, String accountID){ public StatusCreatedEvent(Status status, String accountID){
this.status=status; this.status=status;
this.accountID=accountID; this.accountID=accountID;
status.fromStatusCreated=true;
} }
} }

View File

@@ -150,7 +150,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
public LinearLayout mainLayout; public LinearLayout mainLayout;
private SizeListenerLinearLayout contentView; private SizeListenerLinearLayout contentView;
private TextView selfName, selfUsername, selfExtraText, extraText, pronouns; private TextView selfName, selfUsername, selfExtraText, extraText;
private ImageView selfAvatar; private ImageView selfAvatar;
private Account self; private Account self;
private String instanceDomain; private String instanceDomain;
@@ -326,7 +326,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
selfUsername=view.findViewById(R.id.self_username); selfUsername=view.findViewById(R.id.self_username);
selfAvatar=view.findViewById(R.id.self_avatar); selfAvatar=view.findViewById(R.id.self_avatar);
selfExtraText=view.findViewById(R.id.self_extra_text); selfExtraText=view.findViewById(R.id.self_extra_text);
HtmlParser.setTextWithCustomEmoji(selfName, self.displayName, self.emojis); HtmlParser.setTextWithCustomEmoji(selfName, self.getDisplayName(), self.emojis);
selfUsername.setText('@'+self.username+'@'+instanceDomain); selfUsername.setText('@'+self.username+'@'+instanceDomain);
if(self.avatar!=null) if(self.avatar!=null)
ViewImageLoader.load(selfAvatar, null, new UrlImageLoaderRequest(self.avatar)); ViewImageLoader.load(selfAvatar, null, new UrlImageLoaderRequest(self.avatar));
@@ -626,7 +626,6 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
}); });
View originalPost=view.findViewById(R.id.original_post); View originalPost=view.findViewById(R.id.original_post);
extraText=view.findViewById(R.id.extra_text); extraText=view.findViewById(R.id.extra_text);
pronouns=view.findViewById(R.id.pronouns);
originalPost.setVisibility(View.VISIBLE); originalPost.setVisibility(View.VISIBLE);
originalPost.setOnClickListener(v->{ originalPost.setOnClickListener(v->{
Bundle args=new Bundle(); Bundle args=new Bundle();
@@ -666,7 +665,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
moreBtn.setBackground(null); moreBtn.setBackground(null);
TextView name = view.findViewById(R.id.name); TextView name = view.findViewById(R.id.name);
name.setText(HtmlParser.parseCustomEmoji(status.account.displayName, status.account.emojis)); name.setText(HtmlParser.parseCustomEmoji(status.account.getDisplayName(), status.account.emojis));
UiUtils.loadCustomEmojiInTextView(name); UiUtils.loadCustomEmojiInTextView(name);
String time = status==null || status.editedAt==null String time = status==null || status.editedAt==null
@@ -700,7 +699,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, V.dp(16))); .setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, V.dp(16)));
} }
replyText.setText(getString(quote!=null? R.string.sk_quoting_user : R.string.in_reply_to, status.account.displayName)); replyText.setText(getString(quote!=null? R.string.sk_quoting_user : R.string.in_reply_to, status.account.getDisplayName()));
int visibilityNameRes = switch (status.visibility) { int visibilityNameRes = switch (status.visibility) {
case PUBLIC -> R.string.visibility_public; case PUBLIC -> R.string.visibility_public;
case UNLISTED -> R.string.sk_visibility_unlisted; case UNLISTED -> R.string.sk_visibility_unlisted;
@@ -708,7 +707,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
case DIRECT -> R.string.visibility_private; case DIRECT -> R.string.visibility_private;
case LOCAL -> R.string.sk_local_only; case LOCAL -> R.string.sk_local_only;
}; };
replyText.setContentDescription(getString(R.string.in_reply_to, status.account.displayName) + ", " + getString(visibilityNameRes)); replyText.setContentDescription(getString(R.string.in_reply_to, status.account.getDisplayName()) + ", " + getString(visibilityNameRes));
replyText.setOnClickListener(v->{ replyText.setOnClickListener(v->{
scrollView.smoothScrollTo(0, 0); scrollView.smoothScrollTo(0, 0);
}); });
@@ -1455,8 +1454,8 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
} }
private void updateHeaders() { private void updateHeaders() {
UiUtils.setExtraTextInfo(getContext(), selfExtraText, null, false, false, localOnly || statusVisibility==StatusPrivacy.LOCAL, null); UiUtils.setExtraTextInfo(getContext(), selfExtraText, false, false, localOnly, null);
if (replyTo != null) UiUtils.setExtraTextInfo(getContext(), extraText, pronouns, true, false, replyTo.localOnly || replyTo.visibility==StatusPrivacy.LOCAL, replyTo.account); if (replyTo != null) UiUtils.setExtraTextInfo(getContext(), extraText, true, false, replyTo.localOnly || replyTo.visibility==StatusPrivacy.LOCAL, replyTo.account);
} }
private void buildVisibilityPopup(View v){ private void buildVisibilityPopup(View v){

View File

@@ -20,7 +20,6 @@ import org.joinmastodon.android.api.requests.accounts.GetFollowRequests;
import org.joinmastodon.android.api.session.AccountSessionManager; import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.model.Account; import org.joinmastodon.android.model.Account;
import org.joinmastodon.android.model.HeaderPaginationList; import org.joinmastodon.android.model.HeaderPaginationList;
import org.joinmastodon.android.model.Instance;
import org.joinmastodon.android.model.Relationship; import org.joinmastodon.android.model.Relationship;
import org.joinmastodon.android.ui.OutlineProviders; import org.joinmastodon.android.ui.OutlineProviders;
import org.joinmastodon.android.ui.text.HtmlParser; import org.joinmastodon.android.ui.text.HtmlParser;
@@ -271,7 +270,7 @@ public class FollowRequestsListFragment extends MastodonRecyclerFragment<FollowR
followingCount.setVisibility(item.account.followingCount < 0 ? View.GONE : View.VISIBLE); followingCount.setVisibility(item.account.followingCount < 0 ? View.GONE : View.VISIBLE);
followingLabel.setVisibility(item.account.followingCount < 0 ? View.GONE : View.VISIBLE); followingLabel.setVisibility(item.account.followingCount < 0 ? View.GONE : View.VISIBLE);
relationship=relationships.get(item.account.id); relationship=relationships.get(item.account.id);
UiUtils.setExtraTextInfo(getContext(), null, findViewById(R.id.pronouns), true, false, false, item.account); UiUtils.setExtraTextInfo(getContext(), null, true, false, false, item.account);
if(relationship==null || !relationship.followedBy){ if(relationship==null || !relationship.followedBy){
actionWrap.setVisibility(View.GONE); actionWrap.setVisibility(View.GONE);
@@ -366,9 +365,9 @@ public class FollowRequestsListFragment extends MastodonRecyclerFragment<FollowR
coverRequest=new UrlImageLoaderRequest(account.header, 1000, 1000); coverRequest=new UrlImageLoaderRequest(account.header, 1000, 1000);
parsedBio=HtmlParser.parse(account.note, account.emojis, Collections.emptyList(), Collections.emptyList(), accountID); parsedBio=HtmlParser.parse(account.note, account.emojis, Collections.emptyList(), Collections.emptyList(), accountID);
if(account.emojis.isEmpty()){ if(account.emojis.isEmpty()){
parsedName=account.displayName; parsedName= account.getDisplayName();
}else{ }else{
parsedName=HtmlParser.parseCustomEmoji(account.displayName, account.emojis); parsedName=HtmlParser.parseCustomEmoji(account.getDisplayName(), account.emojis);
emojiHelper.setText(new SpannableStringBuilder(parsedName).append(parsedBio)); emojiHelper.setText(new SpannableStringBuilder(parsedName).append(parsedBio));
} }
} }

View File

@@ -32,7 +32,6 @@ import org.joinmastodon.android.events.NotificationsMarkerUpdatedEvent;
import org.joinmastodon.android.events.StatusDisplaySettingsChangedEvent; import org.joinmastodon.android.events.StatusDisplaySettingsChangedEvent;
import org.joinmastodon.android.fragments.discover.DiscoverFragment; import org.joinmastodon.android.fragments.discover.DiscoverFragment;
import org.joinmastodon.android.model.Account; import org.joinmastodon.android.model.Account;
import org.joinmastodon.android.model.Instance;
import org.joinmastodon.android.model.Notification; import org.joinmastodon.android.model.Notification;
import org.joinmastodon.android.model.PaginatedResponse; import org.joinmastodon.android.model.PaginatedResponse;
import org.joinmastodon.android.ui.AccountSwitcherSheet; import org.joinmastodon.android.ui.AccountSwitcherSheet;
@@ -71,14 +70,12 @@ public class HomeFragment extends AppKitFragment implements OnBackPressedListene
private TextView notificationsBadge; private TextView notificationsBadge;
private String accountID; private String accountID;
private boolean isAkkoma;
@Override @Override
public void onCreate(Bundle savedInstanceState){ public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
accountID=getArguments().getString("account"); accountID=getArguments().getString("account");
setTitle(R.string.sk_app_name); setTitle(R.string.sk_app_name);
isAkkoma = getInstance().map(Instance::isAkkoma).orElse(false);
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.N) if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.N)
setRetainInstance(true); setRetainInstance(true);
@@ -89,7 +86,6 @@ public class HomeFragment extends AppKitFragment implements OnBackPressedListene
homeTabFragment=new HomeTabFragment(); homeTabFragment=new HomeTabFragment();
homeTabFragment.setArguments(args); homeTabFragment.setArguments(args);
args=new Bundle(args); args=new Bundle(args);
args.putBoolean("disableDiscover", isAkkoma);
args.putBoolean("noAutoLoad", true); args.putBoolean("noAutoLoad", true);
discoverFragment=new DiscoverFragment(); discoverFragment=new DiscoverFragment();
discoverFragment.setArguments(args); discoverFragment.setArguments(args);
@@ -296,7 +292,7 @@ public class HomeFragment extends AppKitFragment implements OnBackPressedListene
if(tab==R.id.tab_profile){ if(tab==R.id.tab_profile){
ArrayList<String> options=new ArrayList<>(); ArrayList<String> options=new ArrayList<>();
for(AccountSession session:AccountSessionManager.getInstance().getLoggedInAccounts()){ for(AccountSession session:AccountSessionManager.getInstance().getLoggedInAccounts()){
options.add(session.self.displayName+"\n("+session.self.username+"@"+session.domain+")"); options.add(session.self.getDisplayName()+"\n("+session.self.username+"@"+session.domain+")");
} }
new AccountSwitcherSheet(getActivity(), this).show(); new AccountSwitcherSheet(getActivity(), this).show();
return true; return true;

View File

@@ -233,21 +233,25 @@ public class HomeTabFragment extends MastodonToolbarFragment implements Scrollab
ViewTreeObserver vto = getToolbar().getViewTreeObserver(); ViewTreeObserver vto = getToolbar().getViewTreeObserver();
if (vto.isAlive()) { if (vto.isAlive()) {
vto.addOnGlobalLayoutListener(() -> { vto.addOnGlobalLayoutListener(()->{
Toolbar t = getToolbar(); Toolbar t=getToolbar();
if (t == null) return; if(t==null) return;
int toolbarWidth = t.getWidth(); int toolbarWidth=t.getWidth();
if (toolbarWidth == 0) return; if(toolbarWidth==0) return;
int toolbarFrameWidth = toolbarFrame.getWidth(); int toolbarFrameWidth=toolbarFrame.getWidth();
int padding = toolbarWidth - toolbarFrameWidth; int actionsWidth=toolbarWidth-toolbarFrameWidth;
FrameLayout parent = ((FrameLayout) toolbarShowNewPostsBtn.getParent()); // margin (4) + padding (12) + icon (24) + margin (8) + chevron (16) + padding (12)
if (padding == parent.getPaddingStart()) return; int switcherWidth=V.dp(76);
FrameLayout parent=((FrameLayout) toolbarShowNewPostsBtn.getParent());
if(actionsWidth==parent.getPaddingStart()) return;
int paddingMax=Math.max(actionsWidth, switcherWidth);
int paddingEnd=(Math.max(0, switcherWidth-actionsWidth));
// toolbar frame goes from screen edge to beginning of right-aligned option buttons. // toolbar frame goes from screen edge to beginning of right-aligned option buttons.
// centering button by applying the same space on the left // centering button by applying the same space on the left
parent.setPaddingRelative(padding, 0, 0, 0); parent.setPaddingRelative(paddingMax, 0, paddingEnd, 0);
toolbarShowNewPostsBtn.setMaxWidth(toolbarWidth - padding * 2); toolbarShowNewPostsBtn.setMaxWidth(toolbarWidth-paddingMax*2);
switcher.setPivotX(V.dp(28)); // padding + half of icon switcher.setPivotX(V.dp(28)); // padding + half of icon
switcher.setPivotY(switcher.getHeight() / 2f); switcher.setPivotY(switcher.getHeight() / 2f);

View File

@@ -61,7 +61,7 @@ public class HomeTimelineFragment extends StatusListFragment {
maxID=result.maxID; maxID=result.maxID;
AccountSessionManager.get(accountID).filterStatuses(result.items, getFilterContext()); AccountSessionManager.get(accountID).filterStatuses(result.items, getFilterContext());
onDataLoaded(result.items, !empty); onDataLoaded(result.items, !empty);
if(result.isFromCache()) if(result.isFromCache() && GlobalUserPreferences.loadNewPosts)
loadNewPosts(); loadNewPosts();
} }
}); });
@@ -74,7 +74,7 @@ public class HomeTimelineFragment extends StatusListFragment {
list.addOnScrollListener(new RecyclerView.OnScrollListener(){ list.addOnScrollListener(new RecyclerView.OnScrollListener(){
@Override @Override
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy){ public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy){
if(parent != null && parent.isNewPostsBtnShown() && list.getChildAdapterPosition(list.getChildAt(0))<=getMainAdapterOffset()){ if(parent!=null && parent.isNewPostsBtnShown() && list.getChildAdapterPosition(list.getChildAt(0))<=getMainAdapterOffset()){
parent.hideNewPostsButton(); parent.hideNewPostsButton();
} }
} }
@@ -87,7 +87,7 @@ public class HomeTimelineFragment extends StatusListFragment {
if(!getArguments().getBoolean("noAutoLoad")){ if(!getArguments().getBoolean("noAutoLoad")){
if(!loaded && !dataLoading){ if(!loaded && !dataLoading){
loadData(); loadData();
}else if(!dataLoading){ }else if(!dataLoading && GlobalUserPreferences.loadNewPosts){
loadNewPosts(); loadNewPosts();
} }
} }
@@ -117,48 +117,54 @@ public class HomeTimelineFragment extends StatusListFragment {
} }
public void onStatusCreated(Status status){ public void onStatusCreated(Status status){
if(status.reblog!=null) return;
prependItems(Collections.singletonList(status), true); prependItems(Collections.singletonList(status), true);
} }
private void loadNewPosts(){ private void loadNewPosts(){
if (!GlobalUserPreferences.loadNewPosts) return;
dataLoading=true; dataLoading=true;
// we only care about the data that was actually retrieved from the timeline api since
// user-created statuses are probably in the wrong position
List<Status> dataFromTimeline=data.stream().filter(s->!s.fromStatusCreated).collect(Collectors.toList());
// The idea here is that we request the timeline such that if there are fewer than `limit` posts, // The idea here is that we request the timeline such that if there are fewer than `limit` posts,
// we'll get the currently topmost post as last in the response. This way we know there's no gap // we'll get the currently topmost post as last in the response. This way we know there's no gap
// between the existing and newly loaded parts of the timeline. // between the existing and newly loaded parts of the timeline.
String sinceID=data.size()>1 ? data.get(1).id : "1"; String sinceID=dataFromTimeline.size()>1 ? dataFromTimeline.get(1).id : "1";
currentRequest=new GetHomeTimeline(null, null, 20, sinceID, getLocalPrefs().timelineReplyVisibility) currentRequest=new GetHomeTimeline(null, null, 20, sinceID, getLocalPrefs().timelineReplyVisibility)
.setCallback(new Callback<>(){ .setCallback(new Callback<>(){
@Override @Override
public void onSuccess(List<Status> result){ public void onSuccess(List<Status> result){
currentRequest=null; currentRequest=null;
dataLoading=false; dataLoading=false;
refreshDone();
if(result.isEmpty() || getActivity()==null) if(result.isEmpty() || getActivity()==null)
return; return;
Status last=result.get(result.size()-1); Status last=result.get(result.size()-1);
List<Status> toAdd; List<Status> toAdd;
if(!data.isEmpty() && last.id.equals(data.get(0).id)){ // This part intersects with the existing one if(!dataFromTimeline.isEmpty() && last.id.equals(dataFromTimeline.get(0).id)){ // This part intersects with the existing one
toAdd=new ArrayList<>(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{
last.hasGapAfter=last.id; last.hasGapAfter=last.id;
toAdd=result; toAdd=result;
} }
if(!toAdd.isEmpty())
AccountSessionManager.getInstance().getAccount(accountID).getCacheController().putHomeTimeline(new ArrayList<>(toAdd), false);
// removing statuses that come up as duplicates (hopefully only posts and boosts that were locally created
// and thus were already prepended to the timeline earlier)
List<String> existingIds=data.stream().map(Status::getID).collect(Collectors.toList()); List<String> existingIds=data.stream().map(Status::getID).collect(Collectors.toList());
toAdd.removeIf(s->existingIds.contains(s.getID())); 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();
} }
if(toAddUnfiltered.isEmpty())
AccountSessionManager.getInstance().getAccount(accountID).getCacheController().putHomeTimeline(toAddUnfiltered, false);
} }
@Override @Override
public void onError(ErrorResponse error){ public void onError(ErrorResponse error){
currentRequest=null; currentRequest=null;
dataLoading=false; dataLoading=false;
refreshDone();
} }
}) })
.exec(accountID); .exec(accountID);
@@ -325,8 +331,8 @@ public class HomeTimelineFragment extends StatusListFragment {
currentRequest=null; currentRequest=null;
dataLoading=false; dataLoading=false;
} }
if (parent != null) parent.hideNewPostsButton(); if(parent!=null) parent.hideNewPostsButton();
super.onRefresh(); loadNewPosts();
} }
@Override @Override

View File

@@ -621,14 +621,14 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
@SuppressLint("SetTextI18n") @SuppressLint("SetTextI18n")
private void bindHeaderView(){ private void bindHeaderView(){
setTitle(account.displayName); setTitle(account.getDisplayName());
setSubtitle(getResources().getQuantityString(R.plurals.x_posts, (int)(account.statusesCount%1000), account.statusesCount)); setSubtitle(getResources().getQuantityString(R.plurals.x_posts, (int)(account.statusesCount%1000), account.statusesCount));
ViewImageLoader.load(avatar, null, new UrlImageLoaderRequest( ViewImageLoader.load(avatar, null, new UrlImageLoaderRequest(
TextUtils.isEmpty(account.avatar) ? getSession().getDefaultAvatarUrl() : TextUtils.isEmpty(account.avatar) ? getSession().getDefaultAvatarUrl() :
GlobalUserPreferences.playGifs ? account.avatar : account.avatarStatic, GlobalUserPreferences.playGifs ? account.avatar : account.avatarStatic,
V.dp(100), V.dp(100))); V.dp(100), V.dp(100)));
ViewImageLoader.load(cover, null, new UrlImageLoaderRequest(GlobalUserPreferences.playGifs ? account.header : account.headerStatic, 1000, 1000)); ViewImageLoader.load(cover, null, new UrlImageLoaderRequest(GlobalUserPreferences.playGifs ? account.header : account.headerStatic, 1000, 1000));
SpannableStringBuilder ssb=new SpannableStringBuilder(account.displayName); SpannableStringBuilder ssb=new SpannableStringBuilder(account.getDisplayName());
if(AccountSessionManager.get(accountID).getLocalPreferences().customEmojiInNames) if(AccountSessionManager.get(accountID).getLocalPreferences().customEmojiInNames)
HtmlParser.parseCustomEmoji(ssb, account.emojis); HtmlParser.parseCustomEmoji(ssb, account.emojis);
name.setText(ssb); name.setText(ssb);

View File

@@ -9,6 +9,7 @@ import com.squareup.otto.Subscribe;
import org.joinmastodon.android.E; import org.joinmastodon.android.E;
import org.joinmastodon.android.GlobalUserPreferences; import org.joinmastodon.android.GlobalUserPreferences;
import org.joinmastodon.android.api.CacheController;
import org.joinmastodon.android.api.session.AccountLocalPreferences; import org.joinmastodon.android.api.session.AccountLocalPreferences;
import org.joinmastodon.android.api.session.AccountSessionManager; import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.events.EmojiReactionsUpdatedEvent; import org.joinmastodon.android.events.EmojiReactionsUpdatedEvent;
@@ -31,6 +32,10 @@ import org.parceler.Parcels;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.function.BiPredicate;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
@@ -176,56 +181,71 @@ public abstract class StatusListFragment extends BaseStatusListFragment<Status>
} }
} }
private void iterateRemoveStatus(List<Status> l, String id){ private boolean removeStatusDisplayItems(String parentID, int firstIndex, int ancestorFirstIndex, int ancestorLastIndex){
Iterator<Status> it=l.iterator();
while(it.hasNext()){
if(it.next().getContentStatus().id.equals(id)){
it.remove();
}
}
}
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==firstIndex-1){
for(int i=ancestorFirstIndex; i<=ancestorLastIndex; i++){ // update ancestor to have no descendant anymore
StatusDisplayItem item=displayItems.get(i); displayItems.subList(ancestorFirstIndex, ancestorLastIndex+1).forEach(i->i.hasDescendantNeighbor=false);
String id=deleteContent ? item.getContentID() : item.parentID;
// update ancestor to have no descendant anymore
if(id.equals(status.inReplyToId)) item.hasDescendantNeighbor=false;
}
adapter.notifyItemRangeChanged(ancestorFirstIndex, ancestorLastIndex-ancestorFirstIndex+1); adapter.notifyItemRangeChanged(ancestorFirstIndex, ancestorLastIndex-ancestorFirstIndex+1);
} }
if(index==-1) return; if(firstIndex==-1) return false;
int lastIndex; int lastIndex=firstIndex;
for(lastIndex=index;lastIndex<displayItems.size();lastIndex++){ while(lastIndex<displayItems.size()){
StatusDisplayItem item=displayItems.get(lastIndex); if(!displayItems.get(lastIndex).parentID.equals(parentID)) break;
String id=deleteContent ? item.getContentID() : item.parentID; lastIndex++;
if(!id.equals(status.id)) break;
} }
displayItems.subList(index, lastIndex).clear(); int count=lastIndex-firstIndex;
adapter.notifyItemRangeRemoved(index, lastIndex-index); displayItems.subList(firstIndex, lastIndex).clear();
adapter.notifyItemRangeRemoved(firstIndex, count);
return true;
} }
protected void removeStatus(Status status){ protected void removeStatus(Status status){
boolean deleteContent=status==status.getContentStatus(); final AccountSessionManager asm=AccountSessionManager.getInstance();
final CacheController cache=AccountSessionManager.get(accountID).getCacheController();
final boolean unReblogging=status.reblog!=null && asm.isSelf(accountID, status.account);
final Predicate<Status> isToBeRemovedReblog=item->item!=null && item.reblog!=null
&& item.reblog.id.equals(status.reblog.id)
&& asm.isSelf(accountID, item.account);
final BiPredicate<String, Supplier<String>> isToBeRemovedContent=(parentId, contentIdSupplier)->
parentId.equals(status.id) || contentIdSupplier.get().equals(status.id);
int ancestorFirstIndex=-1, ancestorLastIndex=-1; int ancestorFirstIndex=-1, ancestorLastIndex=-1;
for(int i=0;i<displayItems.size();i++){ for(int i=0;i<displayItems.size();i++){
StatusDisplayItem item=displayItems.get(i); StatusDisplayItem item=displayItems.get(i);
String id=deleteContent ? item.getContentID() : item.parentID; // we found a status that the to-be-removed status replies to!
if(id.equals(status.id)){ // storing indices to maybe update its display items
removeStatusDisplayItems(status, i, ancestorFirstIndex, ancestorLastIndex, deleteContent); if(item.parentID.equals(status.inReplyToId)){
ancestorFirstIndex=ancestorLastIndex=-1;
continue;
}
if(id.equals(status.inReplyToId)){
if(ancestorFirstIndex==-1) ancestorFirstIndex=i; if(ancestorFirstIndex==-1) ancestorFirstIndex=i;
ancestorLastIndex=i; ancestorLastIndex=i;
} }
// if we're un-reblogging, we compare the reblogged status's id with the current status's
if(unReblogging
? isToBeRemovedReblog.test(getStatusByID(item.parentID))
: isToBeRemovedContent.test(item.parentID, item::getContentStatusID)){
// if statuses are removed from index i, the next iteration should be on the same index again
if(removeStatusDisplayItems(item.parentID, i, ancestorFirstIndex, ancestorLastIndex)) i--;
// resetting in case we find another occurrence of the same status that also has ancestors
// (we won't - unless the timeline is being especially weird)
ancestorFirstIndex=-1; ancestorLastIndex=-1;
}
} }
iterateRemoveStatus(data, status.id);
iterateRemoveStatus(preloadedData, status.id); Consumer<List<Status>> removeStatusFromData=(list)->{
Iterator<Status> it=list.iterator();
while(it.hasNext()){
Status s=it.next();
if(unReblogging
? isToBeRemovedReblog.test(s)
: isToBeRemovedContent.test(s.id, s::getContentStatusID)){
it.remove();
cache.deleteStatus(s.id);
}
}
};
removeStatusFromData.accept(data);
removeStatusFromData.accept(preloadedData);
} }
@Override @Override
@@ -296,10 +316,14 @@ public abstract class StatusListFragment extends BaseStatusListFragment<Status>
@Subscribe @Subscribe
public void onReblogDeleted(ReblogDeletedEvent ev){ public void onReblogDeleted(ReblogDeletedEvent ev){
AccountSessionManager asm=AccountSessionManager.getInstance();
if(!ev.accountID.equals(accountID)) if(!ev.accountID.equals(accountID))
return; return;
for(Status item : data){ for(Status item : data){
if(item.getContentStatus().id.equals(ev.statusID) && item.reblog!=null){ boolean itemIsOwnReblog=item.reblog!=null
&& item.getContentStatusID().equals(ev.statusID)
&& asm.isSelf(accountID, item.account);
if(itemIsOwnReblog){
removeStatus(item); removeStatus(item);
break; break;
} }

View File

@@ -64,7 +64,7 @@ public class ThreadFragment extends StatusListFragment implements ProvidesAssist
knownAccounts.put(inReplyToAccount.id, inReplyToAccount); knownAccounts.put(inReplyToAccount.id, inReplyToAccount);
data.add(mainStatus); data.add(mainStatus);
onAppendItems(Collections.singletonList(mainStatus)); onAppendItems(Collections.singletonList(mainStatus));
setTitle(HtmlParser.parseCustomEmoji(getString(R.string.post_from_user, mainStatus.account.displayName), mainStatus.account.emojis)); setTitle(HtmlParser.parseCustomEmoji(getString(R.string.post_from_user, mainStatus.account.getDisplayName()), mainStatus.account.emojis));
transitionFinished = getArguments().getBoolean("noTransition", false); transitionFinished = getArguments().getBoolean("noTransition", false);
} }

View File

@@ -261,7 +261,7 @@ public class DiscoverAccountsFragment extends MastodonRecyclerFragment<DiscoverA
followingCount.setVisibility(item.account.followingCount < 0 ? View.GONE : View.VISIBLE); followingCount.setVisibility(item.account.followingCount < 0 ? View.GONE : View.VISIBLE);
followingLabel.setVisibility(item.account.followingCount < 0 ? View.GONE : View.VISIBLE); followingLabel.setVisibility(item.account.followingCount < 0 ? View.GONE : View.VISIBLE);
relationship=relationships.get(item.account.id); relationship=relationships.get(item.account.id);
UiUtils.setExtraTextInfo(getContext(), null, findViewById(R.id.pronouns), true, false, false, item.account); UiUtils.setExtraTextInfo(getContext(), null, true, false, false, item.account);
if(relationship==null){ if(relationship==null){
actionWrap.setVisibility(View.GONE); actionWrap.setVisibility(View.GONE);
@@ -330,9 +330,9 @@ public class DiscoverAccountsFragment extends MastodonRecyclerFragment<DiscoverA
coverRequest=new UrlImageLoaderRequest(account.header, 1000, 1000); coverRequest=new UrlImageLoaderRequest(account.header, 1000, 1000);
parsedBio=HtmlParser.parse(account.note, account.emojis, Collections.emptyList(), Collections.emptyList(), accountID); parsedBio=HtmlParser.parse(account.note, account.emojis, Collections.emptyList(), Collections.emptyList(), accountID);
if(account.emojis.isEmpty()){ if(account.emojis.isEmpty()){
parsedName=account.displayName; parsedName= account.getDisplayName();
}else{ }else{
parsedName=HtmlParser.parseCustomEmoji(account.displayName, account.emojis); parsedName=HtmlParser.parseCustomEmoji(account.getDisplayName(), account.emojis);
emojiHelper.setText(new SpannableStringBuilder(parsedName).append(parsedBio)); emojiHelper.setText(new SpannableStringBuilder(parsedName).append(parsedBio));
} }
} }

View File

@@ -13,8 +13,10 @@ import android.widget.LinearLayout;
import android.widget.TextView; import android.widget.TextView;
import org.joinmastodon.android.R; import org.joinmastodon.android.R;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.fragments.IsOnTop; import org.joinmastodon.android.fragments.IsOnTop;
import org.joinmastodon.android.fragments.ScrollableToTop; import org.joinmastodon.android.fragments.ScrollableToTop;
import org.joinmastodon.android.model.Instance;
import org.joinmastodon.android.model.SearchResult; import org.joinmastodon.android.model.SearchResult;
import org.joinmastodon.android.ui.OutlineProviders; import org.joinmastodon.android.ui.OutlineProviders;
import org.joinmastodon.android.ui.SimpleViewHolder; import org.joinmastodon.android.ui.SimpleViewHolder;
@@ -155,7 +157,7 @@ public class DiscoverFragment extends AppKitFragment implements ScrollableToTop,
} }
}); });
disableDiscover=getArguments().getBoolean("disableDiscover"); disableDiscover=AccountSessionManager.get(accountID).getInstance().map(Instance::isAkkoma).orElse(false);
searchView=view.findViewById(R.id.search_fragment); searchView=view.findViewById(R.id.search_fragment);
if(searchFragment==null){ if(searchFragment==null){
searchFragment=new SearchFragment(); searchFragment=new SearchFragment();

View File

@@ -36,6 +36,7 @@ import java.util.stream.Collectors;
import me.grishka.appkit.Nav; import me.grishka.appkit.Nav;
import me.grishka.appkit.api.Callback; import me.grishka.appkit.api.Callback;
import me.grishka.appkit.api.ErrorResponse; import me.grishka.appkit.api.ErrorResponse;
import me.grishka.appkit.api.SimpleCallback;
import me.grishka.appkit.utils.V; import me.grishka.appkit.utils.V;
public class SearchFragment extends BaseStatusListFragment<SearchResult>{ public class SearchFragment extends BaseStatusListFragment<SearchResult>{
@@ -142,7 +143,7 @@ public class SearchFragment extends BaseStatusListFragment<SearchResult>{
}*/ }*/
int offset=_offset; int offset=_offset;
currentRequest=new GetSearchResults(currentQuery, type, type==null, maxID, offset, type==null ? 0 : count) currentRequest=new GetSearchResults(currentQuery, type, type==null, maxID, offset, type==null ? 0 : count)
.setCallback(new Callback<>(){ .setCallback(new SimpleCallback<>(this){
@Override @Override
public void onSuccess(SearchResults result){ public void onSuccess(SearchResults result){
ArrayList<SearchResult> results=new ArrayList<>(); ArrayList<SearchResult> results=new ArrayList<>();
@@ -165,16 +166,8 @@ public class SearchFragment extends BaseStatusListFragment<SearchResult>{
unfilteredResults=results; unfilteredResults=results;
onDataLoaded(filterSearchResults(results), type!=null && !results.isEmpty()); onDataLoaded(filterSearchResults(results), type!=null && !results.isEmpty());
} }
@Override
public void onError(ErrorResponse error){
currentRequest=null;
Activity a=getActivity();
if(a==null)
return;
error.showToast(a);
}
}) })
.setTimeout(180000) // 3 minutes (searches can take a long time)
.exec(accountID); .exec(accountID);
} }

View File

@@ -115,7 +115,7 @@ public class SearchQueryFragment extends MastodonRecyclerFragment<SearchResultVi
onDataLoaded(results.stream().map(sr->{ onDataLoaded(results.stream().map(sr->{
SearchResultViewModel vm=new SearchResultViewModel(sr, accountID, true); SearchResultViewModel vm=new SearchResultViewModel(sr, accountID, true);
if(sr.type==SearchResult.Type.HASHTAG){ if(sr.type==SearchResult.Type.HASHTAG){
vm.hashtagItem.onClick=()->openHashtag(sr); vm.hashtagItem.setOnClick(i->openHashtag(sr));
} }
return vm; return vm;
}).collect(Collectors.toList()), false); }).collect(Collectors.toList()), false);
@@ -132,7 +132,7 @@ public class SearchQueryFragment extends MastodonRecyclerFragment<SearchResultVi
.map(sr->{ .map(sr->{
SearchResultViewModel vm=new SearchResultViewModel(sr, accountID, false); SearchResultViewModel vm=new SearchResultViewModel(sr, accountID, false);
if(sr.type==SearchResult.Type.HASHTAG){ if(sr.type==SearchResult.Type.HASHTAG){
vm.hashtagItem.onClick=()->openHashtag(sr); vm.hashtagItem.setOnClick(i->openHashtag(sr));
} }
return vm; return vm;
}) })
@@ -429,11 +429,11 @@ public class SearchQueryFragment extends MastodonRecyclerFragment<SearchResultVi
wrapSuicideDialog(()->deliverResult(currentQuery, null)); wrapSuicideDialog(()->deliverResult(currentQuery, null));
} }
private void onOpenURLClick(){ private void onOpenURLClick(ListItem<?> item_){
UiUtils.openURL(getContext(), accountID, searchViewHelper.getQuery(), false); UiUtils.openURL(getContext(), accountID, searchViewHelper.getQuery(), false);
} }
private void onGoToHashtagClick(){ private void onGoToHashtagClick(ListItem<?> item_){
wrapSuicideDialog(()->{ wrapSuicideDialog(()->{
String q=searchViewHelper.getQuery(); String q=searchViewHelper.getQuery();
if(q.startsWith("#")) if(q.startsWith("#"))
@@ -442,7 +442,7 @@ public class SearchQueryFragment extends MastodonRecyclerFragment<SearchResultVi
}); });
} }
private void onGoToAccountClick(){ private void onGoToAccountClick(ListItem<?> item_){
String q=searchViewHelper.getQuery(); String q=searchViewHelper.getQuery();
if(!q.startsWith("@")){ if(!q.startsWith("@")){
q="@"+q; q="@"+q;
@@ -459,11 +459,11 @@ public class SearchQueryFragment extends MastodonRecyclerFragment<SearchResultVi
}).ifPresent(progress -> progress.wrapProgress((Activity) getContext(), R.string.loading, true)); }).ifPresent(progress -> progress.wrapProgress((Activity) getContext(), R.string.loading, true));
} }
private void onGoToStatusSearchClick(){ private void onGoToStatusSearchClick(ListItem<?> item_){
wrapSuicideDialog(()->deliverResult(searchViewHelper.getQuery(), SearchResult.Type.STATUS)); wrapSuicideDialog(()->deliverResult(searchViewHelper.getQuery(), SearchResult.Type.STATUS));
} }
private void onGoToAccountSearchClick(){ private void onGoToAccountSearchClick(ListItem<?> item_){
wrapSuicideDialog(()->deliverResult(searchViewHelper.getQuery(), SearchResult.Type.ACCOUNT)); wrapSuicideDialog(()->deliverResult(searchViewHelper.getQuery(), SearchResult.Type.ACCOUNT));
} }

View File

@@ -3,7 +3,6 @@ package org.joinmastodon.android.fragments.onboarding;
import android.app.Activity; import android.app.Activity;
import android.content.Intent; import android.content.Intent;
import android.net.Uri; import android.net.Uri;
import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;

View File

@@ -34,7 +34,6 @@ import me.grishka.appkit.api.Callback;
import me.grishka.appkit.api.ErrorResponse; import me.grishka.appkit.api.ErrorResponse;
import me.grishka.appkit.imageloader.ViewImageLoader; import me.grishka.appkit.imageloader.ViewImageLoader;
import me.grishka.appkit.imageloader.requests.UrlImageLoaderRequest; import me.grishka.appkit.imageloader.requests.UrlImageLoaderRequest;
import me.grishka.appkit.utils.CubicBezierInterpolator;
import me.grishka.appkit.utils.V; import me.grishka.appkit.utils.V;
public class ReportDoneFragment extends MastodonToolbarFragment{ public class ReportDoneFragment extends MastodonToolbarFragment{

View File

@@ -73,7 +73,7 @@ public class EditFilterFragment extends BaseSettingsFragment<Void> implements On
durationItem=new ListItem<>(R.string.settings_filter_duration, 0, this::onDurationClick), durationItem=new ListItem<>(R.string.settings_filter_duration, 0, this::onDurationClick),
wordsItem=new ListItem<>(R.string.settings_filter_muted_words, 0, this::onWordsClick), wordsItem=new ListItem<>(R.string.settings_filter_muted_words, 0, this::onWordsClick),
contextItem=new ListItem<>(R.string.settings_filter_context, 0, this::onContextClick), contextItem=new ListItem<>(R.string.settings_filter_context, 0, this::onContextClick),
cwItem=new CheckableListItem<>(R.string.settings_filter_show_cw, R.string.settings_filter_show_cw_explanation, CheckableListItem.Style.SWITCH, filter==null || filter.filterAction==FilterAction.WARN, ()->toggleCheckableItem(cwItem)) cwItem=new CheckableListItem<>(R.string.settings_filter_show_cw, R.string.settings_filter_show_cw_explanation, CheckableListItem.Style.SWITCH, filter==null || filter.filterAction==FilterAction.WARN, this::toggleCheckableItem)
)); ));
if(filter!=null){ if(filter!=null){
@@ -113,7 +113,7 @@ public class EditFilterFragment extends BaseSettingsFragment<Void> implements On
return 1; return 1;
} }
private void onDurationClick(){ private void onDurationClick(ListItem<Void> item_){
int[] durationOptions={ int[] durationOptions={
1800, 1800,
3600, 3600,
@@ -182,21 +182,21 @@ public class EditFilterFragment extends BaseSettingsFragment<Void> implements On
alert.setOnDismissListener(dialog->callback.accept(null)); alert.setOnDismissListener(dialog->callback.accept(null));
} }
private void onWordsClick(){ private void onWordsClick(ListItem<Void> item){
Bundle args=new Bundle(); Bundle args=new Bundle();
args.putString("account", accountID); args.putString("account", accountID);
args.putParcelableArrayList("words", (ArrayList<? extends Parcelable>) keywords.stream().map(Parcels::wrap).collect(Collectors.toCollection(ArrayList::new))); args.putParcelableArrayList("words", (ArrayList<? extends Parcelable>) keywords.stream().map(Parcels::wrap).collect(Collectors.toCollection(ArrayList::new)));
Nav.goForResult(getActivity(), FilterWordsFragment.class, args, WORDS_RESULT, this); Nav.goForResult(getActivity(), FilterWordsFragment.class, args, WORDS_RESULT, this);
} }
private void onContextClick(){ private void onContextClick(ListItem<Void> item){
Bundle args=new Bundle(); Bundle args=new Bundle();
args.putString("account", accountID); args.putString("account", accountID);
args.putSerializable("context", context); args.putSerializable("context", context);
Nav.goForResult(getActivity(), FilterContextFragment.class, args, CONTEXT_RESULT, this); Nav.goForResult(getActivity(), FilterContextFragment.class, args, CONTEXT_RESULT, this);
} }
private void onDeleteClick(){ private void onDeleteClick(ListItem<Void> item_){
AlertDialog alert=new M3AlertDialogBuilder(getActivity()) AlertDialog alert=new M3AlertDialogBuilder(getActivity())
.setTitle(getString(R.string.settings_delete_filter_title, filter.title)) .setTitle(getString(R.string.settings_delete_filter_title, filter.title))
.setMessage(R.string.settings_delete_filter_confirmation) .setMessage(R.string.settings_delete_filter_confirmation)

View File

@@ -22,10 +22,9 @@ public class FilterContextFragment extends BaseSettingsFragment<FilterContext> i
setTitle(R.string.settings_filter_context); setTitle(R.string.settings_filter_context);
context=(EnumSet<FilterContext>) getArguments().getSerializable("context"); context=(EnumSet<FilterContext>) getArguments().getSerializable("context");
onDataLoaded(Arrays.stream(FilterContext.values()).map(c->{ onDataLoaded(Arrays.stream(FilterContext.values()).map(c->{
CheckableListItem<FilterContext> item=new CheckableListItem<>(c.getDisplayNameRes(), 0, CheckableListItem.Style.CHECKBOX, context.contains(c), null); CheckableListItem<FilterContext> item=new CheckableListItem<>(c.getDisplayNameRes(), 0, CheckableListItem.Style.CHECKBOX, context.contains(c), this::toggleCheckableItem);
item.parentObject=c; item.parentObject=c;
item.isEnabled=true; item.isEnabled=true;
item.onClick=()->toggleCheckableItem(item);
return item; return item;
}).collect(Collectors.toList())); }).collect(Collectors.toList()));
} }

View File

@@ -1,11 +1,6 @@
package org.joinmastodon.android.fragments.settings; package org.joinmastodon.android.fragments.settings;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.IntEvaluator;
import android.animation.ObjectAnimator;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.graphics.drawable.Drawable;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.os.Parcelable; import android.os.Parcelable;
@@ -27,6 +22,7 @@ import org.joinmastodon.android.model.FilterKeyword;
import org.joinmastodon.android.model.viewmodel.CheckableListItem; import org.joinmastodon.android.model.viewmodel.CheckableListItem;
import org.joinmastodon.android.model.viewmodel.ListItem; import org.joinmastodon.android.model.viewmodel.ListItem;
import org.joinmastodon.android.ui.M3AlertDialogBuilder; import org.joinmastodon.android.ui.M3AlertDialogBuilder;
import org.joinmastodon.android.ui.utils.ActionModeHelper;
import org.joinmastodon.android.ui.utils.SimpleTextWatcher; import org.joinmastodon.android.ui.utils.SimpleTextWatcher;
import org.joinmastodon.android.ui.utils.UiUtils; import org.joinmastodon.android.ui.utils.UiUtils;
import org.joinmastodon.android.ui.views.FloatingHintEditTextLayout; import org.joinmastodon.android.ui.views.FloatingHintEditTextLayout;
@@ -37,7 +33,6 @@ import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import me.grishka.appkit.FragmentStackActivity;
import me.grishka.appkit.fragments.OnBackPressedListener; import me.grishka.appkit.fragments.OnBackPressedListener;
import me.grishka.appkit.utils.V; import me.grishka.appkit.utils.V;
@@ -60,7 +55,7 @@ public class FilterWordsFragment extends BaseSettingsFragment<FilterKeyword> imp
FilterKeyword word=Parcels.unwrap(p); FilterKeyword word=Parcels.unwrap(p);
ListItem<FilterKeyword> item=new ListItem<>(word.keyword, null, null, word); ListItem<FilterKeyword> item=new ListItem<>(word.keyword, null, null, word);
item.isEnabled=true; item.isEnabled=true;
item.onClick=()->onWordClick(item); item.setOnClick(this::onWordClick);
return item; return item;
}).collect(Collectors.toList())); }).collect(Collectors.toList()));
setHasOptionsMenu(true); setHasOptionsMenu(true);
@@ -114,7 +109,7 @@ public class FilterWordsFragment extends BaseSettingsFragment<FilterKeyword> imp
@Override @Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater){ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater){
inflater.inflate(R.menu.settings_filter_words, menu); inflater.inflate(R.menu.selectable_list, menu);
} }
@Override @Override
@@ -174,7 +169,7 @@ public class FilterWordsFragment extends BaseSettingsFragment<FilterKeyword> imp
w.keyword=input; w.keyword=input;
ListItem<FilterKeyword> item=new ListItem<>(w.keyword, null, null, w); ListItem<FilterKeyword> item=new ListItem<>(w.keyword, null, null, w);
item.isEnabled=true; item.isEnabled=true;
item.onClick=()->onWordClick(item); item.setOnClick(this::onWordClick);
data.add(item); data.add(item);
itemsAdapter.notifyItemInserted(data.size()-1); itemsAdapter.notifyItemInserted(data.size()-1);
}else{ }else{
@@ -228,29 +223,15 @@ public class FilterWordsFragment extends BaseSettingsFragment<FilterKeyword> imp
return; return;
V.setVisibilityAnimated(fab, View.GONE); V.setVisibilityAnimated(fab, View.GONE);
actionMode=getActivity().startActionMode(new ActionMode.Callback(){ actionMode=ActionModeHelper.startActionMode(this, ()->elevationOnScrollListener.getCurrentStatusBarColor(), new ActionMode.Callback(){
@Override @Override
public boolean onCreateActionMode(ActionMode mode, Menu menu){ public boolean onCreateActionMode(ActionMode mode, Menu menu){
ObjectAnimator anim=ObjectAnimator.ofInt(getActivity().getWindow(), "statusBarColor", elevationOnScrollListener.getCurrentStatusBarColor(), UiUtils.getThemeColor(getActivity(), R.attr.colorM3Primary));
anim.setEvaluator(new IntEvaluator(){
@Override
public Integer evaluate(float fraction, Integer startValue, Integer endValue){
return UiUtils.alphaBlendColors(startValue, endValue, fraction);
}
});
anim.start();
((FragmentStackActivity) getActivity()).invalidateSystemBarColors(FilterWordsFragment.this);
return true; return true;
} }
@Override @Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu){ public boolean onPrepareActionMode(ActionMode mode, Menu menu){
mode.getMenuInflater().inflate(R.menu.settings_filter_words_action_mode, menu); mode.getMenuInflater().inflate(R.menu.settings_filter_words_action_mode, menu);
for(int i=0;i<menu.size();i++){
Drawable icon=menu.getItem(i).getIcon().mutate();
icon.setTint(UiUtils.getThemeColor(getActivity(), R.attr.colorM3OnPrimary));
menu.getItem(i).setIcon(icon);
}
deleteItem=menu.findItem(R.id.delete); deleteItem=menu.findItem(R.id.delete);
return true; return true;
} }
@@ -266,21 +247,6 @@ public class FilterWordsFragment extends BaseSettingsFragment<FilterKeyword> imp
@Override @Override
public void onDestroyActionMode(ActionMode mode){ public void onDestroyActionMode(ActionMode mode){
leaveSelectionMode(true); leaveSelectionMode(true);
ObjectAnimator anim=ObjectAnimator.ofInt(getActivity().getWindow(), "statusBarColor", UiUtils.getThemeColor(getActivity(), R.attr.colorM3Primary), elevationOnScrollListener.getCurrentStatusBarColor());
anim.setEvaluator(new IntEvaluator(){
@Override
public Integer evaluate(float fraction, Integer startValue, Integer endValue){
return UiUtils.alphaBlendColors(startValue, endValue, fraction);
}
});
anim.addListener(new AnimatorListenerAdapter(){
@Override
public void onAnimationEnd(Animator animation){
getActivity().getWindow().setStatusBarColor(0);
}
});
anim.start();
((FragmentStackActivity) getActivity()).invalidateSystemBarColors(FilterWordsFragment.this);
} }
}); });
@@ -289,7 +255,7 @@ public class FilterWordsFragment extends BaseSettingsFragment<FilterKeyword> imp
ListItem<FilterKeyword> item=data.get(i); ListItem<FilterKeyword> item=data.get(i);
CheckableListItem<FilterKeyword> newItem=new CheckableListItem<>(item.title, null, CheckableListItem.Style.CHECKBOX, selectAll, null); CheckableListItem<FilterKeyword> newItem=new CheckableListItem<>(item.title, null, CheckableListItem.Style.CHECKBOX, selectAll, null);
newItem.isEnabled=true; newItem.isEnabled=true;
newItem.onClick=()->onSelectionModeWordClick(newItem); newItem.setOnClick(this::onSelectionModeWordClick);
newItem.parentObject=item.parentObject; newItem.parentObject=item.parentObject;
if(selectAll) if(selectAll)
selectedItems.add(newItem); selectedItems.add(newItem);
@@ -313,7 +279,7 @@ public class FilterWordsFragment extends BaseSettingsFragment<FilterKeyword> imp
ListItem<FilterKeyword> item=data.get(i); ListItem<FilterKeyword> item=data.get(i);
ListItem<FilterKeyword> newItem=new ListItem<>(item.title, null, null); ListItem<FilterKeyword> newItem=new ListItem<>(item.title, null, null);
newItem.isEnabled=true; newItem.isEnabled=true;
newItem.onClick=()->onWordClick(newItem); newItem.setOnClick(this::onWordClick);
newItem.parentObject=item.parentObject; newItem.parentObject=item.parentObject;
data.set(i, newItem); data.set(i, newItem);
} }

View File

@@ -16,7 +16,6 @@ import org.joinmastodon.android.model.viewmodel.ListItem;
import org.joinmastodon.android.ui.utils.UiUtils; import org.joinmastodon.android.ui.utils.UiUtils;
import java.util.List; import java.util.List;
import java.util.Objects;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import me.grishka.appkit.imageloader.ImageCache; import me.grishka.appkit.imageloader.ImageCache;
@@ -26,23 +25,32 @@ import me.grishka.appkit.utils.V;
public class SettingsAboutAppFragment extends BaseSettingsFragment<Void>{ public class SettingsAboutAppFragment extends BaseSettingsFragment<Void>{
private ListItem<Void> mediaCacheItem; private ListItem<Void> mediaCacheItem;
private AccountSession session;
private boolean timelineCacheCleared=false;
@Override @Override
public void onCreate(Bundle savedInstanceState){ public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setTitle(getString(R.string.about_app, getString(R.string.sk_app_name))); setTitle(getString(R.string.about_app, getString(R.string.sk_app_name)));
AccountSession s=AccountSessionManager.get(accountID); session=AccountSessionManager.get(accountID);
onDataLoaded(List.of( onDataLoaded(List.of(
new ListItem<>(R.string.sk_settings_donate, 0, R.drawable.ic_fluent_heart_24_regular, ()->UiUtils.openHashtagTimeline(getActivity(), accountID, getString(R.string.donate_hashtag))), new ListItem<>(R.string.sk_settings_donate, 0, R.drawable.ic_fluent_heart_24_regular, i->UiUtils.openHashtagTimeline(getActivity(), accountID, getString(R.string.donate_hashtag))),
new ListItem<>(R.string.sk_settings_contribute, 0, R.drawable.ic_fluent_open_24_regular, ()->UiUtils.launchWebBrowser(getActivity(), getString(R.string.repo_url))), new ListItem<>(R.string.sk_settings_contribute, 0, R.drawable.ic_fluent_open_24_regular, i->UiUtils.launchWebBrowser(getActivity(), getString(R.string.repo_url))),
new ListItem<>(R.string.settings_tos, 0, R.drawable.ic_fluent_open_24_regular, ()->UiUtils.launchWebBrowser(getActivity(), "https://"+s.domain+"/terms")), new ListItem<>(R.string.settings_tos, 0, R.drawable.ic_fluent_open_24_regular, i->UiUtils.launchWebBrowser(getActivity(), "https://"+session.domain+"/terms")),
new ListItem<>(R.string.settings_privacy_policy, 0, R.drawable.ic_fluent_open_24_regular, ()->UiUtils.launchWebBrowser(getActivity(), getString(R.string.privacy_policy_url)), 0, true), new ListItem<>(R.string.settings_privacy_policy, 0, R.drawable.ic_fluent_open_24_regular, i->UiUtils.launchWebBrowser(getActivity(), getString(R.string.privacy_policy_url)), 0, true),
mediaCacheItem=new ListItem<>(R.string.settings_clear_cache, 0, this::onClearMediaCacheClick) mediaCacheItem=new ListItem<>(R.string.settings_clear_cache, 0, this::onClearMediaCacheClick),
new ListItem<>(getString(R.string.sk_settings_clear_timeline_cache), session.domain, this::onClearTimelineCacheClick)
)); ));
updateMediaCacheItem(); updateMediaCacheItem();
} }
@Override
protected void onHidden(){
super.onHidden();
if(timelineCacheCleared) getActivity().recreate();
}
@Override @Override
protected void doLoadData(int offset, int count){} protected void doLoadData(int offset, int count){}
@@ -63,7 +71,7 @@ public class SettingsAboutAppFragment extends BaseSettingsFragment<Void>{
return adapter; return adapter;
} }
private void onClearMediaCacheClick(){ private void onClearMediaCacheClick(ListItem<?> item){
MastodonAPIController.runInBackground(()->{ MastodonAPIController.runInBackground(()->{
Activity activity=getActivity(); Activity activity=getActivity();
ImageCache.getInstance(getActivity()).clear(); ImageCache.getInstance(getActivity()).clear();
@@ -74,6 +82,12 @@ public class SettingsAboutAppFragment extends BaseSettingsFragment<Void>{
}); });
} }
private void onClearTimelineCacheClick(ListItem<?> item){
session.getCacheController().putHomeTimeline(List.of(), true);
Toast.makeText(getContext(), R.string.sk_timeline_cache_cleared, Toast.LENGTH_SHORT).show();
timelineCacheCleared=true;
}
private void updateMediaCacheItem(){ private void updateMediaCacheItem(){
long size=ImageCache.getInstance(getActivity()).getDiskCache().size(); long size=ImageCache.getInstance(getActivity()).getDiskCache().size();
mediaCacheItem.subtitle=UiUtils.formatFileSize(getActivity(), size, false); mediaCacheItem.subtitle=UiUtils.formatFileSize(getActivity(), size, false);

View File

@@ -46,20 +46,20 @@ public class SettingsBehaviorFragment extends BaseSettingsFragment<Void> impleme
List<ListItem<Void>> items = new ArrayList<>(List.of( List<ListItem<Void>> items = new ArrayList<>(List.of(
languageItem=new ListItem<>(getString(R.string.default_post_language), postLanguage!=null ? postLanguage.getDisplayName(getContext()) : null, R.drawable.ic_fluent_local_language_24_regular, this::onDefaultLanguageClick), languageItem=new ListItem<>(getString(R.string.default_post_language), postLanguage!=null ? postLanguage.getDisplayName(getContext()) : null, R.drawable.ic_fluent_local_language_24_regular, this::onDefaultLanguageClick),
altTextItem=new CheckableListItem<>(R.string.settings_alt_text_reminders, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.altTextReminders, R.drawable.ic_fluent_image_alt_text_24_regular, ()->toggleCheckableItem(altTextItem)), altTextItem=new CheckableListItem<>(R.string.settings_alt_text_reminders, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.altTextReminders, R.drawable.ic_fluent_image_alt_text_24_regular, i->toggleCheckableItem(altTextItem)),
playGifsItem=new CheckableListItem<>(R.string.settings_gif, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.playGifs, R.drawable.ic_fluent_gif_24_regular, ()->toggleCheckableItem(playGifsItem)), playGifsItem=new CheckableListItem<>(R.string.settings_gif, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.playGifs, R.drawable.ic_fluent_gif_24_regular, i->toggleCheckableItem(playGifsItem)),
overlayMediaItem=new CheckableListItem<>(R.string.sk_settings_continues_playback, R.string.sk_settings_continues_playback_summary, CheckableListItem.Style.SWITCH, GlobalUserPreferences.overlayMedia, R.drawable.ic_fluent_play_circle_hint_24_regular, ()->toggleCheckableItem(overlayMediaItem)), overlayMediaItem=new CheckableListItem<>(R.string.sk_settings_continues_playback, R.string.sk_settings_continues_playback_summary, CheckableListItem.Style.SWITCH, GlobalUserPreferences.overlayMedia, R.drawable.ic_fluent_play_circle_hint_24_regular, i->toggleCheckableItem(overlayMediaItem)),
customTabsItem=new CheckableListItem<>(R.string.settings_custom_tabs, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.useCustomTabs, R.drawable.ic_fluent_link_24_regular, ()->toggleCheckableItem(customTabsItem)), customTabsItem=new CheckableListItem<>(R.string.settings_custom_tabs, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.useCustomTabs, R.drawable.ic_fluent_link_24_regular, i->toggleCheckableItem(customTabsItem)),
confirmUnfollowItem=new CheckableListItem<>(R.string.settings_confirm_unfollow, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.confirmUnfollow, R.drawable.ic_fluent_person_delete_24_regular, ()->toggleCheckableItem(confirmUnfollowItem)), confirmUnfollowItem=new CheckableListItem<>(R.string.settings_confirm_unfollow, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.confirmUnfollow, R.drawable.ic_fluent_person_delete_24_regular, i->toggleCheckableItem(confirmUnfollowItem)),
confirmBoostItem=new CheckableListItem<>(R.string.settings_confirm_boost, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.confirmBoost, R.drawable.ic_fluent_arrow_repeat_all_24_regular, ()->toggleCheckableItem(confirmBoostItem)), confirmBoostItem=new CheckableListItem<>(R.string.settings_confirm_boost, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.confirmBoost, R.drawable.ic_fluent_arrow_repeat_all_24_regular, i->toggleCheckableItem(confirmBoostItem)),
confirmDeleteItem=new CheckableListItem<>(R.string.settings_confirm_delete_post, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.confirmDeletePost, R.drawable.ic_fluent_delete_24_regular, ()->toggleCheckableItem(confirmDeleteItem)), confirmDeleteItem=new CheckableListItem<>(R.string.settings_confirm_delete_post, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.confirmDeletePost, R.drawable.ic_fluent_delete_24_regular, i->toggleCheckableItem(confirmDeleteItem)),
prefixRepliesItem=new ListItem<>(R.string.sk_settings_prefix_reply_cw_with_re, getPrefixWithRepliesString(), R.drawable.ic_fluent_arrow_reply_24_regular, this::onPrefixRepliesClick), prefixRepliesItem=new ListItem<>(R.string.sk_settings_prefix_reply_cw_with_re, getPrefixWithRepliesString(), R.drawable.ic_fluent_arrow_reply_24_regular, this::onPrefixRepliesClick),
forwardReportsItem=new CheckableListItem<>(R.string.sk_settings_forward_report_default, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.forwardReportDefault, R.drawable.ic_fluent_arrow_forward_24_regular, ()->toggleCheckableItem(forwardReportsItem)), forwardReportsItem=new CheckableListItem<>(R.string.sk_settings_forward_report_default, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.forwardReportDefault, R.drawable.ic_fluent_arrow_forward_24_regular, i->toggleCheckableItem(forwardReportsItem)),
loadNewPostsItem=new CheckableListItem<>(R.string.sk_settings_load_new_posts, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.loadNewPosts, R.drawable.ic_fluent_arrow_sync_24_regular, this::onLoadNewPostsClick), loadNewPostsItem=new CheckableListItem<>(R.string.sk_settings_load_new_posts, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.loadNewPosts, R.drawable.ic_fluent_arrow_sync_24_regular, i->onLoadNewPostsClick()),
seeNewPostsBtnItem=new CheckableListItem<>(R.string.sk_settings_see_new_posts_button, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.showNewPostsButton, R.drawable.ic_fluent_arrow_up_24_regular, ()->toggleCheckableItem(seeNewPostsBtnItem)), seeNewPostsBtnItem=new CheckableListItem<>(R.string.sk_settings_see_new_posts_button, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.showNewPostsButton, R.drawable.ic_fluent_arrow_up_24_regular, i->toggleCheckableItem(seeNewPostsBtnItem)),
remoteLoadingItem=new CheckableListItem<>(R.string.sk_settings_allow_remote_loading, R.string.sk_settings_allow_remote_loading_explanation, CheckableListItem.Style.SWITCH, GlobalUserPreferences.allowRemoteLoading, R.drawable.ic_fluent_communication_24_regular, ()->toggleCheckableItem(remoteLoadingItem), true), remoteLoadingItem=new CheckableListItem<>(R.string.sk_settings_allow_remote_loading, R.string.sk_settings_allow_remote_loading_explanation, CheckableListItem.Style.SWITCH, GlobalUserPreferences.allowRemoteLoading, R.drawable.ic_fluent_communication_24_regular, i->toggleCheckableItem(remoteLoadingItem), true),
showBoostsItem=new CheckableListItem<>(R.string.sk_settings_show_boosts, 0, CheckableListItem.Style.SWITCH, lp.showBoosts, R.drawable.ic_fluent_arrow_repeat_all_24_regular, ()->toggleCheckableItem(showBoostsItem)), showBoostsItem=new CheckableListItem<>(R.string.sk_settings_show_boosts, 0, CheckableListItem.Style.SWITCH, lp.showBoosts, R.drawable.ic_fluent_arrow_repeat_all_24_regular, i->toggleCheckableItem(showBoostsItem)),
showRepliesItem=new CheckableListItem<>(R.string.sk_settings_show_replies, 0, CheckableListItem.Style.SWITCH, lp.showReplies, R.drawable.ic_fluent_arrow_reply_24_regular, ()->toggleCheckableItem(showRepliesItem)) showRepliesItem=new CheckableListItem<>(R.string.sk_settings_show_replies, 0, CheckableListItem.Style.SWITCH, lp.showReplies, R.drawable.ic_fluent_arrow_reply_24_regular, i->toggleCheckableItem(showRepliesItem))
)); ));
if(isInstanceAkkoma()) items.add( if(isInstanceAkkoma()) items.add(
@@ -93,7 +93,7 @@ public class SettingsBehaviorFragment extends BaseSettingsFragment<Void> impleme
@Override @Override
protected void doLoadData(int offset, int count){} protected void doLoadData(int offset, int count){}
private void onDefaultLanguageClick(){ private void onDefaultLanguageClick(ListItem<?> item){
if (languageResolver == null) return; if (languageResolver == null) return;
ComposeLanguageAlertViewController vc=new ComposeLanguageAlertViewController(getActivity(), null, new ComposeLanguageAlertViewController.SelectedOption(postLanguage), null, languageResolver); ComposeLanguageAlertViewController vc=new ComposeLanguageAlertViewController(getActivity(), null, new ComposeLanguageAlertViewController.SelectedOption(postLanguage), null, languageResolver);
new M3AlertDialogBuilder(getActivity()) new M3AlertDialogBuilder(getActivity())
@@ -112,14 +112,14 @@ public class SettingsBehaviorFragment extends BaseSettingsFragment<Void> impleme
.show(); .show();
} }
private void onPrefixRepliesClick(){ private void onPrefixRepliesClick(ListItem<?> item){
int selected=GlobalUserPreferences.prefixReplies.ordinal(); int selected=GlobalUserPreferences.prefixReplies.ordinal();
int[] newSelected={selected}; int[] newSelected={selected};
new M3AlertDialogBuilder(getActivity()) new M3AlertDialogBuilder(getActivity())
.setTitle(R.string.sk_settings_prefix_reply_cw_with_re) .setTitle(R.string.sk_settings_prefix_reply_cw_with_re)
.setSingleChoiceItems((String[]) IntStream.of(R.string.sk_settings_prefix_replies_never, R.string.sk_settings_prefix_replies_always, R.string.sk_settings_prefix_replies_to_others).mapToObj(this::getString).toArray(String[]::new), .setSingleChoiceItems((String[]) IntStream.of(R.string.sk_settings_prefix_replies_never, R.string.sk_settings_prefix_replies_always, R.string.sk_settings_prefix_replies_to_others).mapToObj(this::getString).toArray(String[]::new),
selected, (dlg, item)->newSelected[0]=item) selected, (dlg, which)->newSelected[0]=which)
.setPositiveButton(R.string.ok, (dlg, item)->{ .setPositiveButton(R.string.ok, (dlg, which)->{
GlobalUserPreferences.prefixReplies=GlobalUserPreferences.PrefixRepliesMode.values()[newSelected[0]]; GlobalUserPreferences.prefixReplies=GlobalUserPreferences.PrefixRepliesMode.values()[newSelected[0]];
prefixRepliesItem.subtitleRes=getPrefixWithRepliesString(); prefixRepliesItem.subtitleRes=getPrefixWithRepliesString();
rebindItem(prefixRepliesItem); rebindItem(prefixRepliesItem);
@@ -128,7 +128,7 @@ public class SettingsBehaviorFragment extends BaseSettingsFragment<Void> impleme
.show(); .show();
} }
private void onReplyVisibilityClick(){ private void onReplyVisibilityClick(ListItem<?> item){
AccountLocalPreferences lp=getLocalPrefs(); AccountLocalPreferences lp=getLocalPrefs();
int selected=lp.timelineReplyVisibility==null ? 2 : switch(lp.timelineReplyVisibility){ int selected=lp.timelineReplyVisibility==null ? 2 : switch(lp.timelineReplyVisibility){
case "following" -> 0; case "following" -> 0;
@@ -139,8 +139,8 @@ public class SettingsBehaviorFragment extends BaseSettingsFragment<Void> impleme
new M3AlertDialogBuilder(getActivity()) new M3AlertDialogBuilder(getActivity())
.setTitle(R.string.sk_settings_prefix_reply_cw_with_re) .setTitle(R.string.sk_settings_prefix_reply_cw_with_re)
.setSingleChoiceItems((String[]) IntStream.of(R.string.sk_settings_reply_visibility_following, R.string.sk_settings_reply_visibility_self, R.string.sk_settings_reply_visibility_all).mapToObj(this::getString).toArray(String[]::new), .setSingleChoiceItems((String[]) IntStream.of(R.string.sk_settings_reply_visibility_following, R.string.sk_settings_reply_visibility_self, R.string.sk_settings_reply_visibility_all).mapToObj(this::getString).toArray(String[]::new),
selected, (dlg, item)->newSelected[0]=item) selected, (dlg, which)->newSelected[0]=which)
.setPositiveButton(R.string.ok, (dlg, item)->{ .setPositiveButton(R.string.ok, (dlg, which)->{
lp.timelineReplyVisibility=switch(newSelected[0]){ lp.timelineReplyVisibility=switch(newSelected[0]){
case 0 -> "following"; case 0 -> "following";
case 1 -> "self"; case 1 -> "self";
@@ -176,6 +176,8 @@ public class SettingsBehaviorFragment extends BaseSettingsFragment<Void> impleme
GlobalUserPreferences.allowRemoteLoading=remoteLoadingItem.checked; GlobalUserPreferences.allowRemoteLoading=remoteLoadingItem.checked;
GlobalUserPreferences.save(); GlobalUserPreferences.save();
AccountLocalPreferences lp=getLocalPrefs(); AccountLocalPreferences lp=getLocalPrefs();
boolean restartPlease=lp.showBoosts!=showBoostsItem.checked
|| lp.showReplies!=showRepliesItem.checked;
lp.showBoosts=showBoostsItem.checked; lp.showBoosts=showBoostsItem.checked;
lp.showReplies=showRepliesItem.checked; lp.showReplies=showRepliesItem.checked;
lp.save(); lp.save();
@@ -186,6 +188,7 @@ public class SettingsBehaviorFragment extends BaseSettingsFragment<Void> impleme
s.preferences.postingDefaultLanguage=newPostLanguage.language.getLanguage(); s.preferences.postingDefaultLanguage=newPostLanguage.language.getLanguage();
s.savePreferencesLater(); s.savePreferencesLater();
} }
if(restartPlease) getActivity().recreate();
} }
@Override @Override

View File

@@ -39,7 +39,7 @@ public class SettingsDebugFragment extends BaseSettingsFragment<Void>{
@Override @Override
protected void doLoadData(int offset, int count){} protected void doLoadData(int offset, int count){}
private void onTestEmailConfirmClick(){ private void onTestEmailConfirmClick(ListItem<?> item){
AccountSession sess=AccountSessionManager.getInstance().getAccount(accountID); AccountSession sess=AccountSessionManager.getInstance().getAccount(accountID);
sess.activated=false; sess.activated=false;
sess.activationInfo=new AccountActivationInfo("test@email", System.currentTimeMillis()); sess.activationInfo=new AccountActivationInfo("test@email", System.currentTimeMillis());
@@ -49,18 +49,18 @@ public class SettingsDebugFragment extends BaseSettingsFragment<Void>{
Nav.goClearingStack(getActivity(), AccountActivationFragment.class, args); Nav.goClearingStack(getActivity(), AccountActivationFragment.class, args);
} }
private void onForceSelfUpdateClick(){ private void onForceSelfUpdateClick(ListItem<?> item){
GithubSelfUpdater.forceUpdate=true; GithubSelfUpdater.forceUpdate=true;
GithubSelfUpdater.getInstance().maybeCheckForUpdates(); GithubSelfUpdater.getInstance().maybeCheckForUpdates();
restartUI(); restartUI();
} }
private void onResetUpdaterClick(){ private void onResetUpdaterClick(ListItem<?> item){
GithubSelfUpdater.getInstance().reset(); GithubSelfUpdater.getInstance().reset();
restartUI(); restartUI();
} }
private void onResetDiscoverBannersClick(){ private void onResetDiscoverBannersClick(ListItem<?> item){
DiscoverInfoBannerHelper.reset(); DiscoverInfoBannerHelper.reset();
restartUI(); restartUI();
} }

View File

@@ -56,29 +56,29 @@ public class SettingsDisplayFragment extends BaseSettingsFragment<Void>{
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<>(getString(R.string.sk_settings_color_palette), getColorPaletteValue(), R.drawable.ic_fluent_color_24_regular, this::onColorClick), colorItem=new ListItem<>(getString(R.string.sk_settings_color_palette), getColorPaletteValue(), R.drawable.ic_fluent_color_24_regular, this::onColorClick),
trueBlackModeItem=new CheckableListItem<>(R.string.sk_settings_true_black, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.trueBlackTheme, R.drawable.ic_fluent_dark_theme_24_regular, this::onTrueBlackModeClick, true), trueBlackModeItem=new CheckableListItem<>(R.string.sk_settings_true_black, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.trueBlackTheme, R.drawable.ic_fluent_dark_theme_24_regular, i->onTrueBlackModeClick(), true),
publishTextItem=new ListItem<>(getString(R.string.sk_settings_publish_button_text), getPublishButtonText(), R.drawable.ic_fluent_send_24_regular, this::onPublishTextClick), publishTextItem=new ListItem<>(getString(R.string.sk_settings_publish_button_text), getPublishButtonText(), R.drawable.ic_fluent_send_24_regular, this::onPublishTextClick),
autoRevealCWsItem=new ListItem<>(R.string.sk_settings_auto_reveal_equal_spoilers, getAutoRevealSpoilersText(), R.drawable.ic_fluent_eye_24_regular, this::onAutoRevealSpoilersClick), autoRevealCWsItem=new ListItem<>(R.string.sk_settings_auto_reveal_equal_spoilers, getAutoRevealSpoilersText(), R.drawable.ic_fluent_eye_24_regular, this::onAutoRevealSpoilersClick),
revealCWsItem=new CheckableListItem<>(R.string.sk_settings_always_reveal_content_warnings, 0, CheckableListItem.Style.SWITCH, lp.revealCWs, R.drawable.ic_fluent_chat_warning_24_regular, ()->toggleCheckableItem(revealCWsItem)), revealCWsItem=new CheckableListItem<>(R.string.sk_settings_always_reveal_content_warnings, 0, CheckableListItem.Style.SWITCH, lp.revealCWs, R.drawable.ic_fluent_chat_warning_24_regular, i->toggleCheckableItem(revealCWsItem)),
hideSensitiveMediaItem=new CheckableListItem<>(R.string.settings_hide_sensitive_media, 0, CheckableListItem.Style.SWITCH, lp.hideSensitiveMedia, R.drawable.ic_fluent_flag_24_regular, ()->toggleCheckableItem(hideSensitiveMediaItem)), hideSensitiveMediaItem=new CheckableListItem<>(R.string.settings_hide_sensitive_media, 0, CheckableListItem.Style.SWITCH, lp.hideSensitiveMedia, R.drawable.ic_fluent_flag_24_regular, i->toggleCheckableItem(hideSensitiveMediaItem)),
interactionCountsItem=new CheckableListItem<>(R.string.settings_show_interaction_counts, 0, CheckableListItem.Style.SWITCH, lp.showInteractionCounts, R.drawable.ic_fluent_number_row_24_regular, ()->toggleCheckableItem(interactionCountsItem)), interactionCountsItem=new CheckableListItem<>(R.string.settings_show_interaction_counts, 0, CheckableListItem.Style.SWITCH, lp.showInteractionCounts, R.drawable.ic_fluent_number_row_24_regular, i->toggleCheckableItem(interactionCountsItem)),
emojiInNamesItem=new CheckableListItem<>(R.string.settings_show_emoji_in_names, 0, CheckableListItem.Style.SWITCH, lp.customEmojiInNames, R.drawable.ic_fluent_emoji_24_regular, ()->toggleCheckableItem(emojiInNamesItem)), emojiInNamesItem=new CheckableListItem<>(R.string.settings_show_emoji_in_names, 0, CheckableListItem.Style.SWITCH, lp.customEmojiInNames, R.drawable.ic_fluent_emoji_24_regular, i->toggleCheckableItem(emojiInNamesItem)),
marqueeItem=new CheckableListItem<>(R.string.sk_settings_enable_marquee, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.toolbarMarquee, R.drawable.ic_fluent_text_more_24_regular, ()->toggleCheckableItem(marqueeItem)), marqueeItem=new CheckableListItem<>(R.string.sk_settings_enable_marquee, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.toolbarMarquee, R.drawable.ic_fluent_text_more_24_regular, i->toggleCheckableItem(marqueeItem)),
reduceMotionItem=new CheckableListItem<>(R.string.sk_settings_reduce_motion, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.reduceMotion, R.drawable.ic_fluent_star_emphasis_24_regular, ()->toggleCheckableItem(reduceMotionItem)), reduceMotionItem=new CheckableListItem<>(R.string.sk_settings_reduce_motion, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.reduceMotion, R.drawable.ic_fluent_star_emphasis_24_regular, i->toggleCheckableItem(reduceMotionItem)),
disableSwipeItem=new CheckableListItem<>(R.string.sk_settings_tabs_disable_swipe, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.disableSwipe, R.drawable.ic_fluent_swipe_right_24_regular, ()->toggleCheckableItem(disableSwipeItem)), disableSwipeItem=new CheckableListItem<>(R.string.sk_settings_tabs_disable_swipe, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.disableSwipe, R.drawable.ic_fluent_swipe_right_24_regular, i->toggleCheckableItem(disableSwipeItem)),
altIndicatorItem=new CheckableListItem<>(R.string.sk_settings_show_alt_indicator, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.showAltIndicator, R.drawable.ic_fluent_scan_text_24_regular, ()->toggleCheckableItem(altIndicatorItem)), altIndicatorItem=new CheckableListItem<>(R.string.sk_settings_show_alt_indicator, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.showAltIndicator, R.drawable.ic_fluent_scan_text_24_regular, i->toggleCheckableItem(altIndicatorItem)),
noAltIndicatorItem=new CheckableListItem<>(R.string.sk_settings_show_no_alt_indicator, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.showNoAltIndicator, R.drawable.ic_fluent_important_24_regular, ()->toggleCheckableItem(noAltIndicatorItem)), noAltIndicatorItem=new CheckableListItem<>(R.string.sk_settings_show_no_alt_indicator, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.showNoAltIndicator, R.drawable.ic_fluent_important_24_regular, i->toggleCheckableItem(noAltIndicatorItem)),
collapsePostsItem=new CheckableListItem<>(R.string.sk_settings_collapse_long_posts, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.collapseLongPosts, R.drawable.ic_fluent_chevron_down_24_regular, ()->toggleCheckableItem(collapsePostsItem)), collapsePostsItem=new CheckableListItem<>(R.string.sk_settings_collapse_long_posts, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.collapseLongPosts, R.drawable.ic_fluent_chevron_down_24_regular, i->toggleCheckableItem(collapsePostsItem)),
spectatorModeItem=new CheckableListItem<>(R.string.sk_settings_hide_interaction, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.spectatorMode, R.drawable.ic_fluent_star_off_24_regular, ()->toggleCheckableItem(spectatorModeItem)), spectatorModeItem=new CheckableListItem<>(R.string.sk_settings_hide_interaction, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.spectatorMode, R.drawable.ic_fluent_star_off_24_regular, i->toggleCheckableItem(spectatorModeItem)),
hideFabItem=new CheckableListItem<>(R.string.sk_settings_hide_fab, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.autoHideFab, R.drawable.ic_fluent_edit_24_regular, ()->toggleCheckableItem(hideFabItem)), hideFabItem=new CheckableListItem<>(R.string.sk_settings_hide_fab, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.autoHideFab, R.drawable.ic_fluent_edit_24_regular, i->toggleCheckableItem(hideFabItem)),
translateOpenedItem=new CheckableListItem<>(R.string.sk_settings_translate_only_opened, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.translateButtonOpenedOnly, R.drawable.ic_fluent_translate_24_regular, ()->toggleCheckableItem(translateOpenedItem)), translateOpenedItem=new CheckableListItem<>(R.string.sk_settings_translate_only_opened, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.translateButtonOpenedOnly, R.drawable.ic_fluent_translate_24_regular, i->toggleCheckableItem(translateOpenedItem)),
likeIconItem=new CheckableListItem<>(R.string.sk_settings_like_icon, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.likeIcon, R.drawable.ic_fluent_heart_24_regular, ()->toggleCheckableItem(likeIconItem)), likeIconItem=new CheckableListItem<>(R.string.sk_settings_like_icon, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.likeIcon, R.drawable.ic_fluent_heart_24_regular, i->toggleCheckableItem(likeIconItem)),
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)), underlinedLinksItem=new CheckableListItem<>(R.string.sk_settings_underlined_links, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.underlinedLinks, R.drawable.ic_fluent_text_underline_24_regular, i->toggleCheckableItem(underlinedLinksItem)),
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, i->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, i->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, i->toggleCheckableItem(pronounsInTimelinesItem)),
pronounsInThreadsItem=new CheckableListItem<>(R.string.sk_settings_display_pronouns_in_threads, 0, CheckableListItem.Style.CHECKBOX, GlobalUserPreferences.displayPronounsInThreads, 0, ()->toggleCheckableItem(pronounsInThreadsItem)), pronounsInThreadsItem=new CheckableListItem<>(R.string.sk_settings_display_pronouns_in_threads, 0, CheckableListItem.Style.CHECKBOX, GlobalUserPreferences.displayPronounsInThreads, 0, i->toggleCheckableItem(pronounsInThreadsItem)),
pronounsInUserListingsItem=new CheckableListItem<>(R.string.sk_settings_display_pronouns_in_user_listings, 0, CheckableListItem.Style.CHECKBOX, GlobalUserPreferences.displayPronounsInUserListings, 0, ()->toggleCheckableItem(pronounsInUserListingsItem)) pronounsInUserListingsItem=new CheckableListItem<>(R.string.sk_settings_display_pronouns_in_user_listings, 0, CheckableListItem.Style.CHECKBOX, GlobalUserPreferences.displayPronounsInUserListings, 0, i->toggleCheckableItem(pronounsInUserListingsItem))
)); ));
trueBlackModeItem.checkedChangeListener=checked->onTrueBlackModeClick(); trueBlackModeItem.checkedChangeListener=checked->onTrueBlackModeClick();
} }
@@ -166,7 +166,7 @@ public class SettingsDisplayFragment extends BaseSettingsFragment<Void>{
maybeApplyNewThemeRightNow(null, null, prev); maybeApplyNewThemeRightNow(null, null, prev);
} }
private void onAppearanceClick(){ private void onAppearanceClick(ListItem<?> item_){
int selected=switch(GlobalUserPreferences.theme){ int selected=switch(GlobalUserPreferences.theme){
case LIGHT -> 0; case LIGHT -> 0;
case DARK -> 1; case DARK -> 1;
@@ -197,7 +197,7 @@ public class SettingsDisplayFragment extends BaseSettingsFragment<Void>{
.show(); .show();
} }
private void onColorClick(){ private void onColorClick(ListItem<?> item_){
boolean multiple=AccountSessionManager.getInstance().getLoggedInAccounts().size() > 1; boolean multiple=AccountSessionManager.getInstance().getLoggedInAccounts().size() > 1;
int indexOffset=multiple ? 1 : 0; int indexOffset=multiple ? 1 : 0;
int selected=lp.color==null ? 0 : lp.color.ordinal() + indexOffset; int selected=lp.color==null ? 0 : lp.color.ordinal() + indexOffset;
@@ -234,7 +234,7 @@ public class SettingsDisplayFragment extends BaseSettingsFragment<Void>{
alert.show(); alert.show();
} }
private void onPublishTextClick(){ private void onPublishTextClick(ListItem<?> item_){
TextInputFrameLayout input = new TextInputFrameLayout( TextInputFrameLayout input = new TextInputFrameLayout(
getContext(), getContext(),
getString(R.string.publish), getString(R.string.publish),
@@ -257,7 +257,7 @@ public class SettingsDisplayFragment extends BaseSettingsFragment<Void>{
.show(); .show();
} }
private void onAutoRevealSpoilersClick(){ private void onAutoRevealSpoilersClick(ListItem<?> item_){
int selected=GlobalUserPreferences.autoRevealEqualSpoilers.ordinal(); int selected=GlobalUserPreferences.autoRevealEqualSpoilers.ordinal();
int[] newSelected={selected}; int[] newSelected={selected};
new M3AlertDialogBuilder(getActivity()) new M3AlertDialogBuilder(getActivity())

View File

@@ -67,16 +67,14 @@ public class SettingsFiltersFragment extends BaseSettingsFragment<Filter>{
Nav.go(getActivity(), EditFilterFragment.class, args); Nav.go(getActivity(), EditFilterFragment.class, args);
} }
private void onAddFilterClick(){ private void onAddFilterClick(ListItem<?> item){
Bundle args=new Bundle(); Bundle args=new Bundle();
args.putString("account", accountID); args.putString("account", accountID);
Nav.go(getActivity(), EditFilterFragment.class, args); Nav.go(getActivity(), EditFilterFragment.class, args);
} }
private ListItem<Filter> makeListItem(Filter f){ private ListItem<Filter> makeListItem(Filter f){
ListItem<Filter> item=new ListItem<>(f.title, getString(f.isActive() ? R.string.filter_active : R.string.filter_inactive), null, f); ListItem<Filter> item=new ListItem<>(f.title, getString(f.isActive() ? R.string.filter_active : R.string.filter_inactive), this::onFilterClick, f);
item.onClick=()->onFilterClick(item);
item.isEnabled=true;
return item; return item;
} }

View File

@@ -19,6 +19,7 @@ import org.joinmastodon.android.ui.utils.UiUtils;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream; import java.util.stream.IntStream;
import me.grishka.appkit.Nav; import me.grishka.appkit.Nav;
@@ -36,15 +37,15 @@ public class SettingsInstanceFragment extends BaseSettingsFragment<Void> impleme
lp=s.getLocalPreferences(); lp=s.getLocalPreferences();
onDataLoaded(List.of( onDataLoaded(List.of(
new ListItem<>(AccountSessionManager.get(accountID).domain, getString(R.string.settings_server_explanation), R.drawable.ic_fluent_server_24_regular, this::onServerClick), new ListItem<>(AccountSessionManager.get(accountID).domain, getString(R.string.settings_server_explanation), R.drawable.ic_fluent_server_24_regular, this::onServerClick),
new ListItem<>(R.string.sk_settings_profile, 0, R.drawable.ic_fluent_open_24_regular, ()->UiUtils.launchWebBrowser(getActivity(), "https://"+s.domain+"/settings/profile")), new ListItem<>(R.string.sk_settings_profile, 0, R.drawable.ic_fluent_open_24_regular, i->UiUtils.launchWebBrowser(getActivity(), "https://"+s.domain+"/settings/profile")),
new ListItem<>(R.string.sk_settings_posting, 0, R.drawable.ic_fluent_open_24_regular, ()->UiUtils.launchWebBrowser(getActivity(), "https://"+s.domain+"/settings/preferences/other")), new ListItem<>(R.string.sk_settings_posting, 0, R.drawable.ic_fluent_open_24_regular, i->UiUtils.launchWebBrowser(getActivity(), "https://"+s.domain+"/settings/preferences/other")),
new ListItem<>(R.string.sk_settings_auth, 0, R.drawable.ic_fluent_open_24_regular, ()->UiUtils.launchWebBrowser(getActivity(), "https://"+s.domain+"/auth/edit"), 0, true), new ListItem<>(R.string.sk_settings_auth, 0, R.drawable.ic_fluent_open_24_regular, i->UiUtils.launchWebBrowser(getActivity(), "https://"+s.domain+"/auth/edit"), 0, true),
contentTypesItem=new CheckableListItem<>(R.string.sk_settings_content_types, R.string.sk_settings_content_types_explanation, CheckableListItem.Style.SWITCH, lp.contentTypesEnabled, R.drawable.ic_fluent_text_edit_style_24_regular, this::onContentTypeClick), contentTypesItem=new CheckableListItem<>(R.string.sk_settings_content_types, R.string.sk_settings_content_types_explanation, CheckableListItem.Style.SWITCH, lp.contentTypesEnabled, R.drawable.ic_fluent_text_edit_style_24_regular, i->onContentTypeClick()),
defaultContentTypeItem=new ListItem<>(R.string.sk_settings_default_content_type, lp.defaultContentType.getName(), R.drawable.ic_fluent_text_bold_24_regular, this::onDefaultContentTypeClick, 0, true), defaultContentTypeItem=new ListItem<>(R.string.sk_settings_default_content_type, lp.defaultContentType.getName(), R.drawable.ic_fluent_text_bold_24_regular, this::onDefaultContentTypeClick, 0, true),
emojiReactionsItem=new CheckableListItem<>(R.string.sk_settings_emoji_reactions, R.string.sk_settings_emoji_reactions_explanation, CheckableListItem.Style.SWITCH, lp.emojiReactionsEnabled, R.drawable.ic_fluent_emoji_laugh_24_regular, this::onEmojiReactionsClick), emojiReactionsItem=new CheckableListItem<>(R.string.sk_settings_emoji_reactions, R.string.sk_settings_emoji_reactions_explanation, CheckableListItem.Style.SWITCH, lp.emojiReactionsEnabled, R.drawable.ic_fluent_emoji_laugh_24_regular, i->onEmojiReactionsClick()),
showEmojiReactionsItem=new ListItem<>(R.string.sk_settings_show_emoji_reactions, getShowEmojiReactionsString(), R.drawable.ic_fluent_emoji_24_regular, this::onShowEmojiReactionsClick, 0, true), showEmojiReactionsItem=new ListItem<>(R.string.sk_settings_show_emoji_reactions, getShowEmojiReactionsString(), R.drawable.ic_fluent_emoji_24_regular, this::onShowEmojiReactionsClick, 0, true),
localOnlyItem=new CheckableListItem<>(R.string.sk_settings_support_local_only, R.string.sk_settings_local_only_explanation, CheckableListItem.Style.SWITCH, lp.localOnlySupported, R.drawable.ic_fluent_eye_24_regular, this::onLocalOnlyClick), localOnlyItem=new CheckableListItem<>(R.string.sk_settings_support_local_only, R.string.sk_settings_local_only_explanation, CheckableListItem.Style.SWITCH, lp.localOnlySupported, R.drawable.ic_fluent_eye_24_regular, i->onLocalOnlyClick()),
glitchModeItem=new CheckableListItem<>(R.string.sk_settings_glitch_instance, R.string.sk_settings_glitch_mode_explanation, CheckableListItem.Style.SWITCH, lp.glitchInstance, R.drawable.ic_fluent_eye_24_filled, ()->toggleCheckableItem(glitchModeItem)) glitchModeItem=new CheckableListItem<>(R.string.sk_settings_glitch_instance, R.string.sk_settings_glitch_mode_explanation, CheckableListItem.Style.SWITCH, lp.glitchInstance, R.drawable.ic_fluent_eye_24_filled, i->toggleCheckableItem(glitchModeItem))
)); ));
contentTypesItem.checkedChangeListener=checked->onContentTypeClick(); contentTypesItem.checkedChangeListener=checked->onContentTypeClick();
defaultContentTypeItem.isEnabled=contentTypesItem.checked; defaultContentTypeItem.isEnabled=contentTypesItem.checked;
@@ -68,7 +69,7 @@ public class SettingsInstanceFragment extends BaseSettingsFragment<Void> impleme
E.post(new StatusDisplaySettingsChangedEvent(accountID)); E.post(new StatusDisplaySettingsChangedEvent(accountID));
} }
private void onServerClick(){ private void onServerClick(ListItem<?> item){
Bundle args=new Bundle(); Bundle args=new Bundle();
args.putString("account", accountID); args.putString("account", accountID);
Nav.go(getActivity(), SettingsServerFragment.class, args); Nav.go(getActivity(), SettingsServerFragment.class, args);
@@ -87,23 +88,23 @@ public class SettingsInstanceFragment extends BaseSettingsFragment<Void> impleme
defaultContentTypeItem.subtitleRes=lp.defaultContentType.getName(); defaultContentTypeItem.subtitleRes=lp.defaultContentType.getName();
} }
private void onDefaultContentTypeClick(){ private void onDefaultContentTypeClick(ListItem<?> item_){
int selected=lp.defaultContentType.ordinal(); List<ContentType> supportedContentTypes=Arrays.stream(ContentType.values())
int[] newSelected={selected};
ContentType[] supportedContentTypes=Arrays.stream(ContentType.values())
.filter(t->t.supportedByInstance(getInstance().orElse(null))) .filter(t->t.supportedByInstance(getInstance().orElse(null)))
.toArray(ContentType[]::new); .collect(Collectors.toList());
String[] names=Arrays.stream(supportedContentTypes) int selected=supportedContentTypes.indexOf(lp.defaultContentType);
int[] newSelected={selected};
String[] names=supportedContentTypes.stream()
.map(ContentType::getName) .map(ContentType::getName)
.map(this::getString) .map(this::getString)
.toArray(String[]::new); .toArray(String[]::new);
new M3AlertDialogBuilder(getActivity()) new M3AlertDialogBuilder(getActivity())
.setTitle(R.string.settings_theme) .setTitle(R.string.sk_settings_default_content_type)
.setSingleChoiceItems(names, .setSingleChoiceItems(names,
selected, (dlg, item)->newSelected[0]=item) selected, (dlg, item)->newSelected[0]=item)
.setPositiveButton(R.string.ok, (dlg, item)->{ .setPositiveButton(R.string.ok, (dlg, item)->{
ContentType type=supportedContentTypes[newSelected[0]]; ContentType type=supportedContentTypes.get(newSelected[0]);
lp.defaultContentType=type; lp.defaultContentType=type;
defaultContentTypeItem.subtitleRes=type.getName(); defaultContentTypeItem.subtitleRes=type.getName();
rebindItem(defaultContentTypeItem); rebindItem(defaultContentTypeItem);
@@ -112,7 +113,7 @@ public class SettingsInstanceFragment extends BaseSettingsFragment<Void> impleme
.show(); .show();
} }
private void onShowEmojiReactionsClick(){ private void onShowEmojiReactionsClick(ListItem<?> item_){
int selected=lp.showEmojiReactions.ordinal(); int selected=lp.showEmojiReactions.ordinal();
int[] newSelected={selected}; int[] newSelected={selected};
new M3AlertDialogBuilder(getActivity()) new M3AlertDialogBuilder(getActivity())

View File

@@ -18,6 +18,7 @@ import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.events.SelfUpdateStateChangedEvent; import org.joinmastodon.android.events.SelfUpdateStateChangedEvent;
import org.joinmastodon.android.model.Instance; import org.joinmastodon.android.model.Instance;
import org.joinmastodon.android.model.viewmodel.ListItem; import org.joinmastodon.android.model.viewmodel.ListItem;
import org.joinmastodon.android.ui.AccountSwitcherSheet;
import org.joinmastodon.android.ui.M3AlertDialogBuilder; import org.joinmastodon.android.ui.M3AlertDialogBuilder;
import org.joinmastodon.android.ui.utils.HideableSingleViewRecyclerAdapter; import org.joinmastodon.android.ui.utils.HideableSingleViewRecyclerAdapter;
import org.joinmastodon.android.ui.utils.UiUtils; import org.joinmastodon.android.ui.utils.UiUtils;
@@ -49,7 +50,7 @@ public class SettingsMainFragment extends BaseSettingsFragment<Void>{
@Override @Override
public void onCreate(Bundle savedInstanceState){ public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
account = AccountSessionManager.get(accountID); account=AccountSessionManager.get(accountID);
setTitle(R.string.settings); setTitle(R.string.settings);
setSubtitle(account.getFullUsername()); setSubtitle(account.getFullUsername());
onDataLoaded(List.of( onDataLoaded(List.of(
@@ -59,15 +60,17 @@ public class SettingsMainFragment extends BaseSettingsFragment<Void>{
new ListItem<>(R.string.settings_notifications, 0, R.drawable.ic_fluent_alert_24_regular, this::onNotificationsClick), new ListItem<>(R.string.settings_notifications, 0, R.drawable.ic_fluent_alert_24_regular, this::onNotificationsClick),
new ListItem<>(R.string.sk_settings_instance, 0, R.drawable.ic_fluent_server_24_regular, this::onInstanceClick), new ListItem<>(R.string.sk_settings_instance, 0, R.drawable.ic_fluent_server_24_regular, this::onInstanceClick),
new ListItem<>(getString(R.string.about_app, getString(R.string.sk_app_name)), null, R.drawable.ic_fluent_info_24_regular, this::onAboutClick, null, 0, true), new ListItem<>(getString(R.string.about_app, getString(R.string.sk_app_name)), null, R.drawable.ic_fluent_info_24_regular, this::onAboutClick, null, 0, true),
new ListItem<>(R.string.manage_accounts, 0, R.drawable.ic_fluent_person_swap_24_regular, this::onManageAccountsClick),
new ListItem<>(R.string.log_out, 0, R.drawable.ic_fluent_sign_out_24_regular, this::onLogOutClick, R.attr.colorM3Error, false) new ListItem<>(R.string.log_out, 0, R.drawable.ic_fluent_sign_out_24_regular, this::onLogOutClick, R.attr.colorM3Error, false)
)); ));
Instance instance = AccountSessionManager.getInstance().getInstanceInfo(account.domain); Instance instance=AccountSessionManager.getInstance().getInstanceInfo(account.domain);
if (!instance.isAkkoma()) if(!instance.isAkkoma()){
data.add(3, new ListItem<>(R.string.settings_filters, 0, R.drawable.ic_fluent_filter_24_regular, this::onFiltersClick)); data.add(3, new ListItem<>(R.string.settings_filters, 0, R.drawable.ic_fluent_filter_24_regular, this::onFiltersClick));
}
if(BuildConfig.DEBUG || BuildConfig.BUILD_TYPE.equals("appcenterPrivateBeta")){ if(BuildConfig.DEBUG || BuildConfig.BUILD_TYPE.equals("appcenterPrivateBeta")){
data.add(0, new ListItem<>("Debug settings", null, R.drawable.ic_fluent_wrench_screwdriver_24_regular, ()->Nav.go(getActivity(), SettingsDebugFragment.class, makeFragmentArgs()), null, 0, true)); data.add(0, new ListItem<>("Debug settings", null, R.drawable.ic_fluent_wrench_screwdriver_24_regular, i->Nav.go(getActivity(), SettingsDebugFragment.class, makeFragmentArgs()), null, 0, true));
} }
AccountSession session=AccountSessionManager.get(accountID); AccountSession session=AccountSessionManager.get(accountID);
@@ -128,35 +131,39 @@ public class SettingsMainFragment extends BaseSettingsFragment<Void>{
return args; return args;
} }
private void onBehaviorClick(){ private void onBehaviorClick(ListItem<?> item_){
Nav.go(getActivity(), SettingsBehaviorFragment.class, makeFragmentArgs()); Nav.go(getActivity(), SettingsBehaviorFragment.class, makeFragmentArgs());
} }
private void onDisplayClick(){ private void onDisplayClick(ListItem<?> item_){
Nav.go(getActivity(), SettingsDisplayFragment.class, makeFragmentArgs()); Nav.go(getActivity(), SettingsDisplayFragment.class, makeFragmentArgs());
} }
private void onPrivacyClick(){ private void onPrivacyClick(ListItem<?> item_){
Nav.go(getActivity(), SettingsPrivacyFragment.class, makeFragmentArgs()); Nav.go(getActivity(), SettingsPrivacyFragment.class, makeFragmentArgs());
} }
private void onFiltersClick(){ private void onFiltersClick(ListItem<?> item_){
Nav.go(getActivity(), SettingsFiltersFragment.class, makeFragmentArgs()); Nav.go(getActivity(), SettingsFiltersFragment.class, makeFragmentArgs());
} }
private void onNotificationsClick(){ private void onNotificationsClick(ListItem<?> item_){
Nav.go(getActivity(), SettingsNotificationsFragment.class, makeFragmentArgs()); Nav.go(getActivity(), SettingsNotificationsFragment.class, makeFragmentArgs());
} }
private void onInstanceClick(){ private void onInstanceClick(ListItem<?> item_){
Nav.go(getActivity(), SettingsInstanceFragment.class, makeFragmentArgs()); Nav.go(getActivity(), SettingsInstanceFragment.class, makeFragmentArgs());
} }
private void onAboutClick(){ private void onAboutClick(ListItem<?> item_){
Nav.go(getActivity(), SettingsAboutAppFragment.class, makeFragmentArgs()); Nav.go(getActivity(), SettingsAboutAppFragment.class, makeFragmentArgs());
} }
private void onLogOutClick(){ private void onManageAccountsClick(ListItem<?> item){
new AccountSwitcherSheet(getActivity(), null).show();
}
private void onLogOutClick(ListItem<?> item_){
AccountSession session=AccountSessionManager.getInstance().getAccount(accountID); AccountSession session=AccountSessionManager.getInstance().getAccount(accountID);
new M3AlertDialogBuilder(getActivity()) new M3AlertDialogBuilder(getActivity())
.setMessage(getString(R.string.confirm_log_out, session.getFullUsername())) .setMessage(getString(R.string.confirm_log_out, session.getFullUsername()))

View File

@@ -27,7 +27,6 @@ import org.joinmastodon.android.model.viewmodel.ListItem;
import org.joinmastodon.android.ui.M3AlertDialogBuilder; import org.joinmastodon.android.ui.M3AlertDialogBuilder;
import org.joinmastodon.android.ui.utils.HideableSingleViewRecyclerAdapter; import org.joinmastodon.android.ui.utils.HideableSingleViewRecyclerAdapter;
import org.joinmastodon.android.ui.utils.UiUtils; import org.joinmastodon.android.ui.utils.UiUtils;
import org.unifiedpush.android.connector.RegistrationDialogContent;
import org.unifiedpush.android.connector.UnifiedPush; import org.unifiedpush.android.connector.UnifiedPush;
import java.time.Instant; import java.time.Instant;
@@ -73,21 +72,21 @@ public class SettingsNotificationsFragment extends BaseSettingsFragment<Void>{
useUnifiedPush=!getDistributor(getContext()).isEmpty(); useUnifiedPush=!getDistributor(getContext()).isEmpty();
onDataLoaded(List.of( onDataLoaded(List.of(
pauseItem=new CheckableListItem<>(getString(R.string.pause_all_notifications), getPauseItemSubtitle(), CheckableListItem.Style.SWITCH, false, R.drawable.ic_fluent_alert_snooze_24_regular, ()->onPauseNotificationsClick(false)), pauseItem=new CheckableListItem<>(getString(R.string.pause_all_notifications), getPauseItemSubtitle(), CheckableListItem.Style.SWITCH, false, R.drawable.ic_fluent_alert_snooze_24_regular, i->onPauseNotificationsClick(false)),
policyItem=new ListItem<>(R.string.settings_notifications_policy, 0, R.drawable.ic_fluent_people_24_regular, this::onNotificationsPolicyClick, 0, true), policyItem=new ListItem<>(R.string.settings_notifications_policy, 0, R.drawable.ic_fluent_people_24_regular, this::onNotificationsPolicyClick, 0, true),
mentionsItem=new CheckableListItem<>(R.string.notification_type_mentions_and_replies, 0, CheckableListItem.Style.CHECKBOX, pushSubscription.alerts.mention, R.drawable.ic_fluent_mention_24_regular, ()->toggleCheckableItem(mentionsItem)), mentionsItem=new CheckableListItem<>(R.string.notification_type_mentions_and_replies, 0, CheckableListItem.Style.CHECKBOX, pushSubscription.alerts.mention, R.drawable.ic_fluent_mention_24_regular, i->toggleCheckableItem(mentionsItem)),
boostsItem=new CheckableListItem<>(R.string.notification_type_reblog, 0, CheckableListItem.Style.CHECKBOX, pushSubscription.alerts.reblog, R.drawable.ic_fluent_arrow_repeat_all_24_regular, ()->toggleCheckableItem(boostsItem)), boostsItem=new CheckableListItem<>(R.string.notification_type_reblog, 0, CheckableListItem.Style.CHECKBOX, pushSubscription.alerts.reblog, R.drawable.ic_fluent_arrow_repeat_all_24_regular, i->toggleCheckableItem(boostsItem)),
favoritesItem=new CheckableListItem<>(R.string.notification_type_favorite, 0, CheckableListItem.Style.CHECKBOX, pushSubscription.alerts.favourite, R.drawable.ic_fluent_star_24_regular, ()->toggleCheckableItem(favoritesItem)), favoritesItem=new CheckableListItem<>(R.string.notification_type_favorite, 0, CheckableListItem.Style.CHECKBOX, pushSubscription.alerts.favourite, R.drawable.ic_fluent_star_24_regular, i->toggleCheckableItem(favoritesItem)),
followersItem=new CheckableListItem<>(R.string.notification_type_follow, 0, CheckableListItem.Style.CHECKBOX, pushSubscription.alerts.follow, R.drawable.ic_fluent_person_add_24_regular, ()->toggleCheckableItem(followersItem)), followersItem=new CheckableListItem<>(R.string.notification_type_follow, 0, CheckableListItem.Style.CHECKBOX, pushSubscription.alerts.follow, R.drawable.ic_fluent_person_add_24_regular, i->toggleCheckableItem(followersItem)),
pollsItem=new CheckableListItem<>(R.string.notification_type_poll, 0, CheckableListItem.Style.CHECKBOX, pushSubscription.alerts.poll, R.drawable.ic_fluent_poll_24_regular, ()->toggleCheckableItem(pollsItem)), pollsItem=new CheckableListItem<>(R.string.notification_type_poll, 0, CheckableListItem.Style.CHECKBOX, pushSubscription.alerts.poll, R.drawable.ic_fluent_poll_24_regular, i->toggleCheckableItem(pollsItem)),
updateItem=new CheckableListItem<>(R.string.sk_notification_type_update, 0, CheckableListItem.Style.CHECKBOX, pushSubscription.alerts.update, R.drawable.ic_fluent_history_24_regular, ()->toggleCheckableItem(updateItem)), updateItem=new CheckableListItem<>(R.string.sk_notification_type_update, 0, CheckableListItem.Style.CHECKBOX, pushSubscription.alerts.update, R.drawable.ic_fluent_history_24_regular, i->toggleCheckableItem(updateItem)),
postsItem=new CheckableListItem<>(R.string.sk_notification_type_posts, 0, CheckableListItem.Style.CHECKBOX, pushSubscription.alerts.status, R.drawable.ic_fluent_chat_24_regular, ()->toggleCheckableItem(postsItem), true), postsItem=new CheckableListItem<>(R.string.sk_notification_type_posts, 0, CheckableListItem.Style.CHECKBOX, pushSubscription.alerts.status, R.drawable.ic_fluent_chat_24_regular, i->toggleCheckableItem(postsItem), true),
uniformIconItem=new CheckableListItem<>(R.string.sk_settings_uniform_icon_for_notifications, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.uniformNotificationIcon, R.drawable.ic_ntf_logo, ()->toggleCheckableItem(uniformIconItem)), uniformIconItem=new CheckableListItem<>(R.string.sk_settings_uniform_icon_for_notifications, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.uniformNotificationIcon, R.drawable.ic_ntf_logo, i->toggleCheckableItem(uniformIconItem)),
deleteItem=new CheckableListItem<>(R.string.sk_settings_enable_delete_notifications, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.enableDeleteNotifications, R.drawable.ic_fluent_mail_inbox_dismiss_24_regular, ()->toggleCheckableItem(deleteItem)), deleteItem=new CheckableListItem<>(R.string.sk_settings_enable_delete_notifications, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.enableDeleteNotifications, R.drawable.ic_fluent_mail_inbox_dismiss_24_regular, i->toggleCheckableItem(deleteItem)),
onlyLatestItem=new CheckableListItem<>(R.string.sk_settings_single_notification, 0, CheckableListItem.Style.SWITCH, lp.keepOnlyLatestNotification, R.drawable.ic_fluent_convert_range_24_regular, ()->toggleCheckableItem(onlyLatestItem), true), onlyLatestItem=new CheckableListItem<>(R.string.sk_settings_single_notification, 0, CheckableListItem.Style.SWITCH, lp.keepOnlyLatestNotification, R.drawable.ic_fluent_convert_range_24_regular, i->toggleCheckableItem(onlyLatestItem), true),
unifiedPushItem=new CheckableListItem<>(R.string.sk_settings_unifiedpush, 0, CheckableListItem.Style.SWITCH, useUnifiedPush, R.drawable.ic_fluent_alert_arrow_up_24_regular, this::onUnifiedPush, true) unifiedPushItem=new CheckableListItem<>(R.string.sk_settings_unifiedpush, 0, CheckableListItem.Style.SWITCH, useUnifiedPush, R.drawable.ic_fluent_alert_arrow_up_24_regular, i->onUnifiedPushClick(), true)
)); ));
//only enable when distributors, who can receive notifications, are available //only enable when distributors, who can receive notifications, are available
@@ -98,7 +97,7 @@ public class SettingsNotificationsFragment extends BaseSettingsFragment<Void>{
typeItems=List.of(mentionsItem, boostsItem, favoritesItem, followersItem, pollsItem, updateItem, postsItem); typeItems=List.of(mentionsItem, boostsItem, favoritesItem, followersItem, pollsItem, updateItem, postsItem);
pauseItem.checkedChangeListener=checked->onPauseNotificationsClick(true); pauseItem.checkedChangeListener=checked->onPauseNotificationsClick(true);
unifiedPushItem.checkedChangeListener=checked->onUnifiedPush(); unifiedPushItem.checkedChangeListener=checked->onUnifiedPushClick();
updatePolicyItem(null); updatePolicyItem(null);
updatePauseItem(); updatePauseItem();
} }
@@ -254,7 +253,7 @@ public class SettingsNotificationsFragment extends BaseSettingsFragment<Void>{
alert.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false); alert.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false);
} }
private void onNotificationsPolicyClick(){ private void onNotificationsPolicyClick(ListItem<?> item_){
String[] items=Stream.of( String[] items=Stream.of(
R.string.notifications_policy_anyone, R.string.notifications_policy_anyone,
R.string.notifications_policy_followed, R.string.notifications_policy_followed,
@@ -328,7 +327,7 @@ public class SettingsNotificationsFragment extends BaseSettingsFragment<Void>{
} }
} }
private void onUnifiedPush(){ private void onUnifiedPushClick(){
if(getDistributor(getContext()).isEmpty()){ if(getDistributor(getContext()).isEmpty()){
List<String> distributors = UnifiedPush.getDistributors(getContext(), new ArrayList<>()); List<String> distributors = UnifiedPush.getDistributors(getContext(), new ArrayList<>());
showUnifiedPushRegisterDialog(distributors); showUnifiedPushRegisterDialog(distributors);

View File

@@ -2,40 +2,98 @@ package org.joinmastodon.android.fragments.settings;
import android.os.Bundle; import android.os.Bundle;
import androidx.annotation.StringRes;
import org.joinmastodon.android.R; import org.joinmastodon.android.R;
import org.joinmastodon.android.api.session.AccountSession;
import org.joinmastodon.android.api.session.AccountSessionManager; import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.model.Account; import org.joinmastodon.android.model.Account;
import org.joinmastodon.android.model.Instance;
import org.joinmastodon.android.model.StatusPrivacy;
import org.joinmastodon.android.model.viewmodel.CheckableListItem; import org.joinmastodon.android.model.viewmodel.CheckableListItem;
import org.joinmastodon.android.model.viewmodel.ListItem;
import org.joinmastodon.android.ui.M3AlertDialogBuilder;
import java.util.ArrayList;
import java.util.List; import java.util.List;
public class SettingsPrivacyFragment extends BaseSettingsFragment<Void>{ public class SettingsPrivacyFragment extends BaseSettingsFragment<Void>{
private CheckableListItem<Void> discoverableItem, indexableItem; private CheckableListItem<Void> discoverableItem, indexableItem, lockedItem;
private ListItem<Void> privacyItem;
private StatusPrivacy privacy=null;
private Instance instance;
@Override @Override
public void onCreate(Bundle savedInstanceState){ public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setTitle(R.string.settings_privacy); setTitle(R.string.settings_privacy);
Account self=AccountSessionManager.get(accountID).self; AccountSession session=AccountSessionManager.get(accountID);
Account self=session.self;
instance=AccountSessionManager.getInstance().getInstanceInfo(session.domain);
privacy=self.source.privacy;
onDataLoaded(List.of( onDataLoaded(List.of(
discoverableItem=new CheckableListItem<>(R.string.settings_discoverable, 0, CheckableListItem.Style.SWITCH, self.discoverable, R.drawable.ic_fluent_thumb_like_dislike_24_regular, ()->toggleCheckableItem(discoverableItem)), privacyItem=new ListItem<>(R.string.sk_settings_default_visibility, getPrivacyString(privacy), R.drawable.ic_fluent_eye_24_regular, this::onPrivacyClick, 0, true),
indexableItem=new CheckableListItem<>(R.string.settings_indexable, 0, CheckableListItem.Style.SWITCH, self.source.indexable!=null ? self.source.indexable : true, R.drawable.ic_fluent_search_24_regular, ()->toggleCheckableItem(indexableItem)) lockedItem=new CheckableListItem<>(R.string.sk_settings_lock_account, 0, CheckableListItem.Style.SWITCH, self.locked, R.drawable.ic_fluent_person_available_24_regular, i->toggleCheckableItem(lockedItem))
)); ));
if(self.source.indexable==null)
indexableItem.isEnabled=false; if(!instance.isAkkoma()){
data.addAll(List.of(
discoverableItem=new CheckableListItem<>(R.string.settings_discoverable, 0, CheckableListItem.Style.SWITCH, self.discoverable, R.drawable.ic_fluent_thumb_like_dislike_24_regular, i->toggleCheckableItem(discoverableItem)),
indexableItem=new CheckableListItem<>(R.string.settings_indexable, 0, CheckableListItem.Style.SWITCH, self.source.indexable!=null ? self.source.indexable : true, R.drawable.ic_fluent_search_24_regular, i->toggleCheckableItem(indexableItem))
));
if(self.source.indexable==null)
indexableItem.isEnabled=false;
}
} }
@Override @Override
protected void doLoadData(int offset, int count){} protected void doLoadData(int offset, int count){}
private @StringRes int getPrivacyString(StatusPrivacy p){
if(p==null) return R.string.visibility_public;
return switch(p){
case PUBLIC -> R.string.visibility_public;
case UNLISTED -> R.string.sk_visibility_unlisted;
case PRIVATE -> R.string.visibility_followers_only;
case DIRECT -> R.string.visibility_private;
case LOCAL -> R.string.sk_local_only;
};
}
private void onPrivacyClick(ListItem<?> item_){
Account self=AccountSessionManager.get(accountID).self;
List<StatusPrivacy> options=new ArrayList<>(List.of(StatusPrivacy.PUBLIC, StatusPrivacy.UNLISTED, StatusPrivacy.PRIVATE, StatusPrivacy.DIRECT));
if(instance.isAkkoma()) options.add(StatusPrivacy.LOCAL);
int selected=options.indexOf(self.source.privacy);
int[] newSelected={selected};
new M3AlertDialogBuilder(getActivity())
.setTitle(R.string.sk_settings_default_visibility)
.setSingleChoiceItems(options.stream().map(this::getPrivacyString).map(this::getString).toArray(String[]::new),
selected, (dlg, item)->newSelected[0]=item)
.setPositiveButton(R.string.ok, (dlg, item)->{
privacy=options.get(newSelected[0]);
privacyItem.subtitleRes=getPrivacyString(privacy);
rebindItem(privacyItem);
})
.setNegativeButton(R.string.cancel, null)
.show();
}
@Override @Override
public void onPause(){ public void onPause(){
super.onPause(); super.onPause();
Account self=AccountSessionManager.get(accountID).self; AccountSession s=AccountSessionManager.get(accountID);
if(self.discoverable!=discoverableItem.checked || (self.source.indexable!=null && self.source.indexable!=indexableItem.checked)){ Account self=s.self;
self.discoverable=discoverableItem.checked; boolean savePlease=self.locked!=lockedItem.checked
self.source.indexable=indexableItem.checked; || self.source.privacy!=privacy
AccountSessionManager.get(accountID).savePreferencesLater(); || (discoverableItem!=null && self.discoverable!=discoverableItem.checked)
|| (indexableItem!=null && self.source.indexable!=null && self.source.indexable!=indexableItem.checked);
if(savePlease){
if(discoverableItem!=null) self.discoverable=discoverableItem.checked;
if(indexableItem!=null) self.source.indexable=indexableItem.checked;
self.locked=lockedItem.checked;
s.preferences.postingDefaultVisibility=privacy;
s.savePreferencesLater();
} }
} }
} }

View File

@@ -145,7 +145,7 @@ public class SettingsServerAboutFragment extends LoaderFragment{
if(!TextUtils.isEmpty(instance.email)){ if(!TextUtils.isEmpty(instance.email)){
needDivider=true; needDivider=true;
SimpleListItemViewHolder holder=new SimpleListItemViewHolder(getActivity(), scrollingLayout); SimpleListItemViewHolder holder=new SimpleListItemViewHolder(getActivity(), scrollingLayout);
ListItem<Void> item=new ListItem<>(R.string.send_email_to_server_admin, 0, R.drawable.ic_fluent_mail_24_regular, ()->{}); ListItem<Void> item=new ListItem<>(R.string.send_email_to_server_admin, 0, R.drawable.ic_fluent_mail_24_regular, i->{});
holder.bind(item); holder.bind(item);
holder.itemView.setBackground(UiUtils.getThemeDrawable(getActivity(), android.R.attr.selectableItemBackground)); holder.itemView.setBackground(UiUtils.getThemeDrawable(getActivity(), android.R.attr.selectableItemBackground));
holder.itemView.setOnClickListener(v->openAdminEmail()); holder.itemView.setOnClickListener(v->openAdminEmail());

View File

@@ -6,8 +6,6 @@ import android.text.TextUtils;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import org.joinmastodon.android.api.ObjectValidationException; import org.joinmastodon.android.api.ObjectValidationException;
import org.joinmastodon.android.api.RequiredField;
import org.joinmastodon.android.api.requests.instance.GetInstance;
import org.parceler.Parcel; import org.parceler.Parcel;
import java.time.Instant; import java.time.Instant;
@@ -15,9 +13,6 @@ import java.time.LocalDate;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import me.grishka.appkit.api.Callback;
import me.grishka.appkit.api.ErrorResponse;
/** /**
* Represents a user of Mastodon and their associated profile. * Represents a user of Mastodon and their associated profile.
*/ */
@@ -163,26 +158,26 @@ public class Account extends BaseModel implements Searchable{
if(fields!=null){ if(fields!=null){
for(AccountField f:fields) for(AccountField f:fields)
f.postprocess(); f.postprocess();
} else { }else{
fields = Collections.emptyList(); fields=Collections.emptyList();
} }
if(emojis!=null){ if(emojis!=null){
for(Emoji e:emojis) for(Emoji e:emojis)
e.postprocess(); e.postprocess();
} else { }else{
emojis = Collections.emptyList(); emojis=Collections.emptyList();
} }
if(moved!=null) if(moved!=null)
moved.postprocess(); moved.postprocess();
if(fqn == null) fqn = getFullyQualifiedName(); if(fqn==null) fqn=getFullyQualifiedName();
if(id == null) id = ""; if(id==null) id="";
if(username == null) username = ""; if(username==null) username="";
if(TextUtils.isEmpty(displayName)) if(TextUtils.isEmpty(displayName))
displayName = !TextUtils.isEmpty(username) ? username : ""; displayName=!TextUtils.isEmpty(username) ? username : "";
if(acct == null) acct = ""; if(acct==null) acct="";
if(url == null) url = ""; if(url==null) url="";
if(note == null) note = ""; if(note==null) note="";
if(avatar == null) avatar = ""; if(avatar==null) avatar="";
} }
public boolean isLocal(){ public boolean isLocal(){
@@ -212,6 +207,10 @@ public class Account extends BaseModel implements Searchable{
return fqn != null ? fqn : acct.split("@")[0] + "@" + getDomainFromURL(); return fqn != null ? fqn : acct.split("@")[0] + "@" + getDomainFromURL();
} }
public String getDisplayName(){
return '\u2068'+displayName+'\u2069';
}
@Override @Override
public String toString(){ public String toString(){
return "Account{"+ return "Account{"+

View File

@@ -26,22 +26,13 @@ import com.google.gson.JsonElement;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import com.google.gson.JsonParseException; import com.google.gson.JsonParseException;
import org.joinmastodon.android.api.ObjectValidationException;
import org.joinmastodon.android.api.RequiredField;
import org.joinmastodon.android.api.session.AccountSession; import org.joinmastodon.android.api.session.AccountSession;
import org.joinmastodon.android.api.session.AccountSessionManager; import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.events.EmojiReactionsUpdatedEvent; import org.joinmastodon.android.events.EmojiReactionsUpdatedEvent;
import org.joinmastodon.android.events.StatusCountersUpdatedEvent;
import org.joinmastodon.android.ui.text.HtmlParser;
import org.joinmastodon.android.utils.StatusTextEncoder; import org.joinmastodon.android.utils.StatusTextEncoder;
import org.parceler.Parcel;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.time.Instant;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@Parcel @Parcel
@@ -104,6 +95,7 @@ public class Status extends BaseModel implements DisplayItemsParent, Searchable{
private transient String strippedText; private transient String strippedText;
public transient TranslationState translationState=TranslationState.HIDDEN; public transient TranslationState translationState=TranslationState.HIDDEN;
public transient Translation translation; public transient Translation translation;
public transient boolean fromStatusCreated;
public Status(){} public Status(){}
@@ -203,6 +195,10 @@ public class Status extends BaseModel implements DisplayItemsParent, Searchable{
return reblog!=null ? reblog : this; return reblog!=null ? reblog : this;
} }
public String getContentStatusID(){
return getContentStatus().id;
}
public String getStrippedText(){ public String getStrippedText(){
if(strippedText==null) if(strippedText==null)
strippedText=HtmlParser.strip(content); strippedText=HtmlParser.strip(content);

View File

@@ -33,9 +33,9 @@ public class AccountViewModel{
V.dp(50), V.dp(50)); V.dp(50), V.dp(50));
emojiHelper=new CustomEmojiHelper(); emojiHelper=new CustomEmojiHelper();
if(session.getLocalPreferences().customEmojiInNames) if(session.getLocalPreferences().customEmojiInNames)
parsedName=HtmlParser.parseCustomEmoji(account.displayName, account.emojis); parsedName=HtmlParser.parseCustomEmoji(account.getDisplayName(), account.emojis);
else else
parsedName=account.displayName; parsedName=account.getDisplayName();
parsedBio=HtmlParser.parse(account.note, account.emojis, Collections.emptyList(), Collections.emptyList(), accountID); parsedBio=HtmlParser.parse(account.note, account.emojis, Collections.emptyList(), Collections.emptyList(), accountID);
SpannableStringBuilder ssb=new SpannableStringBuilder(parsedName); SpannableStringBuilder ssb=new SpannableStringBuilder(parsedName);
ssb.append(parsedBio); ssb.append(parsedBio);

View File

@@ -9,42 +9,42 @@ public class CheckableListItem<T> extends ListItem<T>{
public boolean checked; public boolean checked;
public Consumer<Boolean> checkedChangeListener; public Consumer<Boolean> checkedChangeListener;
public CheckableListItem(String title, String subtitle, Style style, boolean checked, int iconRes, Runnable onClick, T parentObject, boolean dividerAfter){ public CheckableListItem(String title, String subtitle, Style style, boolean checked, int iconRes, Consumer<CheckableListItem<T>> onClick, T parentObject, boolean dividerAfter){
super(title, subtitle, iconRes, onClick, parentObject, 0, dividerAfter); super(title, subtitle, iconRes, (Consumer<ListItem<T>>)(Object)onClick, parentObject, 0, dividerAfter);
this.style=style; this.style=style;
this.checked=checked; this.checked=checked;
} }
public CheckableListItem(String title, String subtitle, Style style, boolean checked, Runnable onClick){ public CheckableListItem(String title, String subtitle, Style style, boolean checked, Consumer<CheckableListItem<T>> onClick){
this(title, subtitle, style, checked, 0, onClick, null, false); this(title, subtitle, style, checked, 0, onClick, null, false);
} }
public CheckableListItem(String title, String subtitle, Style style, boolean checked, Runnable onClick, T parentObject){ public CheckableListItem(String title, String subtitle, Style style, boolean checked, Consumer<CheckableListItem<T>> onClick, T parentObject){
this(title, subtitle, style, checked, 0, onClick, parentObject, false); this(title, subtitle, style, checked, 0, onClick, parentObject, false);
} }
public CheckableListItem(String title, String subtitle, Style style, boolean checked, int iconRes, Runnable onClick){ public CheckableListItem(String title, String subtitle, Style style, boolean checked, int iconRes, Consumer<CheckableListItem<T>> onClick){
this(title, subtitle, style, checked, iconRes, onClick, null, false); this(title, subtitle, style, checked, iconRes, onClick, null, false);
} }
public CheckableListItem(String title, String subtitle, Style style, boolean checked, int iconRes, Runnable onClick, T parentObject){ public CheckableListItem(String title, String subtitle, Style style, boolean checked, int iconRes, Consumer<CheckableListItem<T>> onClick, T parentObject){
this(title, subtitle, style, checked, iconRes, onClick, parentObject, false); this(title, subtitle, style, checked, iconRes, onClick, parentObject, false);
} }
public CheckableListItem(int titleRes, int subtitleRes, Style style, boolean checked, Runnable onClick){ public CheckableListItem(int titleRes, int subtitleRes, Style style, boolean checked, Consumer<CheckableListItem<T>> onClick){
this(titleRes, subtitleRes, style, checked, 0, onClick, false); this(titleRes, subtitleRes, style, checked, 0, onClick, false);
} }
public CheckableListItem(int titleRes, int subtitleRes, Style style, boolean checked, Runnable onClick, boolean dividerAfter){ public CheckableListItem(int titleRes, int subtitleRes, Style style, boolean checked, Consumer<CheckableListItem<T>> onClick, boolean dividerAfter){
this(titleRes, subtitleRes, style, checked, 0, onClick, dividerAfter); this(titleRes, subtitleRes, style, checked, 0, onClick, dividerAfter);
} }
public CheckableListItem(int titleRes, int subtitleRes, Style style, boolean checked, int iconRes, Runnable onClick){ public CheckableListItem(int titleRes, int subtitleRes, Style style, boolean checked, int iconRes, Consumer<CheckableListItem<T>> onClick){
this(titleRes, subtitleRes, style, checked, iconRes, onClick, false); this(titleRes, subtitleRes, style, checked, iconRes, onClick, false);
} }
public CheckableListItem(int titleRes, int subtitleRes, Style style, boolean checked, int iconRes, Runnable onClick, boolean dividerAfter){ public CheckableListItem(int titleRes, int subtitleRes, Style style, boolean checked, int iconRes, Consumer<CheckableListItem<T>> onClick, boolean dividerAfter){
super(titleRes, subtitleRes, iconRes, onClick, 0, dividerAfter); super(titleRes, subtitleRes, iconRes, (Consumer<ListItem<T>>)(Object)onClick, 0, dividerAfter);
this.style=style; this.style=style;
this.checked=checked; this.checked=checked;
} }

View File

@@ -2,6 +2,8 @@ package org.joinmastodon.android.model.viewmodel;
import org.joinmastodon.android.R; import org.joinmastodon.android.R;
import java.util.function.Consumer;
import androidx.annotation.DrawableRes; import androidx.annotation.DrawableRes;
import androidx.annotation.StringRes; import androidx.annotation.StringRes;
@@ -16,11 +18,11 @@ public class ListItem<T>{
public int iconRes; public int iconRes;
public int colorOverrideAttr; public int colorOverrideAttr;
public boolean dividerAfter; public boolean dividerAfter;
public Runnable onClick; private Consumer<ListItem<T>> onClick;
public boolean isEnabled=true; public boolean isEnabled=true;
public T parentObject; public T parentObject;
public ListItem(String title, String subtitle, int iconRes, Runnable onClick, T parentObject, int colorOverrideAttr, boolean dividerAfter){ public ListItem(String title, String subtitle, int iconRes, Consumer<ListItem<T>> onClick, T parentObject, int colorOverrideAttr, boolean dividerAfter){
this.title=title; this.title=title;
this.subtitle=subtitle; this.subtitle=subtitle;
this.iconRes=iconRes; this.iconRes=iconRes;
@@ -32,45 +34,41 @@ public class ListItem<T>{
isEnabled=false; isEnabled=false;
} }
public ListItem(String title, String subtitle, Runnable onClick){ public ListItem(String title, String subtitle, Consumer<ListItem<T>> onClick){
this(title, subtitle, 0, onClick, null, 0, false); this(title, subtitle, 0, onClick, null, 0, false);
} }
public ListItem(String title, String subtitle, Runnable onClick, T parentObject){ public ListItem(String title, String subtitle, Consumer<ListItem<T>> onClick, T parentObject){
this(title, subtitle, 0, onClick, parentObject, 0, false); this(title, subtitle, 0, onClick, parentObject, 0, false);
} }
public ListItem(String title, String subtitle, @DrawableRes int iconRes, Runnable onClick){ public ListItem(String title, String subtitle, @DrawableRes int iconRes, Consumer<ListItem<T>> onClick){
this(title, subtitle, iconRes, onClick, null, 0, false); this(title, subtitle, iconRes, onClick, null, 0, false);
} }
public ListItem(String title, String subtitle, @DrawableRes int iconRes, Runnable onClick, boolean dividerAfter){ public ListItem(String title, String subtitle, @DrawableRes int iconRes, Consumer<ListItem<T>> onClick, T parentObject){
this(title, subtitle, iconRes, onClick, null, 0, dividerAfter);
}
public ListItem(String title, String subtitle, @DrawableRes int iconRes, Runnable onClick, T parentObject){
this(title, subtitle, iconRes, onClick, parentObject, 0, false); this(title, subtitle, iconRes, onClick, parentObject, 0, false);
} }
public ListItem(@StringRes int titleRes, @StringRes int subtitleRes, Runnable onClick){ public ListItem(@StringRes int titleRes, @StringRes int subtitleRes, Consumer<ListItem<T>> onClick){
this(null, null, 0, onClick, null, 0, false); this(null, null, 0, onClick, null, 0, false);
this.titleRes=titleRes; this.titleRes=titleRes;
this.subtitleRes=subtitleRes; this.subtitleRes=subtitleRes;
} }
public ListItem(@StringRes int titleRes, @StringRes int subtitleRes, Runnable onClick, int colorOverrideAttr, boolean dividerAfter){ public ListItem(@StringRes int titleRes, @StringRes int subtitleRes, Consumer<ListItem<T>> onClick, int colorOverrideAttr, boolean dividerAfter){
this(null, null, 0, onClick, null, colorOverrideAttr, dividerAfter); this(null, null, 0, onClick, null, colorOverrideAttr, dividerAfter);
this.titleRes=titleRes; this.titleRes=titleRes;
this.subtitleRes=subtitleRes; this.subtitleRes=subtitleRes;
} }
public ListItem(@StringRes int titleRes, @StringRes int subtitleRes, @DrawableRes int iconRes, Runnable onClick){ public ListItem(@StringRes int titleRes, @StringRes int subtitleRes, @DrawableRes int iconRes, Consumer<ListItem<T>> onClick){
this(null, null, iconRes, onClick, null, 0, false); this(null, null, iconRes, onClick, null, 0, false);
this.titleRes=titleRes; this.titleRes=titleRes;
this.subtitleRes=subtitleRes; this.subtitleRes=subtitleRes;
} }
public ListItem(@StringRes int titleRes, @StringRes int subtitleRes, @DrawableRes int iconRes, Runnable onClick, int colorOverrideAttr, boolean dividerAfter){ public ListItem(@StringRes int titleRes, @StringRes int subtitleRes, @DrawableRes int iconRes, Consumer<ListItem<T>> onClick, int colorOverrideAttr, boolean dividerAfter){
this(null, null, iconRes, onClick, null, colorOverrideAttr, dividerAfter); this(null, null, iconRes, onClick, null, colorOverrideAttr, dividerAfter);
this.titleRes=titleRes; this.titleRes=titleRes;
this.subtitleRes=subtitleRes; this.subtitleRes=subtitleRes;
@@ -79,4 +77,13 @@ public class ListItem<T>{
public int getItemViewType(){ public int getItemViewType(){
return colorOverrideAttr==0 ? R.id.list_item_simple : R.id.list_item_simple_tinted; return colorOverrideAttr==0 ? R.id.list_item_simple : R.id.list_item_simple_tinted;
} }
public void performClick(){
if(onClick!=null)
onClick.accept(this);
}
public <I extends ListItem<T>> void setOnClick(Consumer<I> onClick){
this.onClick=(Consumer<ListItem<T>>) onClick;
}
} }

View File

@@ -8,7 +8,7 @@ import android.graphics.drawable.Animatable;
import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.text.SpannableStringBuilder;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.WindowInsets; import android.view.WindowInsets;
@@ -27,6 +27,8 @@ import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.fragments.HomeFragment; import org.joinmastodon.android.fragments.HomeFragment;
import org.joinmastodon.android.fragments.SplashFragment; import org.joinmastodon.android.fragments.SplashFragment;
import org.joinmastodon.android.fragments.onboarding.CustomWelcomeFragment; import org.joinmastodon.android.fragments.onboarding.CustomWelcomeFragment;
import org.joinmastodon.android.ui.text.HtmlParser;
import org.joinmastodon.android.ui.utils.CustomEmojiHelper;
import org.joinmastodon.android.ui.utils.UiUtils; import org.joinmastodon.android.ui.utils.UiUtils;
import org.joinmastodon.android.ui.views.CheckableRelativeLayout; import org.joinmastodon.android.ui.views.CheckableRelativeLayout;
@@ -40,7 +42,6 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.annotation.StringRes; import androidx.annotation.StringRes;
import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.LinearLayoutManager;
import me.grishka.appkit.FragmentStackActivity;
import me.grishka.appkit.Nav; import me.grishka.appkit.Nav;
import me.grishka.appkit.api.Callback; import me.grishka.appkit.api.Callback;
import me.grishka.appkit.api.ErrorResponse; import me.grishka.appkit.api.ErrorResponse;
@@ -282,7 +283,7 @@ public class AccountSwitcherSheet extends BottomSheet{
@SuppressLint("SetTextI18n") @SuppressLint("SetTextI18n")
@Override @Override
public void onBind(AccountSession item){ public void onBind(AccountSession item){
name.setText(item.self.displayName); HtmlParser.setTextWithCustomEmoji(name, item.self.getDisplayName(), item.self.emojis);
username.setText(item.getFullUsername()); username.setText(item.getFullUsername());
radioButton.setVisibility(externalShare ? View.GONE : View.VISIBLE); radioButton.setVisibility(externalShare ? View.GONE : View.VISIBLE);
extraBtnWrap.setVisibility(externalShare && openInApp ? View.VISIBLE : View.GONE); extraBtnWrap.setVisibility(externalShare && openInApp ? View.VISIBLE : View.GONE);

View File

@@ -26,9 +26,7 @@ import org.joinmastodon.android.ui.utils.CustomEmojiHelper;
import org.joinmastodon.android.ui.utils.UiUtils; import org.joinmastodon.android.ui.utils.UiUtils;
import org.joinmastodon.android.ui.views.ProgressBarButton; import org.joinmastodon.android.ui.views.ProgressBarButton;
import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List;
import me.grishka.appkit.imageloader.ImageLoaderViewHolder; import me.grishka.appkit.imageloader.ImageLoaderViewHolder;
import me.grishka.appkit.imageloader.requests.ImageLoaderRequest; import me.grishka.appkit.imageloader.requests.ImageLoaderRequest;
@@ -53,9 +51,9 @@ public class AccountCardStatusDisplayItem extends StatusDisplayItem{
coverRequest=new UrlImageLoaderRequest(account.header, 1000, 1000); coverRequest=new UrlImageLoaderRequest(account.header, 1000, 1000);
parsedBio=HtmlParser.parse(account.note, account.emojis, Collections.emptyList(), Collections.emptyList(), parentFragment.getAccountID()); parsedBio=HtmlParser.parse(account.note, account.emojis, Collections.emptyList(), Collections.emptyList(), parentFragment.getAccountID());
if(account.emojis.isEmpty()){ if(account.emojis.isEmpty()){
parsedName=account.displayName; parsedName=account.getDisplayName();
}else{ }else{
parsedName=HtmlParser.parseCustomEmoji(account.displayName, account.emojis); parsedName=HtmlParser.parseCustomEmoji(account.getDisplayName(), account.emojis);
emojiHelper.setText(new SpannableStringBuilder(parsedName).append(parsedBio)); emojiHelper.setText(new SpannableStringBuilder(parsedName).append(parsedBio));
} }
} }
@@ -149,7 +147,7 @@ public class AccountCardStatusDisplayItem extends StatusDisplayItem{
followingCount.setVisibility(item.account.followingCount < 0 ? View.GONE : View.VISIBLE); followingCount.setVisibility(item.account.followingCount < 0 ? View.GONE : View.VISIBLE);
followingLabel.setVisibility(item.account.followingCount < 0 ? View.GONE : View.VISIBLE); followingLabel.setVisibility(item.account.followingCount < 0 ? View.GONE : View.VISIBLE);
relationship=item.parentFragment.getRelationship(item.account.id); relationship=item.parentFragment.getRelationship(item.account.id);
UiUtils.setExtraTextInfo(item.parentFragment.getContext(), null, findViewById(R.id.pronouns), true, false, false, item.account); UiUtils.setExtraTextInfo(item.parentFragment.getContext(), null,true, false, false, item.account);
if(item.notification.type==Notification.Type.FOLLOW_REQUEST && (relationship==null || !relationship.followedBy)){ if(item.notification.type==Notification.Type.FOLLOW_REQUEST && (relationship==null || !relationship.followedBy)){
actionWrap.setVisibility(View.GONE); actionWrap.setVisibility(View.GONE);

View File

@@ -96,7 +96,7 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
GlobalUserPreferences.playGifs ? user.avatar : user.avatarStatic, GlobalUserPreferences.playGifs ? user.avatar : user.avatarStatic,
V.dp(50), V.dp(50)); V.dp(50), V.dp(50));
this.accountID=accountID; this.accountID=accountID;
parsedName=new SpannableStringBuilder(user.displayName); parsedName=new SpannableStringBuilder(user.getDisplayName());
this.status=status; this.status=status;
this.notification=notification; this.notification=notification;
this.scheduledStatus=scheduledStatus; this.scheduledStatus=scheduledStatus;
@@ -137,7 +137,7 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
} }
public static class Holder extends StatusDisplayItem.Holder<HeaderStatusDisplayItem> implements ImageLoaderViewHolder{ public static class Holder extends StatusDisplayItem.Holder<HeaderStatusDisplayItem> implements ImageLoaderViewHolder{
private final TextView name, time, username, extraText, pronouns; private final TextView name, time, username, extraText;
private final View collapseBtn, timeUsernameSeparator; private final View collapseBtn, timeUsernameSeparator;
private final ImageView avatar, more, visibility, deleteNotification, unreadIndicator, markAsRead, collapseBtnIcon, botIcon; private final ImageView avatar, more, visibility, deleteNotification, unreadIndicator, markAsRead, collapseBtnIcon, botIcon;
private final PopupMenu optionsMenu; private final PopupMenu optionsMenu;
@@ -164,7 +164,6 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
collapseBtn=findViewById(R.id.collapse_btn); collapseBtn=findViewById(R.id.collapse_btn);
collapseBtnIcon=findViewById(R.id.collapse_btn_icon); collapseBtnIcon=findViewById(R.id.collapse_btn_icon);
extraText=findViewById(R.id.extra_text); extraText=findViewById(R.id.extra_text);
pronouns=findViewById(R.id.pronouns);
avatar.setOnClickListener(this::onAvaClick); avatar.setOnClickListener(this::onAvaClick);
avatar.setOutlineProvider(OutlineProviders.roundedRect(12)); avatar.setOutlineProvider(OutlineProviders.roundedRect(12));
avatar.setClipToOutline(true); avatar.setClipToOutline(true);
@@ -332,7 +331,7 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
if(TextUtils.isEmpty(item.extraText)){ if(TextUtils.isEmpty(item.extraText)){
if (item.status != null) { if (item.status != null) {
boolean displayPronouns=item.parentFragment instanceof ThreadFragment ? GlobalUserPreferences.displayPronounsInThreads : GlobalUserPreferences.displayPronounsInTimelines; boolean displayPronouns=item.parentFragment instanceof ThreadFragment ? GlobalUserPreferences.displayPronounsInThreads : GlobalUserPreferences.displayPronounsInTimelines;
UiUtils.setExtraTextInfo(item.parentFragment.getContext(), extraText, pronouns, displayPronouns, item.status.visibility==StatusPrivacy.DIRECT, item.status.localOnly || item.status.visibility==StatusPrivacy.LOCAL, item.status.account); UiUtils.setExtraTextInfo(item.parentFragment.getContext(), extraText, displayPronouns, item.status.visibility==StatusPrivacy.DIRECT, item.status.localOnly || item.status.visibility==StatusPrivacy.LOCAL, item.status.account);
} }
}else{ }else{
extraText.setVisibility(View.VISIBLE); extraText.setVisibility(View.VISIBLE);

View File

@@ -18,7 +18,6 @@ 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;
@@ -62,7 +61,7 @@ public class NotificationHeaderStatusDisplayItem extends StatusDisplayItem{
TextUtils.isEmpty(notification.account.avatar) ? session.getDefaultAvatarUrl() : TextUtils.isEmpty(notification.account.avatar) ? session.getDefaultAvatarUrl() :
GlobalUserPreferences.playGifs ? notification.account.avatar : notification.account.avatarStatic, GlobalUserPreferences.playGifs ? notification.account.avatar : notification.account.avatarStatic,
V.dp(50), V.dp(50)); V.dp(50), V.dp(50));
SpannableStringBuilder parsedName=new SpannableStringBuilder(notification.account.displayName); SpannableStringBuilder parsedName=new SpannableStringBuilder(notification.account.getDisplayName());
HtmlParser.parseCustomEmoji(parsedName, notification.account.emojis); HtmlParser.parseCustomEmoji(parsedName, notification.account.emojis);
String str = parentFragment.getString(switch(notification.type){ String str = parentFragment.getString(switch(notification.type){
case FOLLOW -> R.string.user_followed_you; case FOLLOW -> R.string.user_followed_you;

View File

@@ -87,8 +87,9 @@ public class ReblogOrReplyLineStatusDisplayItem extends StatusDisplayItem{
@Override @Override
public ImageLoaderRequest getImageRequest(int index){ public ImageLoaderRequest getImageRequest(int index){
CustomEmojiHelper helper=index<emojiHelper.getImageCount() ? emojiHelper : extra.emojiHelper; int firstHelperCount=emojiHelper.getImageCount();
return helper.getImageRequest(index%emojiHelper.getImageCount()); CustomEmojiHelper helper=index<firstHelperCount ? emojiHelper : extra.emojiHelper;
return helper.getImageRequest(firstHelperCount>0 ? index%firstHelperCount : index);
} }
public static class Holder extends StatusDisplayItem.Holder<ReblogOrReplyLineStatusDisplayItem> implements ImageLoaderViewHolder{ public static class Holder extends StatusDisplayItem.Holder<ReblogOrReplyLineStatusDisplayItem> implements ImageLoaderViewHolder{
@@ -136,8 +137,9 @@ public class ReblogOrReplyLineStatusDisplayItem extends StatusDisplayItem{
@Override @Override
public void setImage(int index, Drawable image){ public void setImage(int index, Drawable image){
CustomEmojiHelper helper=index<item.emojiHelper.getImageCount() ? item.emojiHelper : item.extra.emojiHelper; int firstHelperCount=item.emojiHelper.getImageCount();
helper.setImageDrawable(index%item.emojiHelper.getImageCount(), image); CustomEmojiHelper helper=index<firstHelperCount ? item.emojiHelper : item.extra.emojiHelper;
helper.setImageDrawable(firstHelperCount>0 ? index%firstHelperCount : index, image);
text.invalidate(); text.invalidate();
extraText.invalidate(); extraText.invalidate();
} }

View File

@@ -15,7 +15,6 @@ import android.view.ViewGroup;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
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;
import org.joinmastodon.android.api.session.AccountSessionManager; import org.joinmastodon.android.api.session.AccountSessionManager;
@@ -30,7 +29,6 @@ import org.joinmastodon.android.model.Account;
import org.joinmastodon.android.model.Attachment; import org.joinmastodon.android.model.Attachment;
import org.joinmastodon.android.model.DisplayItemsParent; import org.joinmastodon.android.model.DisplayItemsParent;
import org.joinmastodon.android.model.LegacyFilter; import org.joinmastodon.android.model.LegacyFilter;
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.Notification;
@@ -41,7 +39,6 @@ import org.joinmastodon.android.ui.PhotoLayoutHelper;
import org.joinmastodon.android.ui.text.HtmlParser; import org.joinmastodon.android.ui.text.HtmlParser;
import org.joinmastodon.android.ui.utils.UiUtils; import org.joinmastodon.android.ui.utils.UiUtils;
import org.joinmastodon.android.ui.viewholders.AccountViewHolder; import org.joinmastodon.android.ui.viewholders.AccountViewHolder;
import org.joinmastodon.android.utils.StatusFilterPredicate;
import org.parceler.Parcels; import org.parceler.Parcels;
import java.util.ArrayList; import java.util.ArrayList;
@@ -92,7 +89,7 @@ public abstract class StatusDisplayItem{
} }
@NonNull @NonNull
public String getContentID(){ public String getContentStatusID(){
if(parentFragment instanceof StatusListFragment slf){ if(parentFragment instanceof StatusListFragment slf){
Status s=slf.getContentStatusByID(parentID); Status s=slf.getContentStatusByID(parentID);
return s!=null ? s.id : parentID; return s!=null ? s.id : parentID;
@@ -142,11 +139,11 @@ public abstract class StatusDisplayItem{
String parentID = parent.getID(); String parentID = parent.getID();
String text = threadReply ? fragment.getString(R.string.sk_show_thread) String text = threadReply ? fragment.getString(R.string.sk_show_thread)
: account == null ? fragment.getString(R.string.sk_in_reply) : account == null ? fragment.getString(R.string.sk_in_reply)
: status.reblog != null ? account.displayName : status.reblog != null ? account.getDisplayName()
: fragment.getString(R.string.in_reply_to, account.displayName); : fragment.getString(R.string.in_reply_to, account.getDisplayName());
String fullText = threadReply ? fragment.getString(R.string.sk_show_thread) String fullText = threadReply ? fragment.getString(R.string.sk_show_thread)
: account == null ? fragment.getString(R.string.sk_in_reply) : account == null ? fragment.getString(R.string.sk_in_reply)
: fragment.getString(R.string.in_reply_to, account.displayName); : fragment.getString(R.string.in_reply_to, account.getDisplayName());
return new ReblogOrReplyLineStatusDisplayItem( return new ReblogOrReplyLineStatusDisplayItem(
parentID, fragment, text, account == null ? List.of() : account.emojis, parentID, fragment, text, account == null ? List.of() : account.emojis,
R.drawable.ic_fluent_arrow_reply_20sp_filled, null, null, fullText, status R.drawable.ic_fluent_arrow_reply_20sp_filled, null, null, fullText, status
@@ -176,12 +173,11 @@ public abstract class StatusDisplayItem{
if(status.reblog!=null){ if(status.reblog!=null){
boolean isOwnPost = AccountSessionManager.getInstance().isSelf(fragment.getAccountID(), status.account); boolean isOwnPost = AccountSessionManager.getInstance().isSelf(fragment.getAccountID(), status.account);
String fullText = fragment.getString(R.string.user_boosted, status.account.displayName); String text=fragment.getString(R.string.user_boosted, status.account.getDisplayName());
String text = replyLine != null ? status.account.displayName : fullText;
items.add(new ReblogOrReplyLineStatusDisplayItem(parentID, fragment, text, status.account.emojis, R.drawable.ic_fluent_arrow_repeat_all_20sp_filled, isOwnPost ? status.visibility : null, i->{ items.add(new ReblogOrReplyLineStatusDisplayItem(parentID, fragment, text, status.account.emojis, R.drawable.ic_fluent_arrow_repeat_all_20sp_filled, isOwnPost ? status.visibility : null, i->{
args.putParcelable("profileAccount", Parcels.wrap(status.account)); args.putParcelable("profileAccount", Parcels.wrap(status.account));
Nav.go(fragment.getActivity(), ProfileFragment.class, args); Nav.go(fragment.getActivity(), ProfileFragment.class, args);
}, fullText, status)); }, null, status));
} else if (!(status.tags.isEmpty() || } else if (!(status.tags.isEmpty() ||
fragment instanceof HashtagTimelineFragment || fragment instanceof HashtagTimelineFragment ||
fragment instanceof ListTimelineFragment fragment instanceof ListTimelineFragment

View File

@@ -210,9 +210,10 @@ public class TextStatusDisplayItem extends StatusDisplayItem{
Translation existingTrans=item.status.getContentStatus().translation; Translation existingTrans=item.status.getContentStatus().translation;
String existingTransLang=existingTrans!=null ? existingTrans.detectedSourceLanguage : null; String existingTransLang=existingTrans!=null ? existingTrans.detectedSourceLanguage : null;
String lang=existingTransLang!=null ? existingTransLang : item.status.getContentStatus().language; String lang=existingTransLang!=null ? existingTransLang : item.status.getContentStatus().language;
String displayLang=Locale.forLanguageTag(lang != null ? lang Locale locale=lang!=null ? Locale.forLanguageTag(lang) : null;
: AccountSessionManager.get(item.parentFragment.getAccountID()).preferences.postingDefaultLanguage).getDisplayLanguage(); translationButton.setText(locale!=null
translationButton.setText(item.parentFragment.getString(R.string.translate_post, !displayLang.isBlank() ? displayLang : lang)); ? item.parentFragment.getString(R.string.translate_post, locale.getDisplayLanguage())
: item.parentFragment.getString(R.string.sk_translate_post));
translationButton.setClickable(true); translationButton.setClickable(true);
translationButton.animate().alpha(1).setDuration(100).start(); translationButton.animate().alpha(1).setDuration(100).start();
translationInfo.setVisibility(View.GONE); translationInfo.setVisibility(View.GONE);

View File

@@ -0,0 +1,88 @@
package org.joinmastodon.android.ui.utils;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.IntEvaluator;
import android.animation.ObjectAnimator;
import android.graphics.drawable.Drawable;
import android.view.ActionMode;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import org.joinmastodon.android.R;
import java.util.function.IntSupplier;
import me.grishka.appkit.FragmentStackActivity;
import me.grishka.appkit.fragments.AppKitFragment;
public class ActionModeHelper{
public static ActionMode startActionMode(AppKitFragment fragment, IntSupplier statusBarColorSupplier, ActionMode.Callback callback){
FragmentStackActivity activity=(FragmentStackActivity) fragment.getActivity();
return activity.startActionMode(new ActionMode.Callback(){
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu){
if(!callback.onCreateActionMode(mode, menu))
return false;
ObjectAnimator anim=ObjectAnimator.ofInt(activity.getWindow(), "statusBarColor", statusBarColorSupplier.getAsInt(), UiUtils.getThemeColor(activity, R.attr.colorM3Primary));
anim.setEvaluator(new IntEvaluator(){
@Override
public Integer evaluate(float fraction, Integer startValue, Integer endValue){
return UiUtils.alphaBlendColors(startValue, endValue, fraction);
}
});
anim.start();
activity.invalidateSystemBarColors(fragment);
View fakeView=new View(activity);
// mode.setCustomView(fakeView);
// int buttonID=activity.getResources().getIdentifier("action_mode_close_button", "id", "android");
// View btn=activity.getWindow().getDecorView().findViewById(buttonID);
// if(btn!=null){
// ((ViewGroup.MarginLayoutParams)btn.getLayoutParams()).setMarginEnd(0);
// }
return true;
}
@Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu){
if(!callback.onPrepareActionMode(mode, menu))
return false;
for(int i=0;i<menu.size();i++){
Drawable icon=menu.getItem(i).getIcon();
if(icon!=null){
icon=icon.mutate();
icon.setTint(UiUtils.getThemeColor(activity, R.attr.colorM3OnPrimary));
menu.getItem(i).setIcon(icon);
}
}
return true;
}
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item){
return callback.onActionItemClicked(mode, item);
}
@Override
public void onDestroyActionMode(ActionMode mode){
ObjectAnimator anim=ObjectAnimator.ofInt(activity.getWindow(), "statusBarColor", UiUtils.getThemeColor(activity, R.attr.colorM3Primary), statusBarColorSupplier.getAsInt());
anim.setEvaluator(new IntEvaluator(){
@Override
public Integer evaluate(float fraction, Integer startValue, Integer endValue){
return UiUtils.alphaBlendColors(startValue, endValue, fraction);
}
});
anim.addListener(new AnimatorListenerAdapter(){
@Override
public void onAnimationEnd(Animator animation){
activity.getWindow().setStatusBarColor(0);
}
});
anim.start();
activity.invalidateSystemBarColors(fragment);
callback.onDestroyActionMode(mode);
}
});
}
}

View File

@@ -480,7 +480,7 @@ public class UiUtils {
public static void confirmToggleBlockUser(Activity activity, String accountID, Account account, boolean currentlyBlocked, Consumer<Relationship> resultCallback) { public static void confirmToggleBlockUser(Activity activity, String accountID, Account account, boolean currentlyBlocked, Consumer<Relationship> resultCallback) {
showConfirmationAlert(activity, activity.getString(currentlyBlocked ? R.string.confirm_unblock_title : R.string.confirm_block_title), showConfirmationAlert(activity, activity.getString(currentlyBlocked ? R.string.confirm_unblock_title : R.string.confirm_block_title),
activity.getString(currentlyBlocked ? R.string.confirm_unblock : R.string.confirm_block, account.displayName), activity.getString(currentlyBlocked ? R.string.confirm_unblock : R.string.confirm_block, account.getDisplayName()),
activity.getString(currentlyBlocked ? R.string.do_unblock : R.string.do_block), activity.getString(currentlyBlocked ? R.string.do_unblock : R.string.do_block),
R.drawable.ic_fluent_person_prohibited_28_regular, R.drawable.ic_fluent_person_prohibited_28_regular,
() -> { () -> {
@@ -508,7 +508,7 @@ public class UiUtils {
public static void confirmSoftBlockUser(Activity activity, String accountID, Account account, Consumer<Relationship> resultCallback) { public static void confirmSoftBlockUser(Activity activity, String accountID, Account account, Consumer<Relationship> resultCallback) {
showConfirmationAlert(activity, showConfirmationAlert(activity,
activity.getString(R.string.sk_remove_follower), activity.getString(R.string.sk_remove_follower),
activity.getString(R.string.sk_remove_follower_confirm, account.displayName), activity.getString(R.string.sk_remove_follower_confirm, account.getDisplayName()),
activity.getString(R.string.sk_do_remove_follower), activity.getString(R.string.sk_do_remove_follower),
R.drawable.ic_fluent_person_delete_24_regular, R.drawable.ic_fluent_person_delete_24_regular,
() -> new SetAccountBlocked(account.id, true).setCallback(new Callback<>() { () -> new SetAccountBlocked(account.id, true).setCallback(new Callback<>() {
@@ -566,7 +566,7 @@ public class UiUtils {
params.setMargins(0, V.dp(-12), 0, 0); params.setMargins(0, V.dp(-12), 0, 0);
durationView.setLayoutParams(params); durationView.setLayoutParams(params);
Button button=durationView.findViewById(R.id.button); Button button=durationView.findViewById(R.id.button);
((TextView) durationView.findViewById(R.id.message)).setText(context.getString(R.string.confirm_mute, account.displayName)); ((TextView) durationView.findViewById(R.id.message)).setText(context.getString(R.string.confirm_mute, account.getDisplayName()));
AtomicReference<Duration> muteDuration=new AtomicReference<>(Duration.ZERO); AtomicReference<Duration> muteDuration=new AtomicReference<>(Duration.ZERO);
@@ -600,7 +600,7 @@ public class UiUtils {
new M3AlertDialogBuilder(context) new M3AlertDialogBuilder(context)
.setTitle(context.getString(currentlyMuted ? R.string.confirm_unmute_title : R.string.confirm_mute_title)) .setTitle(context.getString(currentlyMuted ? R.string.confirm_unmute_title : R.string.confirm_mute_title))
.setMessage(currentlyMuted ? context.getString(R.string.confirm_unmute, account.displayName) : null) .setMessage(currentlyMuted ? context.getString(R.string.confirm_unmute, account.getDisplayName()) : null)
.setView(currentlyMuted ? null : durationView) .setView(currentlyMuted ? null : durationView)
.setPositiveButton(context.getString(currentlyMuted ? R.string.do_unmute : R.string.do_mute), (dlg, i)->{ .setPositiveButton(context.getString(currentlyMuted ? R.string.do_unmute : R.string.do_mute), (dlg, i)->{
new SetAccountMuted(account.id, !currentlyMuted, muteDuration.get().getSeconds()) new SetAccountMuted(account.id, !currentlyMuted, muteDuration.get().getSeconds())
@@ -638,11 +638,8 @@ public class UiUtils {
@Override @Override
public void onSuccess(Status result) { public void onSuccess(Status result) {
resultCallback.accept(result); resultCallback.accept(result);
CacheController cache=AccountSessionManager.get(accountID).getCacheController();
cache.deleteStatus(s.id);
E.post(new StatusDeletedEvent(s.id, accountID)); E.post(new StatusDeletedEvent(s.id, accountID));
if(status!=s){ if(status!=s){
cache.deleteStatus(status.id);
E.post(new StatusDeletedEvent(status.id, accountID)); E.post(new StatusDeletedEvent(status.id, accountID));
} }
} }
@@ -1110,23 +1107,21 @@ public class UiUtils {
return back; return back;
} }
public static boolean setExtraTextInfo(Context ctx, @Nullable TextView extraText, @Nullable TextView pronouns, boolean displayPronouns, boolean mentionedOnly, boolean localOnly, @Nullable Account account) { public static boolean setExtraTextInfo(Context ctx, @Nullable TextView extraText, boolean displayPronouns, boolean mentionedOnly, boolean localOnly, @Nullable Account account) {
List<String> extraParts = extraText!=null && (localOnly || mentionedOnly) ? new ArrayList<>() : null; List<String> extraParts=new ArrayList<>();
Optional<String> p=pronouns==null || !displayPronouns ? Optional.empty() : extractPronouns(ctx, account); Optional<String> p=!displayPronouns ? Optional.empty() : extractPronouns(ctx, account);
if(p.isPresent()) {
HtmlParser.setTextWithCustomEmoji(pronouns, p.get(), account.emojis);
pronouns.setVisibility(View.VISIBLE);
}else if(pronouns!=null){
pronouns.setVisibility(View.GONE);
}
if(localOnly) if(localOnly)
extraParts.add(ctx.getString(R.string.sk_inline_local_only)); extraParts.add(ctx.getString(R.string.sk_inline_local_only));
if(mentionedOnly) if(mentionedOnly)
extraParts.add(ctx.getString(R.string.sk_inline_direct)); extraParts.add(ctx.getString(R.string.sk_inline_direct));
if(extraText!=null && extraParts!=null && !extraParts.isEmpty()) { if(p.isPresent() && extraParts.isEmpty())
String sepp = ctx.getString(R.string.sk_separator); extraParts.add(p.get());
String text = String.join(" " + sepp + " ", extraParts);
if(account == null) extraText.setText(text); if(extraText!=null && !extraParts.isEmpty()) {
String sepp=ctx.getString(R.string.sk_separator);
String text=String.join(" " + sepp + " ", extraParts);
if(account==null) extraText.setText(text);
else HtmlParser.setTextWithCustomEmoji(extraText, text, account.emojis); else HtmlParser.setTextWithCustomEmoji(extraText, text, account.emojis);
extraText.setVisibility(View.VISIBLE); extraText.setVisibility(View.VISIBLE);
return true; return true;
@@ -1702,14 +1697,17 @@ public class UiUtils {
Matcher matcher=trimPronouns.matcher(text); Matcher matcher=trimPronouns.matcher(text);
if(!matcher.find()) return null; if(!matcher.find()) return null;
String matched=matcher.group(1); String pronouns=matcher.group(1);
// crude fix to allow for pronouns like "it(/she)" // crude fix to allow for pronouns like "it(/she)"
int missingClosingParens=0; int missingClosingParens=0;
for(char c : matched.toCharArray()){ for(char c : pronouns.toCharArray()){
if(c=='(') missingClosingParens++; if(c=='(') missingClosingParens++;
if(c==')') missingClosingParens--; if(c==')') missingClosingParens--;
} }
return matched+")".repeat(Math.max(0, missingClosingParens)); pronouns+=")".repeat(Math.max(0, missingClosingParens));
// if ends with an un-closed custom emoji
if(pronouns.matches("^.*\\s+:[a-zA-Z_]+$")) pronouns+=':';
return pronouns;
} }
// https://stackoverflow.com/questions/9475589/how-to-get-string-from-different-locales-in-android // https://stackoverflow.com/questions/9475589/how-to-get-string-from-different-locales-in-android

View File

@@ -73,6 +73,6 @@ public abstract class ListItemViewHolder<T extends ListItem<?>> extends Bindable
@Override @Override
public void onClick(){ public void onClick(){
item.onClick.run(); item.performClick();
} }
} }

View File

@@ -1,33 +1,40 @@
package org.joinmastodon.android.ui.views; package org.joinmastodon.android.ui.views;
import android.content.Context; import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.view.View; import android.view.View;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.TextView; import android.widget.TextView;
import me.grishka.appkit.utils.V; import org.joinmastodon.android.R;
/** /**
* A LinearLayout for TextViews. First child TextView will get truncated if it doesn't fit, remaining will always wrap content. * A LinearLayout for TextViews. First child TextView will get truncated if it doesn't fit, remaining will always wrap content.
*/ */
public class HeaderSubtitleLinearLayout extends LinearLayout{ public class HeaderSubtitleLinearLayout extends LinearLayout{
private float firstFraction;
public HeaderSubtitleLinearLayout(Context context){ public HeaderSubtitleLinearLayout(Context context){
super(context); this(context, null);
} }
public HeaderSubtitleLinearLayout(Context context, AttributeSet attrs){ public HeaderSubtitleLinearLayout(Context context, AttributeSet attrs){
super(context, attrs); this(context, attrs, 0);
} }
public HeaderSubtitleLinearLayout(Context context, AttributeSet attrs, int defStyleAttr){ public HeaderSubtitleLinearLayout(Context context, AttributeSet attrs, int defStyleAttr){
super(context, attrs, defStyleAttr); super(context, attrs, defStyleAttr);
TypedArray ta=context.obtainStyledAttributes(attrs, R.styleable.HeaderSubtitleLinearLayout);
firstFraction=ta.getFraction(R.styleable.HeaderSubtitleLinearLayout_firstFraction, 1, 1, 0.5f);
ta.recycle();
} }
@Override @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
if(getLayoutChildCount()>1){ if(getLayoutChildCount()>1){
int remainingWidth=MeasureSpec.getSize(widthMeasureSpec); int fullWidth=MeasureSpec.getSize(widthMeasureSpec);
int remainingWidth=fullWidth;
for(int i=1;i<getChildCount();i++){ for(int i=1;i<getChildCount();i++){
View v=getChildAt(i); View v=getChildAt(i);
if(v.getVisibility()==GONE) if(v.getVisibility()==GONE)
@@ -38,8 +45,7 @@ public class HeaderSubtitleLinearLayout extends LinearLayout{
} }
View first=getChildAt(0); View first=getChildAt(0);
if(first instanceof TextView){ if(first instanceof TextView){
// guaranteeing at least 64dp of width for the display name ((TextView) first).setMaxWidth(Math.max(remainingWidth, (int)(firstFraction*fullWidth)));
((TextView) first).setMaxWidth(Math.max(remainingWidth, V.dp(64)));
} }
}else{ }else{
View first=getChildAt(0); View first=getChildAt(0);
@@ -58,4 +64,12 @@ public class HeaderSubtitleLinearLayout extends LinearLayout{
} }
return count; return count;
} }
public void setFirstFraction(float firstFraction){
this.firstFraction=firstFraction;
}
public float getFirstFraction(){
return firstFraction;
}
} }

View File

@@ -3,19 +3,13 @@
android:color="@color/m3_primary_overlay"> android:color="@color/m3_primary_overlay">
<item android:gravity="center_vertical" android:height="40dp"> <item android:gravity="center_vertical" android:height="40dp">
<selector> <selector>
<item android:state_enabled="true" android:state_selected="true"> <item android:state_enabled="true">
<shape> <shape>
<solid android:color="?colorM3SecondaryContainer"/> <solid android:color="?colorM3SecondaryContainer"/>
<corners android:radius="20dp"/> <corners android:radius="20dp"/>
</shape> </shape>
</item> </item>
<item android:state_selected="false"> <item>
<shape>
<stroke android:color="@color/m3_on_surface_overlay" android:width="1dp"/>
<corners android:radius="20dp"/>
</shape>
</item>
<item android:state_enabled="false">
<shape> <shape>
<solid android:color="?colorM3DisabledBackground"/> <solid android:color="?colorM3DisabledBackground"/>
<corners android:radius="20dp"/> <corners android:radius="20dp"/>

View File

@@ -3,19 +3,13 @@
android:color="@color/m3_primary_overlay"> android:color="@color/m3_primary_overlay">
<item android:gravity="center" android:height="40dp" android:width="40dp"> <item android:gravity="center" android:height="40dp" android:width="40dp">
<selector> <selector>
<item android:state_enabled="true" android:state_selected="true"> <item android:state_enabled="true">
<shape> <shape>
<solid android:color="?colorM3SecondaryContainer"/> <solid android:color="?colorM3SecondaryContainer"/>
<corners android:radius="20dp"/> <corners android:radius="20dp"/>
</shape> </shape>
</item> </item>
<item android:state_selected="false"> <item>
<shape>
<stroke android:color="@color/m3_on_surface_overlay" android:width="1dp"/>
<corners android:radius="20dp"/>
</shape>
</item>
<item android:state_enabled="false">
<shape> <shape>
<solid android:color="?colorM3DisabledBackground"/> <solid android:color="?colorM3DisabledBackground"/>
<corners android:radius="20dp"/> <corners android:radius="20dp"/>

View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="@color/m3_primary_overlay">
<item android:gravity="center" android:height="40dp" android:width="40dp">
<selector>
<item android:state_enabled="true" android:state_selected="true">
<shape>
<solid android:color="?colorM3SecondaryContainer"/>
<corners android:radius="20dp"/>
</shape>
</item>
<item android:state_selected="false">
<shape>
<stroke android:color="@color/m3_on_surface_overlay" android:width="1dp"/>
<corners android:radius="20dp"/>
</shape>
</item>
<item android:state_enabled="false">
<shape>
<solid android:color="?colorM3DisabledBackground"/>
<corners android:radius="20dp"/>
</shape>
</item>
</selector>
</item>
<item android:id="@android:id/mask" android:gravity="center" android:height="40dp" android:width="40dp">
<shape>
<solid android:color="#000"/>
<corners android:radius="20dp"/>
</shape>
</item>
</ripple>

View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="@color/m3_primary_overlay">
<item android:gravity="center_vertical" android:height="40dp">
<selector>
<item android:state_enabled="true" android:state_selected="true">
<shape>
<solid android:color="?colorM3SecondaryContainer"/>
<corners android:radius="20dp"/>
</shape>
</item>
<item android:state_selected="false">
<shape>
<stroke android:color="@color/m3_on_surface_overlay" android:width="1dp"/>
<corners android:radius="20dp"/>
</shape>
</item>
<item android:state_enabled="false">
<shape>
<solid android:color="?colorM3DisabledBackground"/>
<corners android:radius="20dp"/>
</shape>
</item>
</selector>
</item>
<item android:id="@android:id/mask" android:gravity="center_vertical" android:height="40dp">
<shape>
<solid android:color="#000"/>
<corners android:radius="20dp"/>
</shape>
</item>
</ripple>

View File

@@ -1,10 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android" android:color="@color/highlight_over_dark">
<item>
<shape>
<solid android:color="?colorPrimary800"/>
<corners android:radius="16sp"/>
<padding android:left="16sp" android:right="16sp"/>
</shape>
</item>
</ripple>

View File

@@ -0,0 +1,3 @@
<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="M17.5 12c3.038 0 5.5 2.463 5.5 5.5 0 3.038-2.462 5.5-5.5 5.5-3.037 0-5.5-2.462-5.5-5.5 0-3.037 2.463-5.5 5.5-5.5zm-2.646 5.147c-0.195-0.196-0.512-0.196-0.707 0-0.196 0.195-0.196 0.512 0 0.707l2 2c0.195 0.195 0.512 0.195 0.707 0l4-4c0.195-0.195 0.195-0.512 0-0.707-0.195-0.196-0.512-0.196-0.707 0L16.5 18.793l-1.646-1.646zM12.023 14c-0.297 0.463-0.537 0.966-0.709 1.5H4.253c-0.414 0-0.75 0.335-0.75 0.75v0.577c0 0.535 0.192 1.053 0.54 1.46 1.253 1.469 3.22 2.214 5.957 2.214 0.597 0 1.157-0.035 1.68-0.106 0.246 0.495 0.553 0.954 0.912 1.367-0.795 0.16-1.66 0.24-2.592 0.24-3.146 0-5.532-0.906-7.098-2.74-0.58-0.679-0.898-1.543-0.898-2.435v-0.578C2.004 15.007 3.01 14 4.253 14h7.77zM10 2.005c2.762 0 5 2.239 5 5s-2.238 5-5 5c-2.761 0-5-2.239-5-5s2.239-5 5-5zm0 1.5c-1.933 0-3.5 1.567-3.5 3.5s1.567 3.5 3.5 3.5 3.5-1.567 3.5-3.5-1.567-3.5-3.5-3.5z" android:fillColor="@color/fluent_default_icon_tint"/>
</vector>

View File

@@ -30,7 +30,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:minHeight="48dp" android:minHeight="48dp"
android:minWidth="48dp" android:minWidth="48dp"
android:background="@drawable/bg_button_m3_tonal_circle" android:background="@drawable/bg_button_m3_tonal_circle_selector"
android:tooltipText="@string/sk_button_react" android:tooltipText="@string/sk_button_react"
android:contentDescription="@string/sk_button_react" android:contentDescription="@string/sk_button_react"
android:src="@drawable/ic_fluent_add_24_filled" /> android:src="@drawable/ic_fluent_add_24_filled" />

View File

@@ -22,7 +22,6 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:paddingHorizontal="15dp"> android:paddingHorizontal="15dp">
<!-- avatar width (46sp) / 2 - button width (24dp) / 2 -->
<FrameLayout <FrameLayout
android:layout_weight="1" android:layout_weight="1"

View File

@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:paddingHorizontal="16dp"> android:paddingHorizontal="16dp">
@@ -10,7 +11,7 @@
android:id="@+id/buttons" android:id="@+id/buttons"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="6dp" android:layout_marginTop="5dp"
android:layout_alignParentTop="true" android:layout_alignParentTop="true"
android:layout_alignParentEnd="true"> android:layout_alignParentEnd="true">
@@ -107,6 +108,7 @@
<org.joinmastodon.android.ui.views.HeaderSubtitleLinearLayout <org.joinmastodon.android.ui.views.HeaderSubtitleLinearLayout
android:id="@+id/name_wrap" android:id="@+id/name_wrap"
app:firstFraction="60%"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_toEndOf="@id/avatar" android:layout_toEndOf="@id/avatar"
@@ -125,20 +127,6 @@
android:gravity="start|center_vertical" android:gravity="start|center_vertical"
tools:text="Eugen" /> tools:text="Eugen" />
<TextView
android:id="@+id/pronouns"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8sp"
android:maxWidth="161sp"
android:ellipsize="end"
android:singleLine="true"
android:textAppearance="@style/m3_title_medium"
android:fontFamily="sans-serif"
android:textAlignment="viewStart"
android:textColor="?colorM3OnSurface"
tools:text="they/them" />
<TextView <TextView
android:id="@+id/extra_text" android:id="@+id/extra_text"
android:layout_width="wrap_content" android:layout_width="wrap_content"
@@ -146,8 +134,7 @@
android:layout_marginStart="8sp" android:layout_marginStart="8sp"
android:ellipsize="end" android:ellipsize="end"
android:singleLine="true" android:singleLine="true"
android:textAppearance="@style/m3_title_medium" android:textAppearance="@style/m3_body_medium"
android:fontFamily="sans-serif"
android:textAlignment="viewStart" android:textAlignment="viewStart"
android:textColor="?colorM3OnSurface" android:textColor="?colorM3OnSurface"
tools:text="boosted your cat picture" /> tools:text="boosted your cat picture" />

View File

@@ -1,6 +1,8 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<org.joinmastodon.android.ui.views.HeaderSubtitleLinearLayout <org.joinmastodon.android.ui.views.HeaderSubtitleLinearLayout
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
app:firstFraction="30%"
android:orientation="horizontal" android:orientation="horizontal"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@@ -45,6 +47,6 @@
android:drawableTint="?colorM3OnSurface" android:drawableTint="?colorM3OnSurface"
android:drawablePadding="6dp" android:drawablePadding="6dp"
android:singleLine="true" android:singleLine="true"
android:ellipsize="end"/> android:ellipsize="middle"/>
</org.joinmastodon.android.ui.views.HeaderSubtitleLinearLayout> </org.joinmastodon.android.ui.views.HeaderSubtitleLinearLayout>

View File

@@ -49,7 +49,7 @@
<Button <Button
android:id="@+id/advanced" android:id="@+id/advanced"
style="@style/Widget.Mastodon.M3.Button.Outlined" style="@style/Widget.Mastodon.M3.Button.Outlined"
android:background="@drawable/bg_button_m3_tonal" android:background="@drawable/bg_button_m3_tonal_selector"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginHorizontal="24dp" android:layout_marginHorizontal="24dp"

View File

@@ -110,7 +110,7 @@
android:layout_marginStart="8sp" android:layout_marginStart="8sp"
android:ellipsize="end" android:ellipsize="end"
android:singleLine="true" android:singleLine="true"
android:textAppearance="@style/m3_title_medium" android:textAppearance="@style/m3_body_medium"
android:textAlignment="viewStart" android:textAlignment="viewStart"
android:textColor="?colorM3OnSurface" android:textColor="?colorM3OnSurface"
tools:text="@string/sk_inline_local_only" /> tools:text="@string/sk_inline_local_only" />
@@ -366,6 +366,7 @@
<Button <Button
style="@style/Widget.Mastodon.M3.Button.Tonal.Icon" style="@style/Widget.Mastodon.M3.Button.Tonal.Icon"
android:background="@drawable/bg_button_m3_tonal_selector"
android:id="@+id/sensitive_item" android:id="@+id/sensitive_item"
android:orientation="horizontal" android:orientation="horizontal"
android:layout_width="wrap_content" android:layout_width="wrap_content"

View File

@@ -93,7 +93,7 @@
android:layout_width="48dp" android:layout_width="48dp"
android:layout_height="48dp" android:layout_height="48dp"
style="@style/Widget.Mastodon.M3.Button.Tonal" style="@style/Widget.Mastodon.M3.Button.Tonal"
android:background="@drawable/bg_button_m3_tonal_circle" android:background="@drawable/bg_button_m3_tonal_circle_selector"
android:paddingStart="12dp" android:paddingStart="12dp"
android:drawableStart="@drawable/ic_fluent_alert_24_selector" /> android:drawableStart="@drawable/ic_fluent_alert_24_selector" />

View File

@@ -34,7 +34,7 @@
android:visibility="gone" /> android:visibility="gone" />
<TextView <TextView
android:id="@+id/timeline_title" android:id="@+id/timeline_title"
style="?android:attr/titleTextAppearance" style="@style/action_bar_title"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="16dp" android:layout_marginStart="16dp"
@@ -47,22 +47,21 @@
android:layout_height="match_parent"> android:layout_height="match_parent">
<Button <Button
android:id="@+id/show_new_posts_btn" android:id="@+id/show_new_posts_btn"
android:layout_width="wrap_content" style="@style/Widget.Mastodon.M3.Button.Tonal.Icon"
android:layout_height="wrap_content" android:layout_width="wrap_content"
android:paddingVertical="2dp" android:layout_height="match_parent"
android:paddingStart="16dp" android:background="@drawable/bg_button_m3_tonal_selector"
android:paddingEnd="20dp" android:maxLines="1"
android:minHeight="32sp"
android:maxLines="2"
android:ellipsize="end" android:ellipsize="end"
android:lineSpacingMultiplier="0.8" android:textAppearance="@style/m3_title_medium"
android:textAppearance="@style/m3_title_medium" android:textSize="16sp"
android:textSize="16sp" android:text="@string/see_new_posts"
android:text="@string/see_new_posts"
android:textColor="@color/gray_25"
android:background="@drawable/bg_button_new_posts"
android:drawableStart="@drawable/ic_fluent_arrow_up_16_filled" android:drawableStart="@drawable/ic_fluent_arrow_up_16_filled"
android:drawablePadding="8dp"
android:layout_gravity="center" /> android:layout_gravity="center" />
<!--
using the selector background because..
the selected=false state's border looks better than the one from the outline style
(as per m3 spec) :( i should probably fix this at some point
-->
</FrameLayout> </FrameLayout>
</FrameLayout> </FrameLayout>

View File

@@ -23,5 +23,5 @@
android:layout_marginEnd="8dp" android:layout_marginEnd="8dp"
android:drawableTint="@null" android:drawableTint="@null"
android:drawableStart="@drawable/image_placeholder" android:drawableStart="@drawable/image_placeholder"
android:background="@drawable/bg_button_m3_tonal"/> android:background="@drawable/bg_button_m3_tonal_selector"/>
</FrameLayout> </FrameLayout>

View File

@@ -1,13 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"> <menu xmlns:android="http://schemas.android.com/apk/res/android">
<group android:id="@+id/menu_group1"> <group android:id="@+id/menu_group1">
<item android:id="@+id/open_with_account" android:title="@string/sk_open_with_account" android:visible="false" android:icon="@drawable/ic_fluent_person_swap_24_regular">
<menu android:id="@+id/accounts" />
</item>
<item android:id="@+id/share" android:title="@string/share_user" android:icon="@drawable/ic_fluent_share_24_regular"/>
<item android:id="@+id/open_in_browser" android:title="@string/open_in_browser" android:icon="@drawable/ic_fluent_globe_24_regular"/>
</group>
<group android:id="@+id/menu_group2">
<item android:id="@+id/manage_user_lists" android:title="@string/sk_lists_with_user" android:icon="@drawable/ic_fluent_people_24_regular"/> <item android:id="@+id/manage_user_lists" android:title="@string/sk_lists_with_user" android:icon="@drawable/ic_fluent_people_24_regular"/>
<item android:id="@+id/mute" android:title="@string/mute_user" android:icon="@drawable/ic_fluent_speaker_off_24_regular"/> <item android:id="@+id/mute" android:title="@string/mute_user" android:icon="@drawable/ic_fluent_speaker_off_24_regular"/>
<item android:id="@+id/hide_boosts" android:title="@string/hide_boosts_from_user" android:icon="@drawable/ic_fluent_arrow_repeat_all_off_24_regular"/> <item android:id="@+id/hide_boosts" android:title="@string/hide_boosts_from_user" android:icon="@drawable/ic_fluent_arrow_repeat_all_off_24_regular"/>
@@ -16,4 +9,11 @@
<item android:id="@+id/report" android:title="@string/report_user" android:icon="@drawable/ic_fluent_warning_24_regular"/> <item android:id="@+id/report" android:title="@string/report_user" android:icon="@drawable/ic_fluent_warning_24_regular"/>
<item android:id="@+id/block_domain" android:title="@string/block_domain" android:icon="@drawable/ic_fluent_shield_prohibited_24_regular"/> <item android:id="@+id/block_domain" android:title="@string/block_domain" android:icon="@drawable/ic_fluent_shield_prohibited_24_regular"/>
</group> </group>
<group android:id="@+id/menu_group2">
<item android:id="@+id/open_in_browser" android:title="@string/open_in_browser" android:icon="@drawable/ic_fluent_globe_24_regular"/>
<item android:id="@+id/share" android:title="@string/share_user" android:icon="@drawable/ic_fluent_share_24_regular"/>
<item android:id="@+id/open_with_account" android:title="@string/sk_open_with_account" android:visible="false" android:icon="@drawable/ic_fluent_person_swap_24_regular">
<menu android:id="@+id/accounts" />
</item>
</group>
</menu> </menu>

View File

@@ -1,14 +1,19 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"> <menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/followed_hashtags" android:title="@string/sk_hashtags_you_follow" android:icon="@drawable/ic_fluent_number_symbol_24_regular" android:showAsAction="always"/> <group android:id="@+id/menu_group1">
<item android:id="@+id/bookmarks" android:title="@string/bookmarks" android:icon="@drawable/ic_fluent_bookmark_multiple_24_regular" android:showAsAction="always"/> <item android:id="@+id/followed_hashtags" android:title="@string/sk_hashtags_you_follow" android:icon="@drawable/ic_fluent_number_symbol_24_regular" android:showAsAction="always"/>
<item android:id="@+id/open_with_account" android:title="@string/sk_open_with_account" android:icon="@drawable/ic_fluent_person_swap_24_regular"> <item android:id="@+id/bookmarks" android:title="@string/bookmarks" android:icon="@drawable/ic_fluent_bookmark_multiple_24_regular" android:showAsAction="always"/>
<menu android:id="@+id/accounts" /> <item android:id="@+id/manage_user_lists" android:title="@string/sk_your_lists" android:icon="@drawable/ic_fluent_people_24_regular"/>
</item> <item android:id="@+id/favorites" android:title="@string/your_favorites" android:icon="@drawable/ic_fluent_star_24_regular"/>
<item android:id="@+id/manage_user_lists" android:title="@string/sk_your_lists" android:icon="@drawable/ic_fluent_people_24_regular"/> <item android:id="@+id/muted_accounts" android:title="@string/sk_muted_accounts" android:icon="@drawable/ic_fluent_speaker_off_24_regular"/>
<item android:id="@+id/favorites" android:title="@string/your_favorites" android:icon="@drawable/ic_fluent_star_24_regular"/> <item android:id="@+id/blocked_accounts" android:title="@string/sk_blocked_accounts" android:icon="@drawable/ic_fluent_shield_24_regular"/>
<item android:id="@+id/muted_accounts" android:title="@string/sk_muted_accounts" android:icon="@drawable/ic_fluent_speaker_off_24_regular"/> <item android:id="@+id/scheduled" android:title="@string/sk_unsent_posts" android:icon="@drawable/ic_fluent_folder_open_24_regular"/>
<item android:id="@+id/blocked_accounts" android:title="@string/sk_blocked_accounts" android:icon="@drawable/ic_fluent_shield_24_regular"/> </group>
<item android:id="@+id/scheduled" android:title="@string/sk_unsent_posts" android:icon="@drawable/ic_fluent_folder_open_24_regular"/> <group android:id="@+id/menu_group2">
<item android:id="@+id/share" android:title="@string/share_user" android:icon="@drawable/ic_fluent_share_24_regular"/> <item android:id="@+id/open_in_browser" android:title="@string/open_in_browser" android:icon="@drawable/ic_fluent_globe_24_regular"/>
<item android:id="@+id/share" android:title="@string/share_user" android:icon="@drawable/ic_fluent_share_24_regular"/>
<item android:id="@+id/open_with_account" android:title="@string/sk_open_with_account" android:visible="false" android:icon="@drawable/ic_fluent_person_swap_24_regular">
<menu android:id="@+id/accounts" />
</item>
</group>
</menu> </menu>

View File

@@ -314,7 +314,6 @@
<!-- %s is the server domain --> <!-- %s is the server domain -->
<string name="local_timeline_info_banner">هذه هي جميع المشاركات من جميع المستخدمين في الخادم الخاص بك (%s).</string> <string name="local_timeline_info_banner">هذه هي جميع المشاركات من جميع المستخدمين في الخادم الخاص بك (%s).</string>
<string name="recommended_accounts_info_banner">قد تعجبك هذه الحسابات استنادا إلى حسابات أخرى تتابعها.</string> <string name="recommended_accounts_info_banner">قد تعجبك هذه الحسابات استنادا إلى حسابات أخرى تتابعها.</string>
<string name="see_new_posts">استعرض المنشورات الجديدة</string>
<string name="load_missing_posts">حمّل المَنشورات المَفقودَة</string> <string name="load_missing_posts">حمّل المَنشورات المَفقودَة</string>
<string name="follow_back">رُدّ المتابعة</string> <string name="follow_back">رُدّ المتابعة</string>
<string name="button_follow_pending">معلق</string> <string name="button_follow_pending">معلق</string>

View File

@@ -324,4 +324,5 @@
<string name="sk_settings_continues_playback">تراكُب صوتي</string> <string name="sk_settings_continues_playback">تراكُب صوتي</string>
<string name="sk_settings_enable_marquee">تمكين تمرير النص في عناوين الأشرطة</string> <string name="sk_settings_enable_marquee">تمكين تمرير النص في عناوين الأشرطة</string>
<string name="sk_settings_tabs_disable_swipe">تعطيل التمرير بين الألسِنة</string> <string name="sk_settings_tabs_disable_swipe">تعطيل التمرير بين الألسِنة</string>
<string name="sk_settings_color_palette_default">افتراضي (%s)</string>
</resources> </resources>

View File

@@ -273,7 +273,6 @@
<string name="downloading">Спампоўванне…</string> <string name="downloading">Спампоўванне…</string>
<string name="local_timeline">Лакальнае</string> <string name="local_timeline">Лакальнае</string>
<!-- %s is the server domain --> <!-- %s is the server domain -->
<string name="see_new_posts">Паказаць новыя допісы</string>
<string name="load_missing_posts">Загрузіць адсутныя допісы</string> <string name="load_missing_posts">Загрузіць адсутныя допісы</string>
<string name="follow_back">Падпісацца ў адказ</string> <string name="follow_back">Падпісацца ў адказ</string>
<string name="button_follow_pending">Чакаюць</string> <string name="button_follow_pending">Чакаюць</string>

View File

@@ -208,7 +208,6 @@
<string name="file_saved">Fitxer desat</string> <string name="file_saved">Fitxer desat</string>
<string name="downloading">S\'està baixant…</string> <string name="downloading">S\'està baixant…</string>
<!-- %s is the server domain --> <!-- %s is the server domain -->
<string name="see_new_posts">Publicacions noves</string>
<string name="load_missing_posts">Carrega les publicacions faltants</string> <string name="load_missing_posts">Carrega les publicacions faltants</string>
<string name="follow_back">Segueix</string> <string name="follow_back">Segueix</string>
<string name="button_follow_pending">Pendent</string> <string name="button_follow_pending">Pendent</string>

View File

@@ -288,7 +288,6 @@
<!-- %s is the server domain --> <!-- %s is the server domain -->
<string name="local_timeline_info_banner">Toto jsou všechny příspěvky od všech uživatelů na vašem serveru (%s).</string> <string name="local_timeline_info_banner">Toto jsou všechny příspěvky od všech uživatelů na vašem serveru (%s).</string>
<string name="recommended_accounts_info_banner">Podle toho, koho sledujete, by se vám mohly líbit tyto účty.</string> <string name="recommended_accounts_info_banner">Podle toho, koho sledujete, by se vám mohly líbit tyto účty.</string>
<string name="see_new_posts">Zobrazit nové příspěvky</string>
<string name="load_missing_posts">Načíst chybějící příspěvky</string> <string name="load_missing_posts">Načíst chybějící příspěvky</string>
<string name="follow_back">Sledovat nazpět</string> <string name="follow_back">Sledovat nazpět</string>
<string name="button_follow_pending">Čekající</string> <string name="button_follow_pending">Čekající</string>

View File

@@ -262,7 +262,6 @@
<!-- %s is the server domain --> <!-- %s is the server domain -->
<string name="local_timeline_info_banner">Disse er alle indlæg fra alle brugere på din server (%s).</string> <string name="local_timeline_info_banner">Disse er alle indlæg fra alle brugere på din server (%s).</string>
<string name="recommended_accounts_info_banner">Baseret på andre, du følger, vil du måske synes om disse konti.</string> <string name="recommended_accounts_info_banner">Baseret på andre, du følger, vil du måske synes om disse konti.</string>
<string name="see_new_posts">Se nye indlæg</string>
<string name="load_missing_posts">Indlæs manglende indlæg</string> <string name="load_missing_posts">Indlæs manglende indlæg</string>
<string name="follow_back">Følg Tilbage</string> <string name="follow_back">Følg Tilbage</string>
<string name="button_follow_pending">Afventer</string> <string name="button_follow_pending">Afventer</string>

View File

@@ -262,7 +262,6 @@
<!-- %s is the server domain --> <!-- %s is the server domain -->
<string name="local_timeline_info_banner">Dies sind alle Beiträge von allen Benutzern auf deinem Server (%s).</string> <string name="local_timeline_info_banner">Dies sind alle Beiträge von allen Benutzern auf deinem Server (%s).</string>
<string name="recommended_accounts_info_banner">Dir könnten diese Konten gefallen, basierend auf Leuten, denen du folgst.</string> <string name="recommended_accounts_info_banner">Dir könnten diese Konten gefallen, basierend auf Leuten, denen du folgst.</string>
<string name="see_new_posts">Neue Beiträge anzeigen</string>
<string name="load_missing_posts">Weitere Beiträge laden</string> <string name="load_missing_posts">Weitere Beiträge laden</string>
<string name="follow_back">Zurückfolgen</string> <string name="follow_back">Zurückfolgen</string>
<string name="button_follow_pending">Ausstehend</string> <string name="button_follow_pending">Ausstehend</string>

View File

@@ -255,7 +255,7 @@
<string name="sk_expand">Erweitern</string> <string name="sk_expand">Erweitern</string>
<string name="sk_collapse">Einklappen</string> <string name="sk_collapse">Einklappen</string>
<string name="sk_settings_collapse_long_posts">Sehr lange Beiträge einklappen</string> <string name="sk_settings_collapse_long_posts">Sehr lange Beiträge einklappen</string>
<string name="sk_unfinished_attachments">Anhänge richtig stellen\?</string> <string name="sk_unfinished_attachments">Anhänge laden hoch</string>
<string name="sk_settings_hide_interaction">Interaktions-Buttons verstecken</string> <string name="sk_settings_hide_interaction">Interaktions-Buttons verstecken</string>
<string name="sk_unfinished_attachments_message">Einige Anhänge sind nicht fertig hochgeladen.</string> <string name="sk_unfinished_attachments_message">Einige Anhänge sind nicht fertig hochgeladen.</string>
<string name="sk_followed_as">Mit %s gefolgt</string> <string name="sk_followed_as">Mit %s gefolgt</string>
@@ -295,7 +295,7 @@
<string name="sk_settings_allow_remote_loading">Infos von Remote-Instanzen laden</string> <string name="sk_settings_allow_remote_loading">Infos von Remote-Instanzen laden</string>
<string name="sk_no_remote_info_hint">keine Remote-Infos abrufbar</string> <string name="sk_no_remote_info_hint">keine Remote-Infos abrufbar</string>
<string name="sk_error_loading_profile">Konnte das Profil via %s nicht laden</string> <string name="sk_error_loading_profile">Konnte das Profil via %s nicht laden</string>
<string name="sk_settings_allow_remote_loading_explanation">Für vollständigere Auflistung von Follower*innen, Likes und Boosts können die Informationen von der Ursprungs-Instanz geladen werden.</string> <string name="sk_settings_allow_remote_loading_explanation">Für vollständigere Auflistung von Follower_innen, Likes und Boosts können die Informationen von der Ursprungs-Instanz geladen werden.</string>
<string name="sk_settings_auto_reveal_equal_spoilers">Automatisches Aufdecken von gleichen CWs in Antworten von</string> <string name="sk_settings_auto_reveal_equal_spoilers">Automatisches Aufdecken von gleichen CWs in Antworten von</string>
<string name="sk_settings_auto_reveal_nobody">Nie</string> <string name="sk_settings_auto_reveal_nobody">Nie</string>
<string name="sk_settings_auto_reveal_author">Antworten, die von der gleichen Person verfasst wurden</string> <string name="sk_settings_auto_reveal_author">Antworten, die von der gleichen Person verfasst wurden</string>
@@ -410,4 +410,9 @@
<string name="sk_settings_color_palette_default">Standardwert (%s)</string> <string name="sk_settings_color_palette_default">Standardwert (%s)</string>
<string name="sk_settings_underlined_links">Unterstrichene Links</string> <string name="sk_settings_underlined_links">Unterstrichene Links</string>
<string name="sk_recently_used">Zuletzt verwendet</string> <string name="sk_recently_used">Zuletzt verwendet</string>
<string name="sk_settings_clear_timeline_cache">Start-Timeline leeren</string>
<string name="sk_edit_alt_text">Bildbeschreibung bearbeiten</string>
<string name="sk_settings_default_visibility">Standard-Sichtbarkeit für Posts</string>
<string name="sk_settings_lock_account">Neue Follower_innen manuell genehmigen</string>
<string name="sk_timeline_cache_cleared">Start-Timeline geleert</string>
</resources> </resources>

View File

@@ -262,7 +262,6 @@
<!-- %s is the server domain --> <!-- %s is the server domain -->
<string name="local_timeline_info_banner">Αυτές είναι όλες οι αναρτήσεις από όλους τους χρήστες στο διακομιστή σου (%s).</string> <string name="local_timeline_info_banner">Αυτές είναι όλες οι αναρτήσεις από όλους τους χρήστες στο διακομιστή σου (%s).</string>
<string name="recommended_accounts_info_banner">Μπορεί να σου αρέσουν αυτοί οι λογαριασμοί με βάση άλλους που ακολουθείς.</string> <string name="recommended_accounts_info_banner">Μπορεί να σου αρέσουν αυτοί οι λογαριασμοί με βάση άλλους που ακολουθείς.</string>
<string name="see_new_posts">Δες νέες αναρτήσεις</string>
<string name="load_missing_posts">Φόρτωση αναρτήσεων που λείπουν</string> <string name="load_missing_posts">Φόρτωση αναρτήσεων που λείπουν</string>
<string name="follow_back">Ακολούθησε και εσύ</string> <string name="follow_back">Ακολούθησε και εσύ</string>
<string name="button_follow_pending">Εκκρεμεί</string> <string name="button_follow_pending">Εκκρεμεί</string>

View File

@@ -262,7 +262,7 @@
<!-- %s is the server domain --> <!-- %s is the server domain -->
<string name="local_timeline_info_banner">Estos son todos los mensajes de todos los usuarios de tu servidor (%s).</string> <string name="local_timeline_info_banner">Estos son todos los mensajes de todos los usuarios de tu servidor (%s).</string>
<string name="recommended_accounts_info_banner">Es posible que te gusten estas cuentas basadas en otras que sigues.</string> <string name="recommended_accounts_info_banner">Es posible que te gusten estas cuentas basadas en otras que sigues.</string>
<string name="see_new_posts">Ver nuevas publicaciones</string> <string name="see_new_posts">Nuevas publicaciones</string>
<string name="load_missing_posts">Cargar publicaciones faltantes</string> <string name="load_missing_posts">Cargar publicaciones faltantes</string>
<string name="follow_back">Seguir de vuelta</string> <string name="follow_back">Seguir de vuelta</string>
<string name="button_follow_pending">Pendiente</string> <string name="button_follow_pending">Pendiente</string>
@@ -387,6 +387,7 @@
<string name="welcome_to_mastodon">Bienvenido/da a Mastodon</string> <string name="welcome_to_mastodon">Bienvenido/da a Mastodon</string>
<string name="welcome_paragraph1">Mastodon es una red social descentralizada, lo que significa que no la controla una sola compañía. Está formada por muchos servidores independientes, todos juntos conectados.</string> <string name="welcome_paragraph1">Mastodon es una red social descentralizada, lo que significa que no la controla una sola compañía. Está formada por muchos servidores independientes, todos juntos conectados.</string>
<string name="what_are_servers">¿Qué son los servidores?</string> <string name="what_are_servers">¿Qué son los servidores?</string>
<string name="welcome_paragraph2">Cada cuenta de Mastodon está alojada en un servidor — cada uno con sus propios valores, reglas y administradores. Sin importar cuál elijas, puedes seguir e interactuar con personas en cualquier servidor.</string>
<string name="opening_link">Abriendo enlace…</string> <string name="opening_link">Abriendo enlace…</string>
<string name="link_not_supported">Este enlace no es compatible con la aplicación</string> <string name="link_not_supported">Este enlace no es compatible con la aplicación</string>
<string name="log_out_all_accounts">Cerrar sesión en todas las cuentas</string> <string name="log_out_all_accounts">Cerrar sesión en todas las cuentas</string>
@@ -414,6 +415,7 @@
<string name="alt_text">Texto alternativo</string> <string name="alt_text">Texto alternativo</string>
<string name="help">Ayuda</string> <string name="help">Ayuda</string>
<string name="what_is_alt_text">¿Qué es el texto alternativo?</string> <string name="what_is_alt_text">¿Qué es el texto alternativo?</string>
<string name="alt_text_help">El texto alternativo entrega descripciones de una imagen a las personas con discapacidad visual, conexiones de internet de bajo ancho de banda o a quienes buscan más contexto.\n\nPuedes mejorar la accesibilidad y la comprensión de todos al escribir texto alternativo que sea claro, conciso y objetivo.\n\n&lt;ul&gt;&lt;il&gt; Captura elementos importantes&lt;/li&gt;\n&lt;li&gt;Resume el texto en las imágenes&lt;/li&gt;\n&lt;li&gt;Construye las frases de manera normal&lt;/li&gt;\n&lt;li&gt;Evita la información redundante&lt;/li&gt;\n&lt;li&gt;Enfócate en tendencias y en hallazgos claves en imágenes complejas (como diagramas o mapas)&lt;/li&gt;&lt;/ul&gt;</string>
<string name="edit_post">Editar publicación</string> <string name="edit_post">Editar publicación</string>
<string name="no_verified_link">Enlace no verificado</string> <string name="no_verified_link">Enlace no verificado</string>
<string name="compose_autocomplete_emoji_empty">Explorar emojis</string> <string name="compose_autocomplete_emoji_empty">Explorar emojis</string>
@@ -433,6 +435,7 @@
<string name="forward_report_to_server">Reenviar a %s</string> <string name="forward_report_to_server">Reenviar a %s</string>
<!-- Shown on the "stamp" on the screen that appears after you report a post/user. Please keep the translation short, preferably a single word --> <!-- Shown on the "stamp" on the screen that appears after you report a post/user. Please keep the translation short, preferably a single word -->
<string name="reported">Reportado</string> <string name="reported">Reportado</string>
<string name="report_unfollow_explanation">Para no ver más sus publicaciones en tu feed de inicio, deja de seguirle.</string>
<string name="muted_user">Silenciado %s</string> <string name="muted_user">Silenciado %s</string>
<string name="report_sent_already_blocked">Ya has bloqueado a este usuario, así que no tienes nada más que hacer mientras revisamos tu informe.</string> <string name="report_sent_already_blocked">Ya has bloqueado a este usuario, así que no tienes nada más que hacer mientras revisamos tu informe.</string>
<string name="report_personal_already_blocked">Ya has bloqueado a este usuario, así que no tienes nada más que hacer.\n\n¡Gracias por ayudar a mantener Mastodon un lugar seguro para todos!</string> <string name="report_personal_already_blocked">Ya has bloqueado a este usuario, así que no tienes nada más que hacer.\n\n¡Gracias por ayudar a mantener Mastodon un lugar seguro para todos!</string>
@@ -475,9 +478,13 @@
<string name="about_server">Acerca de</string> <string name="about_server">Acerca de</string>
<string name="server_rules">Reglas</string> <string name="server_rules">Reglas</string>
<string name="server_administrator">Administrador</string> <string name="server_administrator">Administrador</string>
<string name="send_email_to_server_admin">Contacta a un administrador</string>
<string name="notifications_disabled_in_system">Active las notificaciones desde la configuración de su dispositivo para ver actualizaciones desde cualquier lugar.</string> <string name="notifications_disabled_in_system">Active las notificaciones desde la configuración de su dispositivo para ver actualizaciones desde cualquier lugar.</string>
<string name="settings_even_more">Aún más ajustes</string> <string name="settings_even_more">Aún más ajustes</string>
<string name="settings_show_cws">Mostrar advertencias de contenido</string> <string name="settings_show_cws">Mostrar advertencias de contenido</string>
<string name="settings_hide_sensitive_media">Esconder contenidos marcados como explícitos</string>
<string name="settings_show_interaction_counts">Contador de interacciones con una publicación</string>
<string name="settings_show_emoji_in_names">Emoji personalizado en los nombres de las pantallas</string>
<plurals name="in_x_seconds"> <plurals name="in_x_seconds">
<item quantity="one">en %d segundo</item> <item quantity="one">en %d segundo</item>
<item quantity="other">en %d segundos</item> <item quantity="other">en %d segundos</item>
@@ -532,6 +539,7 @@
<string name="selection_4_or_more">%1$s, %2$s, y %3$d más</string> <string name="selection_4_or_more">%1$s, %2$s, y %3$d más</string>
<string name="filter_context_home_lists">Inicio y listas</string> <string name="filter_context_home_lists">Inicio y listas</string>
<string name="filter_context_notifications">Notificaciones</string> <string name="filter_context_notifications">Notificaciones</string>
<string name="filter_context_public_timelines">Líneas de tiempo públicas</string>
<string name="filter_context_threads_replies">Hilos y respuestas</string> <string name="filter_context_threads_replies">Hilos y respuestas</string>
<string name="filter_context_profiles">Profiles</string> <string name="filter_context_profiles">Profiles</string>
<string name="settings_filter_title">Título</string> <string name="settings_filter_title">Título</string>
@@ -541,6 +549,7 @@
<string name="edit_muted_word">Editar palabra silenciada</string> <string name="edit_muted_word">Editar palabra silenciada</string>
<string name="add">Añadir</string> <string name="add">Añadir</string>
<string name="filter_word_or_phrase">Palabra o frase</string> <string name="filter_word_or_phrase">Palabra o frase</string>
<string name="filter_add_word_help">Las palabras no distinguen letras mayúsculas y solo reconocen palabras completas.\n\nSi filtras la palabra \"Agua\", se ocultarán posteos que incluyan \"agua\" o \"aGua\", pero no los que contengan \"paraguas\".</string>
<string name="settings_delete_filter_word">¿Eliminar palabra “%s”?</string> <string name="settings_delete_filter_word">¿Eliminar palabra “%s”?</string>
<string name="enter_selection_mode">Seleccionar</string> <string name="enter_selection_mode">Seleccionar</string>
<string name="select_all">Seleccionar todo</string> <string name="select_all">Seleccionar todo</string>
@@ -574,8 +583,46 @@
<string name="time_hours_ago_short">hace %dh</string> <string name="time_hours_ago_short">hace %dh</string>
<string name="time_days_ago_short">hace %dd</string> <string name="time_days_ago_short">hace %dd</string>
<!-- %s is the name of the post language --> <!-- %s is the name of the post language -->
<string name="translate_post">Traducir desde %s</string>
<!-- %1$s is the language, %2$s is the name of the translation service --> <!-- %1$s is the language, %2$s is the name of the translation service -->
<string name="post_translated">Traducido desde %1$s usando %2$s</string>
<string name="translation_show_original">Ver original</string>
<string name="translation_failed">Error al traducir. Tal vez el administrador no ha habilitado las traducciones en este servidor o este servidor está ejecutando una versión antigua de Mastodon donde las traducciones aún no están soportadas.</string>
<string name="settings_privacy">Privacidad y alcance</string>
<string name="settings_discoverable">Mostrar perfil y publicaciones en algoritmos de descubrimiento</string>
<string name="settings_indexable">Incluir publicaciones públicas en los resultados de búsqueda</string>
<string name="error_playing_video">Error al reproducir el video</string>
<string name="timeline_following">Siguiendo</string>
<string name="lists">Listas</string>
<string name="followed_hashtags">Etiquetas seguidas</string>
<string name="no_lists">Aún no tienes ninguna lista.</string>
<string name="no_followed_hashtags">Aún no sigues ninguna etiqueta.</string>
<string name="manage_lists">Administrar listas</string>
<string name="manage_hashtags">Administrar etiquetas</string>
<!-- Screen reader description for the menu on the home timeline screen --> <!-- Screen reader description for the menu on the home timeline screen -->
<string name="dropdown_menu">Menú desplegable</string>
<string name="edit_list">Editar lista</string>
<string name="list_members">Miembros de la lista</string>
<string name="delete_list">Borrar lista</string>
<!-- %s is the name of the list --> <!-- %s is the name of the list -->
<string name="delete_list_confirm">¿Eliminar “%s”?</string>
<string name="list_exclusive">Ocultar miembros en la lista de Seguidos</string>
<string name="list_exclusive_subtitle">Si alguien está en esta lista, ocúltalos en tu línea de tiempo para evitar ver sus publicaciones dos veces.</string>
<string name="list_name">Nombre de la lista</string>
<string name="list_show_replies_to">Mostrar respuestas a</string>
<string name="list_replies_no_one">Nadie</string>
<string name="list_replies_members">Miembros de la lista</string>
<string name="list_replies_anyone">Cualquiera que yo siga</string>
<string name="confirm_remove_list_members">¿Eliminar miembros?</string>
<string name="remove">Eliminar</string>
<string name="add_list_member">Añadir miembro</string>
<string name="search_among_people_you_follow">Buscar entre las personas a las que sigues</string>
<string name="add_user_to_list">Añadir a lista…</string>
<string name="add_user_to_list_title">Añadir a lista</string>
<!-- %s is a username --> <!-- %s is a username -->
<string name="manage_user_lists">Administrar las listas en las que %s aparece</string>
<string name="remove_from_list">Quitar de lista</string>
<string name="confirm_remove_list_member">¿Eliminar miembro?</string>
<string name="no_followed_hashtags_title">Manténgase al día con los intereses siguiendo las etiquetas</string>
<string name="no_followed_hashtags_subtitle">Los seguidores aparecerán aquí</string>
</resources> </resources>

View File

@@ -254,7 +254,7 @@
<string name="sk_expand">Ampliar</string> <string name="sk_expand">Ampliar</string>
<string name="sk_collapse">Minimizar</string> <string name="sk_collapse">Minimizar</string>
<string name="sk_settings_collapse_long_posts">Minimizar publicaciones largas</string> <string name="sk_settings_collapse_long_posts">Minimizar publicaciones largas</string>
<string name="sk_unfinished_attachments">¿Corregir adjuntos\?</string> <string name="sk_unfinished_attachments">Cargando los archivos adjuntos</string>
<string name="sk_unfinished_attachments_message">Algunos adjuntos no han terminado de subirse.</string> <string name="sk_unfinished_attachments_message">Algunos adjuntos no han terminado de subirse.</string>
<string name="sk_settings_prefix_reply_cw_with_re">Añadir \"re\" a Avisos de Contenido</string> <string name="sk_settings_prefix_reply_cw_with_re">Añadir \"re\" a Avisos de Contenido</string>
<string name="sk_spectator_mode">Modo espectador</string> <string name="sk_spectator_mode">Modo espectador</string>
@@ -407,4 +407,5 @@
<string name="sk_set_as_default">Establecer por defecto</string> <string name="sk_set_as_default">Establecer por defecto</string>
<string name="sk_settings_color_palette_default">Por defecto (%s)</string> <string name="sk_settings_color_palette_default">Por defecto (%s)</string>
<string name="sk_settings_underlined_links">Enlaces subrayados</string> <string name="sk_settings_underlined_links">Enlaces subrayados</string>
<string name="sk_edit_alt_text">Editar el texto alternativo</string>
</resources> </resources>

View File

@@ -246,7 +246,6 @@
<string name="local_timeline">Lokala</string> <string name="local_timeline">Lokala</string>
<string name="trending_posts_info_banner">Hauek dira zure Mastodon txokoan beraien lekua hartzen ari diren argitalpenak.</string> <string name="trending_posts_info_banner">Hauek dira zure Mastodon txokoan beraien lekua hartzen ari diren argitalpenak.</string>
<!-- %s is the server domain --> <!-- %s is the server domain -->
<string name="see_new_posts">Ikusi bidalketa berriak</string>
<string name="load_missing_posts">Falta diren bidalketak kargatu</string> <string name="load_missing_posts">Falta diren bidalketak kargatu</string>
<string name="follow_back">Jarraitu</string> <string name="follow_back">Jarraitu</string>
<string name="button_follow_pending">Zain</string> <string name="button_follow_pending">Zain</string>

View File

@@ -262,7 +262,7 @@
<!-- %s is the server domain --> <!-- %s is the server domain -->
<string name="local_timeline_info_banner">این‌ها همه فرسته‌های همه کاربران در سرور شما (%s) هستند.</string> <string name="local_timeline_info_banner">این‌ها همه فرسته‌های همه کاربران در سرور شما (%s) هستند.</string>
<string name="recommended_accounts_info_banner">ممکن است این حساب‌ها را بر اساس حساب‌های دیگری که پی می‌گیرید بپسندید.</string> <string name="recommended_accounts_info_banner">ممکن است این حساب‌ها را بر اساس حساب‌های دیگری که پی می‌گیرید بپسندید.</string>
<string name="see_new_posts">فرسته‌های جدید را ببینید</string> <string name="see_new_posts">فرسته‌های جدید</string>
<string name="load_missing_posts">بارگذاری فرسته‌های گم شده</string> <string name="load_missing_posts">بارگذاری فرسته‌های گم شده</string>
<string name="follow_back">پی‌گیری متقابل</string> <string name="follow_back">پی‌گیری متقابل</string>
<string name="button_follow_pending">منتظر</string> <string name="button_follow_pending">منتظر</string>
@@ -599,7 +599,37 @@
<item quantity="one">%,d فرسته امروز</item> <item quantity="one">%,d فرسته امروز</item>
<item quantity="other">%,d فرسته امروز</item> <item quantity="other">%,d فرسته امروز</item>
</plurals> </plurals>
<string name="error_playing_video">خطا در پخش ویدئو</string>
<string name="timeline_following">پی‌گرفته</string>
<string name="lists">سیاهه‌ها</string>
<string name="followed_hashtags">برچسب‌های پی‌گرفته</string>
<string name="no_lists">شما هنوز هیچ سیاهه‌ای ندارید.</string>
<string name="no_followed_hashtags">شما هیچ برچسبی را پی نمی‌گیرید.</string>
<string name="manage_lists">مدیریت سیاهه‌ها</string>
<string name="manage_hashtags">مدیریت برچسب‌ها</string>
<!-- Screen reader description for the menu on the home timeline screen --> <!-- Screen reader description for the menu on the home timeline screen -->
<string name="dropdown_menu">منوی کشویی</string>
<string name="edit_list">ویرایش سیاهه</string>
<string name="list_members">اعضای سیاهه</string>
<string name="delete_list">حذف سیاهه</string>
<!-- %s is the name of the list --> <!-- %s is the name of the list -->
<string name="delete_list_confirm">حذف \"%s\"؟</string>
<string name="list_exclusive">نهفتن اعضای پی‌گرفته</string>
<string name="list_name">اسم سیاهه</string>
<string name="list_show_replies_to">نمایش پاسخ‌ها به</string>
<string name="list_replies_no_one">هیچ‌کس</string>
<string name="list_replies_members">اعضای سیاهه</string>
<string name="confirm_remove_list_members">حذف اعضا؟</string>
<string name="remove">برداشتن</string>
<string name="add_list_member">افزودن عضو</string>
<string name="add_user_to_list">افزودن به سیاهه…</string>
<string name="add_user_to_list_title">افزودن به سیاهه</string>
<!-- %s is a username --> <!-- %s is a username -->
<string name="remove_from_list">برداشتن از سیاهه</string>
<string name="confirm_remove_list_member">حذف عضو؟</string>
<string name="manage_accounts">افزودن یا جابجا شدن بین حساب‌ها</string>
<plurals name="x_posts_recently">
<item quantity="one">%,d فرسته اخیرا ارسال کرده</item>
<item quantity="other">%,d فرسته اخیرا ارسال کرده</item>
</plurals>
</resources> </resources>

View File

@@ -310,7 +310,7 @@
<string name="sk_reacted">%s واکنش نشان داد</string> <string name="sk_reacted">%s واکنش نشان داد</string>
<string name="sk_external_share_title">هم‌رسانی با حساب</string> <string name="sk_external_share_title">هم‌رسانی با حساب</string>
<string name="sk_settings_prefix_reply_cw_with_re">وارد کردن پیشوند CW با “re:” هنگام پاسخ دادن</string> <string name="sk_settings_prefix_reply_cw_with_re">وارد کردن پیشوند CW با “re:” هنگام پاسخ دادن</string>
<string name="sk_unfinished_attachments">رفع مشکل پیوست‌ها؟</string> <string name="sk_unfinished_attachments">درحال بارگذاری پیوست‌ها</string>
<string name="sk_settings_allow_remote_loading">بارگیری اطلاعات از نمونه های راه دور</string> <string name="sk_settings_allow_remote_loading">بارگیری اطلاعات از نمونه های راه دور</string>
<string name="sk_error_loading_profile">بارگیری نمایه از طریق %s شکست خورد</string> <string name="sk_error_loading_profile">بارگیری نمایه از طریق %s شکست خورد</string>
<string name="sk_settings_reply_visibility_following">پاسخ به پی‌گیر های من</string> <string name="sk_settings_reply_visibility_following">پاسخ به پی‌گیر های من</string>
@@ -363,7 +363,7 @@
<string name="sk_button_react">واکنش با ایموجی</string> <string name="sk_button_react">واکنش با ایموجی</string>
<string name="sk_again_for_system_keyboard">دوباره برای کیبورد سامانه ضربه بزنید</string> <string name="sk_again_for_system_keyboard">دوباره برای کیبورد سامانه ضربه بزنید</string>
<string name="sk_enter_emoji_toast">لطفا یک ایموجی تایپ کنید</string> <string name="sk_enter_emoji_toast">لطفا یک ایموجی تایپ کنید</string>
<string name="sk_enter_emoji_hint">برای واکنش با ایموجی تایپ کنید</string> <string name="sk_enter_emoji_hint">یک ایموجی بنویسید یا جستجو کنید</string>
<plurals name="sk_users_reacted_with"> <plurals name="sk_users_reacted_with">
<item quantity="one">یک کاربر با %2$s واکنش نشان داد</item> <item quantity="one">یک کاربر با %2$s واکنش نشان داد</item>
<item quantity="other">%1$,d کاربر با %2$s واکنش نشان دادند</item> <item quantity="other">%1$,d کاربر با %2$s واکنش نشان دادند</item>
@@ -388,11 +388,19 @@
<string name="sk_search_suicide_hotlines">یک راه کمکی بیابید</string> <string name="sk_search_suicide_hotlines">یک راه کمکی بیابید</string>
<string name="sk_do_not_show_again">دوباره نمایش نده</string> <string name="sk_do_not_show_again">دوباره نمایش نده</string>
<string name="sk_suicide_helplines_url">https://findahelpline.com</string> <string name="sk_suicide_helplines_url">https://findahelpline.com</string>
<string name="sk_trending_posts_info_banner">اینها فرسته‌هایی هستند که در کارساز شما مورد توجه قرار می گیرند.</string> <string name="sk_trending_posts_info_banner">این فرسته‌ها در حال حاضر در فدیورس مورد توجه قرار گرفته اند.</string>
<string name="sk_load_missing_posts_below">بارگذاری فرسته‌های قدیمی‌تر</string> <string name="sk_load_missing_posts_below">بارگذاری فرسته‌های قدیمی‌تر</string>
<string name="sk_search_suicide_title">اگر نیازمند کمک هستید…</string> <string name="sk_search_suicide_title">اگر نیازمند کمک هستید…</string>
<string name="sk_time_minutes">%d دقیقه</string> <string name="sk_time_minutes">%d دقیقه</string>
<string name="sk_search_suicide_message">اگر به دنبال نشانه ای برای خودکشی نیستید، همین است. لطفاً اگر نیازمند کمک هستید با شماره تلفن محلی خودکشی تماس بگیرید.</string> <string name="sk_search_suicide_message">اگر به دنبال نشانه ای برای خودکشی نیستید، همین است. لطفاً اگر نیازمند کمک هستید با شماره تلفن محلی خودکشی تماس بگیرید.</string>
<string name="sk_trending_links_info_banner">اینها اخباری است که در کارساز شما در مورد آنها صحبت می شود.</string> <string name="sk_trending_links_info_banner">این اخبار در سراسر فدیورس درباره آنها صحبت می شود.</string>
<string name="sk_post_contains_media">فرسته حاوی رسانه‌ست</string> <string name="sk_post_contains_media">فرسته حاوی رسانه‌ست</string>
<string name="sk_set_as_default">تنظیم به‌عنوان پیش‌گزیده</string>
<string name="sk_settings_like_icon">استفاده از قلب به عنوان نماد برگزیدن</string>
<string name="sk_settings_color_palette_default">پیش‌گزیده (%s)</string>
<string name="sk_blocked_accounts">حساب‌های مسدود شده</string>
<string name="sk_settings_underlined_links">پیوندهای خط دار</string>
<string name="sk_muted_accounts">حساب‌های خموش شده</string>
<string name="sk_recently_used">اخیرا مورد استفاده قرار گرفته</string>
<string name="sk_edit_alt_text">ویرایش متن جایگزین</string>
</resources> </resources>

View File

@@ -262,7 +262,6 @@
<!-- %s is the server domain --> <!-- %s is the server domain -->
<string name="local_timeline_info_banner">Nämä ovat viestit kaikilta palvelimesi (%s) käyttäjiltä.</string> <string name="local_timeline_info_banner">Nämä ovat viestit kaikilta palvelimesi (%s) käyttäjiltä.</string>
<string name="recommended_accounts_info_banner">Muiden seuraamiesi perusteella saattaisit pitää näistä tileistä.</string> <string name="recommended_accounts_info_banner">Muiden seuraamiesi perusteella saattaisit pitää näistä tileistä.</string>
<string name="see_new_posts">Uusia julkaisuja</string>
<string name="load_missing_posts">Lataa puuttuvat julkaisut</string> <string name="load_missing_posts">Lataa puuttuvat julkaisut</string>
<string name="follow_back">Seuraa takaisin</string> <string name="follow_back">Seuraa takaisin</string>
<string name="button_follow_pending">Pyydetty</string> <string name="button_follow_pending">Pyydetty</string>

View File

@@ -199,7 +199,6 @@
<string name="file_saved">Nai-save ang File</string> <string name="file_saved">Nai-save ang File</string>
<string name="downloading">Nagda-download…</string> <string name="downloading">Nagda-download…</string>
<!-- %s is the server domain --> <!-- %s is the server domain -->
<string name="see_new_posts">Tingnan ang mga bagong post</string>
<string name="load_missing_posts">Mag-Load ng nawawalang mga post</string> <string name="load_missing_posts">Mag-Load ng nawawalang mga post</string>
<string name="follow_back">Sundan Pabalik</string> <string name="follow_back">Sundan Pabalik</string>
<string name="button_follow_pending">Nakabinbin</string> <string name="button_follow_pending">Nakabinbin</string>

View File

@@ -262,7 +262,6 @@
<!-- %s is the server domain --> <!-- %s is the server domain -->
<string name="local_timeline_info_banner">Voici tous les messages de tous les comptes de votre serveur (%s).</string> <string name="local_timeline_info_banner">Voici tous les messages de tous les comptes de votre serveur (%s).</string>
<string name="recommended_accounts_info_banner">Vous pourriez aimer ces comptes en fonction des autres que vous suivez.</string> <string name="recommended_accounts_info_banner">Vous pourriez aimer ces comptes en fonction des autres que vous suivez.</string>
<string name="see_new_posts">Voir les nouveaux messages</string>
<string name="load_missing_posts">Charger les messages manquants</string> <string name="load_missing_posts">Charger les messages manquants</string>
<string name="follow_back">Suivre en retour</string> <string name="follow_back">Suivre en retour</string>
<string name="button_follow_pending">En attente</string> <string name="button_follow_pending">En attente</string>

View File

@@ -256,7 +256,7 @@
<string name="sk_settings_collapse_long_posts">Réduire les messages très longs</string> <string name="sk_settings_collapse_long_posts">Réduire les messages très longs</string>
<string name="sk_settings_prefix_reply_cw_with_re">Préfixer les CW avec \"re :\" en répondant à</string> <string name="sk_settings_prefix_reply_cw_with_re">Préfixer les CW avec \"re :\" en répondant à</string>
<string name="sk_filtered">Filtré : %s</string> <string name="sk_filtered">Filtré : %s</string>
<string name="sk_unfinished_attachments">Corriger les pièces jointes \?</string> <string name="sk_unfinished_attachments">Téléchargement de pièces jointes</string>
<string name="sk_unfinished_attachments_message">Certaines pièces jointes n\'ont pas fini de se télécharger.</string> <string name="sk_unfinished_attachments_message">Certaines pièces jointes n\'ont pas fini de se télécharger.</string>
<string name="sk_spectator_mode">Mode spectateur</string> <string name="sk_spectator_mode">Mode spectateur</string>
<string name="sk_settings_hide_interaction">Masquer les boutons d\'interaction</string> <string name="sk_settings_hide_interaction">Masquer les boutons d\'interaction</string>
@@ -408,4 +408,10 @@
<string name="sk_set_as_default">Définir par défaut</string> <string name="sk_set_as_default">Définir par défaut</string>
<string name="sk_settings_color_palette_default">Par défaut (%s)</string> <string name="sk_settings_color_palette_default">Par défaut (%s)</string>
<string name="sk_settings_underlined_links">Liens soulignés</string> <string name="sk_settings_underlined_links">Liens soulignés</string>
<string name="sk_edit_alt_text">Modifier le texte alternatif</string>
<string name="sk_message_cache_cleared">Cache des messages vidé</string>
<string name="sk_settings_clear_timeline_cache">Effacer le cache du fil d\'accueil</string>
<string name="sk_settings_default_visibility">Visibilité de publication par défaut</string>
<string name="sk_settings_lock_account">Approuver manuellement les nouveaux abonnés</string>
<string name="sk_timeline_cache_cleared">Cache du fil d\'accueil vidé</string>
</resources> </resources>

View File

@@ -288,7 +288,6 @@
<!-- %s is the server domain --> <!-- %s is the server domain -->
<string name="local_timeline_info_banner">Seo gach post o gach cleachdaiche an fhrithealaiche agad (%s).</string> <string name="local_timeline_info_banner">Seo gach post o gach cleachdaiche an fhrithealaiche agad (%s).</string>
<string name="recommended_accounts_info_banner">Dhfhaoidte gun còrd na cunntasan seo riut stèidhichte air feadhainn eile a tha thu a leantainn.</string> <string name="recommended_accounts_info_banner">Dhfhaoidte gun còrd na cunntasan seo riut stèidhichte air feadhainn eile a tha thu a leantainn.</string>
<string name="see_new_posts">Seall na postaichean ùra</string>
<string name="load_missing_posts">Luchdaich postaichean a dhìth</string> <string name="load_missing_posts">Luchdaich postaichean a dhìth</string>
<string name="follow_back">Lean air ais</string> <string name="follow_back">Lean air ais</string>
<string name="button_follow_pending">Ri dhèiligeadh</string> <string name="button_follow_pending">Ri dhèiligeadh</string>

View File

@@ -262,7 +262,7 @@
<!-- %s is the server domain --> <!-- %s is the server domain -->
<string name="local_timeline_info_banner">Estas son as publicacións das usuarias do teu servidor (%s).</string> <string name="local_timeline_info_banner">Estas son as publicacións das usuarias do teu servidor (%s).</string>
<string name="recommended_accounts_info_banner">Poderían interesarche estas contas en función doutras que segues.</string> <string name="recommended_accounts_info_banner">Poderían interesarche estas contas en función doutras que segues.</string>
<string name="see_new_posts">Ver novas publicacións</string> <string name="see_new_posts">Novas publicacións</string>
<string name="load_missing_posts">Cargar publicacións que faltan</string> <string name="load_missing_posts">Cargar publicacións que faltan</string>
<string name="follow_back">Seguir tamén</string> <string name="follow_back">Seguir tamén</string>
<string name="button_follow_pending">Pendente</string> <string name="button_follow_pending">Pendente</string>
@@ -599,7 +599,45 @@
<item quantity="one">%,d publicación hoxe</item> <item quantity="one">%,d publicación hoxe</item>
<item quantity="other">%,d publicacións hoxe</item> <item quantity="other">%,d publicacións hoxe</item>
</plurals> </plurals>
<string name="error_playing_video">Erro ao reproducir o vídeo</string>
<string name="timeline_following">A Seguir</string>
<string name="lists">Listas</string>
<string name="followed_hashtags">Cancelos seguidos</string>
<string name="no_lists">Aínda non tes ningunha lista.</string>
<string name="no_followed_hashtags">Non segues ningún cancelo.</string>
<string name="manage_lists">Xestionar listas</string>
<string name="manage_hashtags">Xestionar cancelos</string>
<!-- Screen reader description for the menu on the home timeline screen --> <!-- Screen reader description for the menu on the home timeline screen -->
<string name="dropdown_menu">Menú despregable</string>
<string name="edit_list">Editar lista</string>
<string name="list_members">Membros da lista</string>
<string name="delete_list">Eliminar lista</string>
<!-- %s is the name of the list --> <!-- %s is the name of the list -->
<string name="delete_list_confirm">Eliminar \"%s\"?</string>
<string name="list_exclusive">Agochar aos membros no Inicio</string>
<string name="list_exclusive_subtitle">Se alguén está nesta lista, oculta as súas publicacións na Cronoloxía de inicio para non velas dúas veces.</string>
<string name="list_name">Nome da lista</string>
<string name="list_show_replies_to">Mostrar respostas a</string>
<string name="list_replies_no_one">Ninguén</string>
<string name="list_replies_members">Usuarias na lista</string>
<string name="list_replies_anyone">Alguén a quen sigo</string>
<string name="confirm_remove_list_members">Eliminar membros?</string>
<string name="remove">Eliminar</string>
<string name="add_list_member">Engadir usuaria</string>
<string name="search_among_people_you_follow">Procurar entre as persoas que segues</string>
<string name="add_user_to_list">Engadir á lista…</string>
<string name="add_user_to_list_title">Engadir á lista</string>
<!-- %s is a username --> <!-- %s is a username -->
<string name="manage_user_lists">Xestionar as listas nas que aparece %s</string>
<string name="remove_from_list">Eliminar da lista</string>
<string name="confirm_remove_list_member">Eliminar membro?</string>
<string name="no_followed_hashtags_title">Infórmate dos teus intereses seguindo cancelos</string>
<string name="no_followed_hashtags_subtitle">Aquí verás os seguimentos</string>
<string name="no_lists_title">Organiza a cronoloxía de inicio con Listas</string>
<string name="no_lists_subtitle">Aquí verás as túas</string>
<string name="manage_accounts">Engade ou cambia de conta</string>
<plurals name="x_posts_recently">
<item quantity="one">%,d publicación recente</item>
<item quantity="other">%,d publicacións recentes</item>
</plurals>
</resources> </resources>

View File

@@ -258,7 +258,6 @@
<!-- %s is the server domain --> <!-- %s is the server domain -->
<string name="local_timeline_info_banner">Itt található az összes bejegyzés az összes felhasznólótól a példányodon (%s).</string> <string name="local_timeline_info_banner">Itt található az összes bejegyzés az összes felhasznólótól a példányodon (%s).</string>
<string name="recommended_accounts_info_banner">Ezek a fiókok tetszhetnek neked azok alapján, akiket követsz.</string> <string name="recommended_accounts_info_banner">Ezek a fiókok tetszhetnek neked azok alapján, akiket követsz.</string>
<string name="see_new_posts">Új bejegyzések megtekintése</string>
<string name="load_missing_posts">Hiányzó bejegyzések betöltése</string> <string name="load_missing_posts">Hiányzó bejegyzések betöltése</string>
<string name="follow_back">Visszakövetés</string> <string name="follow_back">Visszakövetés</string>
<string name="button_follow_pending">Függőben</string> <string name="button_follow_pending">Függőben</string>

View File

@@ -209,7 +209,6 @@
<string name="trending_posts_info_banner">Այս գրառումները տարածված են Մաստոդոնում։</string> <string name="trending_posts_info_banner">Այս գրառումները տարածված են Մաստոդոնում։</string>
<string name="trending_links_info_banner">Այս նորությունների մասին խոսում են Մաստոդոնում։</string> <string name="trending_links_info_banner">Այս նորությունների մասին խոսում են Մաստոդոնում։</string>
<!-- %s is the server domain --> <!-- %s is the server domain -->
<string name="see_new_posts">Նոր գրառումներ</string>
<string name="load_missing_posts">Բեռնել բաց թողնված գրառումները</string> <string name="load_missing_posts">Բեռնել բաց թողնված գրառումները</string>
<string name="follows_you">Հետեւում է ձեզ</string> <string name="follows_you">Հետեւում է ձեզ</string>
<!-- translators: %,d is a valid placeholder, it formats the number with locale-dependent grouping separators --> <!-- translators: %,d is a valid placeholder, it formats the number with locale-dependent grouping separators -->

View File

@@ -249,7 +249,6 @@
<!-- %s is the server domain --> <!-- %s is the server domain -->
<string name="local_timeline_info_banner">Ini adalah kiriman dari semua pengguna di server Anda (%s).</string> <string name="local_timeline_info_banner">Ini adalah kiriman dari semua pengguna di server Anda (%s).</string>
<string name="recommended_accounts_info_banner">Anda mungkin suka akun berikut berdasarkan orang-orang yang Anda ikuti.</string> <string name="recommended_accounts_info_banner">Anda mungkin suka akun berikut berdasarkan orang-orang yang Anda ikuti.</string>
<string name="see_new_posts">Lihat kiriman baru</string>
<string name="load_missing_posts">Muat kiriman yang hilang</string> <string name="load_missing_posts">Muat kiriman yang hilang</string>
<string name="follow_back">Ikuti Balik</string> <string name="follow_back">Ikuti Balik</string>
<string name="button_follow_pending">Ditunda</string> <string name="button_follow_pending">Ditunda</string>

View File

@@ -260,7 +260,7 @@
<string name="sk_followed_as">Diikuti dari %s</string> <string name="sk_followed_as">Diikuti dari %s</string>
<string name="sk_settings_prefix_reply_cw_with_re">Awali peringatan konten dengan “re:” saat membalas</string> <string name="sk_settings_prefix_reply_cw_with_re">Awali peringatan konten dengan “re:” saat membalas</string>
<string name="sk_settings_collapse_long_posts">Tutup kiriman yang sangat panjang</string> <string name="sk_settings_collapse_long_posts">Tutup kiriman yang sangat panjang</string>
<string name="sk_unfinished_attachments">Perbaiki lampiran\?</string> <string name="sk_unfinished_attachments">Mengunggah lampiran</string>
<string name="sk_unfinished_attachments_message">Beberapa lampiran belum selesai diunggah.</string> <string name="sk_unfinished_attachments_message">Beberapa lampiran belum selesai diunggah.</string>
<string name="sk_settings_hide_fab">Sembunyikan tombol Komposer</string> <string name="sk_settings_hide_fab">Sembunyikan tombol Komposer</string>
<string name="sk_in_reply">Dalam balasan</string> <string name="sk_in_reply">Dalam balasan</string>
@@ -401,4 +401,9 @@
<string name="sk_set_as_default">Tetapkan sebagai bawaan</string> <string name="sk_set_as_default">Tetapkan sebagai bawaan</string>
<string name="sk_settings_color_palette_default">Bawaan (%s)</string> <string name="sk_settings_color_palette_default">Bawaan (%s)</string>
<string name="sk_settings_underlined_links">Tautan yang digarisbawahi</string> <string name="sk_settings_underlined_links">Tautan yang digarisbawahi</string>
<string name="sk_edit_alt_text">Sunting teks alternatif</string>
<string name="sk_settings_default_visibility">Keterlihatan kiriman bawaan</string>
<string name="sk_settings_lock_account">Setujui pengikut baru secara manual</string>
<string name="sk_timeline_cache_cleared">Tembolok lini masa beranda dihapus</string>
<string name="sk_settings_clear_timeline_cache">Hapus tembolok lini masa beranda</string>
</resources> </resources>

View File

@@ -262,7 +262,7 @@
<!-- %s is the server domain --> <!-- %s is the server domain -->
<string name="local_timeline_info_banner">Þetta eru allar færslur frá öllum notendum á netþjóninum þínum (%s).</string> <string name="local_timeline_info_banner">Þetta eru allar færslur frá öllum notendum á netþjóninum þínum (%s).</string>
<string name="recommended_accounts_info_banner">Þú gætir einnig haft áhuga á þessum aðgöngum, miðað við hverjum þú ert að fylgjast með.</string> <string name="recommended_accounts_info_banner">Þú gætir einnig haft áhuga á þessum aðgöngum, miðað við hverjum þú ert að fylgjast með.</string>
<string name="see_new_posts">Skoða nýjar færslur</string> <string name="see_new_posts">Nýjar færslur</string>
<string name="load_missing_posts">Hlaða inn færslum sem vantar</string> <string name="load_missing_posts">Hlaða inn færslum sem vantar</string>
<string name="follow_back">Fylgjast með til baka</string> <string name="follow_back">Fylgjast með til baka</string>
<string name="button_follow_pending">Í bið</string> <string name="button_follow_pending">Í bið</string>
@@ -631,6 +631,10 @@
<string name="manage_user_lists">Sýsla með lista sem %s birtist á</string> <string name="manage_user_lists">Sýsla með lista sem %s birtist á</string>
<string name="remove_from_list">Fjarlægja af lista</string> <string name="remove_from_list">Fjarlægja af lista</string>
<string name="confirm_remove_list_member">Fjarlægja meðlim?</string> <string name="confirm_remove_list_member">Fjarlægja meðlim?</string>
<string name="no_followed_hashtags_title">Haltu í við áhugasviðin þín með því að fylgjast með myllumerkjum</string>
<string name="no_followed_hashtags_subtitle">Þeir sem fylgst er með birtast hér</string>
<string name="no_lists_title">Skipulegðu heimastreymið þitt með listum</string>
<string name="no_lists_subtitle">Þú munt birtast hér</string>
<plurals name="x_posts_recently"> <plurals name="x_posts_recently">
<item quantity="one">%,d nýleg færsla</item> <item quantity="one">%,d nýleg færsla</item>
<item quantity="other">%,d nýlegar færslur</item> <item quantity="other">%,d nýlegar færslur</item>

View File

@@ -262,7 +262,6 @@
<!-- %s is the server domain --> <!-- %s is the server domain -->
<string name="local_timeline_info_banner">Questi sono tutti i post di tutti gli utenti nel tuo server (%s).</string> <string name="local_timeline_info_banner">Questi sono tutti i post di tutti gli utenti nel tuo server (%s).</string>
<string name="recommended_accounts_info_banner">Questi account potrebbero piacerti in base agli altri che segui.</string> <string name="recommended_accounts_info_banner">Questi account potrebbero piacerti in base agli altri che segui.</string>
<string name="see_new_posts">Visualizza nuovi post</string>
<string name="load_missing_posts">Carica i post mancanti</string> <string name="load_missing_posts">Carica i post mancanti</string>
<string name="follow_back">Segui anche tu</string> <string name="follow_back">Segui anche tu</string>
<string name="button_follow_pending">In attesa</string> <string name="button_follow_pending">In attesa</string>

View File

@@ -249,7 +249,6 @@
<!-- %s is the server domain --> <!-- %s is the server domain -->
<string name="local_timeline_info_banner">あなたのサーバー (%s) の全ユーザーの全投稿です。</string> <string name="local_timeline_info_banner">あなたのサーバー (%s) の全ユーザーの全投稿です。</string>
<string name="recommended_accounts_info_banner">こちらは、あなたがフォローしている人に基づいた、おすすめのアカウントです。</string> <string name="recommended_accounts_info_banner">こちらは、あなたがフォローしている人に基づいた、おすすめのアカウントです。</string>
<string name="see_new_posts">新しい投稿を見る</string>
<string name="load_missing_posts">不足している投稿を読み込む</string> <string name="load_missing_posts">不足している投稿を読み込む</string>
<string name="follow_back">フォローバック</string> <string name="follow_back">フォローバック</string>
<string name="button_follow_pending">保留</string> <string name="button_follow_pending">保留</string>

View File

@@ -203,7 +203,6 @@
<string name="file_saved">Afaylu yettwasekles</string> <string name="file_saved">Afaylu yettwasekles</string>
<string name="downloading">Asader…</string> <string name="downloading">Asader…</string>
<!-- %s is the server domain --> <!-- %s is the server domain -->
<string name="see_new_posts">Ẓer tissufaɣ timaynutin</string>
<string name="load_missing_posts">Sali tisuffaɣ i iruḥen</string> <string name="load_missing_posts">Sali tisuffaɣ i iruḥen</string>
<string name="follow_back">Ḍfeṛ</string> <string name="follow_back">Ḍfeṛ</string>
<string name="button_follow_pending">Yettraǧu</string> <string name="button_follow_pending">Yettraǧu</string>

View File

@@ -199,7 +199,6 @@
<string name="file_saved">파일 저장됨</string> <string name="file_saved">파일 저장됨</string>
<string name="downloading">다운로드 중…</string> <string name="downloading">다운로드 중…</string>
<!-- %s is the server domain --> <!-- %s is the server domain -->
<string name="see_new_posts">새 게시물 보기</string>
<string name="load_missing_posts">놓친 게시물 불러오기</string> <string name="load_missing_posts">놓친 게시물 불러오기</string>
<string name="follow_back">맞팔로우</string> <string name="follow_back">맞팔로우</string>
<string name="button_follow_pending">대기 중</string> <string name="button_follow_pending">대기 중</string>

View File

@@ -262,7 +262,6 @@
<!-- %s is the server domain --> <!-- %s is the server domain -->
<string name="local_timeline_info_banner">Dit zijn alle berichten van alle gebruikers op uw server (%s).</string> <string name="local_timeline_info_banner">Dit zijn alle berichten van alle gebruikers op uw server (%s).</string>
<string name="recommended_accounts_info_banner">Mogelijk vind je deze accounts leuk op basis van andere accounts die je volgt.</string> <string name="recommended_accounts_info_banner">Mogelijk vind je deze accounts leuk op basis van andere accounts die je volgt.</string>
<string name="see_new_posts">Nieuwe berichten</string>
<string name="load_missing_posts">Resterende berichten laden</string> <string name="load_missing_posts">Resterende berichten laden</string>
<string name="follow_back">Terugvolgen</string> <string name="follow_back">Terugvolgen</string>
<string name="button_follow_pending">In afwachting</string> <string name="button_follow_pending">In afwachting</string>

View File

@@ -262,7 +262,6 @@
<!-- %s is the server domain --> <!-- %s is the server domain -->
<string name="local_timeline_info_banner">Dette er alle innlegg fra alle brukere på din server (%s).</string> <string name="local_timeline_info_banner">Dette er alle innlegg fra alle brukere på din server (%s).</string>
<string name="recommended_accounts_info_banner">Du liker kanskje disse kontoene basert på de andre du følger.</string> <string name="recommended_accounts_info_banner">Du liker kanskje disse kontoene basert på de andre du følger.</string>
<string name="see_new_posts">Se nye innlegg</string>
<string name="load_missing_posts">Last inn manglende innlegg</string> <string name="load_missing_posts">Last inn manglende innlegg</string>
<string name="follow_back">Følg tilbake</string> <string name="follow_back">Følg tilbake</string>
<string name="button_follow_pending">Ventende</string> <string name="button_follow_pending">Ventende</string>

View File

@@ -288,7 +288,6 @@
<!-- %s is the server domain --> <!-- %s is the server domain -->
<string name="local_timeline_info_banner">To są wszystkie posty od wszystkich użytkowników na Twoim serwerze (%s).</string> <string name="local_timeline_info_banner">To są wszystkie posty od wszystkich użytkowników na Twoim serwerze (%s).</string>
<string name="recommended_accounts_info_banner">Może spodobają się Tobie te konta, bazując na tych, których już obserwujesz?</string> <string name="recommended_accounts_info_banner">Może spodobają się Tobie te konta, bazując na tych, których już obserwujesz?</string>
<string name="see_new_posts">Zobacz nowe wpisy</string>
<string name="load_missing_posts">Załaduj brakujące wpisy</string> <string name="load_missing_posts">Załaduj brakujące wpisy</string>
<string name="follow_back">Obserwuj wzajemnie</string> <string name="follow_back">Obserwuj wzajemnie</string>
<string name="button_follow_pending">Oczekujące</string> <string name="button_follow_pending">Oczekujące</string>

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