Add language preference

pull/437/head
Alex Baker 10 years ago
parent c7e3f4148d
commit d18f35965e

@ -127,6 +127,7 @@ dependencies {
compile "com.android.support:support-v13:${SUPPORT_VERSION}" compile "com.android.support:support-v13:${SUPPORT_VERSION}"
compile 'com.jakewharton.timber:timber:4.1.2' compile 'com.jakewharton.timber:timber:4.1.2'
compile 'com.google.guava:guava:19.0' compile 'com.google.guava:guava:19.0'
compile 'com.jakewharton:process-phoenix:1.0.2'
compile ('com.rubiconproject.oss:jchronic:0.2.6') { compile ('com.rubiconproject.oss:jchronic:0.2.6') {
transitive = false transitive = false
} }

@ -25,6 +25,6 @@ public class BuildSetup {
Timber.plant(new Timber.DebugTree()); Timber.plant(new Timber.DebugTree());
Timber.plant(new StethoTree()); Timber.plant(new StethoTree());
Stetho.initializeWithDefaults(context); Stetho.initializeWithDefaults(context);
LeakCanary.install((Application) context); LeakCanary.install((Application) context.getApplicationContext());
} }
} }

@ -5,7 +5,6 @@
*/ */
package com.todoroo.astrid.adapter; package com.todoroo.astrid.adapter;
import android.app.Activity;
import android.app.PendingIntent.CanceledException; import android.app.PendingIntent.CanceledException;
import android.content.Context; import android.content.Context;
import android.content.res.Resources; import android.content.res.Resources;
@ -163,7 +162,7 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
this.themeCache = themeCache; this.themeCache = themeCache;
this.resources = fragment.getResources(); this.resources = fragment.getResources();
this.onCompletedTaskListener = onCompletedTaskListener; this.onCompletedTaskListener = onCompletedTaskListener;
inflater = (LayoutInflater) fragment.getActivity().getSystemService( inflater = (LayoutInflater) context.getSystemService(
Context.LAYOUT_INFLATER_SERVICE); Context.LAYOUT_INFLATER_SERVICE);
TypedValue typedValue = new TypedValue(); TypedValue typedValue = new TypedValue();
@ -475,11 +474,6 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
* uncompleted. * uncompleted.
*/ */
protected void setTaskAppearance(ViewHolder viewHolder, Task task) { protected void setTaskAppearance(ViewHolder viewHolder, Task task) {
Activity activity = fragment.getActivity();
if (activity == null) {
return;
}
boolean state = task.isCompleted(); boolean state = task.isCompleted();
TextView name = viewHolder.nameView; TextView name = viewHolder.nameView;
@ -501,7 +495,6 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
} }
setupCompleteBox(viewHolder); setupCompleteBox(viewHolder);
} }
private void setupCompleteBox(ViewHolder viewHolder) { private void setupCompleteBox(ViewHolder viewHolder) {
@ -570,62 +563,59 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
private void setupDueDateAndTags(ViewHolder viewHolder, Task task) { private void setupDueDateAndTags(ViewHolder viewHolder, Task task) {
// due date / completion date // due date / completion date
final TextView dueDateView = viewHolder.dueDate; { final TextView dueDateView = viewHolder.dueDate; {
Activity activity = fragment.getActivity(); if(!task.isCompleted() && task.hasDueDate()) {
if (activity != null) { long dueDate = task.getDueDate();
if(!task.isCompleted() && task.hasDueDate()) { if(task.isOverdue()) {
long dueDate = task.getDueDate(); dueDateView.setTextColor(textColorOverdue);
if(task.isOverdue()) {
dueDateView.setTextColor(textColorOverdue);
} else {
dueDateView.setTextColor(textColorSecondary);
}
String dateValue = DateUtilities.getRelativeDateStringWithTime(context, dueDate);
dueDateView.setText(dateValue);
dueDateView.setVisibility(View.VISIBLE);
} else if(task.isCompleted()) {
String dateValue = DateUtilities.getRelativeDateStringWithTime(context, task.getCompletionDate());
dueDateView.setText(resources.getString(R.string.TAd_completed, dateValue));
dueDateView.setTextColor(textColorHint);
dueDateView.setVisibility(View.VISIBLE);
} else { } else {
dueDateView.setVisibility(View.GONE); dueDateView.setTextColor(textColorSecondary);
} }
String dateValue = DateUtilities.getRelativeDateStringWithTime(context, dueDate);
dueDateView.setText(dateValue);
dueDateView.setVisibility(View.VISIBLE);
} else if(task.isCompleted()) {
String dateValue = DateUtilities.getRelativeDateStringWithTime(context, task.getCompletionDate());
dueDateView.setText(resources.getString(R.string.TAd_completed, dateValue));
dueDateView.setTextColor(textColorHint);
dueDateView.setVisibility(View.VISIBLE);
} else {
dueDateView.setVisibility(View.GONE);
}
if (task.isCompleted()) { if (task.isCompleted()) {
viewHolder.tagBlock.setVisibility(View.GONE); viewHolder.tagBlock.setVisibility(View.GONE);
} else { } else {
String tags = viewHolder.tagsString; String tags = viewHolder.tagsString;
List<String> tagUuids = tags != null ? newArrayList(tags.split(",")) : Lists.<String>newArrayList(); List<String> tagUuids = tags != null ? newArrayList(tags.split(",")) : Lists.<String>newArrayList();
Iterable<TagData> t = filter(transform(tagUuids, uuidToTag), Predicates.notNull()); Iterable<TagData> t = filter(transform(tagUuids, uuidToTag), Predicates.notNull());
List<TagData> firstFourByName = orderByName.leastOf(t, 4); List<TagData> firstFourByName = orderByName.leastOf(t, 4);
int numTags = firstFourByName.size(); int numTags = firstFourByName.size();
if (numTags > 0) { if (numTags > 0) {
List<TagData> firstFourByNameLength = orderByLength.sortedCopy(firstFourByName); List<TagData> firstFourByNameLength = orderByLength.sortedCopy(firstFourByName);
float maxLength = tagCharacters / numTags; float maxLength = tagCharacters / numTags;
for (int i = 0; i < numTags - 1; i++) { for (int i = 0; i < numTags - 1; i++) {
TagData tagData = firstFourByNameLength.get(i); TagData tagData = firstFourByNameLength.get(i);
String name = tagData.getName(); String name = tagData.getName();
if (name.length() >= maxLength) { if (name.length() >= maxLength) {
break; break;
}
float excess = maxLength - name.length();
int beneficiaries = numTags - i - 1;
float additional = excess / beneficiaries;
maxLength += additional;
} }
List<SpannableString> tagStrings = transform(firstFourByName, tagToString(maxLength)); float excess = maxLength - name.length();
SpannableStringBuilder builder = new SpannableStringBuilder(); int beneficiaries = numTags - i - 1;
for (SpannableString tagString : tagStrings) { float additional = excess / beneficiaries;
if (builder.length() > 0) { maxLength += additional;
builder.append(HAIR_SPACE); }
} List<SpannableString> tagStrings = transform(firstFourByName, tagToString(maxLength));
builder.append(tagString); SpannableStringBuilder builder = new SpannableStringBuilder();
for (SpannableString tagString : tagStrings) {
if (builder.length() > 0) {
builder.append(HAIR_SPACE);
} }
viewHolder.tagBlock.setText(builder); builder.append(tagString);
viewHolder.tagBlock.setVisibility(View.VISIBLE);
} else {
viewHolder.tagBlock.setVisibility(View.GONE);
} }
viewHolder.tagBlock.setText(builder);
viewHolder.tagBlock.setVisibility(View.VISIBLE);
} else {
viewHolder.tagBlock.setVisibility(View.GONE);
} }
} }
} }

@ -17,7 +17,6 @@ import com.todoroo.andlib.utility.AndroidUtilities;
import com.todoroo.astrid.api.Filter; import com.todoroo.astrid.api.Filter;
import com.todoroo.astrid.api.PermaSql; import com.todoroo.astrid.api.PermaSql;
import com.todoroo.astrid.dao.MetadataDao; import com.todoroo.astrid.dao.MetadataDao;
import com.todoroo.astrid.dao.MetadataDao.MetadataCriteria;
import com.todoroo.astrid.dao.TaskDao.TaskCriteria; import com.todoroo.astrid.dao.TaskDao.TaskCriteria;
import com.todoroo.astrid.data.Metadata; import com.todoroo.astrid.data.Metadata;
import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.Task;

@ -3,7 +3,7 @@ package org.tasks.dialogs;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.support.v7.app.AlertDialog; import android.support.v7.app.AlertDialog;
import android.support.v7.view.ContextThemeWrapper; import android.view.ContextThemeWrapper;
import android.view.View; import android.view.View;
import android.widget.ListAdapter; import android.widget.ListAdapter;

@ -1,9 +1,13 @@
package org.tasks.injection; package org.tasks.injection;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import org.tasks.ErrorReportingSingleThreadExecutor; import org.tasks.ErrorReportingSingleThreadExecutor;
import org.tasks.R;
import org.tasks.analytics.Tracker; import org.tasks.analytics.Tracker;
import org.tasks.locale.LocaleUtils;
import org.tasks.preferences.Preferences; import org.tasks.preferences.Preferences;
import org.tasks.themes.ThemeAccent; import org.tasks.themes.ThemeAccent;
import org.tasks.themes.ThemeBase; import org.tasks.themes.ThemeBase;
@ -28,7 +32,10 @@ public class ApplicationModule {
private Context context; private Context context;
public ApplicationModule(Context context) { public ApplicationModule(Context context) {
this.context = context.getApplicationContext(); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
String language = prefs.getString(context.getString(R.string.p_language), null);
LocaleUtils.setLocale(language);
this.context = LocaleUtils.withLocale(context.getApplicationContext());
} }
@Provides @Provides

@ -3,6 +3,7 @@ package org.tasks.injection;
import org.tasks.activities.CalendarSelectionDialog; import org.tasks.activities.CalendarSelectionDialog;
import org.tasks.dialogs.AccountSelectionDialog; import org.tasks.dialogs.AccountSelectionDialog;
import org.tasks.dialogs.AddAttachmentDialog; import org.tasks.dialogs.AddAttachmentDialog;
import org.tasks.locale.LocalePickerDialog;
import org.tasks.dialogs.SortDialog; import org.tasks.dialogs.SortDialog;
import org.tasks.dialogs.ThemePickerDialog; import org.tasks.dialogs.ThemePickerDialog;
import org.tasks.reminders.MissedCallDialog; import org.tasks.reminders.MissedCallDialog;
@ -28,4 +29,6 @@ public interface BaseDialogFragmentComponent {
void inject(ThemePickerDialog themePickerDialog); void inject(ThemePickerDialog themePickerDialog);
void inject(SortDialog sortDialog); void inject(SortDialog sortDialog);
void inject(LocalePickerDialog localePickerDialog);
} }

@ -4,6 +4,7 @@ import android.os.Bundle;
import android.support.v7.app.AppCompatActivity; import android.support.v7.app.AppCompatActivity;
import org.tasks.analytics.Tracker; import org.tasks.analytics.Tracker;
import org.tasks.locale.LocaleUtils;
import javax.inject.Inject; import javax.inject.Inject;
@ -12,6 +13,10 @@ public abstract class InjectingAppCompatActivity extends AppCompatActivity imple
@Inject Tracker tracker; @Inject Tracker tracker;
public InjectingAppCompatActivity() {
LocaleUtils.updateConfig(this);
}
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
activityComponent = ((InjectingApplication) getApplication()).getComponent().plus(new ActivityModule(this)); activityComponent = ((InjectingApplication) getApplication()).getComponent().plus(new ActivityModule(this));

@ -1,5 +1,7 @@
package org.tasks.injection; package org.tasks.injection;
import android.content.ComponentName;
import android.content.pm.ActivityInfo;
import android.os.Bundle; import android.os.Bundle;
import android.preference.Preference; import android.preference.Preference;
import android.preference.PreferenceCategory; import android.preference.PreferenceCategory;
@ -11,12 +13,15 @@ import android.widget.LinearLayout;
import org.tasks.R; import org.tasks.R;
import org.tasks.analytics.Tracker; import org.tasks.analytics.Tracker;
import org.tasks.locale.LocaleUtils;
import org.tasks.preferences.AppCompatPreferenceActivity; import org.tasks.preferences.AppCompatPreferenceActivity;
import org.tasks.themes.Theme; import org.tasks.themes.Theme;
import org.tasks.ui.MenuColorizer; import org.tasks.ui.MenuColorizer;
import javax.inject.Inject; import javax.inject.Inject;
import timber.log.Timber;
public abstract class InjectingPreferenceActivity extends AppCompatPreferenceActivity implements InjectingActivity { public abstract class InjectingPreferenceActivity extends AppCompatPreferenceActivity implements InjectingActivity {
private ActivityComponent activityComponent; private ActivityComponent activityComponent;
@ -26,6 +31,10 @@ public abstract class InjectingPreferenceActivity extends AppCompatPreferenceAct
@Inject Theme theme; @Inject Theme theme;
@Inject Tracker tracker; @Inject Tracker tracker;
public InjectingPreferenceActivity() {
LocaleUtils.updateConfig(this);
}
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
activityComponent = ((InjectingApplication) getApplication()) activityComponent = ((InjectingApplication) getApplication())
@ -46,7 +55,14 @@ public abstract class InjectingPreferenceActivity extends AppCompatPreferenceAct
root.addView(toolbarContainer); root.addView(toolbarContainer);
toolbar = (Toolbar) toolbarContainer.findViewById(R.id.toolbar); toolbar = (Toolbar) toolbarContainer.findViewById(R.id.toolbar);
toolbar.setTitle(getTitle()); try {
ComponentName componentName = new ComponentName(this, getClass());
ActivityInfo activityInfo = getPackageManager().getActivityInfo(componentName, 0);
toolbar.setTitle(activityInfo.labelRes);
} catch (Exception e) {
Timber.e(e, e.getMessage());
toolbar.setTitle(getTitle());
}
toolbar.setNavigationIcon(getResources().getDrawable(R.drawable.ic_arrow_back_24dp)); toolbar.setNavigationIcon(getResources().getDrawable(R.drawable.ic_arrow_back_24dp));
toolbar.setNavigationOnClickListener(new View.OnClickListener() { toolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override @Override

@ -6,7 +6,6 @@ import android.support.v4.app.TaskStackBuilder;
import com.google.common.base.Strings; import com.google.common.base.Strings;
import com.todoroo.astrid.activity.TaskListActivity; import com.todoroo.astrid.activity.TaskListActivity;
import com.todoroo.astrid.activity.TaskListFragment;
import com.todoroo.astrid.api.Filter; import com.todoroo.astrid.api.Filter;
public class TaskIntents { public class TaskIntents {

@ -0,0 +1,81 @@
package org.tasks.locale;
import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import com.google.common.base.Function;
import com.google.common.collect.Lists;
import org.tasks.R;
import org.tasks.dialogs.DialogBuilder;
import org.tasks.injection.DialogFragmentComponent;
import org.tasks.injection.ForApplication;
import org.tasks.injection.InjectingDialogFragment;
import java.util.Arrays;
import java.util.List;
import javax.inject.Inject;
import static com.google.common.collect.Iterables.toArray;
import static org.tasks.locale.LocaleUtils.localeFromString;
public class LocalePickerDialog extends InjectingDialogFragment {
public static LocalePickerDialog newLocalePickerDialog() {
return new LocalePickerDialog();
}
public interface LocaleSelectionHandler {
void onLocaleSelected(String locale);
}
@Inject DialogBuilder dialogBuilder;
@Inject @ForApplication Context context;
private LocaleSelectionHandler callback;
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
final String[] translations = context.getResources().getStringArray(R.array.localization);
final List<String> display = Lists.transform(Arrays.asList(translations), new Function<String, String>() {
@Override
public String apply(String locale) {
return localeFromString(locale).getDisplayName();
}
});
return dialogBuilder.newDialog()
.setItems(toArray(display, String.class), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
dialogInterface.dismiss();
callback.onLocaleSelected(translations[i]);
}
})
.setNegativeButton(android.R.string.cancel, null)
.setNeutralButton(R.string.default_value, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
dialogInterface.dismiss();
callback.onLocaleSelected(null);
}
})
.show();
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
callback = (LocaleSelectionHandler) activity;
}
@Override
protected void inject(DialogFragmentComponent component) {
component.inject(this);
}
}

@ -0,0 +1,62 @@
package org.tasks.locale;
import android.content.Context;
import android.content.res.Configuration;
import android.view.ContextThemeWrapper;
import com.google.api.client.repackaged.com.google.common.base.Strings;
import java.util.Locale;
import static com.todoroo.andlib.utility.AndroidUtilities.atLeastJellybeanMR1;
public class LocaleUtils {
public static Locale localeFromString(String locale) {
if (Strings.isNullOrEmpty(locale)) {
return null;
}
String[] split = locale.split("-");
if (split.length == 1) {
return new Locale(split[0]);
} else if (split.length == 2) {
return new Locale(split[0], split[1]);
}
throw new RuntimeException();
}
private static String sLocaleString;
private static Locale sLocale;
public static Locale getLocale() {
return sLocale == null ? Locale.getDefault() : sLocale;
}
public static String getsLocaleString() {
return sLocaleString;
}
public static void setLocale(String locale) {
sLocaleString = locale;
sLocale = localeFromString(locale);
if (sLocale != null) {
Locale.setDefault(sLocale);
}
}
public static void updateConfig(ContextThemeWrapper wrapper) {
if (sLocale != null && atLeastJellybeanMR1()) {
wrapper.applyOverrideConfiguration(getLocaleConfiguration());
}
}
public static Context withLocale(Context context) {
return sLocale == null ? context : context.createConfigurationContext(getLocaleConfiguration());
}
private static Configuration getLocaleConfiguration() {
Configuration configuration = new Configuration();
configuration.setLocale(sLocale);
return configuration;
}
}

@ -28,6 +28,8 @@ import android.view.MenuInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import org.tasks.locale.LocaleUtils;
/** /**
* A {@link android.preference.PreferenceActivity} which implements and proxies the necessary calls * A {@link android.preference.PreferenceActivity} which implements and proxies the necessary calls
* to be used with AppCompat. * to be used with AppCompat.

@ -2,31 +2,49 @@ package org.tasks.preferences;
import android.app.Activity; import android.app.Activity;
import android.app.FragmentManager; import android.app.FragmentManager;
import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.preference.Preference; import android.preference.Preference;
import android.text.TextUtils;
import com.google.common.base.Strings;
import com.jakewharton.processphoenix.ProcessPhoenix;
import com.todoroo.astrid.activity.TaskListActivity;
import com.todoroo.astrid.api.Filter;
import com.todoroo.astrid.core.OldTaskPreferences; import com.todoroo.astrid.core.OldTaskPreferences;
import com.todoroo.astrid.reminders.ReminderPreferences; import com.todoroo.astrid.reminders.ReminderPreferences;
import org.tasks.R; import org.tasks.R;
import org.tasks.analytics.Tracker; import org.tasks.analytics.Tracker;
import org.tasks.analytics.Tracking; import org.tasks.analytics.Tracking;
import org.tasks.dialogs.DialogBuilder;
import org.tasks.locale.LocalePickerDialog;
import org.tasks.dialogs.ThemePickerDialog; import org.tasks.dialogs.ThemePickerDialog;
import org.tasks.injection.InjectingPreferenceActivity; import org.tasks.injection.InjectingPreferenceActivity;
import org.tasks.locale.LocaleUtils;
import org.tasks.themes.ThemeAccent; import org.tasks.themes.ThemeAccent;
import org.tasks.themes.ThemeBase; import org.tasks.themes.ThemeBase;
import org.tasks.themes.ThemeColor; import org.tasks.themes.ThemeColor;
import java.util.Locale;
import javax.inject.Inject; import javax.inject.Inject;
import static com.todoroo.andlib.utility.AndroidUtilities.atLeastJellybeanMR1;
import static org.tasks.locale.LocalePickerDialog.newLocalePickerDialog;
import static org.tasks.dialogs.ThemePickerDialog.newThemePickerDialog; import static org.tasks.dialogs.ThemePickerDialog.newThemePickerDialog;
import static org.tasks.locale.LocaleUtils.localeFromString;
public abstract class BaseBasicPreferences extends InjectingPreferenceActivity implements ThemePickerDialog.ThemePickerCallback { public abstract class BaseBasicPreferences extends InjectingPreferenceActivity implements
ThemePickerDialog.ThemePickerCallback,
LocalePickerDialog.LocaleSelectionHandler {
private static final String EXTRA_RESULT = "extra_result"; private static final String EXTRA_RESULT = "extra_result";
private static final String FRAG_TAG_THEME_PICKER = "frag_tag_theme_picker"; private static final String FRAG_TAG_THEME_PICKER = "frag_tag_theme_picker";
private static final String FRAG_TAG_COLOR_PICKER = "frag_tag_color_picker";
private static final String FRAG_TAG_ACCENT_PICKER = "frag_tag_accent_picker"; private static final String FRAG_TAG_ACCENT_PICKER = "frag_tag_accent_picker";
private static final String FRAG_TAG_LOCALE_PICKER = "frag_tag_locale_picker";
private static final int RC_PREFS = 10001; private static final int RC_PREFS = 10001;
@Inject Tracker tracker; @Inject Tracker tracker;
@ -34,6 +52,7 @@ public abstract class BaseBasicPreferences extends InjectingPreferenceActivity i
@Inject ThemeBase themeBase; @Inject ThemeBase themeBase;
@Inject ThemeColor themeColor; @Inject ThemeColor themeColor;
@Inject ThemeAccent themeAccent; @Inject ThemeAccent themeAccent;
@Inject DialogBuilder dialogBuilder;
private Bundle result; private Bundle result;
@Override @Override
@ -67,7 +86,7 @@ public abstract class BaseBasicPreferences extends InjectingPreferenceActivity i
FragmentManager fragmentManager = getFragmentManager(); FragmentManager fragmentManager = getFragmentManager();
if (fragmentManager.findFragmentByTag(FRAG_TAG_THEME_PICKER) == null) { if (fragmentManager.findFragmentByTag(FRAG_TAG_THEME_PICKER) == null) {
newThemePickerDialog(ThemePickerDialog.ColorPalette.COLORS) newThemePickerDialog(ThemePickerDialog.ColorPalette.COLORS)
.show(fragmentManager, FRAG_TAG_THEME_PICKER); .show(fragmentManager, FRAG_TAG_COLOR_PICKER);
} }
return false; return false;
} }
@ -85,7 +104,16 @@ public abstract class BaseBasicPreferences extends InjectingPreferenceActivity i
return false; return false;
} }
}); });
Preference languagePreference = findPreference(getString(R.string.p_language));
updateLocale();
languagePreference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
newLocalePickerDialog()
.show(getFragmentManager(), FRAG_TAG_LOCALE_PICKER);
return false;
}
});
findPreference(getString(R.string.p_collect_statistics)).setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { findPreference(getString(R.string.p_collect_statistics)).setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override @Override
public boolean onPreferenceChange(Preference preference, Object newValue) { public boolean onPreferenceChange(Preference preference, Object newValue) {
@ -100,6 +128,8 @@ public abstract class BaseBasicPreferences extends InjectingPreferenceActivity i
setupActivity(R.string.EPr_appearance_header, AppearancePreferences.class); setupActivity(R.string.EPr_appearance_header, AppearancePreferences.class);
setupActivity(R.string.notifications, ReminderPreferences.class); setupActivity(R.string.notifications, ReminderPreferences.class);
setupActivity(R.string.EPr_manage_header, OldTaskPreferences.class); setupActivity(R.string.EPr_manage_header, OldTaskPreferences.class);
requires(R.string.settings_general, atLeastJellybeanMR1(), R.string.p_language);
} }
private void setupActivity(int key, final Class<?> target) { private void setupActivity(int key, final Class<?> target) {
@ -149,6 +179,39 @@ public abstract class BaseBasicPreferences extends InjectingPreferenceActivity i
recreate(); recreate();
} }
@Override
public void onLocaleSelected(String newValue) {
if (newValue == null) {
preferences.remove(R.string.p_language);
} else {
preferences.setString(R.string.p_language, newValue);
}
updateLocale();
String currentValue = LocaleUtils.getsLocaleString();
if (!TextUtils.equals(currentValue, newValue)) {
dialogBuilder.newDialog()
.setMessage(R.string.restart_required)
.setPositiveButton(R.string.restart_now, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
ProcessPhoenix.triggerRebirth(BaseBasicPreferences.this, new Intent(BaseBasicPreferences.this, TaskListActivity.class) {{
putExtra(TaskListActivity.OPEN_FILTER, (Filter) null);
}});
}
})
.setNegativeButton(R.string.restart_later, null)
.show();
}
}
private void updateLocale() {
Preference languagePreference = findPreference(getString(R.string.p_language));
String locale = preferences.getStringValue(R.string.p_language);
languagePreference.setSummary(Strings.isNullOrEmpty(locale)
? getString(R.string.default_value)
: localeFromString(locale).getDisplayName());
}
@Override @Override
public void finish() { public void finish() {
setResult(Activity.RESULT_OK, new Intent() {{ setResult(Activity.RESULT_OK, new Intent() {{

@ -369,4 +369,10 @@ public class Preferences {
} }
return Longs.toArray(pattern); return Longs.toArray(pattern);
} }
public void remove(int resId) {
Editor editor = prefs.edit();
editor.remove(context.getString(resId));
editor.apply();
}
} }

@ -4,7 +4,7 @@ import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.content.res.Resources; import android.content.res.Resources;
import android.graphics.PixelFormat; import android.graphics.PixelFormat;
import android.support.v7.view.ContextThemeWrapper; import android.view.ContextThemeWrapper;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import org.tasks.R; import org.tasks.R;

@ -2,7 +2,7 @@ package org.tasks.themes;
import android.app.Activity; import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.support.v7.view.ContextThemeWrapper; import android.view.ContextThemeWrapper;
import org.tasks.R; import org.tasks.R;

@ -1,8 +1,11 @@
package org.tasks.time; package org.tasks.time;
import org.tasks.locale.LocaleUtils;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Calendar; import java.util.Calendar;
import java.util.GregorianCalendar; import java.util.GregorianCalendar;
import java.util.Locale;
import java.util.TimeZone; import java.util.TimeZone;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -273,7 +276,7 @@ public class DateTime {
public String toString(String format) { public String toString(String format) {
Calendar calendar = getCalendar(); Calendar calendar = getCalendar();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format); SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format, LocaleUtils.getLocale());
simpleDateFormat.setCalendar(calendar); simpleDateFormat.setCalendar(calendar);
return simpleDateFormat.format(calendar.getTime()); return simpleDateFormat.format(calendar.getTime());
} }

@ -10,6 +10,7 @@ import com.todoroo.astrid.subtasks.SubtasksHelper;
import org.tasks.injection.InjectingRemoteViewsService; import org.tasks.injection.InjectingRemoteViewsService;
import org.tasks.injection.ServiceComponent; import org.tasks.injection.ServiceComponent;
import org.tasks.locale.LocaleUtils;
import org.tasks.preferences.DefaultFilterProvider; import org.tasks.preferences.DefaultFilterProvider;
import org.tasks.preferences.Preferences; import org.tasks.preferences.Preferences;
import org.tasks.themes.ThemeBase; import org.tasks.themes.ThemeBase;
@ -51,7 +52,7 @@ public class ScrollableWidgetUpdateService extends InjectingRemoteViewsService {
String filterId = (String) extras.get(FILTER_ID); String filterId = (String) extras.get(FILTER_ID);
int widgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID); int widgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID);
ThemeBase themeBase = themeCache.getThemeBase(preferences.getInt(WidgetConfigActivity.PREF_THEME + widgetId, 0)); ThemeBase themeBase = themeCache.getThemeBase(preferences.getInt(WidgetConfigActivity.PREF_THEME + widgetId, 0));
return new ScrollableViewsFactory(subtasksHelper, preferences, this, filterId, return new ScrollableViewsFactory(subtasksHelper, preferences, LocaleUtils.withLocale(getApplicationContext()), filterId,
themeBase.getTextColor(), widgetId, database, taskService, defaultFilterProvider, widgetCheckBoxes); themeBase.getTextColor(), widgetId, database, taskService, defaultFilterProvider, widgetCheckBoxes);
} }

@ -129,4 +129,38 @@
<item>@string/theme_deep_orange</item> <item>@string/theme_deep_orange</item>
</string-array> </string-array>
<string-array name="localization">
<item>ar</item>
<item>bg-bg</item>
<item>ca</item>
<item>cs</item>
<item>da</item>
<item>de</item>
<item>el</item>
<item>en</item>
<item>es</item>
<item>fa</item>
<item>fi</item>
<item>fr</item>
<item>hu</item>
<item>it</item>
<item>iw</item>
<item>ja</item>
<item>ko</item>
<item>nb</item>
<item>nl</item>
<item>pl</item>
<item>pt</item>
<item>pt-br</item>
<item>ru</item>
<item>sk</item>
<item>sl-si</item>
<item>sv</item>
<item>th</item>
<item>tr</item>
<item>uk</item>
<item>zh-cn</item>
<item>zh-tw</item>
</string-array>
</resources> </resources>

@ -305,5 +305,5 @@
<string name="p_theme_accent">theme_accent</string> <string name="p_theme_accent">theme_accent</string>
<string name="p_gtasks_default_list">default_gtasks_list</string> <string name="p_gtasks_default_list">default_gtasks_list</string>
<string name="p_sync_warning_shown">sync_warning_shown</string> <string name="p_sync_warning_shown">sync_warning_shown</string>
<string name="p_language">language</string>
</resources> </resources>

@ -893,5 +893,10 @@ File %1$s contained %2$s.\n\n
<string name="sync_interval_three_days">every three days</string> <string name="sync_interval_three_days">every three days</string>
<string name="sync_interval_one_week">every week</string> <string name="sync_interval_one_week">every week</string>
<string name="master_sync_warning">Automatic synchronization is currently disabled by Android</string> <string name="master_sync_warning">Automatic synchronization is currently disabled by Android</string>
<string name="settings_general">General</string>
<string name="language">Language</string>
<string name="restart_required">Tasks must be restarted for change to take effect</string>
<string name="restart_now">Restart now</string>
<string name="restart_later">Later</string>
</resources> </resources>

@ -1,17 +1,31 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<Preference <PreferenceCategory android:title="@string/theme">
android:key="@string/p_theme"
android:title="@string/theme" />
<Preference <Preference
android:key="@string/p_theme_color" android:key="@string/p_theme"
android:title="@string/color" /> android:title="@string/theme" />
<Preference <Preference
android:key="@string/p_theme_accent" android:key="@string/p_theme_color"
android:title="@string/accent" /> android:title="@string/color" />
<Preference
android:key="@string/p_theme_accent"
android:title="@string/accent" />
</PreferenceCategory>
<PreferenceCategory
android:key="@string/settings_general"
android:title="@string/settings_general">
<Preference
android:key="@string/p_language"
android:title="@string/language" />
</PreferenceCategory>
<Preference <Preference
android:key="@string/EPr_appearance_header" android:key="@string/EPr_appearance_header"

Loading…
Cancel
Save