Skip to content

Commit

Permalink
Settings: add custom language/locale chooser (SDK33+).
Browse files Browse the repository at this point in the history
Corsican was not available using Android's per-app-language-chooser.

Fixes #1974.
  • Loading branch information
dennisguse committed Nov 30, 2024
1 parent cba55ea commit 4313b51
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 0 deletions.
107 changes: 107 additions & 0 deletions src/main/java/de/dennisguse/opentracks/settings/LocalePreference.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package de.dennisguse.opentracks.settings;

import android.app.LocaleConfig;
import android.content.Context;
import android.os.Build;
import android.os.LocaleList;
import android.util.AttributeSet;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.core.os.LocaleListCompat;
import androidx.preference.ListPreference;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.Locale;

import de.dennisguse.opentracks.R;

public class LocalePreference extends ListPreference {

public LocalePreference(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(context);
}

public LocalePreference(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}

public LocalePreference(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init(context);
}

public LocalePreference(@NonNull Context context) {
super(context);
init(context);
}

private void init(Context context) {
setPersistent(false);
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
setEnabled(false);
return;
}
LocaleItem systemDefaultLocale = new LocaleItem("", context.getString(R.string.settings_locale_system_default));

LocaleItem currentLocale = new LocaleItem(Locale.getDefault().toLanguageTag(), Locale.getDefault().getDisplayName());

// All available options
LocaleList supportedLocales = LocaleConfig.fromContextIgnoringOverride(context).getSupportedLocales();
ArrayList<LocaleItem> localeItemsSorting = new ArrayList<>();
for (int i = 0; i < supportedLocales.size(); i++) {
Locale current = supportedLocales.get(i);
localeItemsSorting.add(new LocaleItem(current.toLanguageTag(), current.getDisplayName()));
}

localeItemsSorting.removeIf(current -> current.languageTag.equals(currentLocale.languageTag));
localeItemsSorting.sort(Comparator.comparing(o -> o.displayName));

ArrayList<LocaleItem> localeItemList = new ArrayList<>();
localeItemList.add(systemDefaultLocale);
localeItemList.add(currentLocale);
localeItemList.addAll(localeItemsSorting);

ArrayList<String> entries = new ArrayList<>();
ArrayList<String> entryValues = new ArrayList<>();

for (LocaleItem current : localeItemList) {
entries.add(current.displayName);
entryValues.add(current.languageTag);
}

setEntries(entries.toArray(new String[]{}));
setEntryValues(entryValues.toArray(new String[]{}));

if (AppCompatDelegate.getApplicationLocales().equals(LocaleListCompat.getEmptyLocaleList())) {
setValue(systemDefaultLocale.languageTag);
} else {
setValue(currentLocale.languageTag);
}
}

@Override
public void setOnPreferenceChangeListener(@Nullable OnPreferenceChangeListener onPreferenceChangeListener) {
super.setOnPreferenceChangeListener(onPreferenceChangeListener);
}

@Override
public boolean callChangeListener(Object newValue) {
LocaleListCompat newLocale = LocaleListCompat.getEmptyLocaleList();
if (!newValue.equals("")) {
newLocale = LocaleListCompat.forLanguageTags((String) newValue);
}
AppCompatDelegate.setApplicationLocales(newLocale);
return super.callChangeListener(newValue);
}

record LocaleItem(
String languageTag,
String displayName
) {
}
}
3 changes: 3 additions & 0 deletions src/main/res/values/settings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,9 @@
<string name="settings_ui_dynamic_colors_key" translatable="false">uiDynamicColors</string>
<bool name="settings_ui_dynamic_colors_default" translatable="false">false</bool>

<!-- androidx.appcompat.app.AppCompatDelegate.setDefaultNightMode() -->
<string name="locale_key" translatable="false">localeKey</string>

<!-- androidx.appcompat.app.AppCompatDelegate.setDefaultNightMode() -->
<string name="night_mode_key" translatable="false">nightMode</string>
<string name="night_mode_default" translatable="false">@string/night_mode_system_value</string>
Expand Down
3 changes: 3 additions & 0 deletions src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,9 @@ limitations under the License.
<string name="settings_recording_track_name_number_option">Number</string>
<string name="settings_recording_track_name_title">Default track name</string>
<string name="settings_recording_idle_timeout_title">Idle threshold</string>
<string name="settings_locale_title">Language</string>
<string name="settings_locale_system_default">System default</string>

<string name="settings_night_mode_title">UI Theme</string>
<string name="settings_night_mode_option_system">System</string>
<string name="settings_night_mode_option_day">Day</string>
Expand Down
6 changes: 6 additions & 0 deletions src/main/res/xml/settings_user_interface.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
android:title="@string/settings_ui_title">

<de.dennisguse.opentracks.settings.LocalePreference
android:key="@string/locale_key"
android:persistent="false"
android:title="@string/settings_locale_title"
app:useSimpleSummaryProvider="true" />

<ListPreference
android:defaultValue="@string/night_mode_default"
android:entries="@array/night_mode_options"
Expand Down

0 comments on commit 4313b51

Please sign in to comment.