Merge branch 'feature/language-selector'

This commit is contained in:
sk 2022-12-10 22:22:38 +01:00
commit 661f545e35
5 changed files with 153 additions and 64 deletions

View File

@ -1,15 +1,17 @@
package org.joinmastodon.android; package org.joinmastodon.android;
import static org.joinmastodon.android.api.MastodonAPIController.gson;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.content.res.Resources;
import android.os.Build; import com.google.gson.JsonSyntaxException;
import android.os.LocaleList; import com.google.gson.reflect.TypeToken;
import java.util.ArrayList;
import java.util.Arrays; import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Map;
import java.util.stream.Collectors;
public class GlobalUserPreferences{ public class GlobalUserPreferences{
public static boolean playGifs; public static boolean playGifs;
@ -25,26 +27,19 @@ public class GlobalUserPreferences{
public static boolean voteButtonForSingleChoice; public static boolean voteButtonForSingleChoice;
public static ThemePreference theme; public static ThemePreference theme;
public static ColorPreference color; public static ColorPreference color;
public static List<String> recentLanguages;
private static String defaultRecentLanguages; private final static Type recentLanguagesType = new TypeToken<Map<String, List<String>>>() {}.getType();
public static Map<String, List<String>> recentLanguages;
static {
List<Locale> systemLocales = new ArrayList<>();;
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
systemLocales.add(Resources.getSystem().getConfiguration().locale);
} else {
LocaleList localeList = Resources.getSystem().getConfiguration().getLocales();
for (int i = 0; i < localeList.size(); i++) systemLocales.add(localeList.get(i));
}
defaultRecentLanguages = systemLocales.stream().map(Locale::getLanguage).collect(Collectors.joining(","));
}
private static SharedPreferences getPrefs(){ private static SharedPreferences getPrefs(){
return MastodonApp.context.getSharedPreferences("global", Context.MODE_PRIVATE); return MastodonApp.context.getSharedPreferences("global", Context.MODE_PRIVATE);
} }
private static <T> T fromJson(String json, Type type, T orElse) {
try { return gson.fromJson(json, type); }
catch (JsonSyntaxException ignored) { return orElse; }
}
public static void load(){ public static void load(){
SharedPreferences prefs=getPrefs(); SharedPreferences prefs=getPrefs();
playGifs=prefs.getBoolean("playGifs", true); playGifs=prefs.getBoolean("playGifs", true);
@ -60,7 +55,7 @@ public class GlobalUserPreferences{
voteButtonForSingleChoice=prefs.getBoolean("voteButtonForSingleChoice", true); voteButtonForSingleChoice=prefs.getBoolean("voteButtonForSingleChoice", true);
theme=ThemePreference.values()[prefs.getInt("theme", 0)]; theme=ThemePreference.values()[prefs.getInt("theme", 0)];
color=ColorPreference.values()[prefs.getInt("color", 0)]; color=ColorPreference.values()[prefs.getInt("color", 0)];
recentLanguages=Arrays.stream(prefs.getString("recentLanguages", defaultRecentLanguages).split(",")).filter(s->!s.isEmpty()).collect(Collectors.toList()); recentLanguages=fromJson(prefs.getString("recentLanguages", "{}"), recentLanguagesType, new HashMap<>());
} }
public static void save(){ public static void save(){
@ -77,7 +72,7 @@ public class GlobalUserPreferences{
.putBoolean("disableMarquee", disableMarquee) .putBoolean("disableMarquee", disableMarquee)
.putInt("theme", theme.ordinal()) .putInt("theme", theme.ordinal())
.putInt("color", color.ordinal()) .putInt("color", color.ordinal())
.putString("recentLanguages", String.join(",", recentLanguages)) .putString("recentLanguages", gson.toJson(recentLanguages))
.apply(); .apply();
} }

View File

@ -1,5 +1,9 @@
package org.joinmastodon.android.fragments; package org.joinmastodon.android.fragments;
import static org.joinmastodon.android.GlobalUserPreferences.recentLanguages;
import static org.joinmastodon.android.utils.MastodonLanguage.allLanguages;
import static org.joinmastodon.android.utils.MastodonLanguage.defaultRecentLanguages;
import android.animation.ObjectAnimator; import android.animation.ObjectAnimator;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.app.Activity; import android.app.Activity;
@ -98,6 +102,7 @@ import org.joinmastodon.android.ui.views.ComposeEditText;
import org.joinmastodon.android.ui.views.ComposeMediaLayout; import org.joinmastodon.android.ui.views.ComposeMediaLayout;
import org.joinmastodon.android.ui.views.ReorderableLinearLayout; import org.joinmastodon.android.ui.views.ReorderableLinearLayout;
import org.joinmastodon.android.ui.views.SizeListenerLinearLayout; import org.joinmastodon.android.ui.views.SizeListenerLinearLayout;
import org.joinmastodon.android.utils.MastodonLanguage;
import org.parceler.Parcel; import org.parceler.Parcel;
import org.parceler.Parcels; import org.parceler.Parcels;
@ -106,10 +111,9 @@ import java.net.SocketException;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.time.temporal.ChronoUnit; import java.time.temporal.ChronoUnit;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Optional;
import java.util.UUID; import java.util.UUID;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@ -135,7 +139,6 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
// from https://github.com/mastodon/mastodon-ios/blob/main/Mastodon/Helper/MastodonRegex.swift // from https://github.com/mastodon/mastodon-ios/blob/main/Mastodon/Helper/MastodonRegex.swift
private static final Pattern AUTO_COMPLETE_PATTERN=Pattern.compile("(?<!\\w)(?:@([a-zA-Z0-9_]+)(@[a-zA-Z0-9_.-]+)?|#([^\\s.]+)|:([a-zA-Z0-9_]+))"); private static final Pattern AUTO_COMPLETE_PATTERN=Pattern.compile("(?<!\\w)(?:@([a-zA-Z0-9_]+)(@[a-zA-Z0-9_.-]+)?|#([^\\s.]+)|:([a-zA-Z0-9_]+))");
private static final Pattern HIGHLIGHT_PATTERN=Pattern.compile("(?<!\\w)(?:@([a-zA-Z0-9_]+)(@[a-zA-Z0-9_.-]+)?|#([^\\s.]+))"); private static final Pattern HIGHLIGHT_PATTERN=Pattern.compile("(?<!\\w)(?:@([a-zA-Z0-9_]+)(@[a-zA-Z0-9_.-]+)?|#([^\\s.]+))");
private static final List<Locale> allIsoLanguages;
@SuppressLint("NewApi") // this class actually exists on 6.0 @SuppressLint("NewApi") // this class actually exists on 6.0
private final BreakIterator breakIterator=BreakIterator.getCharacterInstance(); private final BreakIterator breakIterator=BreakIterator.getCharacterInstance();
@ -198,22 +201,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
private Runnable updateUploadEtaRunnable; private Runnable updateUploadEtaRunnable;
private String language; private String language;
private MastodonLanguage.LanguageResolver languageResolver;
static {
Locale[] locales = Locale.getAvailableLocales();
List<Locale> allLocales = new ArrayList<>();
List<String> addedLanguages = new ArrayList<>();
for (Locale locale : locales) {
String lang = locale.getLanguage();
if (!addedLanguages.contains(lang)) {
allLocales.add(locale);
addedLanguages.add(lang);
}
}
Collections.sort(allLocales, Comparator.comparing(l -> l.getDisplayLanguage(Locale.getDefault())));
allIsoLanguages = allLocales;
}
@Override @Override
public void onCreate(Bundle savedInstanceState){ public void onCreate(Bundle savedInstanceState){
@ -226,6 +214,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
instanceDomain=session.domain; instanceDomain=session.domain;
customEmojis=AccountSessionManager.getInstance().getCustomEmojis(instanceDomain); customEmojis=AccountSessionManager.getInstance().getCustomEmojis(instanceDomain);
instance=AccountSessionManager.getInstance().getInstanceInfo(instanceDomain); instance=AccountSessionManager.getInstance().getInstanceInfo(instanceDomain);
languageResolver=new MastodonLanguage.LanguageResolver(instance);
if(getArguments().containsKey("editStatus")){ if(getArguments().containsKey("editStatus")){
editingStatus=Parcels.unwrap(getArguments().getParcelable("editStatus")); editingStatus=Parcels.unwrap(getArguments().getParcelable("editStatus"));
redraftStatus=getArguments().getBoolean("redraftStatus"); redraftStatus=getArguments().getBoolean("redraftStatus");
@ -657,13 +646,13 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
} }
private void updateLanguage(String lang) { private void updateLanguage(String lang) {
updateLanguage(new Locale(lang)); updateLanguage(languageResolver.from(lang));
} }
private void updateLanguage(Locale loc) { private void updateLanguage(MastodonLanguage loc) {
language = loc.getLanguage(); language = loc.getLanguage();
languageButton.setText(loc.getDisplayLanguage(loc)); languageButton.setText(loc.getLanguageName());
languageButton.setContentDescription(getActivity().getString(R.string.sk_post_language, loc.getDisplayLanguage(Locale.getDefault()))); languageButton.setContentDescription(getActivity().getString(R.string.sk_post_language, loc.getDefaultName()));
} }
@SuppressLint("ClickableViewAccessibility") @SuppressLint("ClickableViewAccessibility")
@ -678,31 +667,31 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
languageButton.setCompoundDrawableTintList(languageButton.getTextColors()); languageButton.setCompoundDrawableTintList(languageButton.getTextColors());
languageButton.setCompoundDrawablePadding(V.dp(6)); languageButton.setCompoundDrawablePadding(V.dp(6));
Preferences prefs = AccountSessionManager.getInstance().getAccount(accountID).preferences;
String defaultLang = prefs != null ? prefs.postingDefaultLanguage : null;
if (defaultLang != null) updateLanguage(defaultLang);
else updateLanguage(languageResolver.getDefault());
languagePopup=new PopupMenu(getActivity(), languageButton); languagePopup=new PopupMenu(getActivity(), languageButton);
languageButton.setOnTouchListener(languagePopup.getDragToOpenListener()); languageButton.setOnTouchListener(languagePopup.getDragToOpenListener());
languageButton.setOnClickListener(v->languagePopup.show()); languageButton.setOnClickListener(v->languagePopup.show());
Preferences prefs = AccountSessionManager.getInstance().getAccount(accountID).preferences;
String defaultLang = prefs != null ? prefs.postingDefaultLanguage : null;
if (defaultLang != null) updateLanguage(defaultLang);
else updateLanguage(Locale.getDefault());
Menu languageMenu = languagePopup.getMenu(); Menu languageMenu = languagePopup.getMenu();
for (String recentLanguage : GlobalUserPreferences.recentLanguages) { for (String recentLanguage : Optional.ofNullable(recentLanguages.get(accountID)).orElse(defaultRecentLanguages)) {
Locale loc = new Locale(recentLanguage); MastodonLanguage l = languageResolver.from(recentLanguage);
languageMenu.add(0, allIsoLanguages.indexOf(loc), Menu.NONE, loc.getDisplayLanguage(Locale.getDefault())); languageMenu.add(0, allLanguages.indexOf(l), Menu.NONE, getActivity().getString(R.string.sk_language_name, l.getDefaultName(), l.getLanguageName()));
} }
SubMenu allLanguagesMenu = languageMenu.addSubMenu(R.string.sk_all_languages); SubMenu allLanguagesMenu = languageMenu.addSubMenu(R.string.sk_all_languages);
for (int i = 0; i < allIsoLanguages.size(); i++) { for (int i = 0; i < allLanguages.size(); i++) {
Locale loc = allIsoLanguages.get(i); MastodonLanguage l = allLanguages.get(i);
allLanguagesMenu.add(0, i, Menu.NONE, loc.getDisplayLanguage(Locale.getDefault())); allLanguagesMenu.add(0, i, Menu.NONE, getActivity().getString(R.string.sk_language_name, l.getDefaultName(), l.getLanguageName()));
} }
languagePopup.setOnMenuItemClickListener(i->{ languagePopup.setOnMenuItemClickListener(i->{
if (i.hasSubMenu()) return false; if (i.hasSubMenu()) return false;
updateLanguage(allIsoLanguages.get(i.getItemId())); updateLanguage(allLanguages.get(i.getItemId()));
return true; return true;
}); });
@ -861,11 +850,13 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
.exec(accountID); .exec(accountID);
} }
List<String> recentLanguages = new ArrayList<>(GlobalUserPreferences.recentLanguages); if (replyTo == null) {
recentLanguages.remove(language); List<String> newRecentLanguages = new ArrayList<>(Optional.ofNullable(recentLanguages.get(accountID)).orElse(defaultRecentLanguages));
recentLanguages.add(0, language); newRecentLanguages.remove(language);
GlobalUserPreferences.recentLanguages = recentLanguages.stream().limit(4).collect(Collectors.toList()); newRecentLanguages.add(0, language);
GlobalUserPreferences.save(); recentLanguages.put(accountID, newRecentLanguages.stream().limit(4).collect(Collectors.toList()));
GlobalUserPreferences.save();
}
} }
private boolean hasDraft(){ private boolean hasDraft(){

View File

@ -48,6 +48,7 @@ import org.joinmastodon.android.ui.utils.UiUtils;
import org.joinmastodon.android.updater.GithubSelfUpdater; import org.joinmastodon.android.updater.GithubSelfUpdater;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Objects;
import java.util.function.Consumer; import java.util.function.Consumer;
import androidx.annotation.DrawableRes; import androidx.annotation.DrawableRes;
@ -160,7 +161,7 @@ public class SettingsFragment extends MastodonToolbarFragment{
items.add(new TextItem(R.string.sk_settings_contribute, ()->UiUtils.launchWebBrowser(getActivity(), "https://github.com/sk22/megalodon"))); items.add(new TextItem(R.string.sk_settings_contribute, ()->UiUtils.launchWebBrowser(getActivity(), "https://github.com/sk22/megalodon")));
items.add(new TextItem(R.string.settings_clear_cache, this::clearImageCache)); items.add(new TextItem(R.string.settings_clear_cache, this::clearImageCache));
items.add(new TextItem(R.string.sk_clear_recent_languages, ()->UiUtils.showConfirmationAlert(getActivity(), R.string.sk_clear_recent_languages, R.string.sk_confirm_clear_recent_languages, R.string.clear, ()->{ items.add(new TextItem(R.string.sk_clear_recent_languages, ()->UiUtils.showConfirmationAlert(getActivity(), R.string.sk_clear_recent_languages, R.string.sk_confirm_clear_recent_languages, R.string.clear, ()->{
GlobalUserPreferences.recentLanguages.clear(); GlobalUserPreferences.recentLanguages.remove(accountID);
GlobalUserPreferences.save(); GlobalUserPreferences.save();
}))); })));
items.add(new TextItem(R.string.log_out, this::confirmLogOut)); items.add(new TextItem(R.string.log_out, this::confirmLogOut));

File diff suppressed because one or more lines are too long

View File

@ -53,6 +53,7 @@
<string name="sk_translated_using">Translated using %s</string> <string name="sk_translated_using">Translated using %s</string>
<string name="sk_post_language">Language: %s</string> <string name="sk_post_language">Language: %s</string>
<string name="sk_all_languages">All languages</string> <string name="sk_all_languages">All languages</string>
<string name="sk_language_name">%s (%s)</string>
<string name="sk_clear_recent_languages">Clear recent languages</string> <string name="sk_clear_recent_languages">Clear recent languages</string>
<string name="sk_confirm_clear_recent_languages">Are you sure you want to clear your recently used languages?</string> <string name="sk_confirm_clear_recent_languages">Are you sure you want to clear your recently used languages?</string>
</resources> </resources>