Add locale chooser (#304)

* Add locale chooser

* Prevent AppBundle crashes

* Reload activity on language change

* Make spotBugs happy
This commit is contained in:
Sylvia van Os
2021-08-15 22:18:40 +02:00
committed by GitHub
parent 86be5d1994
commit edba5d5dca
16 changed files with 225 additions and 34 deletions

View File

@@ -1,5 +1,11 @@
# Changelog
## Unreleased
Changes:
- Option to override language
## v2.2.3 (2021-08-13)
Changes:

View File

@@ -37,6 +37,12 @@ android {
}
}
bundle {
language {
enableSplit = false
}
}
compileOptions {
encoding "UTF-8"

View File

@@ -1,5 +1,6 @@
package protect.card_locker;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Bundle;
@@ -21,10 +22,16 @@ public class AboutActivity extends AppCompatActivity
{
private static final String TAG = "Catima";
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(Utils.updateBaseContextLocale(base));
}
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setTitle(R.string.about);
setContentView(R.layout.about_activity);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);

View File

@@ -1,6 +1,7 @@
package protect.card_locker;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
@@ -63,11 +64,16 @@ public class BarcodeSelectorActivity extends AppCompatActivity
private Map<String, Pair<Integer, Integer>> barcodeViewMap;
private LinkedList<AsyncTask> barcodeGeneratorTasks = new LinkedList<>();
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(Utils.updateBaseContextLocale(base));
}
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setTitle(R.string.selectBarcodeTitle);
setContentView(R.layout.barcode_selector_activity);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);

View File

@@ -2,6 +2,7 @@ package protect.card_locker;
import android.Manifest;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
@@ -48,10 +49,16 @@ public class ImportExportActivity extends AppCompatActivity
private String importAlertMessage;
private DataFormat importDataFormat;
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(Utils.updateBaseContextLocale(base));
}
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setTitle(R.string.importExport);
setContentView(R.layout.import_export_activity);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);

View File

@@ -141,6 +141,11 @@ public class LoyaltyCardEditActivity extends AppCompatActivity
LoyaltyCard tempLoyaltyCard;
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(Utils.updateBaseContextLocale(base));
}
private static LoyaltyCard updateTempState(LoyaltyCard loyaltyCard, LoyaltyCardField fieldName, Object value) {
return new LoyaltyCard(
(int) (fieldName == LoyaltyCardField.id ? value : loyaltyCard.id),

View File

@@ -1,5 +1,6 @@
package protect.card_locker;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
@@ -104,6 +105,11 @@ public class LoyaltyCardViewActivity extends AppCompatActivity
IMAGE_BACK
}
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(Utils.updateBaseContextLocale(base));
}
private void extractIntentFields(Intent intent)
{
final Bundle b = intent.getExtras();

View File

@@ -50,6 +50,11 @@ public class MainActivity extends AppCompatActivity implements LoyaltyCardCursor
private View mHelpText;
private View mNoMatchingCardsText;
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(Utils.updateBaseContextLocale(base));
}
private ActionMode.Callback mCurrentActionModeCallback = new ActionMode.Callback()
{
@Override
@@ -179,6 +184,7 @@ public class MainActivity extends AppCompatActivity implements LoyaltyCardCursor
{
setTheme(R.style.AppTheme_NoActionBar);
super.onCreate(inputSavedInstanceState);
setTitle(R.string.app_name);
setContentView(R.layout.main_activity);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);

View File

@@ -31,10 +31,16 @@ public class ManageGroupsActivity extends AppCompatActivity implements GroupCurs
private RecyclerView mGroupList;
GroupCursorAdapter mAdapter;
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(Utils.updateBaseContextLocale(base));
}
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setTitle(R.string.groups);
setContentView(R.layout.manage_groups_activity);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);

View File

@@ -1,6 +1,7 @@
package protect.card_locker;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
@@ -39,6 +40,11 @@ public class ScanActivity extends AppCompatActivity {
private String addGroup;
private boolean torch = false;
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(Utils.updateBaseContextLocale(base));
}
private void extractIntentFields(Intent intent) {
final Bundle b = intent.getExtras();
cardId = b != null ? b.getString(LoyaltyCardEditActivity.BUNDLE_CARDID) : null;
@@ -49,6 +55,7 @@ public class ScanActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setTitle(R.string.scanCardBarcode);
setContentView(R.layout.scan_activity);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);

View File

@@ -3,10 +3,14 @@ package protect.card_locker;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.Matrix;
import android.os.Build;
import android.os.LocaleList;
import android.provider.MediaStore;
import android.util.Log;
import android.widget.Toast;
@@ -31,8 +35,10 @@ import java.util.Currency;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Locale;
import androidx.core.graphics.ColorUtils;
import protect.card_locker.preferences.Settings;
import androidx.exifinterface.media.ExifInterface;
public class Utils {
@@ -343,4 +349,35 @@ public class Utils {
static public Object hashmapGetOrDefault(HashMap hashMap, String key, Object defaultValue) {
return hashmapGetOrDefault(hashMap, key, defaultValue, String.class);
}
static public Locale stringToLocale(String localeString) {
String[] localeParts = localeString.split("-");
if (localeParts.length == 1) {
return new Locale(localeParts[0]);
}
if (localeParts[1].startsWith("r")) {
localeParts[1] = localeParts[1].substring(1);
}
return new Locale(localeParts[0], localeParts[1]);
}
static public Context updateBaseContextLocale(Context context) {
Settings settings = new Settings(context);
Locale chosenLocale = settings.getLocale();
Resources res = context.getResources();
Configuration configuration = res.getConfiguration();
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
configuration.locale = chosenLocale != null ? chosenLocale : Locale.getDefault();
res.updateConfiguration(configuration, res.getDisplayMetrics());
return context;
}
LocaleList localeList = chosenLocale != null ? new LocaleList(chosenLocale) : LocaleList.getDefault();
LocaleList.setDefault(localeList);
configuration.setLocales(localeList);
return context.createConfigurationContext(configuration);
}
}

View File

@@ -3,11 +3,14 @@ package protect.card_locker.preferences;
import android.content.Context;
import android.content.SharedPreferences;
import java.util.Locale;
import androidx.annotation.IntegerRes;
import androidx.annotation.StringRes;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.preference.PreferenceManager;
import protect.card_locker.R;
import protect.card_locker.Utils;
public class Settings
{
@@ -45,6 +48,17 @@ public class Settings
return settings.getBoolean(getResString(keyId), defaultValue);
}
public Locale getLocale()
{
String value = getString(R.string.settings_key_locale, "");
if (value.length() == 0) {
return null;
}
return Utils.stringToLocale(value);
}
public int getTheme()
{
String value = getString(R.string.settings_key_theme, getResString(R.string.settings_key_system_theme));

View File

@@ -1,26 +1,47 @@
package protect.card_locker.preferences;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.MenuItem;
import com.journeyapps.barcodescanner.Util;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.core.app.ActivityCompat;
import androidx.fragment.app.DialogFragment;
import androidx.fragment.app.FragmentActivity;
import androidx.preference.ListPreference;
import androidx.preference.Preference;
import androidx.preference.PreferenceFragmentCompat;
import nl.invissvenska.numberpickerpreference.NumberDialogPreference;
import nl.invissvenska.numberpickerpreference.NumberPickerPreferenceDialogFragment;
import protect.card_locker.MainActivity;
import protect.card_locker.R;
import protect.card_locker.Utils;
public class SettingsActivity extends AppCompatActivity
{
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(Utils.updateBaseContextLocale(base));
}
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setTitle(R.string.settings);
setContentView(R.layout.settings_activity);
ActionBar actionBar = getSupportActionBar();
@@ -30,8 +51,10 @@ public class SettingsActivity extends AppCompatActivity
}
// Display the fragment as the main content.
SettingsFragment fragment = new SettingsFragment();
fragment.setParentReference(this);
getSupportFragmentManager().beginTransaction()
.replace(R.id.settings_container, new SettingsFragment())
.replace(R.id.settings_container, fragment)
.commit();
}
@@ -52,46 +75,63 @@ public class SettingsActivity extends AppCompatActivity
public static class SettingsFragment extends PreferenceFragmentCompat
{
private static final String DIALOG_FRAGMENT_TAG = "SettingsFragment";
private SettingsActivity parent;
public void setParentReference(SettingsActivity settingsActivity) {
parent = settingsActivity;
}
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey)
{
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
// Load the preferences from an XML resource
addPreferencesFromResource(R.xml.preferences);
// Show pretty names
ListPreference localePreference = findPreference(getResources().getString(R.string.settings_key_locale));
assert localePreference != null;
CharSequence[] entryValues = localePreference.getEntryValues();
List<CharSequence> entries = new ArrayList<>();
for (CharSequence entry : entryValues) {
if (entry.length() == 0) {
entries.add(getResources().getString(R.string.settings_system_locale));
} else {
Locale entryLocale = Utils.stringToLocale(entry.toString());
entries.add(entryLocale.getDisplayName(entryLocale));
}
}
localePreference.setEntries(entries.toArray(new CharSequence[entryValues.length]));
Preference themePreference = findPreference(getResources().getString(R.string.settings_key_theme));
assert themePreference != null;
themePreference.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener()
{
@Override
public boolean onPreferenceChange(Preference preference, Object o)
{
if(o.toString().equals(getResources().getString(R.string.settings_key_light_theme)))
{
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
}
else if(o.toString().equals(getResources().getString(R.string.settings_key_dark_theme)))
{
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
}
else
{
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM);
}
FragmentActivity activity = getActivity();
if (activity != null) {
ActivityCompat.recreate(activity);
}
return true;
themePreference.setOnPreferenceChangeListener((preference, o) -> {
if (o.toString().equals(getResources().getString(R.string.settings_key_light_theme))) {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
} else if (o.toString().equals(getResources().getString(R.string.settings_key_dark_theme))) {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
} else {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM);
}
FragmentActivity activity = getActivity();
if (activity != null) {
ActivityCompat.recreate(activity);
}
return true;
});
localePreference.setOnPreferenceChangeListener((preference, newValue) -> {
// Refresh the activity
parent.finish();
startActivity(parent.getIntent());
return true;
});
}
@Override
public void onDisplayPreferenceDialog(Preference preference)
{
if (preference instanceof NumberDialogPreference)
{
public void onDisplayPreferenceDialog(Preference preference) {
if (preference instanceof NumberDialogPreference) {
NumberDialogPreference dialogPreference = (NumberDialogPreference) preference;
DialogFragment dialogFragment = NumberPickerPreferenceDialogFragment
.newInstance(
@@ -103,9 +143,7 @@ public class SettingsActivity extends AppCompatActivity
);
dialogFragment.setTargetFragment(this, 0);
dialogFragment.show(getParentFragmentManager(), DIALOG_FRAGMENT_TAG);
}
else
{
} else {
super.onDisplayPreferenceDialog(preference);
}
}

View File

@@ -12,6 +12,34 @@
<item>@string/settings_dark_theme</item>
</string-array>
<string-array name="locale_values">
<item />
<item>bg</item>
<item>cs</item>
<item>de</item>
<item>el-rGR</item>
<item>eo</item>
<item>es-rAR</item>
<item>es</item>
<item>fi</item>
<item>fr</item>
<item>he-rIL</item>
<item>it</item>
<item>ja</item>
<item>ko</item>
<item>lt</item>
<item>nb-rNO</item>
<item>nl</item>
<item>oc</item>
<item>pl</item>
<item>ro-rRO</item>
<item>ru</item>
<item>sk</item>
<item>sl</item>
<item>uk</item>
<item>zh-rCN</item>
</string-array>
<array name="letter_tile_colors">
<item>#f16364</item>
<item>#f58559</item>

View File

@@ -213,4 +213,7 @@
<string name="failedGeneratingShareURL">Could not generate sharable URL. Please report this.</string>
<string name="turn_flashlight_on">Turn flashlight on</string>
<string name="turn_flashlight_off">Turn flashlight off</string>
<string name="settings_locale">Language</string>
<string name="settings_key_locale" translatable="false">pref_locale</string>
<string name="settings_system_locale">System</string>
</resources>

View File

@@ -16,6 +16,15 @@
app:iconSpaceReserved="false"
app:singleLineTitle="false" />
<ListPreference
android:key="@string/settings_key_locale"
android:title="@string/settings_locale"
android:defaultValue=""
android:entries="@array/locale_values"
android:entryValues="@array/locale_values"
app:iconSpaceReserved="false"
app:singleLineTitle="false" />
<nl.invissvenska.numberpickerpreference.NumberDialogPreference
android:key="@string/settings_key_max_font_size_scale"
android:title="@string/settings_max_font_size_scale"