Application language now can be changed in the settings

This commit is contained in:
serso 2015-05-30 18:53:30 +02:00
parent a8d6039083
commit 224cd16591
14 changed files with 636 additions and 101 deletions

View File

@ -95,6 +95,10 @@
public static int e(...); public static int e(...);
} }
-assumenosideeffects class org.solovyev.android.Check {
*;
}
# #
#********************************************************************* #*********************************************************************
# #

View File

@ -0,0 +1,166 @@
/*
* Copyright 2014 serso aka se.solovyev
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Contact details
*
* Email: se.solovyev@gmail.com
* Site: http://se.solovyev.org
*/
package org.solovyev.android;
import android.os.Looper;
import java.util.Collection;
import java.util.Map;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import static java.lang.Thread.currentThread;
public final class Check {
private static final boolean junit = isJunit();
private static boolean isJunit() {
final StackTraceElement[] stackTrace = currentThread().getStackTrace();
for (StackTraceElement element : stackTrace) {
if (element.getClassName().startsWith("org.junit.")) {
return true;
}
}
return false;
}
private Check() {
throw new AssertionError();
}
public static void isMainThread() {
if (!junit && Looper.getMainLooper() != Looper.myLooper()) {
throw new AssertionException("Should be called on the main thread");
}
}
public static void isNotNull(@Nullable Object o) {
isNotNull(o, "Object should not be null");
}
public static void isNotNull(@Nullable Object o, @Nonnull String message) {
if (o == null) {
throw new AssertionException(message);
}
}
public static void notEquals(int expected, int actual) {
if (expected == actual) {
throw new AssertionException("Should not be equal");
}
}
public static void equals(int expected, int actual) {
if (expected != actual) {
throw new AssertionException("Should be equal");
}
}
public static void equals(@Nullable Object expected, @Nullable Object actual) {
equals(expected, actual, "Should be equal");
}
public static void equals(@Nullable Object expected, @Nullable Object actual, @Nonnull String message) {
if (expected == actual) {
// both nulls or same
return;
}
if (expected != null && actual != null && expected.equals(actual)) {
// equals
return;
}
throw new AssertionException(message);
}
public static void isTrue(boolean expression, @Nonnull String message) {
if (!expression) {
throw new AssertionException(message);
}
}
public static void isFalse(boolean expression, @Nonnull String message) {
if (expression) {
throw new AssertionException(message);
}
}
public static void isNull(@Nullable Object o) {
isNull(o, "Object should be null");
}
public static void isNull(@Nullable Object o, @Nonnull String message) {
if (o != null) {
throw new AssertionException(message);
}
}
public static void isNotEmpty(@Nullable String s) {
if (s == null || s.length() == 0) {
throw new AssertionException("String should not be empty");
}
}
public static void isNotEmpty(@Nullable String[] array) {
if (array == null || array.length == 0) {
throw new AssertionException("Array should not be empty");
}
}
public static void isNotEmpty(@Nullable Collection<?> c) {
if (c == null || c.size() == 0) {
throw new AssertionException("Collection should not be empty");
}
}
public static void isNotEmpty(@Nullable Map<?, ?> c) {
if (c == null || c.size() == 0) {
throw new AssertionException("Map should not be empty");
}
}
public static void same(Object expected, Object actual) {
if (expected != actual) {
throw new AssertionException("Objects should be the same");
}
}
public static void isEmpty(@Nullable Collection<?> c) {
if (c != null && !c.isEmpty()) {
throw new AssertionException("Collection should be empty");
}
}
public static void shouldNotHappen() {
throw new AssertionException("Should not happen");
}
private static final class AssertionException extends RuntimeException {
private AssertionException(@Nonnull String message) {
super(message);
}
}
}

View File

@ -38,8 +38,11 @@ import android.util.DisplayMetrics;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.TextView; import android.widget.TextView;
import org.solovyev.android.Activities; import org.solovyev.android.Activities;
import org.solovyev.android.Views; import org.solovyev.android.Views;
import org.solovyev.android.calculator.language.Language;
import org.solovyev.android.calculator.language.Languages;
import org.solovyev.android.sherlock.tabs.ActionBarFragmentTabListener; import org.solovyev.android.sherlock.tabs.ActionBarFragmentTabListener;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
@ -50,10 +53,13 @@ public class ActivityUi extends BaseUi {
private int layoutId; private int layoutId;
@Nonnull @Nonnull
private Preferences.Gui.Theme theme; private Preferences.Gui.Theme theme = Preferences.Gui.Theme.default_theme;
@Nonnull @Nonnull
private Preferences.Gui.Layout layout; private Preferences.Gui.Layout layout = Preferences.Gui.Layout.main_calculator;
@Nonnull
private Language language = Languages.SYSTEM_LANGUAGE;
private int selectedNavigationIndex = 0; private int selectedNavigationIndex = 0;
@ -73,11 +79,13 @@ public class ActivityUi extends BaseUi {
activity.setTheme(theme.getThemeId(activity)); activity.setTheme(theme.getThemeId(activity));
layout = Preferences.Gui.getLayout(preferences); layout = Preferences.Gui.getLayout(preferences);
language = App.getLanguages().getCurrent();
} }
@Override @Override
public void onCreate(@Nonnull Activity activity) { public void onCreate(@Nonnull Activity activity) {
super.onCreate(activity); super.onCreate(activity);
App.getLanguages().updateLanguage(activity, false);
if (activity instanceof CalculatorEventListener) { if (activity instanceof CalculatorEventListener) {
Locator.getInstance().getCalculator().addCalculatorEventListener((CalculatorEventListener) activity); Locator.getInstance().getCalculator().addCalculatorEventListener((CalculatorEventListener) activity);
@ -146,16 +154,29 @@ public class ActivityUi extends BaseUi {
} }
public void onResume(@Nonnull Activity activity) { public void onResume(@Nonnull Activity activity) {
restartIfThemeChanged(activity, theme); if (!restartIfThemeChanged(activity, theme)) {
restartIfLanguageChanged(activity, language);
}
} }
public static void restartIfThemeChanged(@Nonnull Activity activity, @Nonnull Preferences.Gui.Theme oldTheme) { public static boolean restartIfThemeChanged(@Nonnull Activity activity, @Nonnull Preferences.Gui.Theme oldTheme) {
final Preferences.Gui.Theme newTheme = Preferences.Gui.theme.getPreference(App.getPreferences()); final Preferences.Gui.Theme newTheme = Preferences.Gui.theme.getPreference(App.getPreferences());
final int themeId = oldTheme.getThemeId(activity); final int themeId = oldTheme.getThemeId(activity);
final int newThemeId = newTheme.getThemeId(activity); final int newThemeId = newTheme.getThemeId(activity);
if (themeId != newThemeId) { if (themeId != newThemeId) {
Activities.restartActivity(activity); Activities.restartActivity(activity);
return true;
} }
return false;
}
public static boolean restartIfLanguageChanged(@Nonnull Activity activity, @Nonnull Language oldLanguage) {
final Language current = App.getLanguages().getCurrent();
if (!current.equals(oldLanguage)) {
Activities.restartActivity(activity);
return true;
}
return false;
} }
public void onPause(@Nonnull Activity activity) { public void onPause(@Nonnull Activity activity) {
@ -254,6 +275,11 @@ public class ActivityUi extends BaseUi {
return theme; return theme;
} }
@Nonnull
public Language getLanguage() {
return language;
}
@Nonnull @Nonnull
public Preferences.Gui.Layout getLayout() { public Preferences.Gui.Layout getLayout() {
return layout; return layout;

View File

@ -39,6 +39,7 @@ import org.solovyev.android.Android;
import org.solovyev.android.UiThreadExecutor; import org.solovyev.android.UiThreadExecutor;
import org.solovyev.android.Views; import org.solovyev.android.Views;
import org.solovyev.android.calculator.ga.Ga; import org.solovyev.android.calculator.ga.Ga;
import org.solovyev.android.calculator.language.Languages;
import org.solovyev.android.calculator.view.ScreenMetrics; import org.solovyev.android.calculator.view.ScreenMetrics;
import org.solovyev.android.calculator.widget.BaseCalculatorWidgetProvider; import org.solovyev.android.calculator.widget.BaseCalculatorWidgetProvider;
import org.solovyev.android.calculator.widget.CalculatorWidgetProvider; import org.solovyev.android.calculator.widget.CalculatorWidgetProvider;
@ -117,6 +118,9 @@ public final class App {
@Nonnull @Nonnull
private static volatile ScreenMetrics screenMetrics; private static volatile ScreenMetrics screenMetrics;
@Nonnull
private static final Languages languages = new Languages();
private App() { private App() {
throw new AssertionError(); throw new AssertionError();
} }
@ -177,6 +181,7 @@ public final class App {
Android.enableComponent(application, CalculatorWidgetProvider4x4.class, false); Android.enableComponent(application, CalculatorWidgetProvider4x4.class, false);
} }
} }
App.languages.init(App.preferences);
App.initialized = true; App.initialized = true;
} else { } else {
@ -277,6 +282,11 @@ public final class App {
return Preferences.Gui.getTheme(getPreferences()); return Preferences.Gui.getTheme(getPreferences());
} }
@Nonnull
public static Languages getLanguages() {
return languages;
}
public static boolean isLg() { public static boolean isLg() {
if (lg == null) { if (lg == null) {
lg = "lge".equalsIgnoreCase(Build.BRAND) || "lge".equalsIgnoreCase(Build.MANUFACTURER); lg = "lge".equalsIgnoreCase(Build.BRAND) || "lge".equalsIgnoreCase(Build.MANUFACTURER);

View File

@ -37,6 +37,7 @@ import org.acra.ReportingInteractionMode;
import org.acra.annotation.ReportsCrashes; import org.acra.annotation.ReportsCrashes;
import org.solovyev.android.Android; import org.solovyev.android.Android;
import org.solovyev.android.calculator.history.AndroidCalculatorHistory; import org.solovyev.android.calculator.history.AndroidCalculatorHistory;
import org.solovyev.android.calculator.language.Language;
import org.solovyev.android.calculator.model.AndroidCalculatorEngine; import org.solovyev.android.calculator.model.AndroidCalculatorEngine;
import org.solovyev.android.calculator.onscreen.CalculatorOnscreenStartActivity; import org.solovyev.android.calculator.onscreen.CalculatorOnscreenStartActivity;
import org.solovyev.android.calculator.plot.AndroidCalculatorPlotter; import org.solovyev.android.calculator.plot.AndroidCalculatorPlotter;
@ -48,6 +49,7 @@ import org.solovyev.common.msg.MessageType;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Locale;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
@ -139,8 +141,10 @@ public class CalculatorApplication extends android.app.Application implements Sh
preferences.registerOnSharedPreferenceChangeListener(this); preferences.registerOnSharedPreferenceChangeListener(this);
setTheme(preferences); setTheme(preferences);
setLanguageInitially();
super.onCreate(); super.onCreate();
App.getLanguages().updateLanguage(this, true);
if (!Preferences.Ga.initialReportDone.getPreference(preferences)) { if (!Preferences.Ga.initialReportDone.getPreference(preferences)) {
App.getGa().reportInitially(preferences); App.getGa().reportInitially(preferences);
@ -199,6 +203,14 @@ public class CalculatorApplication extends android.app.Application implements Sh
}, 100, TimeUnit.MILLISECONDS); }, 100, TimeUnit.MILLISECONDS);
} }
private void setLanguageInitially() {
// should be called before onCreate()
final Language language = App.getLanguages().getCurrent();
if (!language.isSystem() && !language.locale.equals(Locale.getDefault())) {
Locale.setDefault(language.locale);
}
}
private void setTheme(@Nonnull SharedPreferences preferences) { private void setTheme(@Nonnull SharedPreferences preferences) {
final Preferences.Gui.Theme theme = Preferences.Gui.getTheme(preferences); final Preferences.Gui.Theme theme = Preferences.Gui.getTheme(preferences);
setTheme(theme.getThemeId()); setTheme(theme.getThemeId());

View File

@ -29,19 +29,28 @@ import android.graphics.Color;
import android.support.annotation.StyleRes; import android.support.annotation.StyleRes;
import android.util.SparseArray; import android.util.SparseArray;
import android.view.ContextThemeWrapper; import android.view.ContextThemeWrapper;
import jscl.AngleUnit;
import jscl.NumeralBase; import org.solovyev.android.calculator.language.Languages;
import org.solovyev.android.calculator.math.MathType; import org.solovyev.android.calculator.math.MathType;
import org.solovyev.android.calculator.model.AndroidCalculatorEngine; import org.solovyev.android.calculator.model.AndroidCalculatorEngine;
import org.solovyev.android.calculator.onscreen.CalculatorOnscreenService; import org.solovyev.android.calculator.onscreen.CalculatorOnscreenService;
import org.solovyev.android.calculator.preferences.PurchaseDialogActivity; import org.solovyev.android.calculator.preferences.PurchaseDialogActivity;
import org.solovyev.android.calculator.wizard.WizardActivity; import org.solovyev.android.calculator.wizard.WizardActivity;
import org.solovyev.android.prefs.*; import org.solovyev.android.prefs.BooleanPreference;
import org.solovyev.android.prefs.IntegerPreference;
import org.solovyev.android.prefs.LongPreference;
import org.solovyev.android.prefs.NumberToStringPreference;
import org.solovyev.android.prefs.Preference;
import org.solovyev.android.prefs.StringPreference;
import java.text.DecimalFormatSymbols;
import java.util.Locale;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.text.DecimalFormatSymbols;
import java.util.Locale; import jscl.AngleUnit;
import jscl.NumeralBase;
import static org.solovyev.android.Android.isPhoneModel; import static org.solovyev.android.Android.isPhoneModel;
import static org.solovyev.android.DeviceModel.samsung_galaxy_s; import static org.solovyev.android.DeviceModel.samsung_galaxy_s;
@ -80,8 +89,8 @@ public final class Preferences {
public static final Preference<Theme> theme = StringPreference.ofEnum("org.solovyev.android.calculator.CalculatorActivity_calc_theme", Theme.material_theme, Theme.class); public static final Preference<Theme> theme = StringPreference.ofEnum("org.solovyev.android.calculator.CalculatorActivity_calc_theme", Theme.material_theme, Theme.class);
public static final Preference<Layout> layout = StringPreference.ofEnum("org.solovyev.android.calculator.CalculatorActivity_calc_layout", Layout.simple, Layout.class); public static final Preference<Layout> layout = StringPreference.ofEnum("org.solovyev.android.calculator.CalculatorActivity_calc_layout", Layout.simple, Layout.class);
public static final Preference<String> language = StringPreference.of("gui.language", Languages.SYSTEM_LANGUAGE_CODE);
public static final Preference<Boolean> feedbackWindowShown = BooleanPreference.of("feedback_window_shown", false); public static final Preference<Boolean> feedbackWindowShown = BooleanPreference.of("feedback_window_shown", false);
public static final Preference<Boolean> notesppAnnounceShown = BooleanPreference.of("notespp_announce_shown", false);
public static final Preference<Boolean> showReleaseNotes = BooleanPreference.of("org.solovyev.android.calculator.CalculatorActivity_show_release_notes", true); public static final Preference<Boolean> showReleaseNotes = BooleanPreference.of("org.solovyev.android.calculator.CalculatorActivity_show_release_notes", true);
public static final Preference<Boolean> usePrevAsBack = BooleanPreference.of("org.solovyev.android.calculator.CalculatorActivity_use_back_button_as_prev", false); public static final Preference<Boolean> usePrevAsBack = BooleanPreference.of("org.solovyev.android.calculator.CalculatorActivity_use_back_button_as_prev", false);
public static final Preference<Boolean> showEqualsButton = BooleanPreference.of("showEqualsButton", true); public static final Preference<Boolean> showEqualsButton = BooleanPreference.of("showEqualsButton", true);
@ -264,13 +273,13 @@ public final class Preferences {
Gui.layout.putDefault(preferences); Gui.layout.putDefault(preferences);
} }
applyDefaultPreference(preferences, Gui.feedbackWindowShown); applyDefaultPreference(preferences, Gui.feedbackWindowShown);
applyDefaultPreference(preferences, Gui.notesppAnnounceShown);
applyDefaultPreference(preferences, Gui.showReleaseNotes); applyDefaultPreference(preferences, Gui.showReleaseNotes);
applyDefaultPreference(preferences, Gui.usePrevAsBack); applyDefaultPreference(preferences, Gui.usePrevAsBack);
applyDefaultPreference(preferences, Gui.showEqualsButton); applyDefaultPreference(preferences, Gui.showEqualsButton);
applyDefaultPreference(preferences, Gui.autoOrientation); applyDefaultPreference(preferences, Gui.autoOrientation);
applyDefaultPreference(preferences, Gui.hideNumeralBaseDigits); applyDefaultPreference(preferences, Gui.hideNumeralBaseDigits);
applyDefaultPreference(preferences, Gui.preventScreenFromFading); applyDefaultPreference(preferences, Gui.preventScreenFromFading);
applyDefaultPreference(preferences, Gui.language);
applyDefaultPreference(preferences, Graph.plotImag); applyDefaultPreference(preferences, Graph.plotImag);
applyDefaultPreference(preferences, History.showIntermediateCalculations); applyDefaultPreference(preferences, History.showIntermediateCalculations);

View File

@ -0,0 +1,69 @@
package org.solovyev.android.calculator.language;
import android.content.Context;
import android.text.TextUtils;
import org.solovyev.android.calculator.R;
import java.util.Locale;
import javax.annotation.Nonnull;
public final class Language {
@Nonnull
public final String code;
@Nonnull
public final Locale locale;
@Nonnull
final String name;
public Language(@Nonnull String code, @Nonnull Locale locale) {
this.code = code;
this.locale = locale;
this.name = makeName(code, locale);
}
@Nonnull
public String getName(@Nonnull Context context) {
if (!isSystem()) {
return name;
} else {
return context.getString(R.string.cpp_system_language) + " (" + locale.getDisplayLanguage(locale) + ")";
}
}
@Nonnull
private static String makeName(@Nonnull String code, @Nonnull Locale locale) {
if (code.equals(Languages.SYSTEM_LANGUAGE_CODE)) {
return "";
}
final int underscore = code.indexOf("_");
if (underscore >= 0 && TextUtils.isEmpty(locale.getDisplayCountry(locale))) {
return locale.getDisplayName(locale) + " (" + code.substring(underscore + 1) + ")";
}
return locale.getDisplayName(locale);
}
public boolean isSystem() {
return code.equals(Languages.SYSTEM_LANGUAGE_CODE);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
final Language language = (Language) o;
return code.equals(language.code);
}
@Override
public int hashCode() {
return code.hashCode();
}
}

View File

@ -0,0 +1,168 @@
package org.solovyev.android.calculator.language;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.util.Log;
import org.solovyev.android.Check;
import org.solovyev.android.calculator.App;
import org.solovyev.android.calculator.Preferences;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Locale;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public final class Languages implements SharedPreferences.OnSharedPreferenceChangeListener {
@Nonnull
private static final Locale[] locales = Locale.getAvailableLocales();
@Nonnull
public static final String SYSTEM_LANGUAGE_CODE = "00";
@Nonnull
public static final Language SYSTEM_LANGUAGE = new Language(SYSTEM_LANGUAGE_CODE, Locale.getDefault());
@Nonnull
private final List<Language> list = new ArrayList<>();
public void init(@Nonnull SharedPreferences preferences) {
preferences.registerOnSharedPreferenceChangeListener(this);
}
@Nonnull
public List<Language> getList() {
Check.isMainThread();
if (list.isEmpty()) {
loadList();
}
return list;
}
private void loadList() {
Check.isMainThread();
Check.isEmpty(list);
tryAddLanguage("ar");
tryAddLanguage("cs");
tryAddLanguage("en");
tryAddLanguage("es_ES");
tryAddLanguage("de");
tryAddLanguage("fi");
tryAddLanguage("fr");
tryAddLanguage("it");
tryAddLanguage("it");
tryAddLanguage("pl");
tryAddLanguage("pt_BR");
tryAddLanguage("pt_PT");
tryAddLanguage("ru");
tryAddLanguage("vi");
tryAddLanguage("uk");
tryAddLanguage("ja");
tryAddLanguage("zh_CN");
tryAddLanguage("zh_TW");
Collections.sort(list, new Comparator<Language>() {
@Override
public int compare(Language lhs, Language rhs) {
return lhs.name.compareTo(rhs.name);
}
});
list.add(0, SYSTEM_LANGUAGE);
}
private void tryAddLanguage(@Nonnull String locale) {
final Language language = makeLanguage(locale);
if (language != null) {
list.add(language);
}
}
@Nullable
private static Language makeLanguage(@Nonnull String localeId) {
final Locale locale = findLocaleById(localeId);
if (locale == null) {
return null;
}
return new Language(localeId, locale);
}
@Nullable
private static Locale findLocaleById(@Nonnull String id) {
for (Locale locale : locales) {
if (TextUtils.equals(locale.toString(), id)) {
return locale;
}
}
final String language;
final int underscore = id.indexOf("_");
if (underscore >= 0) {
language = id.substring(0, underscore);
} else {
language = id;
}
for (Locale locale : locales) {
if (TextUtils.equals(locale.getLanguage(), language)) {
return locale;
}
}
Log.d("Languages", "No locale found for " + id);
return null;
}
@Nonnull
public Language getCurrent() {
return get(Preferences.Gui.language.getPreference(App.getPreferences()));
}
@Nonnull
public Language get(@Nonnull String code) {
Language language = findLanguageByCode(code);
if (language != null) {
return language;
}
return SYSTEM_LANGUAGE;
}
@Nullable
private Language findLanguageByCode(@Nonnull String code) {
for (Language language : getList()) {
if (TextUtils.equals(language.code, code)) {
return language;
}
}
return null;
}
@Override
public void onSharedPreferenceChanged(@Nonnull SharedPreferences p, String key) {
if (Preferences.Gui.language.isSameKey(key)) {
updateLanguage(App.getApplication(), false);
}
}
public void updateLanguage(@Nonnull Context context, boolean initial) {
final Language language = getCurrent();
// we don't need to set system language while starting up the app
if (!initial || !language.isSystem()) {
if (!Locale.getDefault().equals(language.locale)) {
Locale.setDefault(language.locale);
}
final Resources r = context.getResources();
final DisplayMetrics dm = r.getDisplayMetrics();
final Configuration c = r.getConfiguration();
if (c.locale == null || !c.locale.equals(language.locale)) {
c.locale = language.locale;
r.updateConfiguration(c, dm);
}
}
}
}

View File

@ -6,7 +6,6 @@ import android.content.SharedPreferences;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.StringRes; import android.support.annotation.StringRes;
import android.support.annotation.XmlRes; import android.support.annotation.XmlRes;
import android.text.TextUtils;
import android.util.SparseArray; import android.util.SparseArray;
import org.solovyev.android.calculator.ActivityUi; import org.solovyev.android.calculator.ActivityUi;
@ -27,15 +26,27 @@ public class PreferencesActivity extends BaseActivity implements SharedPreferenc
static final String EXTRA_PREFERENCE_TITLE = "preference-title"; static final String EXTRA_PREFERENCE_TITLE = "preference-title";
@Nonnull @Nonnull
private static final SparseArray<String> preferences = new SparseArray<>(); private static final SparseArray<PrefDef> preferences = new SparseArray<>();
static { static {
preferences.append(R.xml.preferences, "screen-main"); preferences.append(R.xml.preferences, new PrefDef("screen-main", R.string.c_app_settings));
preferences.append(R.xml.preferences_calculations, "screen-calculations"); preferences.append(R.xml.preferences_calculations, new PrefDef("screen-calculations", R.string.c_prefs_calculations_category));
preferences.append(R.xml.preferences_appearance, "screen-appearance"); preferences.append(R.xml.preferences_appearance, new PrefDef("screen-appearance", R.string.c_prefs_appearance_category));
preferences.append(R.xml.preferences_plot, "screen-plot"); preferences.append(R.xml.preferences_plot, new PrefDef("screen-plot", R.string.prefs_graph_screen_title));
preferences.append(R.xml.preferences_other, "screen-other"); preferences.append(R.xml.preferences_other, new PrefDef("screen-other", R.string.c_prefs_other_category));
preferences.append(R.xml.preferences_onscreen, "screen-onscreen"); preferences.append(R.xml.preferences_onscreen, new PrefDef("screen-onscreen", R.string.prefs_onscreen_title));
}
static class PrefDef {
@Nonnull
public final String id;
@StringRes
public final int title;
PrefDef(@Nonnull String id, int title) {
this.id = id;
this.title = title;
}
} }
@Nonnull @Nonnull
@ -53,8 +64,8 @@ public class PreferencesActivity extends BaseActivity implements SharedPreferenc
App.getPreferences().registerOnSharedPreferenceChangeListener(this); App.getPreferences().registerOnSharedPreferenceChangeListener(this);
final Intent intent = getIntent(); final Intent intent = getIntent();
final String preferenceTitle = intent.getStringExtra(EXTRA_PREFERENCE_TITLE); final int preferenceTitle = intent.getIntExtra(EXTRA_PREFERENCE_TITLE, 0);
if (!TextUtils.isEmpty(preferenceTitle)) { if (preferenceTitle != 0) {
setTitle(preferenceTitle); setTitle(preferenceTitle);
} }
@ -72,8 +83,12 @@ public class PreferencesActivity extends BaseActivity implements SharedPreferenc
@Override @Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
if (!paused && Preferences.Gui.theme.isSameKey(key)) { if (!paused) {
if (Preferences.Gui.theme.isSameKey(key)) {
ActivityUi.restartIfThemeChanged(this, ui.getTheme()); ActivityUi.restartIfThemeChanged(this, ui.getTheme());
} else if (Preferences.Gui.language.isSameKey(key)) {
ActivityUi.restartIfLanguageChanged(this, ui.getLanguage());
}
} }
} }
@ -97,7 +112,7 @@ public class PreferencesActivity extends BaseActivity implements SharedPreferenc
} }
@Nonnull @Nonnull
static SparseArray<String> getPreferences() { static SparseArray<PrefDef> getPreferences() {
return preferences; return preferences;
} }
@ -107,11 +122,11 @@ public class PreferencesActivity extends BaseActivity implements SharedPreferenc
} }
@Nonnull @Nonnull
static Intent makeIntent(@Nonnull Context context, int preference, int title) { static Intent makeIntent(@Nonnull Context context, @XmlRes int preference, @StringRes int title) {
final Intent intent = new Intent(context, PreferencesActivity.class); final Intent intent = new Intent(context, PreferencesActivity.class);
intent.putExtra(EXTRA_PREFERENCE, preference); intent.putExtra(EXTRA_PREFERENCE, preference);
if (title != 0) { if (title != 0) {
intent.putExtra(EXTRA_PREFERENCE_TITLE, context.getString(title)); intent.putExtra(EXTRA_PREFERENCE_TITLE, title);
} }
return intent; return intent;
} }

View File

@ -4,6 +4,7 @@ import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.preference.ListPreference;
import android.preference.Preference; import android.preference.Preference;
import android.util.SparseArray; import android.util.SparseArray;
import android.view.LayoutInflater; import android.view.LayoutInflater;
@ -13,12 +14,17 @@ import android.widget.ListView;
import org.solovyev.android.calculator.AdView; import org.solovyev.android.calculator.AdView;
import org.solovyev.android.calculator.App; import org.solovyev.android.calculator.App;
import org.solovyev.android.calculator.CalculatorApplication; import org.solovyev.android.calculator.CalculatorApplication;
import org.solovyev.android.calculator.Preferences;
import org.solovyev.android.calculator.R; import org.solovyev.android.calculator.R;
import org.solovyev.android.calculator.language.Language;
import org.solovyev.android.calculator.language.Languages;
import org.solovyev.android.checkout.BillingRequests; import org.solovyev.android.checkout.BillingRequests;
import org.solovyev.android.checkout.Checkout; import org.solovyev.android.checkout.Checkout;
import org.solovyev.android.checkout.ProductTypes; import org.solovyev.android.checkout.ProductTypes;
import org.solovyev.android.checkout.RequestListener; import org.solovyev.android.checkout.RequestListener;
import java.util.List;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -51,12 +57,12 @@ public class PreferencesFragment extends org.solovyev.android.material.preferenc
App.getPreferences().registerOnSharedPreferenceChangeListener(this); App.getPreferences().registerOnSharedPreferenceChangeListener(this);
} }
private void setPreferenceIntent(int xml, @Nonnull String name) { private void setPreferenceIntent(int xml, @Nonnull PreferencesActivity.PrefDef def) {
final Preference preference = findPreference(name); final Preference preference = findPreference(def.id);
if (preference != null) { if (preference != null) {
final Intent intent = new Intent(getActivity(), PreferencesActivity.class); final Intent intent = new Intent(getActivity(), PreferencesActivity.class);
intent.putExtra(PreferencesActivity.EXTRA_PREFERENCE, xml); intent.putExtra(PreferencesActivity.EXTRA_PREFERENCE, xml);
intent.putExtra(PreferencesActivity.EXTRA_PREFERENCE_TITLE, preference.getTitle()); intent.putExtra(PreferencesActivity.EXTRA_PREFERENCE_TITLE, def.title);
preference.setIntent(intent); preference.setIntent(intent);
} }
} }
@ -67,11 +73,11 @@ public class PreferencesFragment extends org.solovyev.android.material.preferenc
final int preference = getPreferencesResId(); final int preference = getPreferencesResId();
if (preference == R.xml.preferences) { if (preference == R.xml.preferences) {
final SparseArray<String> preferences = PreferencesActivity.getPreferences(); final SparseArray<PreferencesActivity.PrefDef> preferences = PreferencesActivity.getPreferences();
for (int i = 0; i < preferences.size(); i++) { for (int i = 0; i < preferences.size(); i++) {
final int xml = preferences.keyAt(i); final int xml = preferences.keyAt(i);
final String name = preferences.valueAt(i); final PreferencesActivity.PrefDef def = preferences.valueAt(i);
setPreferenceIntent(xml, name); setPreferenceIntent(xml, def);
} }
final Preference restartWizardPreference = findPreference("restart_wizard"); final Preference restartWizardPreference = findPreference("restart_wizard");
restartWizardPreference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { restartWizardPreference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
@ -96,6 +102,8 @@ public class PreferencesFragment extends org.solovyev.android.material.preferenc
} }
} }
prepareLanguagePreference(preference);
getCheckout().whenReady(new Checkout.ListenerAdapter() { getCheckout().whenReady(new Checkout.ListenerAdapter() {
@Override @Override
public void onReady(@Nonnull BillingRequests requests) { public void onReady(@Nonnull BillingRequests requests) {
@ -121,6 +129,34 @@ public class PreferencesFragment extends org.solovyev.android.material.preferenc
onSharedPreferenceChanged(preferences, roundResult.getKey()); onSharedPreferenceChanged(preferences, roundResult.getKey());
} }
private void prepareLanguagePreference(int preference) {
if (preference != R.xml.preferences_appearance) {
return;
}
final ListPreference language = (ListPreference) preferenceManager.findPreference(Preferences.Gui.language.getKey());
final Languages languages = App.getLanguages();
final List<Language> languagesList = languages.getList();
final CharSequence[] entries = new CharSequence[languagesList.size()];
final CharSequence[] entryValues = new CharSequence[languagesList.size()];
for (int i = 0; i < languagesList.size(); i++) {
final Language l = languagesList.get(i);
entries[i] = l.getName(getActivity());
entryValues[i] = l.code;
}
language.setEntries(entries);
language.setEntryValues(entryValues);
language.setSummary(languages.getCurrent().getName(getActivity()));
language.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
final Language l = languages.get((String) newValue);
language.setSummary(l.getName(getActivity()));
return true;
}
});
}
@Nonnull @Nonnull
private Checkout getCheckout() { private Checkout getCheckout() {
return ((PreferencesActivity) getActivity()).getCheckout(); return ((PreferencesActivity) getActivity()).getCheckout();

View File

@ -8,9 +8,22 @@ import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentStatePagerAdapter; import android.support.v4.app.FragmentStatePagerAdapter;
import android.support.v4.view.ViewPager; import android.support.v4.view.ViewPager;
import com.viewpagerindicator.PageIndicator; import com.viewpagerindicator.PageIndicator;
import org.solovyev.android.calculator.*;
import org.solovyev.android.wizard.*; import org.solovyev.android.calculator.ActivityUi;
import org.solovyev.android.calculator.App;
import org.solovyev.android.calculator.BaseActivity;
import org.solovyev.android.calculator.CalculatorApplication;
import org.solovyev.android.calculator.Preferences;
import org.solovyev.android.calculator.R;
import org.solovyev.android.wizard.ListWizardFlow;
import org.solovyev.android.wizard.Wizard;
import org.solovyev.android.wizard.WizardFlow;
import org.solovyev.android.wizard.WizardStep;
import org.solovyev.android.wizard.WizardUi;
import org.solovyev.android.wizard.Wizards;
import org.solovyev.android.wizard.WizardsAware;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -190,6 +203,8 @@ public class WizardActivity extends BaseActivity implements WizardsAware, Shared
public void onSharedPreferenceChanged(SharedPreferences preferences, String key) { public void onSharedPreferenceChanged(SharedPreferences preferences, String key) {
if (Preferences.Gui.theme.isSameKey(key)) { if (Preferences.Gui.theme.isSameKey(key)) {
ActivityUi.restartIfThemeChanged(this, ui.getTheme()); ActivityUi.restartIfThemeChanged(this, ui.getTheme());
} else if (Preferences.Gui.language.isSameKey(key)) {
ActivityUi.restartIfLanguageChanged(this, ui.getLanguage());
} }
} }

View File

@ -7,9 +7,7 @@
<string name="c_show_equals_button_title">Show equals button</string> <string name="c_show_equals_button_title">Show equals button</string>
<string name="c_show_equals_button_summary">If turned on equals button is shown</string> <string name="c_show_equals_button_summary">If turned on equals button is shown</string>
<string name="c_hide_numeral_base_digits_title">Hide digits of other numeral systems</string> <string name="c_hide_numeral_base_digits_title">Hide digits of other numeral systems</string>
<string name="c_hide_numeral_base_digits_summary">If turned on numeral base digits of other numeral bases will be <string name="c_hide_numeral_base_digits_summary">If turned on numeral base digits of other numeral bases will be hidden</string>
hidden
</string>
<string name="prefs_history_show_intermediate_calculations_title">Show intermediate calculations in history</string> <string name="prefs_history_show_intermediate_calculations_title">Show intermediate calculations in history</string>
<string name="prefs_history_show_intermediate_calculations_summary">If turned on all calculations will be shown in the <string name="prefs_history_show_intermediate_calculations_summary">If turned on all calculations will be shown in the
history screen history screen
@ -19,4 +17,5 @@
<string name="prefs_prevent_screen_from_fading_title">Prevent screen from fading</string> <string name="prefs_prevent_screen_from_fading_title">Prevent screen from fading</string>
<string name="prefs_prevent_screen_from_fading_summary">If turned on screen will not fade while using the app <string name="prefs_prevent_screen_from_fading_summary">If turned on screen will not fade while using the app
</string> </string>
<string name="prefs_language_title">Language</string>
</resources> </resources>

View File

@ -231,4 +231,5 @@
<string name="cpp_clear_history">Clear</string> <string name="cpp_clear_history">Clear</string>
<string name="cpp_new_in_version">New in %1$s version</string> <string name="cpp_new_in_version">New in %1$s version</string>
<string name="cpp_release_notes_choose_theme">Do you want to try new Material themes? Choose them from the list:</string> <string name="cpp_release_notes_choose_theme">Do you want to try new Material themes? Choose them from the list:</string>
<string name="cpp_system_language">System language</string>
</resources> </resources>

View File

@ -23,69 +23,74 @@
--> -->
<PreferenceScreen xmlns:a="http://schemas.android.com/apk/res/android" <PreferenceScreen xmlns:a="http://schemas.android.com/apk/res/android"
xmlns:range="http://schemas.android.com/apk/res-auto"> xmlns:m="http://schemas.android.com/apk/res-auto">
<org.solovyev.android.material.preferences.ListPreference
a:key="gui.language"
a:title="@string/prefs_language_title"
m:materialColor="@color/material_text_selector"/>
<android.preference.CheckBoxPreference <android.preference.CheckBoxPreference
a:defaultValue="true"
a:key="@string/p_calc_color_display_key" a:key="@string/p_calc_color_display_key"
a:summary="@string/c_calc_color_display_summary" a:summary="@string/c_calc_color_display_summary"
a:title="@string/c_calc_color_display_title" a:title="@string/c_calc_color_display_title"/>
a:defaultValue="true"/>
<ListPreference <ListPreference
a:key="hapticFeedback"
a:title="@string/c_calc_haptic_feedback_title"
a:entries="@array/cpp_haptic_feedback_names" a:entries="@array/cpp_haptic_feedback_names"
a:entryValues="@array/cpp_haptic_feedback_values"
a:key="hapticFeedback"
a:summary="@string/c_calc_haptic_feedback_summary" a:summary="@string/c_calc_haptic_feedback_summary"
a:entryValues="@array/cpp_haptic_feedback_values"/> a:title="@string/c_calc_haptic_feedback_title"/>
<ListPreference <ListPreference
a:key="@string/p_calc_multiplication_sign_key"
a:title="@string/c_calc_multiplication_sign"
a:entries="@array/p_multiplication_sign_values" a:entries="@array/p_multiplication_sign_values"
a:entryValues="@array/p_multiplication_sign_values"
a:key="@string/p_calc_multiplication_sign_key"
a:summary="@string/c_calc_multiplication_sign_summary" a:summary="@string/c_calc_multiplication_sign_summary"
a:entryValues="@array/p_multiplication_sign_values"/> a:title="@string/c_calc_multiplication_sign"/>
<ListPreference <ListPreference
a:key="@string/p_calc_theme_key"
a:title="@string/c_calc_theme"
a:entries="@array/p_theme_names" a:entries="@array/p_theme_names"
a:entryValues="@array/p_theme_values"
a:key="@string/p_calc_theme_key"
a:summary="@string/c_calc_theme_summary" a:summary="@string/c_calc_theme_summary"
a:entryValues="@array/p_theme_values"/> a:title="@string/c_calc_theme"/>
<ListPreference <ListPreference
a:key="@string/p_calc_layout_key"
a:title="@string/c_calc_layout"
a:entries="@array/p_layout_names" a:entries="@array/p_layout_names"
a:entryValues="@array/p_layout_values"
a:key="@string/p_calc_layout_key"
a:summary="@string/c_calc_layout_summary" a:summary="@string/c_calc_layout_summary"
a:entryValues="@array/p_layout_values"/> a:title="@string/c_calc_layout"/>
<android.preference.CheckBoxPreference <android.preference.CheckBoxPreference
a:defaultValue="true"
a:key="autoOrientation" a:key="autoOrientation"
a:title="@string/c_auto_orientation_title"
a:summary="@string/c_auto_orientation_summary" a:summary="@string/c_auto_orientation_summary"
a:defaultValue="true"/> a:title="@string/c_auto_orientation_title"/>
<android.preference.CheckBoxPreference <android.preference.CheckBoxPreference
a:defaultValue="true"
a:key="showEqualsButton" a:key="showEqualsButton"
a:title="@string/c_show_equals_button_title"
a:summary="@string/c_show_equals_button_summary" a:summary="@string/c_show_equals_button_summary"
a:defaultValue="true"/> a:title="@string/c_show_equals_button_title"/>
<android.preference.CheckBoxPreference <android.preference.CheckBoxPreference
a:defaultValue="true"
a:key="hideNumeralBaseDigits" a:key="hideNumeralBaseDigits"
a:title="@string/c_hide_numeral_base_digits_title"
a:summary="@string/c_hide_numeral_base_digits_summary" a:summary="@string/c_hide_numeral_base_digits_summary"
a:defaultValue="true"/> a:title="@string/c_hide_numeral_base_digits_title"/>
<android.preference.CheckBoxPreference <android.preference.CheckBoxPreference
a:key="history_show_intermediate_calculations" a:key="history_show_intermediate_calculations"
a:title="@string/prefs_history_show_intermediate_calculations_title" a:summary="@string/prefs_history_show_intermediate_calculations_summary"
a:summary="@string/prefs_history_show_intermediate_calculations_summary"/> a:title="@string/prefs_history_show_intermediate_calculations_title"/>
<android.preference.CheckBoxPreference <android.preference.CheckBoxPreference
a:key="preventScreenFromFading" a:key="preventScreenFromFading"
a:title="@string/prefs_prevent_screen_from_fading_title" a:summary="@string/prefs_prevent_screen_from_fading_summary"
a:summary="@string/prefs_prevent_screen_from_fading_summary"/> a:title="@string/prefs_prevent_screen_from_fading_title"/>
</PreferenceScreen> </PreferenceScreen>