From 19941817d7b73a8a31ed512c722710882a1a16b8 Mon Sep 17 00:00:00 2001 From: Carifio24 Date: Tue, 23 May 2023 00:04:17 -0400 Subject: [PATCH 1/9] Add functionality for getting localized resources and for switching spell files. --- .../main/java/dnd/jon/spellbook/SpellbookUtils.java | 11 +++++++++++ .../java/dnd/jon/spellbook/SpellbookViewModel.java | 13 +++++++++++-- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/dnd/jon/spellbook/SpellbookUtils.java b/app/src/main/java/dnd/jon/spellbook/SpellbookUtils.java index 42f5af0e..762582bd 100755 --- a/app/src/main/java/dnd/jon/spellbook/SpellbookUtils.java +++ b/app/src/main/java/dnd/jon/spellbook/SpellbookUtils.java @@ -3,6 +3,8 @@ import android.app.AlertDialog; import android.app.Dialog; import android.content.Context; +import android.content.res.Configuration; +import android.content.res.Resources; import android.graphics.Color; import android.view.LayoutInflater; import android.widget.Spinner; @@ -22,6 +24,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.function.BiFunction; @@ -216,4 +219,12 @@ static Collection mutableCollectionFromArray(T[] items) { return new ArrayList<>(Arrays.asList(items)); } + static @NonNull Resources getLocalizedResources(Context context, Locale desiredLocale) { + Configuration conf = context.getResources().getConfiguration(); + conf = new Configuration(conf); + conf.setLocale(desiredLocale); + final Context localizedContext = context.createConfigurationContext(conf); + return localizedContext.getResources(); + } + } diff --git a/app/src/main/java/dnd/jon/spellbook/SpellbookViewModel.java b/app/src/main/java/dnd/jon/spellbook/SpellbookViewModel.java index 1876151d..1e766ba1 100644 --- a/app/src/main/java/dnd/jon/spellbook/SpellbookViewModel.java +++ b/app/src/main/java/dnd/jon/spellbook/SpellbookViewModel.java @@ -2,6 +2,7 @@ import android.app.Application; import android.content.Context; +import android.content.res.Resources; import android.os.Build; import android.os.FileObserver; import android.util.Log; @@ -25,6 +26,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Locale; import java.util.function.BiConsumer; import java.util.function.BiFunction; import java.util.function.Consumer; @@ -74,8 +76,9 @@ public class SpellbookViewModel extends ViewModel implements Filterable { private final MutableLiveData currentSpellSlotStatusLD; private static List englishSpells = new ArrayList<>(); - private final List spells; + private List spells; private List currentSpellList; + private String spellsFilename; private final MutableLiveData> currentSpellsLD; private final MutableLiveData currentSpellFavoriteLD; private final MutableLiveData currentSpellPreparedLD; @@ -110,7 +113,7 @@ public SpellbookViewModel(Application application) { this.currentSpellFilterStatusLD = new MutableLiveData<>(); this.currentSortFilterStatusLD = new MutableLiveData<>(); this.currentSpellSlotStatusLD = new MutableLiveData<>(); - final String spellsFilename = application.getResources().getString(R.string.spells_filename); + this.spellsFilename = application.getResources().getString(R.string.spells_filename); this.spells = loadSpellsFromFile(spellsFilename, false); this.currentSpellList = new ArrayList<>(spells); this.currentSpellsLD = new MutableLiveData<>(spells); @@ -150,6 +153,12 @@ public SpellbookViewModel(Application application) { createdSpellsDirObserver.startWatching(); } + private void updateSpellsForLocale(Locale locale) { + final Resources resources = SpellbookUtils.getLocalizedResources(this.getContext(), locale); + final String filename = resources.getString(R.string.spells_filename); + this.spells = loadSpellsFromFile(filename, false); + } + private List loadSpellsFromFile(String filename, boolean useInternalParse) { try { final JSONArray jsonArray = JSONUtils.loadJSONArrayFromAsset(application, filename); From f49d04a1a2256c18bfd91c1f3c260eec90239e06 Mon Sep 17 00:00:00 2001 From: Jon Carifio Date: Tue, 23 May 2023 01:30:35 -0400 Subject: [PATCH 2/9] Add spell language selection to settings screen UI. Work more on switching spell list in view model. --- .../java/dnd/jon/spellbook/LocalizationUtils.java | 10 +++++++--- .../main/java/dnd/jon/spellbook/MainActivity.java | 4 ++++ .../main/java/dnd/jon/spellbook/SpellCodec.java | 14 +++++++++++--- .../java/dnd/jon/spellbook/SpellbookViewModel.java | 13 +++++++++++-- app/src/main/res/values-pt/strings.xml | 3 +++ app/src/main/res/values/array.xml | 10 ++++++++++ app/src/main/res/values/strings.xml | 7 +++++++ app/src/main/res/xml-sw600dp/settings_screen.xml | 9 +++++++++ app/src/main/res/xml/settings_screen.xml | 9 +++++++++ 9 files changed, 71 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/dnd/jon/spellbook/LocalizationUtils.java b/app/src/main/java/dnd/jon/spellbook/LocalizationUtils.java index be698112..42f2d17f 100644 --- a/app/src/main/java/dnd/jon/spellbook/LocalizationUtils.java +++ b/app/src/main/java/dnd/jon/spellbook/LocalizationUtils.java @@ -33,14 +33,18 @@ public class LocalizationUtils { put(CasterClass.WIZARD, R.string.wizard_spellcasting_info); }}; - static String getCurrentLanguage(){ + static Locale getLocale() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){ - return LocaleList.getDefault().get(0).getLanguage(); + return LocaleList.getDefault().get(0); } else{ - return Locale.getDefault().getLanguage(); + return Locale.getDefault(); } } + static String getCurrentLanguage() { + return getLocale().getLanguage(); + } + static CasterClass[] supportedClasses() { return CasterClass.values(); } static Source[] supportedSources() { return Source.values(); } static Source[] supportedCoreSourcebooks() { return Source.coreSourcebooks(); } diff --git a/app/src/main/java/dnd/jon/spellbook/MainActivity.java b/app/src/main/java/dnd/jon/spellbook/MainActivity.java index 1dfa95a2..09632a17 100755 --- a/app/src/main/java/dnd/jon/spellbook/MainActivity.java +++ b/app/src/main/java/dnd/jon/spellbook/MainActivity.java @@ -53,6 +53,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.stream.Collectors; import java.util.stream.IntStream; @@ -1330,6 +1331,9 @@ public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, Strin } else if (key.equals(getString(string.spell_list_locations))) { updateBottomBarVisibility(); updateSpellListMenuVisibility(); + } else if (key.equals(getString(string.spell_language))) { + final Locale locale = new Locale(sharedPreferences.getString(key, getString(string.english_code))); + viewModel.updateSpellsForLocale(locale); } } diff --git a/app/src/main/java/dnd/jon/spellbook/SpellCodec.java b/app/src/main/java/dnd/jon/spellbook/SpellCodec.java index bb08e941..8491dbd4 100755 --- a/app/src/main/java/dnd/jon/spellbook/SpellCodec.java +++ b/app/src/main/java/dnd/jon/spellbook/SpellCodec.java @@ -142,10 +142,10 @@ private Spell parseSpell(JSONObject json, SpellBuilder b, boolean useInternal) t return b.buildAndReset(); } - List parseSpellList(@Nullable JSONArray jsonArray, boolean useInternal) throws Exception { + private List parseSpellList(@Nullable JSONArray jsonArray, boolean useInternal, Locale locale) throws Exception { final List spells = new ArrayList<>(); - final SpellBuilder b = useInternal ? new SpellBuilder(context, Locale.US) : new SpellBuilder(context); + final SpellBuilder b = useInternal ? new SpellBuilder(context, Locale.US) : new SpellBuilder(context, locale); try { for (int i = 0; i < jsonArray.length(); i++) { @@ -159,8 +159,16 @@ List parseSpellList(@Nullable JSONArray jsonArray, boolean useInternal) t return spells; } + List parseSpellList(JSONArray jsonArray, Locale locale) throws Exception { + return parseSpellList(jsonArray, false, locale); + } + + List parseSpellList(JSONArray jsonArray, boolean useInternalParse) throws Exception { + return parseSpellList(jsonArray, useInternalParse, LocalizationUtils.getLocale()); + } + List parseSpellList(JSONArray jsonArray) throws Exception { - return parseSpellList(jsonArray, false); + return parseSpellList(jsonArray, false, LocalizationUtils.getLocale()); } JSONObject toJSON(Spell spell) throws JSONException { diff --git a/app/src/main/java/dnd/jon/spellbook/SpellbookViewModel.java b/app/src/main/java/dnd/jon/spellbook/SpellbookViewModel.java index 1e766ba1..1b151cd3 100644 --- a/app/src/main/java/dnd/jon/spellbook/SpellbookViewModel.java +++ b/app/src/main/java/dnd/jon/spellbook/SpellbookViewModel.java @@ -79,6 +79,7 @@ public class SpellbookViewModel extends ViewModel implements Filterable { private List spells; private List currentSpellList; private String spellsFilename; + private Locale spellsLocale; private final MutableLiveData> currentSpellsLD; private final MutableLiveData currentSpellFavoriteLD; private final MutableLiveData currentSpellPreparedLD; @@ -115,6 +116,7 @@ public SpellbookViewModel(Application application) { this.currentSpellSlotStatusLD = new MutableLiveData<>(); this.spellsFilename = application.getResources().getString(R.string.spells_filename); this.spells = loadSpellsFromFile(spellsFilename, false); + this.spellsLocale = LocalizationUtils.getLocale(); this.currentSpellList = new ArrayList<>(spells); this.currentSpellsLD = new MutableLiveData<>(spells); this.currentSpellLD = new MutableLiveData<>(); @@ -153,17 +155,24 @@ public SpellbookViewModel(Application application) { createdSpellsDirObserver.startWatching(); } - private void updateSpellsForLocale(Locale locale) { + void updateSpellsForLocale(Locale locale) { + this.spellsLocale = locale; final Resources resources = SpellbookUtils.getLocalizedResources(this.getContext(), locale); final String filename = resources.getString(R.string.spells_filename); this.spells = loadSpellsFromFile(filename, false); + filter(); } private List loadSpellsFromFile(String filename, boolean useInternalParse) { try { final JSONArray jsonArray = JSONUtils.loadJSONArrayFromAsset(application, filename); final SpellCodec codec = new SpellCodec(application); - return codec.parseSpellList(jsonArray, useInternalParse); + if (useInternalParse) { + return codec.parseSpellList(jsonArray, true); + } else { + final Locale locale = SpellbookUtils.coalesce(this.spellsLocale, LocalizationUtils.getLocale()); + return codec.parseSpellList(jsonArray, locale); + } } catch (Exception e) { //TODO: Better error handling? e.printStackTrace(); diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index 993ab546..d2040bdb 100755 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -437,6 +437,9 @@ BAF Botão circular + + Soletrar linguagem + Imagem de fundo do livro diff --git a/app/src/main/res/values/array.xml b/app/src/main/res/values/array.xml index 9c623ec1..cec2a2bd 100755 --- a/app/src/main/res/values/array.xml +++ b/app/src/main/res/values/array.xml @@ -78,4 +78,14 @@ @string/both + + @string/english + @string/portuguese + + + + @string/english_code + @string/portuguese_code + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 52f4166e..72697cf2 100755 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -438,6 +438,13 @@ FAB Circular button + + Spell language + English + en + Português + pt + Book background image diff --git a/app/src/main/res/xml-sw600dp/settings_screen.xml b/app/src/main/res/xml-sw600dp/settings_screen.xml index 4994808b..4ac8943c 100644 --- a/app/src/main/res/xml-sw600dp/settings_screen.xml +++ b/app/src/main/res/xml-sw600dp/settings_screen.xml @@ -41,6 +41,15 @@ android:defaultValue="@string/bottom_navbar" /> + + \ No newline at end of file diff --git a/app/src/main/res/xml/settings_screen.xml b/app/src/main/res/xml/settings_screen.xml index ebfe927b..c6419c48 100644 --- a/app/src/main/res/xml/settings_screen.xml +++ b/app/src/main/res/xml/settings_screen.xml @@ -50,6 +50,15 @@ android:defaultValue="@string/bottom_navbar" /> + + \ No newline at end of file From 3aa55ace1468e739a7632139ce835cc7642f0e6d Mon Sep 17 00:00:00 2001 From: Jon Carifio Date: Wed, 24 May 2023 00:55:26 -0400 Subject: [PATCH 3/9] Changing the selected language changes spells correctly --- .../dnd/jon/spellbook/LocalizationUtils.java | 16 +++++++++++++++ .../java/dnd/jon/spellbook/SpellCodec.java | 2 +- .../dnd/jon/spellbook/SpellbookUtils.java | 8 -------- .../dnd/jon/spellbook/SpellbookViewModel.java | 20 ++++++++----------- 4 files changed, 25 insertions(+), 21 deletions(-) diff --git a/app/src/main/java/dnd/jon/spellbook/LocalizationUtils.java b/app/src/main/java/dnd/jon/spellbook/LocalizationUtils.java index 42f2d17f..806d9507 100644 --- a/app/src/main/java/dnd/jon/spellbook/LocalizationUtils.java +++ b/app/src/main/java/dnd/jon/spellbook/LocalizationUtils.java @@ -1,8 +1,13 @@ package dnd.jon.spellbook; +import android.content.Context; +import android.content.res.Configuration; +import android.content.res.Resources; import android.os.Build; import android.os.LocaleList; +import androidx.annotation.NonNull; + import java.util.Arrays; import java.util.EnumMap; import java.util.Locale; @@ -45,6 +50,17 @@ static String getCurrentLanguage() { return getLocale().getLanguage(); } + static @NonNull Context getLocalizedContext(Context context, Locale desiredLocale) { + Configuration conf = context.getResources().getConfiguration(); + conf = new Configuration(conf); + conf.setLocale(desiredLocale); + return context.createConfigurationContext(conf); + } + + static @NonNull Resources getLocalizedResources(Context context, Locale desiredLocale) { + return getLocalizedContext(context, desiredLocale).getResources(); + } + static CasterClass[] supportedClasses() { return CasterClass.values(); } static Source[] supportedSources() { return Source.values(); } static Source[] supportedCoreSourcebooks() { return Source.coreSourcebooks(); } diff --git a/app/src/main/java/dnd/jon/spellbook/SpellCodec.java b/app/src/main/java/dnd/jon/spellbook/SpellCodec.java index 8491dbd4..f943edfc 100755 --- a/app/src/main/java/dnd/jon/spellbook/SpellCodec.java +++ b/app/src/main/java/dnd/jon/spellbook/SpellCodec.java @@ -142,7 +142,7 @@ private Spell parseSpell(JSONObject json, SpellBuilder b, boolean useInternal) t return b.buildAndReset(); } - private List parseSpellList(@Nullable JSONArray jsonArray, boolean useInternal, Locale locale) throws Exception { + List parseSpellList(@Nullable JSONArray jsonArray, boolean useInternal, Locale locale) throws Exception { final List spells = new ArrayList<>(); final SpellBuilder b = useInternal ? new SpellBuilder(context, Locale.US) : new SpellBuilder(context, locale); diff --git a/app/src/main/java/dnd/jon/spellbook/SpellbookUtils.java b/app/src/main/java/dnd/jon/spellbook/SpellbookUtils.java index 762582bd..d01512d1 100755 --- a/app/src/main/java/dnd/jon/spellbook/SpellbookUtils.java +++ b/app/src/main/java/dnd/jon/spellbook/SpellbookUtils.java @@ -219,12 +219,4 @@ static Collection mutableCollectionFromArray(T[] items) { return new ArrayList<>(Arrays.asList(items)); } - static @NonNull Resources getLocalizedResources(Context context, Locale desiredLocale) { - Configuration conf = context.getResources().getConfiguration(); - conf = new Configuration(conf); - conf.setLocale(desiredLocale); - final Context localizedContext = context.createConfigurationContext(conf); - return localizedContext.getResources(); - } - } diff --git a/app/src/main/java/dnd/jon/spellbook/SpellbookViewModel.java b/app/src/main/java/dnd/jon/spellbook/SpellbookViewModel.java index 1b151cd3..508f016c 100644 --- a/app/src/main/java/dnd/jon/spellbook/SpellbookViewModel.java +++ b/app/src/main/java/dnd/jon/spellbook/SpellbookViewModel.java @@ -115,8 +115,8 @@ public SpellbookViewModel(Application application) { this.currentSortFilterStatusLD = new MutableLiveData<>(); this.currentSpellSlotStatusLD = new MutableLiveData<>(); this.spellsFilename = application.getResources().getString(R.string.spells_filename); - this.spells = loadSpellsFromFile(spellsFilename, false); this.spellsLocale = LocalizationUtils.getLocale(); + this.spells = loadSpellsFromFile(spellsFilename, this.spellsLocale); this.currentSpellList = new ArrayList<>(spells); this.currentSpellsLD = new MutableLiveData<>(spells); this.currentSpellLD = new MutableLiveData<>(); @@ -139,7 +139,7 @@ public SpellbookViewModel(Application application) { // If we don't already have the english spells, get them if (englishSpells.size() == 0) { - englishSpells = loadSpellsFromFile(ENGLISH_SPELLS_FILENAME, true); + englishSpells = loadSpellsFromFile(ENGLISH_SPELLS_FILENAME, Locale.US); } // Whenever a file is created or deleted in the profiles folder @@ -157,22 +157,18 @@ public SpellbookViewModel(Application application) { void updateSpellsForLocale(Locale locale) { this.spellsLocale = locale; - final Resources resources = SpellbookUtils.getLocalizedResources(this.getContext(), locale); + final Resources resources = LocalizationUtils.getLocalizedResources(this.getContext(), locale); final String filename = resources.getString(R.string.spells_filename); - this.spells = loadSpellsFromFile(filename, false); + this.spells = loadSpellsFromFile(filename, locale); filter(); } - private List loadSpellsFromFile(String filename, boolean useInternalParse) { + private List loadSpellsFromFile(String filename, Locale locale) { try { final JSONArray jsonArray = JSONUtils.loadJSONArrayFromAsset(application, filename); - final SpellCodec codec = new SpellCodec(application); - if (useInternalParse) { - return codec.parseSpellList(jsonArray, true); - } else { - final Locale locale = SpellbookUtils.coalesce(this.spellsLocale, LocalizationUtils.getLocale()); - return codec.parseSpellList(jsonArray, locale); - } + final SpellCodec codec = new SpellCodec(LocalizationUtils.getLocalizedContext(application, locale)); + final boolean useInternalParse = locale == Locale.US; + return codec.parseSpellList(jsonArray, useInternalParse, locale); } catch (Exception e) { //TODO: Better error handling? e.printStackTrace(); From 84b9271d635a0575836e78544b3029915128ff57 Mon Sep 17 00:00:00 2001 From: Jon Carifio Date: Wed, 24 May 2023 01:33:33 -0400 Subject: [PATCH 4/9] Set the spells locale during the view model constructor, rather than waiting and updating after. --- app/src/main/java/dnd/jon/spellbook/MainActivity.java | 5 +++-- app/src/main/java/dnd/jon/spellbook/SpellCodec.java | 2 ++ .../java/dnd/jon/spellbook/SpellbookViewModel.java | 10 ++++++++-- app/src/main/res/values/strings.xml | 1 + app/src/main/res/xml/settings_screen.xml | 2 +- 5 files changed, 15 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/dnd/jon/spellbook/MainActivity.java b/app/src/main/java/dnd/jon/spellbook/MainActivity.java index 09632a17..2d226b1c 100755 --- a/app/src/main/java/dnd/jon/spellbook/MainActivity.java +++ b/app/src/main/java/dnd/jon/spellbook/MainActivity.java @@ -229,7 +229,8 @@ protected void onCreate(final Bundle savedInstanceState) { setSupportActionBar(binding.toolbar); // Listen for preference changes - PreferenceManager.getDefaultSharedPreferences(this).registerOnSharedPreferenceChangeListener(this); + final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); + prefs.registerOnSharedPreferenceChangeListener(this); // The DrawerLayout and the left navigation view drawerLayout = binding.drawerLayout; @@ -1331,7 +1332,7 @@ public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, Strin } else if (key.equals(getString(string.spell_list_locations))) { updateBottomBarVisibility(); updateSpellListMenuVisibility(); - } else if (key.equals(getString(string.spell_language))) { + } else if (key.equals(getString(string.spell_language_key))) { final Locale locale = new Locale(sharedPreferences.getString(key, getString(string.english_code))); viewModel.updateSpellsForLocale(locale); } diff --git a/app/src/main/java/dnd/jon/spellbook/SpellCodec.java b/app/src/main/java/dnd/jon/spellbook/SpellCodec.java index f943edfc..045a8c35 100755 --- a/app/src/main/java/dnd/jon/spellbook/SpellCodec.java +++ b/app/src/main/java/dnd/jon/spellbook/SpellCodec.java @@ -142,6 +142,8 @@ private Spell parseSpell(JSONObject json, SpellBuilder b, boolean useInternal) t return b.buildAndReset(); } + // TODO: This is kinda gross - try to find a way not to need the useInternal + // It should be possible to just replace it with the locale List parseSpellList(@Nullable JSONArray jsonArray, boolean useInternal, Locale locale) throws Exception { final List spells = new ArrayList<>(); diff --git a/app/src/main/java/dnd/jon/spellbook/SpellbookViewModel.java b/app/src/main/java/dnd/jon/spellbook/SpellbookViewModel.java index 508f016c..5bfc7b2b 100644 --- a/app/src/main/java/dnd/jon/spellbook/SpellbookViewModel.java +++ b/app/src/main/java/dnd/jon/spellbook/SpellbookViewModel.java @@ -2,6 +2,7 @@ import android.app.Application; import android.content.Context; +import android.content.SharedPreferences; import android.content.res.Resources; import android.os.Build; import android.os.FileObserver; @@ -17,6 +18,7 @@ import androidx.lifecycle.MutableLiveData; import androidx.lifecycle.Transformations; import androidx.lifecycle.ViewModel; +import androidx.preference.PreferenceManager; import org.json.JSONArray; import org.json.JSONException; @@ -99,6 +101,11 @@ private static LiveData distinctTransform(LiveData source, Function< public SpellbookViewModel(Application application) { this.application = application; + final String spellsLocaleString = PreferenceManager.getDefaultSharedPreferences(application) + .getString(application.getString(R.string.spell_language_key), null); + this.spellsLocale = spellsLocaleString == null ? LocalizationUtils.getLocale() : new Locale(spellsLocaleString); + final Context spellsContext = LocalizationUtils.getLocalizedContext(application, this.spellsLocale); + this.profilesDir = FilesystemUtils.createFileDirectory(application, PROFILES_DIR_NAME); this.statusesDir = FilesystemUtils.createFileDirectory(application, STATUSES_DIR_NAME); this.createdSourcesDir = FilesystemUtils.createFileDirectory(application, CREATED_SOURCES_DIR_NAME); @@ -114,8 +121,7 @@ public SpellbookViewModel(Application application) { this.currentSpellFilterStatusLD = new MutableLiveData<>(); this.currentSortFilterStatusLD = new MutableLiveData<>(); this.currentSpellSlotStatusLD = new MutableLiveData<>(); - this.spellsFilename = application.getResources().getString(R.string.spells_filename); - this.spellsLocale = LocalizationUtils.getLocale(); + this.spellsFilename = spellsContext.getResources().getString(R.string.spells_filename); this.spells = loadSpellsFromFile(spellsFilename, this.spellsLocale); this.currentSpellList = new ArrayList<>(spells); this.currentSpellsLD = new MutableLiveData<>(spells); diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 72697cf2..89454b28 100755 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -439,6 +439,7 @@ Circular button + spell_language Spell language English en diff --git a/app/src/main/res/xml/settings_screen.xml b/app/src/main/res/xml/settings_screen.xml index c6419c48..30a66c06 100644 --- a/app/src/main/res/xml/settings_screen.xml +++ b/app/src/main/res/xml/settings_screen.xml @@ -51,7 +51,7 @@ /> Date: Thu, 25 May 2023 01:20:53 -0400 Subject: [PATCH 5/9] Update version and what's new info. Set default value for spell language based on locale. --- .../main/java/dnd/jon/spellbook/GlobalInfo.java | 4 ++-- .../main/java/dnd/jon/spellbook/MainActivity.java | 4 ++-- .../java/dnd/jon/spellbook/SpellbookViewModel.java | 14 ++++++++++++-- app/src/main/res/values-pt/strings.xml | 3 +++ app/src/main/res/values/strings.xml | 3 +++ app/src/main/res/xml/settings_screen.xml | 1 - 6 files changed, 22 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/dnd/jon/spellbook/GlobalInfo.java b/app/src/main/java/dnd/jon/spellbook/GlobalInfo.java index aa810d5b..1d0404f3 100644 --- a/app/src/main/java/dnd/jon/spellbook/GlobalInfo.java +++ b/app/src/main/java/dnd/jon/spellbook/GlobalInfo.java @@ -2,13 +2,13 @@ class GlobalInfo { - static final Version VERSION = new Version(3,0,6); + static final Version VERSION = new Version(3,1,0); static final String VERSION_CODE = VERSION.string(); // We don't always want to show an update message // i.e. for updates that are pure bugfixes, the old message may be // more useful to users - static final Version UPDATE_LOG_VERSION = new Version(3,0,6); + static final Version UPDATE_LOG_VERSION = new Version(3,1,0); static final String UPDATE_LOG_CODE = UPDATE_LOG_VERSION.string(); static final int ANDROID_VERSION = android.os.Build.VERSION.SDK_INT; diff --git a/app/src/main/java/dnd/jon/spellbook/MainActivity.java b/app/src/main/java/dnd/jon/spellbook/MainActivity.java index 2d226b1c..3a48cb26 100755 --- a/app/src/main/java/dnd/jon/spellbook/MainActivity.java +++ b/app/src/main/java/dnd/jon/spellbook/MainActivity.java @@ -1249,8 +1249,8 @@ private void showUpdateDialog(boolean checkIfNecessary) { final boolean noCharacters = (characterNames == null) || characterNames.size() <= 0; final boolean toShow = !checkIfNecessary || !(prefs.contains(key) || noCharacters); if (toShow) { - final int titleID = string.update_03_00_06_title; - final int descriptionID = string.update_03_00_06_description; + final int titleID = string.update_03_01_00_title; + final int descriptionID = string.update_03_01_00_description; final Runnable onDismissAction = () -> { final SharedPreferences.Editor editor = prefs.edit(); editor.putBoolean(key, true).apply(); diff --git a/app/src/main/java/dnd/jon/spellbook/SpellbookViewModel.java b/app/src/main/java/dnd/jon/spellbook/SpellbookViewModel.java index 5bfc7b2b..1294dafe 100644 --- a/app/src/main/java/dnd/jon/spellbook/SpellbookViewModel.java +++ b/app/src/main/java/dnd/jon/spellbook/SpellbookViewModel.java @@ -101,9 +101,19 @@ private static LiveData distinctTransform(LiveData source, Function< public SpellbookViewModel(Application application) { this.application = application; - final String spellsLocaleString = PreferenceManager.getDefaultSharedPreferences(application) - .getString(application.getString(R.string.spell_language_key), null); + final SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(application); + final String spellLanguageKey = application.getString(R.string.spell_language_key); + final String spellsLocaleString = sharedPreferences.getString(spellLanguageKey, null); this.spellsLocale = spellsLocaleString == null ? LocalizationUtils.getLocale() : new Locale(spellsLocaleString); + + // If we don't have an existing value for the spell language setting + // we set the default. + // TODO: Can we do this in the XML? It's default locale-dependent + if (spellsLocaleString == null) { + final SharedPreferences.Editor editor = sharedPreferences.edit(); + editor.putString(spellLanguageKey, this.spellsLocale.getLanguage()); + editor.apply(); + } final Context spellsContext = LocalizationUtils.getLocalizedContext(application, this.spellsLocale); this.profilesDir = FilesystemUtils.createFileDirectory(application, PROFILES_DIR_NAME); diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index d2040bdb..98a59bc3 100755 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -393,6 +393,8 @@ Esta atualização adiciona novamente os feitiços do Guia do Aventureiro Astral, que foram removidos por engano na v3.0.0.\n\nAlém disso, existem algumas pequenas correções de bugs. Atualização da versão 3.0.6 O livro de feitiços foi atualizado para incluir o feitiço do Guia do Mestre da Guilda para Ravnica.\n\nUm erro no conteúdo de Parede de Luz foi corrigido. + Atualização da versão 3.1 + Esta atualização adiciona a capacidade de alterar o idioma dos feitiços (atualmente inglês e português estão disponíveis). Renomear @@ -439,6 +441,7 @@ Soletrar linguagem + ${portuguese_code} Imagem de fundo do livro diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 89454b28..726ff3aa 100755 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -394,6 +394,8 @@ This update re-adds spells from the Astral Adventurer\'s Guide, which were mistakenly removed in v3.0.0.\n\nAdditionally, there are some small bugfixes. Version 3.0.6 update The spellbook has been updated to include the spell from the Guildmaster\'s Guide to Ravnica.\n\nA mistake in the content of Wall of Light has been corrected. + Version 3.1 update + This update adds the ability to change the language of spells (currently English and Portuguese are available). Rename @@ -445,6 +447,7 @@ en Português pt + ${english_code} Book background image diff --git a/app/src/main/res/xml/settings_screen.xml b/app/src/main/res/xml/settings_screen.xml index 30a66c06..aadbbbd7 100644 --- a/app/src/main/res/xml/settings_screen.xml +++ b/app/src/main/res/xml/settings_screen.xml @@ -56,7 +56,6 @@ android:summary="%s" android:entryValues="@array/language_codes" android:entries="@array/language_names" - android:defaultValue="@string/english_code" /> From f9b970f2362cdeee7bc7328c770470095547bc6f Mon Sep 17 00:00:00 2001 From: Jon Carifio Date: Fri, 26 May 2023 02:10:10 -0400 Subject: [PATCH 6/9] Make sure default spell locale is either English or Portuguese. Do some additional locale changing in spell window display. --- .../java/dnd/jon/spellbook/DisplayUtils.java | 16 ++++++++++++ .../dnd/jon/spellbook/LocalizationUtils.java | 18 +++++++++++++ .../java/dnd/jon/spellbook/SpellAdapter.java | 1 + .../jon/spellbook/SpellWindowFragment.java | 4 ++- .../dnd/jon/spellbook/SpellbookViewModel.java | 16 ++++++++---- app/src/main/res/layout/spell_row.xml | 1 + app/src/main/res/layout/spell_window.xml | 25 ++++++++++--------- 7 files changed, 63 insertions(+), 18 deletions(-) diff --git a/app/src/main/java/dnd/jon/spellbook/DisplayUtils.java b/app/src/main/java/dnd/jon/spellbook/DisplayUtils.java index f622c5b9..444d810d 100644 --- a/app/src/main/java/dnd/jon/spellbook/DisplayUtils.java +++ b/app/src/main/java/dnd/jon/spellbook/DisplayUtils.java @@ -182,4 +182,20 @@ static Range rangeFromString(Context context, String s) { return Range.fromString(s, (t) -> getDisplayName(context, t), (us) -> unitFromString(context, LengthUnit.class, us)); } + + // Spell prompt text + public static String locationPrompt(Context context, int nLocations) { + return context.getString(nLocations == 1 ? R.string.location : R.string.location); + } + public static String concentrationPrompt(Context context) { return context.getString(R.string.concentration); } + public static String castingTimePrompt(Context context) { return context.getString(R.string.casting_time); } + public static String rangePrompt(Context context) { return context.getString(R.string.range); } + public static String componentsPrompt(Context context) { return context.getString(R.string.components); } + public static String materialsPrompt(Context context) { return context.getString(R.string.materials); } + public static String royaltyPrompt(Context context) { return context.getString(R.string.royalty); } + public static String durationPrompt(Context context) { return context.getString(R.string.duration); } + public static String classesPrompt(Context context) { return context.getString(R.string.classes); } + public static String tceExpandedClassesPrompt(Context context) { return context.getString(R.string.tce_expanded_classes); } + public static String descriptionPrompt(Context context) { return context.getString(R.string.description); } + public static String higherLevelsPrompt(Context context) { return context.getString(R.string.higher_level); } } diff --git a/app/src/main/java/dnd/jon/spellbook/LocalizationUtils.java b/app/src/main/java/dnd/jon/spellbook/LocalizationUtils.java index 806d9507..cd78ff1a 100644 --- a/app/src/main/java/dnd/jon/spellbook/LocalizationUtils.java +++ b/app/src/main/java/dnd/jon/spellbook/LocalizationUtils.java @@ -8,13 +8,21 @@ import androidx.annotation.NonNull; +import java.util.ArrayList; import java.util.Arrays; import java.util.EnumMap; +import java.util.List; import java.util.Locale; import java.util.Map; public class LocalizationUtils { + private static final List supportedLanguages = new ArrayList<>(); + static { + supportedLanguages.add("en"); + supportedLanguages.add("pt"); + } + private static final Map tableLayoutIDs = new EnumMap(CasterClass.class) {{ put(CasterClass.ARTIFICER, R.layout.artificer_table_layout); put(CasterClass.BARD, R.layout.bard_table_layout); @@ -46,6 +54,16 @@ static Locale getLocale() { } } + static Locale defaultSpellLocale() { + final Locale locale = getLocale(); + final String language = locale.getLanguage(); + if (supportedLanguages.contains(language)) { + return locale; + } else { + return Locale.US; + } + } + static String getCurrentLanguage() { return getLocale().getLanguage(); } diff --git a/app/src/main/java/dnd/jon/spellbook/SpellAdapter.java b/app/src/main/java/dnd/jon/spellbook/SpellAdapter.java index fce68f96..1a29ea81 100755 --- a/app/src/main/java/dnd/jon/spellbook/SpellAdapter.java +++ b/app/src/main/java/dnd/jon/spellbook/SpellAdapter.java @@ -45,6 +45,7 @@ public SpellRowHolder(SpellRowBinding binding, SpellbookViewModel viewModel) { public void bind(Spell s) { spell = s; binding.setSpell(spell); + binding.setContext(viewModel.getSpellContext()); binding.executePendingBindings(); //Set the buttons to show the appropriate images diff --git a/app/src/main/java/dnd/jon/spellbook/SpellWindowFragment.java b/app/src/main/java/dnd/jon/spellbook/SpellWindowFragment.java index b0b35381..ee6651e8 100644 --- a/app/src/main/java/dnd/jon/spellbook/SpellWindowFragment.java +++ b/app/src/main/java/dnd/jon/spellbook/SpellWindowFragment.java @@ -95,13 +95,15 @@ public View onCreateView(@NonNull LayoutInflater inflater, binding.setSpell(spell); //binding.getRoot().setVisibility(spell == null ? View.GONE : View.VISIBLE); binding.setUseExpanded(useExpanded); - binding.executePendingBindings(); binding.setTextSize(textSize); binding.setTextColor(textColor); + binding.setContext(viewModel.getSpellContext()); + binding.executePendingBindings(); viewModel.currentSpellFavoriteLD().observe(lifecycleOwner, binding.favoriteButton::set); viewModel.currentSpellPreparedLD().observe(lifecycleOwner, binding.preparedButton::set); viewModel.currentSpellKnownLD().observe(lifecycleOwner, binding.knownButton::set); + viewModel.currentSpellsContext().observe(lifecycleOwner, binding::setContext); // spellStatus.addOnPropertyChangedCallback(new Observable.OnPropertyChangedCallback() { // @Override diff --git a/app/src/main/java/dnd/jon/spellbook/SpellbookViewModel.java b/app/src/main/java/dnd/jon/spellbook/SpellbookViewModel.java index 1294dafe..a551034c 100644 --- a/app/src/main/java/dnd/jon/spellbook/SpellbookViewModel.java +++ b/app/src/main/java/dnd/jon/spellbook/SpellbookViewModel.java @@ -81,6 +81,7 @@ public class SpellbookViewModel extends ViewModel implements Filterable { private List spells; private List currentSpellList; private String spellsFilename; + private final MutableLiveData spellsContext; private Locale spellsLocale; private final MutableLiveData> currentSpellsLD; private final MutableLiveData currentSpellFavoriteLD; @@ -90,7 +91,7 @@ public class SpellbookViewModel extends ViewModel implements Filterable { private final MutableLiveData currentUseExpandedLD; private final MutableLiveData spellTableVisibleLD; - private final SpellCodec spellCodec; + private SpellCodec spellCodec; private static final List SORT_PROPERTY_IDS = Arrays.asList(BR.firstSortField, BR.firstSortReverse, BR.secondSortField, BR.secondSortReverse); @@ -104,7 +105,7 @@ public SpellbookViewModel(Application application) { final SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(application); final String spellLanguageKey = application.getString(R.string.spell_language_key); final String spellsLocaleString = sharedPreferences.getString(spellLanguageKey, null); - this.spellsLocale = spellsLocaleString == null ? LocalizationUtils.getLocale() : new Locale(spellsLocaleString); + this.spellsLocale = spellsLocaleString == null ? LocalizationUtils.defaultSpellLocale() : new Locale(spellsLocaleString); // If we don't have an existing value for the spell language setting // we set the default. @@ -115,14 +116,14 @@ public SpellbookViewModel(Application application) { editor.apply(); } final Context spellsContext = LocalizationUtils.getLocalizedContext(application, this.spellsLocale); + this.spellsContext = new MutableLiveData<>(spellsContext); + this.spellCodec = new SpellCodec(spellsContext); this.profilesDir = FilesystemUtils.createFileDirectory(application, PROFILES_DIR_NAME); this.statusesDir = FilesystemUtils.createFileDirectory(application, STATUSES_DIR_NAME); this.createdSourcesDir = FilesystemUtils.createFileDirectory(application, CREATED_SOURCES_DIR_NAME); this.createdSpellsDir = FilesystemUtils.createFileDirectory(application, CREATED_SPELLS_DIR_NAME); - this.spellCodec = new SpellCodec(application); - this.currentProfileLD = new MutableLiveData<>(); this.characterNamesLD = new MutableLiveData<>(); this.statusNamesLD = new MutableLiveData<>(); @@ -173,9 +174,12 @@ public SpellbookViewModel(Application application) { void updateSpellsForLocale(Locale locale) { this.spellsLocale = locale; - final Resources resources = LocalizationUtils.getLocalizedResources(this.getContext(), locale); + final Context context = LocalizationUtils.getLocalizedContext(this.getContext(), locale); + this.spellsContext.setValue(context); + final Resources resources = context.getResources(); final String filename = resources.getString(R.string.spells_filename); this.spells = loadSpellsFromFile(filename, locale); + this.spellCodec = new SpellCodec(context); filter(); } @@ -230,6 +234,8 @@ void setCurrentSpell(Spell spell) { } List getAllSpells() { return spells; } + LiveData currentSpellsContext() { return spellsContext; } + Context getSpellContext() { return spellsContext.getValue(); } private String nameValidator(String name, int emptyItemID, int itemTypeID, List existingItems) { if (name.isEmpty()) { diff --git a/app/src/main/res/layout/spell_row.xml b/app/src/main/res/layout/spell_row.xml index 8d772368..3e1dee9b 100755 --- a/app/src/main/res/layout/spell_row.xml +++ b/app/src/main/res/layout/spell_row.xml @@ -5,6 +5,7 @@ + + @@ -277,7 +278,7 @@ android:layout_width="0dp" android:layout_height="wrap_content" android:textSize="@{textSize}" - android:text="@string/higher_level" + android:text="@{DisplayUtils.higherLevelsPrompt(context)}" android:textStyle="bold" android:visibility="@{spell.higherLevel.isEmpty ? View.GONE : View.VISIBLE}" app:layout_constraintStart_toStartOf="parent" From 261279c464cc66854109e3fd1126295155efca47 Mon Sep 17 00:00:00 2001 From: Jon Carifio Date: Fri, 26 May 2023 12:43:24 -0400 Subject: [PATCH 7/9] Fix some issues with changing spell language on a tablet. --- .../java/dnd/jon/spellbook/SpellbookViewModel.java | 11 +++++++++++ app/src/main/res/xml-sw600dp/settings_screen.xml | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/dnd/jon/spellbook/SpellbookViewModel.java b/app/src/main/java/dnd/jon/spellbook/SpellbookViewModel.java index a551034c..90ff2e4d 100644 --- a/app/src/main/java/dnd/jon/spellbook/SpellbookViewModel.java +++ b/app/src/main/java/dnd/jon/spellbook/SpellbookViewModel.java @@ -180,7 +180,18 @@ void updateSpellsForLocale(Locale locale) { final String filename = resources.getString(R.string.spells_filename); this.spells = loadSpellsFromFile(filename, locale); this.spellCodec = new SpellCodec(context); + + // If we switch locales, we need to update the current spell + // to the version from the new locale + final Spell spell = currentSpell().getValue(); + if (spell != null) { + final int spellID = spell.getID(); + final Spell newSpell = this.spells.stream().filter(s -> s.getID() == spellID).findAny().orElse(null); + currentSpellLD.setValue(newSpell); + } filter(); + + } private List loadSpellsFromFile(String filename, Locale locale) { diff --git a/app/src/main/res/xml-sw600dp/settings_screen.xml b/app/src/main/res/xml-sw600dp/settings_screen.xml index 4ac8943c..a351151d 100644 --- a/app/src/main/res/xml-sw600dp/settings_screen.xml +++ b/app/src/main/res/xml-sw600dp/settings_screen.xml @@ -42,7 +42,7 @@ /> Date: Fri, 26 May 2023 12:44:01 -0400 Subject: [PATCH 8/9] Remove print statement. --- app/src/main/java/dnd/jon/spellbook/SpellAdapter.java | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/java/dnd/jon/spellbook/SpellAdapter.java b/app/src/main/java/dnd/jon/spellbook/SpellAdapter.java index 1a29ea81..72399ca4 100755 --- a/app/src/main/java/dnd/jon/spellbook/SpellAdapter.java +++ b/app/src/main/java/dnd/jon/spellbook/SpellAdapter.java @@ -92,7 +92,6 @@ public void bind(Spell s) { final SpellRowHolder srh = (SpellRowHolder) view.getTag(); final Spell spell = srh.getSpell(); this.viewModel.setCurrentSpell(spell); - System.out.println(spell.getName()); }; } From f6b6fd5d9afd47b4ff7e40cb84cd602f18b8478e Mon Sep 17 00:00:00 2001 From: Jon Carifio Date: Fri, 26 May 2023 12:48:10 -0400 Subject: [PATCH 9/9] Bump app version in build.gradle. --- app/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 5f65a282..a1291ebb 100755 --- a/app/build.gradle +++ b/app/build.gradle @@ -15,8 +15,8 @@ android { applicationId "dnd.jon.spellbook" minSdkVersion 24 targetSdkVersion 33 - versionCode 300060 - versionName "3.0.6" + versionCode 300100 + versionName "3.1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" signingConfig signingConfigs.release }