Add layout direction preference

pull/437/head
Alex Baker 8 years ago
parent f8508940a8
commit ea45c636d3

@ -35,7 +35,7 @@ public class MultilineListPreference extends ListPreference {
@Override
protected void showDialog(Bundle state) {
super.showDialog(state);
Locale.INSTANCE.fixDialogButtonDirectionality(getDialog());
Locale.INSTANCE.applyDirectionality(getDialog());
}
@Override

@ -128,14 +128,14 @@ public class AlertDialogBuilder {
AlertDialog dialog = create();
theme.applyToContext(dialog.getListView().getContext());
dialog.show();
locale.fixDialogButtonDirectionality(dialog);
locale.applyDirectionality(dialog);
return dialog;
}
public AlertDialog show() {
AlertDialog dialog = create();
dialog.show();
locale.fixDialogButtonDirectionality(dialog);
locale.applyDirectionality(dialog);
return dialog;
}
}

@ -1,11 +1,8 @@
package org.tasks.injection;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import org.tasks.ErrorReportingSingleThreadExecutor;
import org.tasks.R;
import org.tasks.analytics.Tracker;
import org.tasks.locale.Locale;
import org.tasks.themes.ThemeCache;
@ -28,10 +25,7 @@ public class ApplicationModule {
private Context context;
public ApplicationModule(Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
String language = prefs.getString(context.getString(R.string.p_language), null);
Locale.INSTANCE = new Locale(java.util.Locale.getDefault(), language);
this.context = Locale.INSTANCE.createConfigurationContext(context.getApplicationContext());
this.context = context;
}
@Provides

@ -1,7 +1,13 @@
package org.tasks.injection;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.support.multidex.MultiDexApplication;
import org.tasks.R;
import org.tasks.locale.Locale;
public abstract class InjectingApplication extends MultiDexApplication {
private ApplicationComponent applicationComponent;
@ -10,8 +16,15 @@ public abstract class InjectingApplication extends MultiDexApplication {
public void onCreate() {
super.onCreate();
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
String language = prefs.getString(getString(R.string.p_language), null);
int directionOverride = Integer.parseInt(prefs.getString(getString(R.string.p_layout_direction), "-1"));
Locale.INSTANCE = new Locale(java.util.Locale.getDefault(), language, directionOverride);
java.util.Locale.setDefault(Locale.INSTANCE.getLocale());
Context context = Locale.INSTANCE.createConfigurationContext(getApplicationContext());
applicationComponent = DaggerApplicationComponent.builder()
.applicationModule(new ApplicationModule(this))
.applicationModule(new ApplicationModule(context))
.build();
inject(applicationComponent);
@ -22,6 +35,4 @@ public abstract class InjectingApplication extends MultiDexApplication {
public ApplicationComponent getComponent() {
return applicationComponent;
}
}

@ -8,7 +8,7 @@ public abstract class InjectingContentProvider extends ContentProvider {
public boolean onCreate() {
Context context = getContext();
inject(DaggerContentProviderComponent.builder()
.applicationModule(new ApplicationModule(context))
.applicationModule(new ApplicationModule(context.getApplicationContext()))
.contentProviderModule(new ContentProviderModule())
.build());

@ -20,7 +20,7 @@ public class Locale {
private static final char LEFT_TO_RIGHT_MARK = '\u200e';
private static final char RIGHT_TO_LEFT_MARK = '\u200f';
public static java.util.Locale localeFromString(String locale) {
private static java.util.Locale localeFromString(String locale) {
if (Strings.isNullOrEmpty(locale)) {
return null;
}
@ -38,29 +38,36 @@ public class Locale {
private final java.util.Locale appLocale;
private final int deviceDirectionality;
private final int appDirectionality;
private final String override;
private final String languageOverride;
private final int directionOverride;
private final boolean hasUserOverrides;
public Locale(java.util.Locale deviceLocale, String override) {
public Locale(java.util.Locale deviceLocale, String languageOverride, int directionOverride) {
this.deviceLocale = deviceLocale;
this.appLocale = localeFromString(override);
this.override = override;
this.languageOverride = languageOverride;
this.directionOverride = directionOverride;
deviceDirectionality = TextUtils.getLayoutDirectionFromLocale(deviceLocale);
if (appLocale != null) {
java.util.Locale.setDefault(appLocale);
java.util.Locale override = localeFromString(languageOverride);
if (override != null) {
appLocale = override;
} else {
appLocale = deviceLocale;
}
if (directionOverride == View.LAYOUT_DIRECTION_LTR || directionOverride == View.LAYOUT_DIRECTION_RTL) {
appDirectionality = directionOverride;
} else if (appLocale != null) {
appDirectionality = TextUtils.getLayoutDirectionFromLocale(appLocale);
} else {
appDirectionality = deviceDirectionality;
}
}
public java.util.Locale getLocale() {
return appLocale == null ? deviceLocale : appLocale;
hasUserOverrides = !(deviceLocale.equals(appLocale) && appDirectionality == deviceDirectionality) && atLeastJellybeanMR1();
}
public char getDeviceDirectionalityMark() {
return getDirectionalityMark(deviceDirectionality);
public java.util.Locale getLocale() {
return appLocale;
}
public char getDirectionalityMark() {
@ -75,37 +82,37 @@ public class Locale {
return appDirectionality;
}
public String getOverride() {
return override;
public String getLanguageOverride() {
return languageOverride;
}
public Context createConfigurationContext(Context context) {
return appLocale == null ? context : context.createConfigurationContext(getLocaleConfiguration());
return hasUserOverrides
? context.createConfigurationContext(getLocaleConfiguration())
: context;
}
private Configuration getLocaleConfiguration() {
Configuration configuration = new Configuration();
configuration.setLocale(appLocale);
configuration.locale = getLocale();
final int layoutDirection = 1 + appDirectionality;
configuration.screenLayout = (configuration.screenLayout&~Configuration.SCREENLAYOUT_LAYOUTDIR_MASK)|
(layoutDirection << Configuration.SCREENLAYOUT_LAYOUTDIR_SHIFT);
return configuration;
}
public void fixDialogButtonDirectionality(Dialog dialog) {
if (appDirectionality != deviceDirectionality) {
for (int id : sDialogButtons) {
ViewParent parent = dialog.findViewById(id).getParent();
((View) parent).setLayoutDirection(appDirectionality);
}
}
}
public void applyOverrideConfiguration(ContextThemeWrapper wrapper) {
if (appLocale != null && atLeastJellybeanMR1()) {
if (hasUserOverrides) {
wrapper.applyOverrideConfiguration(getLocaleConfiguration());
}
}
public Locale withOverride(String language) {
return new Locale(deviceLocale, language);
public Locale withLanguage(String language) {
return new Locale(deviceLocale, language, directionOverride);
}
public Locale withDirectionality(int directionality) {
return new Locale(deviceLocale, languageOverride, directionality);
}
public String getDisplayName() {
@ -120,12 +127,12 @@ public class Locale {
Locale locale = (Locale) o;
return override != null ? override.equals(locale.override) : locale.override == null;
return languageOverride != null ? languageOverride.equals(locale.languageOverride) : locale.languageOverride == null;
}
@Override
public int hashCode() {
return override != null ? override.hashCode() : 0;
return languageOverride != null ? languageOverride.hashCode() : 0;
}
@Override
@ -133,7 +140,21 @@ public class Locale {
return "Locale{" +
"deviceLocale=" + deviceLocale +
", appLocale=" + appLocale +
", override='" + override + '\'' +
", deviceDirectionality=" + deviceDirectionality +
", appDirectionality=" + appDirectionality +
", languageOverride='" + languageOverride + '\'' +
", directionOverride=" + directionOverride +
", hasUserOverrides=" + hasUserOverrides +
'}';
}
public void applyDirectionality(Dialog dialog) {
if (hasUserOverrides) {
dialog.findViewById(android.R.id.content).setLayoutDirection(appDirectionality);
for (int id : sDialogButtons) {
ViewParent parent = dialog.findViewById(id).getParent();
((View) parent).setLayoutDirection(appDirectionality);
}
}
}
}

@ -42,7 +42,7 @@ public class LocalePickerDialog extends InjectingDialogFragment {
public Dialog onCreateDialog(Bundle savedInstanceState) {
final List<Locale> locales = new ArrayList<>();
for (String override : getResources().getStringArray(R.array.localization)) {
locales.add(locale.withOverride(override));
locales.add(locale.withLanguage(override));
}
final List<String> display = transform(locales, new Function<Locale, String>() {
@Override

@ -110,6 +110,17 @@ public abstract class BaseBasicPreferences extends InjectingPreferenceActivity i
return false;
}
});
findPreference(getString(R.string.p_layout_direction)).setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object o) {
tracker.reportEvent(Tracking.Events.SET_PREFERENCE, R.string.p_layout_direction, o.toString());
int newValue = Integer.parseInt((String) o);
if (locale.getDirectionality() != locale.withDirectionality(newValue).getDirectionality()) {
showRestartDialog();
}
return true;
}
});
findPreference(getString(R.string.p_collect_statistics)).setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
@ -125,7 +136,7 @@ public abstract class BaseBasicPreferences extends InjectingPreferenceActivity i
setupActivity(R.string.notifications, ReminderPreferences.class);
setupActivity(R.string.EPr_manage_header, OldTaskPreferences.class);
requires(R.string.settings_localization, atLeastJellybeanMR1(), R.string.p_language);
requires(R.string.settings_localization, atLeastJellybeanMR1(), R.string.p_language, R.string.p_layout_direction);
}
private void setupActivity(int key, final Class<?> target) {
@ -180,31 +191,35 @@ public abstract class BaseBasicPreferences extends InjectingPreferenceActivity i
if (newValue == null) {
preferences.remove(R.string.p_language);
} else {
String override = newValue.getOverride();
String override = newValue.getLanguageOverride();
preferences.setString(R.string.p_language, override);
tracker.reportEvent(Tracking.Events.SET_PREFERENCE, R.string.p_language, override);
}
updateLocale();
if (!locale.equals(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();
showRestartDialog();
}
}
private void showRestartDialog() {
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 preference = preferences.getStringValue(R.string.p_language);
languagePreference.setSummary(locale.withOverride(preference).getDisplayName());
languagePreference.setSummary(locale.withLanguage(preference).getDisplayName());
}
@Override

@ -22,12 +22,15 @@ import com.todoroo.astrid.subtasks.SubtasksHelper;
import org.tasks.BuildConfig;
import org.tasks.R;
import org.tasks.locale.Locale;
import org.tasks.preferences.DefaultFilterProvider;
import org.tasks.preferences.Preferences;
import org.tasks.ui.WidgetCheckBoxes;
import timber.log.Timber;
import static com.todoroo.andlib.utility.AndroidUtilities.atLeastJellybeanMR1;
public class ScrollableViewsFactory implements RemoteViewsService.RemoteViewsFactory {
private final WidgetCheckBoxes checkBoxes;
@ -172,6 +175,10 @@ public class ScrollableViewsFactory implements RemoteViewsService.RemoteViewsFac
row.setOnClickFillInIntent(R.id.widget_complete_box, completeIntent);
}
if (atLeastJellybeanMR1()) {
row.setInt(R.id.widget_row, "setLayoutDirection", Locale.INSTANCE.getDirectionality());
}
return row;
} catch (Exception e) {
Timber.e(e, e.getMessage());
@ -203,6 +210,9 @@ public class ScrollableViewsFactory implements RemoteViewsService.RemoteViewsFac
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
RemoteViews rv = new RemoteViews(context.getPackageName(), R.layout.scrollable_widget);
rv.setTextViewText(R.id.widget_title, filter.listingTitle);
if (atLeastJellybeanMR1()) {
rv.setInt(R.id.widget, "setLayoutDirection", Locale.INSTANCE.getDirectionality());
}
appWidgetManager.partiallyUpdateAppWidget(widgetId, rv);
String query = SortHelper.adjustQueryForFlagsAndSort(preferences, filter.getSqlQuery(), sort).replaceAll("LIMIT \\d+", "");
return subtasksHelper.applySubtasksToWidgetFilter(filter, query, filter.listingTitle, 0);

@ -13,7 +13,7 @@
<TextView
android:id="@+id/title"
android:layout_width="fill_parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="?android:attr/textColorPrimary"
android:textSize="16sp" />

@ -19,6 +19,7 @@
style="@style/TaskEditTextPrimary"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAlignment="viewStart"
android:text="@string/TEA_timer_controls" />
</LinearLayout>

@ -9,12 +9,15 @@
android:layout_gravity="top" />
<TextView
android:paddingRight="0dp"
android:paddingEnd="0dp"
android:paddingLeft="@dimen/keyline_first"
android:paddingStart="@dimen/keyline_first"
android:gravity="center_vertical"
android:id="@+id/subheader_text"
android:textColor="?attr/asTextColor"
android:textSize="14sp"
android:textAlignment="viewStart"
android:fontFamily="@string/font_fontFamily_medium"
android:alpha="0.54"
android:layout_width="match_parent"

@ -32,6 +32,7 @@
android:hint="@string/TVA_add_comment"
android:imeOptions="flagNoExtractUi|actionDone"
android:inputType="textCapSentences"
android:textAlignment="viewStart"
android:paddingLeft="@dimen/keyline_second"
android:paddingStart="@dimen/keyline_second"
android:textColor="?attr/actionBarPrimaryText"

@ -29,6 +29,7 @@
android:layout_toLeftOf="@id/selected_filter"
android:layout_toStartOf="@id/selected_filter"
android:text="@string/filter"
android:textAlignment="viewStart"
android:textColor="?attr/asTextColor"
android:textSize="18sp" />
@ -55,6 +56,7 @@
android:layout_toLeftOf="@id/selected_theme"
android:layout_toStartOf="@id/selected_theme"
android:text="@string/theme"
android:textAlignment="viewStart"
android:textColor="?attr/asTextColor"
android:textSize="18sp" />
@ -81,6 +83,7 @@
android:layout_toLeftOf="@id/selected_color"
android:layout_toStartOf="@id/selected_color"
android:text="@string/color"
android:textAlignment="viewStart"
android:textColor="?attr/asTextColor"
android:textSize="18sp" />
@ -105,6 +108,7 @@
android:layout_toLeftOf="@id/opacity_value"
android:layout_toStartOf="@id/opacity_value"
android:text="@string/opacity"
android:textAlignment="viewStart"
android:textColor="?attr/asTextColor"
android:textSize="18sp" />
@ -115,8 +119,8 @@
style="@style/WidgetConfigRow"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:max="255"
android:indeterminate="false" />
android:indeterminate="false"
android:max="255" />
<CheckBox
android:id="@+id/hideDueDate"

@ -23,35 +23,37 @@
android:paddingStart="5dp"
android:paddingTop="5dp" />
<LinearLayout
<TextView
android:id="@+id/widget_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_toEndOf="@id/widget_complete_box"
android:layout_toRightOf="@id/widget_complete_box"
android:gravity="center_vertical"
android:orientation="vertical">
<TextView
android:id="@+id/widget_text"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:singleLine="true"
android:textAlignment="viewStart"
android:textSize="16sp" />
<TextView
android:id="@+id/widget_due_date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:gravity="center_vertical"
android:singleLine="true"
android:textAlignment="viewStart"
android:textSize="12sp"
android:visibility="gone" />
android:paddingEnd="5dp"
android:paddingLeft="0dp"
android:paddingRight="5dp"
android:paddingStart="0dp"
android:singleLine="true"
android:textAlignment="viewStart"
android:textSize="16sp" />
</LinearLayout>
<TextView
android:id="@+id/widget_due_date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/widget_text"
android:layout_toEndOf="@id/widget_complete_box"
android:layout_toRightOf="@id/widget_complete_box"
android:ellipsize="end"
android:gravity="center_vertical"
android:paddingEnd="5dp"
android:paddingLeft="0dp"
android:paddingRight="5dp"
android:paddingStart="0dp"
android:singleLine="true"
android:textAlignment="viewStart"
android:textSize="12sp"
android:visibility="gone" />
</RelativeLayout>

@ -163,4 +163,15 @@
<item>zh-tw</item>
</string-array>
<string-array name="layout_direction_entries">
<item>@string/layout_direction_locale</item>
<item>@string/layout_direction_left_to_right</item>
<item>@string/layout_direction_right_to_left</item>
</string-array>
<string-array name="layout_direction_values">
<item>-1</item>
<item>0</item>
<item>1</item>
</string-array>
</resources>

@ -306,4 +306,5 @@
<string name="p_gtasks_default_list">default_gtasks_list</string>
<string name="p_sync_warning_shown">sync_warning_shown</string>
<string name="p_language">language</string>
<string name="p_layout_direction">layout_direction</string>
</resources>

@ -899,5 +899,9 @@ File %1$s contained %2$s.\n\n
<string name="restart_now">Restart now</string>
<string name="restart_later">Later</string>
<string name="settings_localization">Localization</string>
<string name="layout_direction">Layout direction</string>
<string name="layout_direction_locale">Use locale direction</string>
<string name="layout_direction_left_to_right">Left to right</string>
<string name="layout_direction_right_to_left">Right to left</string>
</resources>

@ -76,6 +76,7 @@
<item name="android:button">@null</item>
<item name="android:drawableRight">?android:attr/listChoiceIndicatorMultiple</item>
<item name="android:drawableEnd">?android:attr/listChoiceIndicatorMultiple</item>
<item name="android:textAlignment">viewStart</item>
</style>
<!--================================================== General == -->

@ -73,6 +73,13 @@
android:key="@string/p_language"
android:title="@string/language" />
<com.todoroo.astrid.ui.MultilineListPreference
android:defaultValue="-1"
android:key="@string/p_layout_direction"
android:title="@string/layout_direction"
android:entries="@array/layout_direction_entries"
android:entryValues="@array/layout_direction_values" />
<Preference android:title="@string/translations">
<intent
android:action="android.intent.action.VIEW"

@ -11,6 +11,6 @@
android:minHeight="142dip"
android:minResizeWidth="142dip"
android:minResizeHeight="142dip"
android:updatePeriodMillis="86400000"
android:updatePeriodMillis="1800000"
android:initialLayout="@layout/widget_loading"
android:resizeMode="horizontal|vertical"/>

Loading…
Cancel
Save