Skip to content

Commit

Permalink
Merge pull request #23 from Carifio24/spells-language
Browse files Browse the repository at this point in the history
Allow changing language of spells
  • Loading branch information
Carifio24 authored May 27, 2023
2 parents 8b2b660 + f6b6fd5 commit f198e74
Show file tree
Hide file tree
Showing 17 changed files with 204 additions and 37 deletions.
4 changes: 2 additions & 2 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
16 changes: 16 additions & 0 deletions app/src/main/java/dnd/jon/spellbook/DisplayUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -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); }
}
4 changes: 2 additions & 2 deletions app/src/main/java/dnd/jon/spellbook/GlobalInfo.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
44 changes: 41 additions & 3 deletions app/src/main/java/dnd/jon/spellbook/LocalizationUtils.java
Original file line number Diff line number Diff line change
@@ -1,15 +1,28 @@
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.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<String> supportedLanguages = new ArrayList<>();
static {
supportedLanguages.add("en");
supportedLanguages.add("pt");
}

private static final Map<CasterClass,Integer> tableLayoutIDs = new EnumMap<CasterClass,Integer>(CasterClass.class) {{
put(CasterClass.ARTIFICER, R.layout.artificer_table_layout);
put(CasterClass.BARD, R.layout.bard_table_layout);
Expand All @@ -33,14 +46,39 @@ 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 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();
}

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(); }
Expand Down
11 changes: 8 additions & 3 deletions app/src/main/java/dnd/jon/spellbook/MainActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -228,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;
Expand Down Expand Up @@ -1247,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();
Expand Down Expand Up @@ -1330,6 +1332,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_key))) {
final Locale locale = new Locale(sharedPreferences.getString(key, getString(string.english_code)));
viewModel.updateSpellsForLocale(locale);
}
}

Expand Down
2 changes: 1 addition & 1 deletion app/src/main/java/dnd/jon/spellbook/SpellAdapter.java
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -91,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());
};
}

Expand Down
16 changes: 13 additions & 3 deletions app/src/main/java/dnd/jon/spellbook/SpellCodec.java
Original file line number Diff line number Diff line change
Expand Up @@ -142,10 +142,12 @@ private Spell parseSpell(JSONObject json, SpellBuilder b, boolean useInternal) t
return b.buildAndReset();
}

List<Spell> parseSpellList(@Nullable JSONArray jsonArray, boolean useInternal) throws Exception {
// 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<Spell> parseSpellList(@Nullable JSONArray jsonArray, boolean useInternal, Locale locale) throws Exception {

final List<Spell> 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++) {
Expand All @@ -159,8 +161,16 @@ List<Spell> parseSpellList(@Nullable JSONArray jsonArray, boolean useInternal) t
return spells;
}

List<Spell> parseSpellList(JSONArray jsonArray, Locale locale) throws Exception {
return parseSpellList(jsonArray, false, locale);
}

List<Spell> parseSpellList(JSONArray jsonArray, boolean useInternalParse) throws Exception {
return parseSpellList(jsonArray, useInternalParse, LocalizationUtils.getLocale());
}

List<Spell> parseSpellList(JSONArray jsonArray) throws Exception {
return parseSpellList(jsonArray, false);
return parseSpellList(jsonArray, false, LocalizationUtils.getLocale());
}

JSONObject toJSON(Spell spell) throws JSONException {
Expand Down
4 changes: 3 additions & 1 deletion app/src/main/java/dnd/jon/spellbook/SpellWindowFragment.java
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions app/src/main/java/dnd/jon/spellbook/SpellbookUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down
67 changes: 57 additions & 10 deletions app/src/main/java/dnd/jon/spellbook/SpellbookViewModel.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

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;
import android.util.Log;
Expand All @@ -16,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;
Expand All @@ -25,6 +28,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;
Expand Down Expand Up @@ -74,8 +78,11 @@ public class SpellbookViewModel extends ViewModel implements Filterable {
private final MutableLiveData<SpellSlotStatus> currentSpellSlotStatusLD;

private static List<Spell> englishSpells = new ArrayList<>();
private final List<Spell> spells;
private List<Spell> spells;
private List<Spell> currentSpellList;
private String spellsFilename;
private final MutableLiveData<Context> spellsContext;
private Locale spellsLocale;
private final MutableLiveData<List<Spell>> currentSpellsLD;
private final MutableLiveData<Boolean> currentSpellFavoriteLD;
private final MutableLiveData<Boolean> currentSpellPreparedLD;
Expand All @@ -84,7 +91,7 @@ public class SpellbookViewModel extends ViewModel implements Filterable {
private final MutableLiveData<Boolean> currentUseExpandedLD;
private final MutableLiveData<Boolean> spellTableVisibleLD;

private final SpellCodec spellCodec;
private SpellCodec spellCodec;

private static final List<Integer> SORT_PROPERTY_IDS = Arrays.asList(BR.firstSortField, BR.firstSortReverse, BR.secondSortField, BR.secondSortReverse);

Expand All @@ -95,13 +102,28 @@ private static <S,T> LiveData<T> distinctTransform(LiveData<S> source, Function<
public SpellbookViewModel(Application application) {
this.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.defaultSpellLocale() : 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.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<>();
Expand All @@ -110,8 +132,8 @@ 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.spells = loadSpellsFromFile(spellsFilename, false);
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);
this.currentSpellLD = new MutableLiveData<>();
Expand All @@ -134,7 +156,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
Expand All @@ -150,11 +172,34 @@ public SpellbookViewModel(Application application) {
createdSpellsDirObserver.startWatching();
}

private List<Spell> loadSpellsFromFile(String filename, boolean useInternalParse) {
void updateSpellsForLocale(Locale locale) {
this.spellsLocale = 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);

// 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<Spell> loadSpellsFromFile(String filename, Locale locale) {
try {
final JSONArray jsonArray = JSONUtils.loadJSONArrayFromAsset(application, filename);
final SpellCodec codec = new SpellCodec(application);
return codec.parseSpellList(jsonArray, useInternalParse);
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();
Expand Down Expand Up @@ -200,6 +245,8 @@ void setCurrentSpell(Spell spell) {
}

List<Spell> getAllSpells() { return spells; }
LiveData<Context> currentSpellsContext() { return spellsContext; }
Context getSpellContext() { return spellsContext.getValue(); }

private String nameValidator(String name, int emptyItemID, int itemTypeID, List<String> existingItems) {
if (name.isEmpty()) {
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/layout/spell_row.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
<data>
<import type="dnd.jon.spellbook.DisplayUtils" />
<variable name="spell" type="dnd.jon.spellbook.Spell" />
<variable name="context" type="android.content.Context" />
</data>

<androidx.constraintlayout.widget.ConstraintLayout
Expand Down
Loading

0 comments on commit f198e74

Please sign in to comment.