mirror of https://github.com/tasks/tasks
Migrate settings to androidx preferences
parent
bf3088ad0b
commit
00b57e1af7
@ -1,79 +0,0 @@
|
|||||||
package org.tasks.preferences;
|
|
||||||
|
|
||||||
import static com.google.common.primitives.Ints.asList;
|
|
||||||
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.preference.Preference;
|
|
||||||
import androidx.annotation.StringRes;
|
|
||||||
import at.bitfire.cert4android.CustomCertManager;
|
|
||||||
import javax.inject.Inject;
|
|
||||||
import org.tasks.R;
|
|
||||||
import org.tasks.billing.BillingClient;
|
|
||||||
import org.tasks.billing.Inventory;
|
|
||||||
import org.tasks.injection.ActivityComponent;
|
|
||||||
import org.tasks.injection.InjectingPreferenceActivity;
|
|
||||||
import org.tasks.ui.Toaster;
|
|
||||||
|
|
||||||
public class DebugPreferences extends InjectingPreferenceActivity {
|
|
||||||
|
|
||||||
@Inject Inventory inventory;
|
|
||||||
@Inject BillingClient billingClient;
|
|
||||||
@Inject Toaster toaster;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
|
|
||||||
addPreferencesFromResource(R.xml.preferences_debug);
|
|
||||||
|
|
||||||
for (int pref :
|
|
||||||
asList(
|
|
||||||
R.string.p_leakcanary,
|
|
||||||
R.string.p_flipper,
|
|
||||||
R.string.p_strict_mode_vm,
|
|
||||||
R.string.p_strict_mode_thread)) {
|
|
||||||
findPreference(pref)
|
|
||||||
.setOnPreferenceChangeListener(
|
|
||||||
(preference, newValue) -> {
|
|
||||||
showRestartDialog();
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
findPreference(R.string.debug_reset_ssl)
|
|
||||||
.setOnPreferenceClickListener(
|
|
||||||
preference -> {
|
|
||||||
CustomCertManager.Companion.resetCertificates(this);
|
|
||||||
toaster.longToast("SSL certificates reset");
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
|
|
||||||
setupIap(R.string.debug_themes, Inventory.SKU_THEMES);
|
|
||||||
setupIap(R.string.debug_tasker, Inventory.SKU_TASKER);
|
|
||||||
setupIap(R.string.debug_dashclock, Inventory.SKU_DASHCLOCK);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setupIap(@StringRes int prefId, String sku) {
|
|
||||||
Preference preference = findPreference(prefId);
|
|
||||||
if (inventory.getPurchase(sku) == null) {
|
|
||||||
preference.setTitle(getString(R.string.debug_purchase, sku));
|
|
||||||
preference.setOnPreferenceClickListener(
|
|
||||||
p -> {
|
|
||||||
billingClient.initiatePurchaseFlow(DebugPreferences.this, sku, "inapp" /*SkuType.INAPP*/, null);
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
preference.setTitle(getString(R.string.debug_consume, sku));
|
|
||||||
preference.setOnPreferenceClickListener(
|
|
||||||
p -> {
|
|
||||||
billingClient.consume(sku);
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void inject(ActivityComponent component) {
|
|
||||||
component.inject(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -0,0 +1,65 @@
|
|||||||
|
package org.tasks.preferences.fragments
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import androidx.annotation.StringRes
|
||||||
|
import androidx.preference.Preference
|
||||||
|
import at.bitfire.cert4android.CustomCertManager.Companion.resetCertificates
|
||||||
|
import com.android.billingclient.api.BillingClient.SkuType
|
||||||
|
import com.google.common.primitives.Ints
|
||||||
|
import org.tasks.R
|
||||||
|
import org.tasks.billing.BillingClient
|
||||||
|
import org.tasks.billing.Inventory
|
||||||
|
import org.tasks.injection.FragmentComponent
|
||||||
|
import org.tasks.injection.InjectingPreferenceFragment
|
||||||
|
import org.tasks.ui.Toaster
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class Debug : InjectingPreferenceFragment() {
|
||||||
|
|
||||||
|
@Inject lateinit var inventory: Inventory
|
||||||
|
@Inject lateinit var billingClient: BillingClient
|
||||||
|
@Inject lateinit var toaster: Toaster
|
||||||
|
|
||||||
|
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||||
|
setPreferencesFromResource(R.xml.preferences_debug, rootKey)
|
||||||
|
|
||||||
|
for (pref in Ints.asList(
|
||||||
|
R.string.p_leakcanary,
|
||||||
|
R.string.p_flipper,
|
||||||
|
R.string.p_strict_mode_vm,
|
||||||
|
R.string.p_strict_mode_thread)) findPreference(pref)
|
||||||
|
.setOnPreferenceChangeListener { _: Preference?, _: Any? ->
|
||||||
|
showRestartDialog()
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
findPreference(R.string.debug_reset_ssl).setOnPreferenceClickListener {
|
||||||
|
resetCertificates(context!!)
|
||||||
|
toaster.longToast("SSL certificates reset")
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
setupIap(R.string.debug_themes, Inventory.SKU_THEMES)
|
||||||
|
setupIap(R.string.debug_tasker, Inventory.SKU_TASKER)
|
||||||
|
setupIap(R.string.debug_dashclock, Inventory.SKU_DASHCLOCK)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupIap(@StringRes prefId: Int, sku: String) {
|
||||||
|
val preference: Preference = findPreference(prefId)
|
||||||
|
if (inventory.getPurchase(sku) == null) {
|
||||||
|
preference.title = getString(R.string.debug_purchase, sku)
|
||||||
|
preference.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||||
|
billingClient.initiatePurchaseFlow(activity, sku, SkuType.INAPP, null)
|
||||||
|
false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
preference.title = getString(R.string.debug_consume, sku)
|
||||||
|
preference.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||||
|
billingClient.consume(sku)
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun inject(component: FragmentComponent) = component.inject(this)
|
||||||
|
}
|
||||||
@ -1,179 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2012 Todoroo Inc
|
|
||||||
*
|
|
||||||
* See the file "LICENSE" for the full license governing this code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.todoroo.astrid.core;
|
|
||||||
|
|
||||||
import static org.tasks.PermissionUtil.verifyPermissions;
|
|
||||||
import static org.tasks.activities.RemoteListNativePicker.newRemoteListNativePicker;
|
|
||||||
import static org.tasks.dialogs.NativeSeekBarDialog.newSeekBarDialog;
|
|
||||||
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.preference.Preference;
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import com.todoroo.astrid.api.CaldavFilter;
|
|
||||||
import com.todoroo.astrid.api.Filter;
|
|
||||||
import com.todoroo.astrid.api.GtasksFilter;
|
|
||||||
import javax.inject.Inject;
|
|
||||||
import org.tasks.R;
|
|
||||||
import org.tasks.activities.CalendarSelectionActivity;
|
|
||||||
import org.tasks.calendars.AndroidCalendar;
|
|
||||||
import org.tasks.calendars.CalendarProvider;
|
|
||||||
import org.tasks.dialogs.DialogBuilder;
|
|
||||||
import org.tasks.dialogs.NativeSeekBarDialog;
|
|
||||||
import org.tasks.gtasks.RemoteListSelectionHandler;
|
|
||||||
import org.tasks.injection.ActivityComponent;
|
|
||||||
import org.tasks.injection.InjectingPreferenceActivity;
|
|
||||||
import org.tasks.locale.Locale;
|
|
||||||
import org.tasks.preferences.ActivityPermissionRequestor;
|
|
||||||
import org.tasks.preferences.DefaultFilterProvider;
|
|
||||||
import org.tasks.preferences.Device;
|
|
||||||
import org.tasks.preferences.PermissionRequestor;
|
|
||||||
import org.tasks.preferences.Preferences;
|
|
||||||
import org.tasks.sync.AddAccountDialog;
|
|
||||||
|
|
||||||
public class DefaultsPreferences extends InjectingPreferenceActivity
|
|
||||||
implements RemoteListSelectionHandler, NativeSeekBarDialog.SeekBarCallback {
|
|
||||||
|
|
||||||
private static final String FRAG_TAG_REMOTE_LIST_SELECTION = "frag_tag_remote_list_selection";
|
|
||||||
private static final String FRAG_TAG_RADIUS_PICKER = "frag_tag_radius_picker";
|
|
||||||
|
|
||||||
private static final int REQUEST_CALENDAR_SELECTION = 10412;
|
|
||||||
|
|
||||||
@Inject Preferences preferences;
|
|
||||||
@Inject CalendarProvider calendarProvider;
|
|
||||||
@Inject ActivityPermissionRequestor permissionRequester;
|
|
||||||
@Inject DefaultFilterProvider defaultFilterProvider;
|
|
||||||
@Inject Locale locale;
|
|
||||||
@Inject Device device;
|
|
||||||
@Inject DialogBuilder dialogBuilder;
|
|
||||||
|
|
||||||
private Preference defaultCalendarPref;
|
|
||||||
private Preference defaultRadiusPref;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
|
|
||||||
addPreferencesFromResource(R.xml.preferences_defaults);
|
|
||||||
|
|
||||||
defaultCalendarPref = findPreference(getString(R.string.gcal_p_default));
|
|
||||||
defaultCalendarPref.setOnPreferenceClickListener(
|
|
||||||
preference -> {
|
|
||||||
if (permissionRequester.requestCalendarPermissions()) {
|
|
||||||
startCalendarSelectionActivity();
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
String defaultCalendarName = getDefaultCalendarName();
|
|
||||||
defaultCalendarPref.setSummary(
|
|
||||||
defaultCalendarName == null
|
|
||||||
? getString(R.string.dont_add_to_calendar)
|
|
||||||
: defaultCalendarName);
|
|
||||||
|
|
||||||
findPreference(R.string.p_default_remote_list)
|
|
||||||
.setOnPreferenceClickListener(
|
|
||||||
preference -> {
|
|
||||||
newRemoteListNativePicker(defaultFilterProvider.getDefaultRemoteList())
|
|
||||||
.show(getFragmentManager(), FRAG_TAG_REMOTE_LIST_SELECTION);
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
updateRemoteListSummary();
|
|
||||||
defaultRadiusPref = findPreference(R.string.p_default_location_radius);
|
|
||||||
defaultRadiusPref.setOnPreferenceClickListener(
|
|
||||||
preference -> {
|
|
||||||
newSeekBarDialog(
|
|
||||||
R.layout.dialog_radius_seekbar,
|
|
||||||
75,
|
|
||||||
1000,
|
|
||||||
preferences.getInt(R.string.p_default_location_radius, 250),
|
|
||||||
0)
|
|
||||||
.show(getFragmentManager(), FRAG_TAG_RADIUS_PICKER);
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
updateRadius();
|
|
||||||
|
|
||||||
requires(device.supportsGeofences(), R.string.p_default_location_reminder_key);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void startCalendarSelectionActivity() {
|
|
||||||
Intent intent = new Intent(DefaultsPreferences.this, CalendarSelectionActivity.class);
|
|
||||||
intent.putExtra(CalendarSelectionActivity.EXTRA_CALENDAR_NAME, getDefaultCalendarName());
|
|
||||||
startActivityForResult(intent, REQUEST_CALENDAR_SELECTION);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getDefaultCalendarName() {
|
|
||||||
AndroidCalendar calendar =
|
|
||||||
calendarProvider.getCalendar(preferences.getStringValue(R.string.gcal_p_default));
|
|
||||||
return calendar == null ? null : calendar.getName();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onRequestPermissionsResult(
|
|
||||||
int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
|
||||||
if (requestCode == PermissionRequestor.REQUEST_CALENDAR) {
|
|
||||||
if (verifyPermissions(grantResults)) {
|
|
||||||
startCalendarSelectionActivity();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
|
||||||
if (requestCode == REQUEST_CALENDAR_SELECTION && resultCode == RESULT_OK) {
|
|
||||||
preferences.setString(
|
|
||||||
R.string.gcal_p_default,
|
|
||||||
data.getStringExtra(CalendarSelectionActivity.EXTRA_CALENDAR_ID));
|
|
||||||
defaultCalendarPref.setSummary(
|
|
||||||
data.getStringExtra(CalendarSelectionActivity.EXTRA_CALENDAR_NAME));
|
|
||||||
} else {
|
|
||||||
super.onActivityResult(requestCode, resultCode, data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addAccount() {
|
|
||||||
AddAccountDialog.showAddAccountDialog(this, dialogBuilder);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void selectedList(Filter list) {
|
|
||||||
if (list == null) {
|
|
||||||
preferences.setString(R.string.p_default_remote_list, null);
|
|
||||||
} else if (list instanceof GtasksFilter || list instanceof CaldavFilter) {
|
|
||||||
defaultFilterProvider.setDefaultRemoteList(list);
|
|
||||||
} else {
|
|
||||||
throw new RuntimeException("Unhandled filter type");
|
|
||||||
}
|
|
||||||
updateRemoteListSummary();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateRemoteListSummary() {
|
|
||||||
Filter defaultFilter = defaultFilterProvider.getDefaultRemoteList();
|
|
||||||
findPreference(R.string.p_default_remote_list)
|
|
||||||
.setSummary(
|
|
||||||
defaultFilter == null ? getString(R.string.dont_sync) : defaultFilter.listingTitle);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateRadius() {
|
|
||||||
String radius =
|
|
||||||
locale.formatNumber(preferences.getInt(R.string.p_default_location_radius, 250));
|
|
||||||
defaultRadiusPref.setSummary(getString(R.string.location_radius_meters, radius));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void inject(ActivityComponent component) {
|
|
||||||
component.inject(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void valueSelected(int radius, int requestCode) {
|
|
||||||
preferences.setInt(R.string.p_default_location_radius, radius);
|
|
||||||
updateRadius();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,183 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2012 Todoroo Inc
|
|
||||||
*
|
|
||||||
* See the file "LICENSE" for the full license governing this code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.todoroo.astrid.core;
|
|
||||||
|
|
||||||
import android.os.Bundle;
|
|
||||||
import androidx.annotation.StringRes;
|
|
||||||
import com.todoroo.astrid.dao.Database;
|
|
||||||
import com.todoroo.astrid.dao.TaskDao;
|
|
||||||
import com.todoroo.astrid.service.TaskDeleter;
|
|
||||||
import io.reactivex.Single;
|
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
|
||||||
import io.reactivex.disposables.CompositeDisposable;
|
|
||||||
import io.reactivex.schedulers.Schedulers;
|
|
||||||
import java.util.concurrent.Callable;
|
|
||||||
import javax.inject.Inject;
|
|
||||||
import org.tasks.R;
|
|
||||||
import org.tasks.calendars.CalendarEventProvider;
|
|
||||||
import org.tasks.dialogs.DialogBuilder;
|
|
||||||
import org.tasks.injection.ActivityComponent;
|
|
||||||
import org.tasks.injection.InjectingPreferenceActivity;
|
|
||||||
import org.tasks.preferences.Preferences;
|
|
||||||
import org.tasks.ui.Toaster;
|
|
||||||
|
|
||||||
public class OldTaskPreferences extends InjectingPreferenceActivity {
|
|
||||||
|
|
||||||
@Inject DialogBuilder dialogBuilder;
|
|
||||||
@Inject Preferences preferences;
|
|
||||||
@Inject Database database;
|
|
||||||
@Inject TaskDao taskDao;
|
|
||||||
@Inject CalendarEventProvider calendarEventProvider;
|
|
||||||
@Inject TaskDeleter taskDeleter;
|
|
||||||
@Inject Toaster toaster;
|
|
||||||
|
|
||||||
private CompositeDisposable disposables;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
|
|
||||||
addPreferencesFromResource(R.xml.preferences_oldtasks);
|
|
||||||
|
|
||||||
findPreference(getString(R.string.EPr_manage_purge_deleted))
|
|
||||||
.setOnPreferenceClickListener(
|
|
||||||
preference -> {
|
|
||||||
purgeDeletedTasks();
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
|
|
||||||
findPreference(getString(R.string.EPr_manage_delete_completed_gcal))
|
|
||||||
.setOnPreferenceClickListener(
|
|
||||||
preference -> {
|
|
||||||
deleteCompletedEvents();
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
|
|
||||||
findPreference(getString(R.string.EPr_manage_delete_all_gcal))
|
|
||||||
.setOnPreferenceClickListener(
|
|
||||||
preference -> {
|
|
||||||
deleteAllCalendarEvents();
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
|
|
||||||
findPreference(getString(R.string.EPr_reset_preferences))
|
|
||||||
.setOnPreferenceClickListener(
|
|
||||||
preference -> {
|
|
||||||
resetPreferences();
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
|
|
||||||
findPreference(getString(R.string.EPr_delete_task_data))
|
|
||||||
.setOnPreferenceClickListener(
|
|
||||||
preference -> {
|
|
||||||
deleteTaskData();
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void purgeDeletedTasks() {
|
|
||||||
dialogBuilder
|
|
||||||
.newDialog()
|
|
||||||
.setMessage(R.string.EPr_manage_purge_deleted_message)
|
|
||||||
.setPositiveButton(
|
|
||||||
android.R.string.ok,
|
|
||||||
(dialog, which) ->
|
|
||||||
performAction(
|
|
||||||
R.string.EPr_manage_purge_deleted_status, () -> taskDeleter.purgeDeleted()))
|
|
||||||
.setNegativeButton(android.R.string.cancel, null)
|
|
||||||
.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void deleteCompletedEvents() {
|
|
||||||
dialogBuilder
|
|
||||||
.newDialog()
|
|
||||||
.setMessage(R.string.EPr_manage_delete_completed_gcal_message)
|
|
||||||
.setPositiveButton(
|
|
||||||
android.R.string.ok,
|
|
||||||
(dialog, which) ->
|
|
||||||
performAction(
|
|
||||||
R.string.EPr_manage_delete_completed_gcal_status,
|
|
||||||
() -> {
|
|
||||||
calendarEventProvider.deleteEvents(taskDao.getCompletedCalendarEvents());
|
|
||||||
return taskDao.clearCompletedCalendarEvents();
|
|
||||||
}))
|
|
||||||
.setNegativeButton(android.R.string.cancel, null)
|
|
||||||
.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void deleteAllCalendarEvents() {
|
|
||||||
dialogBuilder
|
|
||||||
.newDialog()
|
|
||||||
.setMessage(R.string.EPr_manage_delete_all_gcal_message)
|
|
||||||
.setPositiveButton(
|
|
||||||
android.R.string.ok,
|
|
||||||
(dialog, which) ->
|
|
||||||
performAction(
|
|
||||||
R.string.EPr_manage_delete_all_gcal_status,
|
|
||||||
() -> {
|
|
||||||
calendarEventProvider.deleteEvents(taskDao.getAllCalendarEvents());
|
|
||||||
return taskDao.clearAllCalendarEvents();
|
|
||||||
}))
|
|
||||||
.setNegativeButton(android.R.string.cancel, null)
|
|
||||||
.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void performAction(@StringRes int message, Callable<Integer> callable) {
|
|
||||||
disposables.add(
|
|
||||||
Single.fromCallable(callable)
|
|
||||||
.subscribeOn(Schedulers.io())
|
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
|
||||||
.subscribe(c -> toaster.longToastUnformatted(message, c)));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void resetPreferences() {
|
|
||||||
dialogBuilder
|
|
||||||
.newDialog()
|
|
||||||
.setMessage(R.string.EPr_reset_preferences_warning)
|
|
||||||
.setPositiveButton(
|
|
||||||
R.string.EPr_reset_preferences,
|
|
||||||
(dialog, which) -> {
|
|
||||||
preferences.reset();
|
|
||||||
System.exit(0);
|
|
||||||
})
|
|
||||||
.setNegativeButton(android.R.string.cancel, null)
|
|
||||||
.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void deleteTaskData() {
|
|
||||||
dialogBuilder
|
|
||||||
.newDialog()
|
|
||||||
.setMessage(R.string.EPr_delete_task_data_warning)
|
|
||||||
.setPositiveButton(
|
|
||||||
R.string.EPr_delete_task_data,
|
|
||||||
(dialog, which) -> {
|
|
||||||
deleteDatabase(database.getName());
|
|
||||||
System.exit(0);
|
|
||||||
})
|
|
||||||
.setNegativeButton(android.R.string.cancel, null)
|
|
||||||
.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onResume() {
|
|
||||||
super.onResume();
|
|
||||||
|
|
||||||
disposables = new CompositeDisposable();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onPause() {
|
|
||||||
super.onPause();
|
|
||||||
|
|
||||||
disposables.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void inject(ActivityComponent component) {
|
|
||||||
component.inject(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,220 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2012 Todoroo Inc
|
|
||||||
*
|
|
||||||
* See the file "LICENSE" for the full license governing this code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.todoroo.astrid.reminders;
|
|
||||||
|
|
||||||
import static com.todoroo.andlib.utility.AndroidUtilities.atLeastMarshmallow;
|
|
||||||
import static com.todoroo.andlib.utility.AndroidUtilities.atLeastOreo;
|
|
||||||
import static com.todoroo.andlib.utility.AndroidUtilities.preOreo;
|
|
||||||
|
|
||||||
import android.annotation.TargetApi;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.media.Ringtone;
|
|
||||||
import android.media.RingtoneManager;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Build;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.preference.Preference;
|
|
||||||
import android.preference.PreferenceManager;
|
|
||||||
import android.provider.Settings;
|
|
||||||
import com.todoroo.astrid.api.Filter;
|
|
||||||
import javax.inject.Inject;
|
|
||||||
import org.tasks.LocalBroadcastManager;
|
|
||||||
import org.tasks.R;
|
|
||||||
import org.tasks.activities.FilterSelectionActivity;
|
|
||||||
import org.tasks.activities.TimePickerActivity;
|
|
||||||
import org.tasks.injection.ActivityComponent;
|
|
||||||
import org.tasks.injection.InjectingPreferenceActivity;
|
|
||||||
import org.tasks.preferences.DefaultFilterProvider;
|
|
||||||
import org.tasks.receivers.ShortcutBadger;
|
|
||||||
import org.tasks.scheduling.NotificationSchedulerIntentService;
|
|
||||||
import org.tasks.time.DateTime;
|
|
||||||
import org.tasks.ui.TimePreference;
|
|
||||||
|
|
||||||
public class ReminderPreferences extends InjectingPreferenceActivity {
|
|
||||||
|
|
||||||
private static final int REQUEST_QUIET_START = 10001;
|
|
||||||
private static final int REQUEST_QUIET_END = 10002;
|
|
||||||
private static final int REQUEST_DEFAULT_REMIND = 10003;
|
|
||||||
private static final int REQUEST_BADGE_LIST = 10004;
|
|
||||||
|
|
||||||
@Inject DefaultFilterProvider defaultFilterProvider;
|
|
||||||
@Inject LocalBroadcastManager localBroadcastManager;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
|
|
||||||
addPreferencesFromResource(R.xml.preferences_reminders);
|
|
||||||
|
|
||||||
rescheduleNotificationsOnChange(
|
|
||||||
R.string.p_rmd_time,
|
|
||||||
R.string.p_rmd_enable_quiet,
|
|
||||||
R.string.p_rmd_quietStart,
|
|
||||||
R.string.p_rmd_quietEnd,
|
|
||||||
R.string.p_rmd_persistent);
|
|
||||||
|
|
||||||
initializeRingtonePreference();
|
|
||||||
initializeTimePreference(getDefaultRemindTimePreference(), REQUEST_DEFAULT_REMIND);
|
|
||||||
initializeTimePreference(getQuietStartPreference(), REQUEST_QUIET_START);
|
|
||||||
initializeTimePreference(getQuietEndPreference(), REQUEST_QUIET_END);
|
|
||||||
|
|
||||||
findPreference(R.string.notification_channel_settings)
|
|
||||||
.setOnPreferenceClickListener(this::openNotificationChannelSettings);
|
|
||||||
findPreference(R.string.battery_optimization_settings)
|
|
||||||
.setOnPreferenceClickListener(this::openBatteryOptimizationSettings);
|
|
||||||
|
|
||||||
findPreference(R.string.p_bundle_notifications)
|
|
||||||
.setOnPreferenceChangeListener(
|
|
||||||
(preference, o) -> {
|
|
||||||
NotificationSchedulerIntentService.enqueueWork(this, true);
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
|
|
||||||
findPreference(R.string.p_badges_enabled)
|
|
||||||
.setOnPreferenceChangeListener(
|
|
||||||
(preference, newValue) -> {
|
|
||||||
if (newValue != null) {
|
|
||||||
if ((boolean) newValue) {
|
|
||||||
showRestartDialog();
|
|
||||||
} else {
|
|
||||||
ShortcutBadger.removeCount(this);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
|
|
||||||
Preference badgePreference = findPreference(getString(R.string.p_badge_list));
|
|
||||||
Filter filter = defaultFilterProvider.getBadgeFilter();
|
|
||||||
badgePreference.setSummary(filter.listingTitle);
|
|
||||||
badgePreference.setOnPreferenceClickListener(
|
|
||||||
preference -> {
|
|
||||||
Intent intent = new Intent(ReminderPreferences.this, FilterSelectionActivity.class);
|
|
||||||
intent.putExtra(
|
|
||||||
FilterSelectionActivity.EXTRA_FILTER, defaultFilterProvider.getBadgeFilter());
|
|
||||||
intent.putExtra(FilterSelectionActivity.EXTRA_RETURN_FILTER, true);
|
|
||||||
startActivityForResult(intent, REQUEST_BADGE_LIST);
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
|
|
||||||
requires(atLeastOreo(), R.string.notification_channel_settings);
|
|
||||||
requires(atLeastMarshmallow(), R.string.battery_optimization_settings);
|
|
||||||
requires(
|
|
||||||
preOreo(), R.string.p_rmd_ringtone, R.string.p_rmd_vibrate, R.string.p_led_notification);
|
|
||||||
}
|
|
||||||
|
|
||||||
@TargetApi(Build.VERSION_CODES.O)
|
|
||||||
private boolean openNotificationChannelSettings(Preference ignored) {
|
|
||||||
Intent intent = new Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS);
|
|
||||||
intent.putExtra(Settings.EXTRA_APP_PACKAGE, ReminderPreferences.this.getPackageName());
|
|
||||||
startActivity(intent);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@TargetApi(Build.VERSION_CODES.M)
|
|
||||||
private boolean openBatteryOptimizationSettings(Preference ignored) {
|
|
||||||
Intent intent = new Intent();
|
|
||||||
intent.setAction(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS);
|
|
||||||
startActivity(intent);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void rescheduleNotificationsOnChange(int... resIds) {
|
|
||||||
for (int resId : resIds) {
|
|
||||||
findPreference(getString(resId))
|
|
||||||
.setOnPreferenceChangeListener(
|
|
||||||
(preference, newValue) -> {
|
|
||||||
NotificationSchedulerIntentService.enqueueWork(this, false);
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initializeTimePreference(final TimePreference preference, final int requestCode) {
|
|
||||||
preference.setOnPreferenceClickListener(
|
|
||||||
ignored -> {
|
|
||||||
final DateTime current = new DateTime().withMillisOfDay(preference.getMillisOfDay());
|
|
||||||
Intent intent = new Intent(ReminderPreferences.this, TimePickerActivity.class);
|
|
||||||
intent.putExtra(TimePickerActivity.EXTRA_TIMESTAMP, current.getMillis());
|
|
||||||
startActivityForResult(intent, requestCode);
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initializeRingtonePreference() {
|
|
||||||
Preference.OnPreferenceChangeListener ringtoneChangedListener =
|
|
||||||
(preference, value) -> {
|
|
||||||
if ("".equals(value)) {
|
|
||||||
preference.setSummary(R.string.silent);
|
|
||||||
} else {
|
|
||||||
Ringtone ringtone =
|
|
||||||
RingtoneManager.getRingtone(
|
|
||||||
ReminderPreferences.this,
|
|
||||||
value == null
|
|
||||||
? Settings.System.DEFAULT_NOTIFICATION_URI
|
|
||||||
: Uri.parse((String) value));
|
|
||||||
preference.setSummary(
|
|
||||||
ringtone == null ? "" : ringtone.getTitle(ReminderPreferences.this));
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
String ringtoneKey = getString(R.string.p_rmd_ringtone);
|
|
||||||
Preference ringtonePreference = findPreference(ringtoneKey);
|
|
||||||
ringtonePreference.setOnPreferenceChangeListener(ringtoneChangedListener);
|
|
||||||
ringtoneChangedListener.onPreferenceChange(
|
|
||||||
ringtonePreference,
|
|
||||||
PreferenceManager.getDefaultSharedPreferences(this).getString(ringtoneKey, null));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
|
||||||
if (requestCode == REQUEST_QUIET_START) {
|
|
||||||
if (resultCode == RESULT_OK) {
|
|
||||||
getQuietStartPreference().handleTimePickerActivityIntent(data);
|
|
||||||
}
|
|
||||||
} else if (requestCode == REQUEST_QUIET_END) {
|
|
||||||
if (resultCode == RESULT_OK) {
|
|
||||||
getQuietEndPreference().handleTimePickerActivityIntent(data);
|
|
||||||
}
|
|
||||||
} else if (requestCode == REQUEST_DEFAULT_REMIND) {
|
|
||||||
if (resultCode == RESULT_OK) {
|
|
||||||
getDefaultRemindTimePreference().handleTimePickerActivityIntent(data);
|
|
||||||
}
|
|
||||||
} else if (requestCode == REQUEST_BADGE_LIST) {
|
|
||||||
if (resultCode == RESULT_OK) {
|
|
||||||
Filter filter = data.getParcelableExtra(FilterSelectionActivity.EXTRA_FILTER);
|
|
||||||
defaultFilterProvider.setBadgeFilter(filter);
|
|
||||||
findPreference(getString(R.string.p_badge_list)).setSummary(filter.listingTitle);
|
|
||||||
localBroadcastManager.broadcastRefresh();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
super.onActivityResult(requestCode, resultCode, data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private TimePreference getQuietStartPreference() {
|
|
||||||
return getTimePreference(R.string.p_rmd_quietStart);
|
|
||||||
}
|
|
||||||
|
|
||||||
private TimePreference getQuietEndPreference() {
|
|
||||||
return getTimePreference(R.string.p_rmd_quietEnd);
|
|
||||||
}
|
|
||||||
|
|
||||||
private TimePreference getDefaultRemindTimePreference() {
|
|
||||||
return getTimePreference(R.string.p_rmd_time);
|
|
||||||
}
|
|
||||||
|
|
||||||
private TimePreference getTimePreference(int resId) {
|
|
||||||
return (TimePreference) findPreference(getString(resId));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void inject(ActivityComponent component) {
|
|
||||||
component.inject(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,25 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2012 Todoroo Inc
|
|
||||||
*
|
|
||||||
* See the file "LICENSE" for the full license governing this code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.todoroo.astrid.ui;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.preference.CheckBoxPreference;
|
|
||||||
import android.util.AttributeSet;
|
|
||||||
import android.view.View;
|
|
||||||
|
|
||||||
public class MultilineCheckboxPreference extends CheckBoxPreference {
|
|
||||||
|
|
||||||
public MultilineCheckboxPreference(Context context, AttributeSet attrs) {
|
|
||||||
super(context, attrs);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onBindView(View view) {
|
|
||||||
super.onBindView(view);
|
|
||||||
MultilineHelper.makeMultiline(view);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,29 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2012 Todoroo Inc
|
|
||||||
*
|
|
||||||
* See the file "LICENSE" for the full license governing this code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.todoroo.astrid.ui;
|
|
||||||
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
class MultilineHelper {
|
|
||||||
|
|
||||||
static void makeMultiline(View view) {
|
|
||||||
if (view instanceof ViewGroup) {
|
|
||||||
|
|
||||||
ViewGroup grp = (ViewGroup) view;
|
|
||||||
|
|
||||||
for (int index = 0; index < grp.getChildCount(); index++) {
|
|
||||||
makeMultiline(grp.getChildAt(index));
|
|
||||||
}
|
|
||||||
} else if (view instanceof TextView) {
|
|
||||||
TextView t = (TextView) view;
|
|
||||||
t.setSingleLine(false);
|
|
||||||
t.setEllipsize(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,45 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2012 Todoroo Inc
|
|
||||||
*
|
|
||||||
* See the file "LICENSE" for the full license governing this code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.todoroo.astrid.ui;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.preference.ListPreference;
|
|
||||||
import android.util.AttributeSet;
|
|
||||||
import android.view.View;
|
|
||||||
import org.tasks.locale.Locale;
|
|
||||||
import timber.log.Timber;
|
|
||||||
|
|
||||||
public class MultilineListPreference extends ListPreference {
|
|
||||||
|
|
||||||
public MultilineListPreference(Context context, AttributeSet attrs) {
|
|
||||||
super(context, attrs);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onBindView(View view) {
|
|
||||||
try {
|
|
||||||
super.onBindView(view);
|
|
||||||
} catch (Exception e) {
|
|
||||||
// happens on 4.0 emulators
|
|
||||||
Timber.e(e);
|
|
||||||
}
|
|
||||||
MultilineHelper.makeMultiline(view);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void showDialog(Bundle state) {
|
|
||||||
super.showDialog(state);
|
|
||||||
Locale.getInstance(getContext()).applyDirectionality(getDialog());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setValue(String value) {
|
|
||||||
super.setValue(value);
|
|
||||||
setSummary(getEntry());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,25 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2012 Todoroo Inc
|
|
||||||
*
|
|
||||||
* See the file "LICENSE" for the full license governing this code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.todoroo.astrid.ui;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.preference.Preference;
|
|
||||||
import android.util.AttributeSet;
|
|
||||||
import android.view.View;
|
|
||||||
|
|
||||||
public class MultilinePreference extends Preference {
|
|
||||||
|
|
||||||
public MultilinePreference(Context context, AttributeSet attrs) {
|
|
||||||
super(context, attrs);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onBindView(View view) {
|
|
||||||
super.onBindView(view);
|
|
||||||
MultilineHelper.makeMultiline(view);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,91 +0,0 @@
|
|||||||
package org.tasks.activities;
|
|
||||||
|
|
||||||
import static org.tasks.activities.RemoteListSupportPicker.createDialog;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.app.Dialog;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import com.todoroo.astrid.adapter.FilterAdapter;
|
|
||||||
import com.todoroo.astrid.api.Filter;
|
|
||||||
import io.reactivex.Single;
|
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
|
||||||
import io.reactivex.disposables.CompositeDisposable;
|
|
||||||
import io.reactivex.schedulers.Schedulers;
|
|
||||||
import javax.inject.Inject;
|
|
||||||
import org.tasks.dialogs.DialogBuilder;
|
|
||||||
import org.tasks.filters.FilterProvider;
|
|
||||||
import org.tasks.gtasks.RemoteListSelectionHandler;
|
|
||||||
import org.tasks.injection.InjectingNativeDialogFragment;
|
|
||||||
import org.tasks.injection.NativeDialogFragmentComponent;
|
|
||||||
import org.tasks.sync.SyncAdapters;
|
|
||||||
|
|
||||||
public class RemoteListNativePicker extends InjectingNativeDialogFragment {
|
|
||||||
|
|
||||||
private static final String EXTRA_SELECTED = "extra_selected";
|
|
||||||
|
|
||||||
@Inject DialogBuilder dialogBuilder;
|
|
||||||
@Inject FilterAdapter filterAdapter;
|
|
||||||
@Inject FilterProvider filterProvider;
|
|
||||||
@Inject SyncAdapters syncAdapters;
|
|
||||||
private RemoteListSelectionHandler handler;
|
|
||||||
private CompositeDisposable disposables;
|
|
||||||
|
|
||||||
public static RemoteListNativePicker newRemoteListNativePicker(Filter selected) {
|
|
||||||
RemoteListNativePicker dialog = new RemoteListNativePicker();
|
|
||||||
Bundle arguments = new Bundle();
|
|
||||||
if (selected != null) {
|
|
||||||
arguments.putParcelable(EXTRA_SELECTED, selected);
|
|
||||||
}
|
|
||||||
dialog.setArguments(arguments);
|
|
||||||
return dialog;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
|
||||||
if (savedInstanceState != null) {
|
|
||||||
filterAdapter.restore(savedInstanceState);
|
|
||||||
}
|
|
||||||
|
|
||||||
return createDialog(filterAdapter, dialogBuilder, syncAdapters, handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onResume() {
|
|
||||||
super.onResume();
|
|
||||||
|
|
||||||
Filter selected = getArguments().getParcelable(EXTRA_SELECTED);
|
|
||||||
|
|
||||||
disposables =
|
|
||||||
new CompositeDisposable(
|
|
||||||
Single.fromCallable(filterProvider::getRemoteListPickerItems)
|
|
||||||
.subscribeOn(Schedulers.io())
|
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
|
||||||
.subscribe(items -> filterAdapter.setData(items, selected, 0)));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onPause() {
|
|
||||||
super.onPause();
|
|
||||||
|
|
||||||
disposables.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onAttach(Activity activity) {
|
|
||||||
super.onAttach(activity);
|
|
||||||
|
|
||||||
handler = (RemoteListSelectionHandler) activity;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onSaveInstanceState(Bundle outState) {
|
|
||||||
super.onSaveInstanceState(outState);
|
|
||||||
|
|
||||||
filterAdapter.save(outState);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void inject(NativeDialogFragmentComponent component) {
|
|
||||||
component.inject(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,98 +0,0 @@
|
|||||||
package org.tasks.dialogs;
|
|
||||||
|
|
||||||
import static com.todoroo.andlib.utility.AndroidUtilities.atLeastMarshmallow;
|
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.app.DatePickerDialog;
|
|
||||||
import android.app.Dialog;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.DialogInterface;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.widget.DatePicker;
|
|
||||||
import javax.inject.Inject;
|
|
||||||
import org.tasks.injection.ForActivity;
|
|
||||||
import org.tasks.injection.InjectingNativeDialogFragment;
|
|
||||||
import org.tasks.injection.NativeDialogFragmentComponent;
|
|
||||||
import org.tasks.preferences.Preferences;
|
|
||||||
import org.tasks.themes.Theme;
|
|
||||||
import org.tasks.time.DateTime;
|
|
||||||
|
|
||||||
public class NativeDatePickerDialog extends InjectingNativeDialogFragment
|
|
||||||
implements DatePickerDialog.OnDateSetListener {
|
|
||||||
|
|
||||||
private static final String EXTRA_YEAR = "extra_year";
|
|
||||||
private static final String EXTRA_MONTH = "extra_month";
|
|
||||||
private static final String EXTRA_DAY = "extra_day";
|
|
||||||
@Inject @ForActivity Context context;
|
|
||||||
@Inject Theme theme;
|
|
||||||
@Inject Preferences preferences;
|
|
||||||
private NativeDatePickerDialogCallback callback;
|
|
||||||
|
|
||||||
public static NativeDatePickerDialog newNativeDatePickerDialog(DateTime initial) {
|
|
||||||
NativeDatePickerDialog dialog = new NativeDatePickerDialog();
|
|
||||||
Bundle args = new Bundle();
|
|
||||||
args.putInt(EXTRA_YEAR, initial.getYear());
|
|
||||||
args.putInt(EXTRA_MONTH, initial.getMonthOfYear() - 1);
|
|
||||||
args.putInt(EXTRA_DAY, initial.getDayOfMonth());
|
|
||||||
dialog.setArguments(args);
|
|
||||||
return dialog;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
|
|
||||||
setRetainInstance(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressLint("NewApi")
|
|
||||||
@Override
|
|
||||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
|
||||||
Bundle args = getArguments();
|
|
||||||
DatePickerDialog datePickerDialog =
|
|
||||||
new DatePickerDialog(
|
|
||||||
theme.wrap(context),
|
|
||||||
this,
|
|
||||||
args.getInt(EXTRA_YEAR),
|
|
||||||
args.getInt(EXTRA_MONTH),
|
|
||||||
args.getInt(EXTRA_DAY));
|
|
||||||
int firstDayOfWeek = preferences.getFirstDayOfWeek();
|
|
||||||
if (firstDayOfWeek >= 1 && firstDayOfWeek <= 7 && atLeastMarshmallow()) {
|
|
||||||
datePickerDialog.getDatePicker().setFirstDayOfWeek(firstDayOfWeek);
|
|
||||||
}
|
|
||||||
datePickerDialog.setTitle("");
|
|
||||||
return datePickerDialog;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDateSet(DatePicker datePicker, int year, int month, int day) {
|
|
||||||
callback.onDateSet(year, month, day);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCancel(DialogInterface dialog) {
|
|
||||||
super.onCancel(dialog);
|
|
||||||
|
|
||||||
callback.cancel();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onAttach(Activity activity) {
|
|
||||||
super.onAttach(activity);
|
|
||||||
|
|
||||||
callback = (NativeDatePickerDialogCallback) activity;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void inject(NativeDialogFragmentComponent component) {
|
|
||||||
component.inject(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface NativeDatePickerDialogCallback {
|
|
||||||
|
|
||||||
void cancel();
|
|
||||||
|
|
||||||
void onDateSet(int year, int month, int day);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,109 +0,0 @@
|
|||||||
package org.tasks.dialogs;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.app.Dialog;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.widget.TextView;
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import butterknife.BindView;
|
|
||||||
import butterknife.ButterKnife;
|
|
||||||
import com.rey.material.widget.Slider;
|
|
||||||
import javax.inject.Inject;
|
|
||||||
import org.tasks.R;
|
|
||||||
import org.tasks.injection.InjectingNativeDialogFragment;
|
|
||||||
import org.tasks.injection.NativeDialogFragmentComponent;
|
|
||||||
import org.tasks.locale.Locale;
|
|
||||||
import org.tasks.themes.Theme;
|
|
||||||
|
|
||||||
public class NativeSeekBarDialog extends InjectingNativeDialogFragment {
|
|
||||||
|
|
||||||
private static final String EXTRA_LAYOUT = "extra_layout";
|
|
||||||
private static final String EXTRA_INITIAL_VALUE = "extra_initial_value";
|
|
||||||
private static final String EXTRA_MIN = "extra_min";
|
|
||||||
private static final String EXTRA_MAX = "extra_max";
|
|
||||||
private static final String EXTRA_REQUEST_CODE = "extra_request_code";
|
|
||||||
|
|
||||||
@BindView(R.id.slider)
|
|
||||||
Slider slider;
|
|
||||||
|
|
||||||
@BindView(R.id.min)
|
|
||||||
TextView min;
|
|
||||||
|
|
||||||
@BindView(R.id.max)
|
|
||||||
TextView max;
|
|
||||||
|
|
||||||
@Inject DialogBuilder dialogBuilder;
|
|
||||||
@Inject Theme theme;
|
|
||||||
@Inject Locale locale;
|
|
||||||
private int requestCode;
|
|
||||||
private SeekBarCallback callback;
|
|
||||||
|
|
||||||
public static NativeSeekBarDialog newSeekBarDialog(
|
|
||||||
int layout, int min, int max, int initial, int requestCode) {
|
|
||||||
NativeSeekBarDialog dialog = new NativeSeekBarDialog();
|
|
||||||
Bundle args = new Bundle();
|
|
||||||
args.putInt(EXTRA_LAYOUT, layout);
|
|
||||||
args.putInt(EXTRA_MIN, min);
|
|
||||||
args.putInt(EXTRA_MAX, max);
|
|
||||||
args.putInt(EXTRA_INITIAL_VALUE, initial);
|
|
||||||
args.putInt(EXTRA_REQUEST_CODE, requestCode);
|
|
||||||
dialog.setArguments(args);
|
|
||||||
return dialog;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@Override
|
|
||||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
|
||||||
Bundle arguments = getArguments();
|
|
||||||
requestCode = arguments.getInt(EXTRA_REQUEST_CODE);
|
|
||||||
int initial =
|
|
||||||
savedInstanceState == null
|
|
||||||
? arguments.getInt(EXTRA_INITIAL_VALUE)
|
|
||||||
: savedInstanceState.getInt(EXTRA_INITIAL_VALUE);
|
|
||||||
int layout = arguments.getInt(EXTRA_LAYOUT);
|
|
||||||
|
|
||||||
LayoutInflater layoutInflater = theme.getLayoutInflater(getActivity());
|
|
||||||
View view = layoutInflater.inflate(layout, null);
|
|
||||||
ButterKnife.bind(this, view);
|
|
||||||
|
|
||||||
slider.setValueDescriptionProvider(value -> locale.formatNumber(value));
|
|
||||||
slider.setValueRange(arguments.getInt(EXTRA_MIN), arguments.getInt(EXTRA_MAX), false);
|
|
||||||
slider.setValue(initial, true);
|
|
||||||
min.setText(locale.formatNumber(slider.getMinValue()));
|
|
||||||
max.setText(locale.formatNumber(slider.getMaxValue()));
|
|
||||||
return dialogBuilder
|
|
||||||
.newDialog()
|
|
||||||
.setView(view)
|
|
||||||
.setPositiveButton(
|
|
||||||
android.R.string.ok,
|
|
||||||
(dialogInterface, i) -> callback.valueSelected(slider.getValue(), requestCode))
|
|
||||||
.setNegativeButton(android.R.string.cancel, null)
|
|
||||||
.create();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onAttach(Activity activity) {
|
|
||||||
super.onAttach(activity);
|
|
||||||
|
|
||||||
callback = (SeekBarCallback) activity;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onSaveInstanceState(Bundle outState) {
|
|
||||||
super.onSaveInstanceState(outState);
|
|
||||||
|
|
||||||
outState.putInt(EXTRA_INITIAL_VALUE, slider.getValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void inject(NativeDialogFragmentComponent component) {
|
|
||||||
component.inject(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface SeekBarCallback {
|
|
||||||
|
|
||||||
void valueSelected(int value, int requestCode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,87 +0,0 @@
|
|||||||
package org.tasks.dialogs;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.app.Dialog;
|
|
||||||
import android.app.TimePickerDialog;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.DialogInterface;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.widget.TimePicker;
|
|
||||||
import com.todoroo.andlib.utility.DateUtilities;
|
|
||||||
import javax.inject.Inject;
|
|
||||||
import org.tasks.injection.InjectingNativeDialogFragment;
|
|
||||||
import org.tasks.injection.NativeDialogFragmentComponent;
|
|
||||||
import org.tasks.themes.Theme;
|
|
||||||
import org.tasks.time.DateTime;
|
|
||||||
|
|
||||||
public class NativeTimePickerDialog extends InjectingNativeDialogFragment
|
|
||||||
implements TimePickerDialog.OnTimeSetListener {
|
|
||||||
|
|
||||||
private static final String EXTRA_HOUR = "extra_hour";
|
|
||||||
private static final String EXTRA_MINUTE = "extra_minute";
|
|
||||||
@Inject Theme theme;
|
|
||||||
private NativeTimePickerDialogCallback callback;
|
|
||||||
|
|
||||||
public static NativeTimePickerDialog newNativeTimePickerDialog(DateTime initial) {
|
|
||||||
NativeTimePickerDialog dialog = new NativeTimePickerDialog();
|
|
||||||
Bundle args = new Bundle();
|
|
||||||
args.putInt(EXTRA_HOUR, initial.getHourOfDay());
|
|
||||||
args.putInt(EXTRA_MINUTE, initial.getMinuteOfHour());
|
|
||||||
dialog.setArguments(args);
|
|
||||||
return dialog;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
|
|
||||||
setRetainInstance(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
|
||||||
Bundle args = getArguments();
|
|
||||||
Context context = getActivity();
|
|
||||||
theme.applyToContext(context);
|
|
||||||
TimePickerDialog timePickerDialog =
|
|
||||||
new TimePickerDialog(
|
|
||||||
context,
|
|
||||||
this,
|
|
||||||
args.getInt(EXTRA_HOUR),
|
|
||||||
args.getInt(EXTRA_MINUTE),
|
|
||||||
DateUtilities.is24HourFormat(context));
|
|
||||||
timePickerDialog.setTitle("");
|
|
||||||
return timePickerDialog;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCancel(DialogInterface dialog) {
|
|
||||||
super.onCancel(dialog);
|
|
||||||
|
|
||||||
callback.cancel();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onTimeSet(TimePicker timePicker, int hour, int minute) {
|
|
||||||
callback.onTimeSet(hour, minute);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onAttach(Activity activity) {
|
|
||||||
super.onAttach(activity);
|
|
||||||
|
|
||||||
callback = (NativeTimePickerDialogCallback) activity;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void inject(NativeDialogFragmentComponent component) {
|
|
||||||
component.inject(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface NativeTimePickerDialogCallback {
|
|
||||||
|
|
||||||
void cancel();
|
|
||||||
|
|
||||||
void onTimeSet(int hour, int minute);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,33 +0,0 @@
|
|||||||
package org.tasks.injection;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.app.Dialog;
|
|
||||||
import android.app.DialogFragment;
|
|
||||||
|
|
||||||
public abstract class InjectingNativeDialogFragment extends DialogFragment {
|
|
||||||
|
|
||||||
private boolean injected;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onAttach(Activity activity) {
|
|
||||||
super.onAttach(activity);
|
|
||||||
|
|
||||||
if (!injected) {
|
|
||||||
inject(
|
|
||||||
((InjectingActivity) activity).getComponent().plus(new NativeDialogFragmentModule(this)));
|
|
||||||
injected = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDestroyView() {
|
|
||||||
// https://code.google.com/p/android/issues/detail?id=17423
|
|
||||||
Dialog dialog = getDialog();
|
|
||||||
if (dialog != null && getRetainInstance()) {
|
|
||||||
dialog.setDismissMessage(null);
|
|
||||||
}
|
|
||||||
super.onDestroyView();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract void inject(NativeDialogFragmentComponent component);
|
|
||||||
}
|
|
||||||
@ -1,215 +0,0 @@
|
|||||||
package org.tasks.injection;
|
|
||||||
|
|
||||||
import android.content.ComponentName;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.pm.ActivityInfo;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.preference.Preference;
|
|
||||||
import android.preference.PreferenceCategory;
|
|
||||||
import android.preference.PreferenceGroup;
|
|
||||||
import android.view.MenuItem;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.LinearLayout;
|
|
||||||
import androidx.appcompat.widget.Toolbar;
|
|
||||||
import androidx.appcompat.widget.Toolbar.OnMenuItemClickListener;
|
|
||||||
import androidx.core.content.ContextCompat;
|
|
||||||
import com.jakewharton.processphoenix.ProcessPhoenix;
|
|
||||||
import com.todoroo.astrid.activity.MainActivity;
|
|
||||||
import com.todoroo.astrid.api.Filter;
|
|
||||||
import javax.inject.Inject;
|
|
||||||
import org.tasks.R;
|
|
||||||
import org.tasks.dialogs.DialogBuilder;
|
|
||||||
import org.tasks.locale.Locale;
|
|
||||||
import org.tasks.preferences.AppCompatPreferenceActivity;
|
|
||||||
import org.tasks.preferences.Device;
|
|
||||||
import org.tasks.themes.Theme;
|
|
||||||
import org.tasks.ui.MenuColorizer;
|
|
||||||
import timber.log.Timber;
|
|
||||||
|
|
||||||
public abstract class InjectingPreferenceActivity extends AppCompatPreferenceActivity
|
|
||||||
implements InjectingActivity, OnMenuItemClickListener {
|
|
||||||
|
|
||||||
public static final String EXTRA_RESTART = "extra_restart";
|
|
||||||
private static final String EXTRA_BUNDLE = "extra_bundle";
|
|
||||||
|
|
||||||
@Inject DialogBuilder dialogBuilder;
|
|
||||||
@Inject Device device;
|
|
||||||
|
|
||||||
private ActivityComponent activityComponent;
|
|
||||||
private Bundle result;
|
|
||||||
|
|
||||||
protected InjectingPreferenceActivity() {
|
|
||||||
Locale.getInstance(this).applyOverrideConfiguration(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
|
||||||
activityComponent =
|
|
||||||
((InjectingApplication) getApplication()).getComponent().plus(new ActivityModule(this));
|
|
||||||
inject(activityComponent);
|
|
||||||
|
|
||||||
Theme theme = activityComponent.getTheme();
|
|
||||||
|
|
||||||
theme.applyThemeAndStatusBarColor(this, getDelegate());
|
|
||||||
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
|
|
||||||
result = savedInstanceState == null ? new Bundle() : savedInstanceState.getBundle(EXTRA_BUNDLE);
|
|
||||||
|
|
||||||
ViewGroup root = findViewById(android.R.id.content);
|
|
||||||
View content = root.getChildAt(0);
|
|
||||||
LinearLayout toolbarContainer =
|
|
||||||
(LinearLayout) View.inflate(this, R.layout.activity_prefs, null);
|
|
||||||
|
|
||||||
root.removeAllViews();
|
|
||||||
toolbarContainer.addView(content);
|
|
||||||
root.addView(toolbarContainer);
|
|
||||||
|
|
||||||
Toolbar toolbar = toolbarContainer.findViewById(R.id.toolbar);
|
|
||||||
try {
|
|
||||||
ComponentName componentName = new ComponentName(this, getClass());
|
|
||||||
ActivityInfo activityInfo = getPackageManager().getActivityInfo(componentName, 0);
|
|
||||||
toolbar.setTitle(activityInfo.labelRes);
|
|
||||||
} catch (Exception e) {
|
|
||||||
Timber.e(e);
|
|
||||||
toolbar.setTitle(getTitle());
|
|
||||||
}
|
|
||||||
toolbar.setNavigationIcon(
|
|
||||||
ContextCompat.getDrawable(this, R.drawable.ic_outline_arrow_back_24px));
|
|
||||||
toolbar.setNavigationOnClickListener(v -> finish());
|
|
||||||
toolbar.inflateMenu(R.menu.menu_preferences);
|
|
||||||
toolbar.setOnMenuItemClickListener(this);
|
|
||||||
MenuColorizer.colorToolbar(this, toolbar);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ActivityComponent getComponent() {
|
|
||||||
return activityComponent;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void requires(int prefGroup, boolean passesCheck, int... resIds) {
|
|
||||||
if (!passesCheck) {
|
|
||||||
remove((PreferenceCategory) findPreference(getString(prefGroup)), resIds);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void requires(boolean passesCheck, int... resIds) {
|
|
||||||
if (!passesCheck) {
|
|
||||||
remove(resIds);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void remove(int... resIds) {
|
|
||||||
//noinspection deprecation
|
|
||||||
remove(getPreferenceScreen(), resIds);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void remove(PreferenceGroup preferenceGroup, int[] resIds) {
|
|
||||||
for (int resId : resIds) {
|
|
||||||
preferenceGroup.removePreference(findPreference(resId));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings({"deprecation", "EmptyMethod"})
|
|
||||||
@Override
|
|
||||||
public void addPreferencesFromResource(int preferencesResId) {
|
|
||||||
super.addPreferencesFromResource(preferencesResId);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Preference findPreference(int resId) {
|
|
||||||
return findPreference(getString(resId));
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Preference findPreference(String key) {
|
|
||||||
//noinspection deprecation
|
|
||||||
return super.findPreference(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void showRestartDialog() {
|
|
||||||
dialogBuilder
|
|
||||||
.newDialog()
|
|
||||||
.setMessage(R.string.restart_required)
|
|
||||||
.setPositiveButton(
|
|
||||||
R.string.restart_now,
|
|
||||||
(dialogInterface, i) -> {
|
|
||||||
Intent nextIntent = new Intent(InjectingPreferenceActivity.this, MainActivity.class);
|
|
||||||
nextIntent.putExtra(MainActivity.OPEN_FILTER, (Filter) null);
|
|
||||||
ProcessPhoenix.triggerRebirth(InjectingPreferenceActivity.this, nextIntent);
|
|
||||||
})
|
|
||||||
.setNegativeButton(R.string.restart_later, null)
|
|
||||||
.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onMenuItemClick(MenuItem item) {
|
|
||||||
switch (item.getItemId()) {
|
|
||||||
case R.id.menu_contact:
|
|
||||||
emailSupport();
|
|
||||||
return true;
|
|
||||||
case R.id.menu_help:
|
|
||||||
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(getHelpUrl())));
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onSaveInstanceState(Bundle outState) {
|
|
||||||
super.onSaveInstanceState(outState);
|
|
||||||
|
|
||||||
outState.putBundle(EXTRA_BUNDLE, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void finish() {
|
|
||||||
Intent data = new Intent();
|
|
||||||
data.putExtras(result);
|
|
||||||
setResult(RESULT_OK, data);
|
|
||||||
super.finish();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void restart() {
|
|
||||||
Intent intent = getIntent();
|
|
||||||
finish();
|
|
||||||
startActivity(intent);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void emailSupport() {
|
|
||||||
startActivity(
|
|
||||||
new Intent(
|
|
||||||
Intent.ACTION_SENDTO,
|
|
||||||
Uri.fromParts("mailto", "Alex <" + getString(R.string.support_email) + ">", null))
|
|
||||||
.putExtra(Intent.EXTRA_SUBJECT, "Tasks Feedback")
|
|
||||||
.putExtra(Intent.EXTRA_TEXT, device.getDebugInfo()));
|
|
||||||
}
|
|
||||||
|
|
||||||
protected String getHelpUrl() {
|
|
||||||
return "http://tasks.org/help";
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void forceRestart() {
|
|
||||||
result.putBoolean(EXTRA_RESTART, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void mergeResults(Bundle bundle) {
|
|
||||||
result.putAll(bundle);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void setExtraOnChange(final String extra, final int... resIds) {
|
|
||||||
for (int resId : resIds) {
|
|
||||||
setExtraOnChange(resId, extra);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void setExtraOnChange(final int resId, final String extra) {
|
|
||||||
findPreference(getString(resId))
|
|
||||||
.setOnPreferenceChangeListener(
|
|
||||||
(preference, newValue) -> {
|
|
||||||
result.putBoolean(extra, true);
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,28 +0,0 @@
|
|||||||
package org.tasks.injection;
|
|
||||||
|
|
||||||
import dagger.Subcomponent;
|
|
||||||
import org.tasks.activities.RemoteListNativePicker;
|
|
||||||
import org.tasks.dialogs.ExportTasksDialog;
|
|
||||||
import org.tasks.dialogs.ImportTasksDialog;
|
|
||||||
import org.tasks.dialogs.NativeDatePickerDialog;
|
|
||||||
import org.tasks.dialogs.NativeSeekBarDialog;
|
|
||||||
import org.tasks.dialogs.NativeTimePickerDialog;
|
|
||||||
import org.tasks.locale.LocalePickerDialog;
|
|
||||||
|
|
||||||
@Subcomponent(modules = NativeDialogFragmentModule.class)
|
|
||||||
public interface NativeDialogFragmentComponent {
|
|
||||||
|
|
||||||
void inject(RemoteListNativePicker remoteListNativePicker);
|
|
||||||
|
|
||||||
void inject(LocalePickerDialog localePickerDialog);
|
|
||||||
|
|
||||||
void inject(NativeDatePickerDialog nativeDatePickerDialog);
|
|
||||||
|
|
||||||
void inject(NativeTimePickerDialog nativeTimePickerDialog);
|
|
||||||
|
|
||||||
void inject(NativeSeekBarDialog nativeSeekBarDialog);
|
|
||||||
|
|
||||||
void inject(ExportTasksDialog exportTasksDialog);
|
|
||||||
|
|
||||||
void inject(ImportTasksDialog importTasksDialog);
|
|
||||||
}
|
|
||||||
@ -1,21 +0,0 @@
|
|||||||
package org.tasks.injection;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.app.DialogFragment;
|
|
||||||
import dagger.Module;
|
|
||||||
import dagger.Provides;
|
|
||||||
|
|
||||||
@Module
|
|
||||||
public class NativeDialogFragmentModule {
|
|
||||||
|
|
||||||
private final DialogFragment dialogFragment;
|
|
||||||
|
|
||||||
public NativeDialogFragmentModule(DialogFragment dialogFragment) {
|
|
||||||
this.dialogFragment = dialogFragment;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Provides
|
|
||||||
public Activity getActivity() {
|
|
||||||
return dialogFragment.getActivity();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,120 +0,0 @@
|
|||||||
package org.tasks.preferences;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (C) 2014 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import android.content.res.Configuration;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.preference.PreferenceActivity;
|
|
||||||
import android.view.MenuInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import androidx.annotation.LayoutRes;
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.appcompat.app.AppCompatDelegate;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A {@link android.preference.PreferenceActivity} which implements and proxies the necessary calls
|
|
||||||
* to be used with AppCompat.
|
|
||||||
*
|
|
||||||
* <p>This technique can be used with an {@link android.app.Activity} class, not just {@link
|
|
||||||
* android.preference.PreferenceActivity}.
|
|
||||||
*/
|
|
||||||
public abstract class AppCompatPreferenceActivity extends PreferenceActivity {
|
|
||||||
|
|
||||||
private AppCompatDelegate mDelegate;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
|
||||||
getDelegate().installViewFactory();
|
|
||||||
getDelegate().onCreate(savedInstanceState);
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onPostCreate(Bundle savedInstanceState) {
|
|
||||||
super.onPostCreate(savedInstanceState);
|
|
||||||
getDelegate().onPostCreate(savedInstanceState);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@Override
|
|
||||||
public MenuInflater getMenuInflater() {
|
|
||||||
return getDelegate().getMenuInflater();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setContentView(@LayoutRes int layoutResID) {
|
|
||||||
getDelegate().setContentView(layoutResID);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setContentView(View view) {
|
|
||||||
getDelegate().setContentView(view);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setContentView(View view, ViewGroup.LayoutParams params) {
|
|
||||||
getDelegate().setContentView(view, params);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addContentView(View view, ViewGroup.LayoutParams params) {
|
|
||||||
getDelegate().addContentView(view, params);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onPostResume() {
|
|
||||||
super.onPostResume();
|
|
||||||
getDelegate().onPostResume();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onTitleChanged(CharSequence title, int color) {
|
|
||||||
super.onTitleChanged(title, color);
|
|
||||||
getDelegate().setTitle(title);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onConfigurationChanged(Configuration newConfig) {
|
|
||||||
super.onConfigurationChanged(newConfig);
|
|
||||||
getDelegate().onConfigurationChanged(newConfig);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onStop() {
|
|
||||||
super.onStop();
|
|
||||||
getDelegate().onStop();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onDestroy() {
|
|
||||||
super.onDestroy();
|
|
||||||
getDelegate().onDestroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void invalidateOptionsMenu() {
|
|
||||||
getDelegate().invalidateOptionsMenu();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected AppCompatDelegate getDelegate() {
|
|
||||||
if (mDelegate == null) {
|
|
||||||
mDelegate = AppCompatDelegate.create(this, null);
|
|
||||||
}
|
|
||||||
return mDelegate;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,724 +0,0 @@
|
|||||||
package org.tasks.preferences;
|
|
||||||
|
|
||||||
import static com.todoroo.andlib.utility.AndroidUtilities.atLeastJellybeanMR1;
|
|
||||||
import static com.todoroo.andlib.utility.AndroidUtilities.atLeastLollipop;
|
|
||||||
import static com.todoroo.andlib.utility.DateUtilities.now;
|
|
||||||
import static java.util.Arrays.asList;
|
|
||||||
import static org.tasks.PermissionUtil.verifyPermissions;
|
|
||||||
import static org.tasks.dialogs.ExportTasksDialog.newExportTasksDialog;
|
|
||||||
import static org.tasks.dialogs.ImportTasksDialog.newImportTasksDialog;
|
|
||||||
import static org.tasks.dialogs.NativeSeekBarDialog.newSeekBarDialog;
|
|
||||||
import static org.tasks.files.FileHelper.newFilePickerIntent;
|
|
||||||
import static org.tasks.files.FileHelper.uri2String;
|
|
||||||
import static org.tasks.locale.LocalePickerDialog.newLocalePickerDialog;
|
|
||||||
import static org.tasks.themes.ThemeColor.LAUNCHERS;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.content.ComponentName;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.pm.PackageManager;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.preference.CheckBoxPreference;
|
|
||||||
import android.preference.Preference;
|
|
||||||
import android.preference.PreferenceCategory;
|
|
||||||
import android.preference.PreferenceScreen;
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.appcompat.app.AlertDialog;
|
|
||||||
import com.google.common.base.Strings;
|
|
||||||
import com.todoroo.astrid.activity.BeastModePreferences;
|
|
||||||
import com.todoroo.astrid.api.Filter;
|
|
||||||
import com.todoroo.astrid.core.OldTaskPreferences;
|
|
||||||
import com.todoroo.astrid.gtasks.auth.GtasksLoginActivity;
|
|
||||||
import com.todoroo.astrid.reminders.ReminderPreferences;
|
|
||||||
import com.todoroo.astrid.service.TaskDeleter;
|
|
||||||
import java.util.List;
|
|
||||||
import javax.inject.Inject;
|
|
||||||
import org.tasks.BuildConfig;
|
|
||||||
import org.tasks.LocalBroadcastManager;
|
|
||||||
import org.tasks.R;
|
|
||||||
import org.tasks.activities.ColorPickerActivity;
|
|
||||||
import org.tasks.activities.ColorPickerActivity.ColorPalette;
|
|
||||||
import org.tasks.activities.FilterSelectionActivity;
|
|
||||||
import org.tasks.billing.Inventory;
|
|
||||||
import org.tasks.caldav.CaldavAccountSettingsActivity;
|
|
||||||
import org.tasks.data.CaldavAccount;
|
|
||||||
import org.tasks.data.CaldavDao;
|
|
||||||
import org.tasks.data.GoogleTaskAccount;
|
|
||||||
import org.tasks.data.GoogleTaskListDao;
|
|
||||||
import org.tasks.dialogs.DialogBuilder;
|
|
||||||
import org.tasks.dialogs.NativeSeekBarDialog;
|
|
||||||
import org.tasks.drive.DriveLoginActivity;
|
|
||||||
import org.tasks.etesync.EteSyncAccountSettingsActivity;
|
|
||||||
import org.tasks.files.FileHelper;
|
|
||||||
import org.tasks.gtasks.GoogleAccountManager;
|
|
||||||
import org.tasks.gtasks.PlayServices;
|
|
||||||
import org.tasks.injection.ActivityComponent;
|
|
||||||
import org.tasks.injection.InjectingPreferenceActivity;
|
|
||||||
import org.tasks.jobs.WorkManager;
|
|
||||||
import org.tasks.locale.Locale;
|
|
||||||
import org.tasks.locale.LocalePickerDialog;
|
|
||||||
import org.tasks.sync.AddAccountDialog;
|
|
||||||
import org.tasks.themes.ThemeAccent;
|
|
||||||
import org.tasks.themes.ThemeBase;
|
|
||||||
import org.tasks.themes.ThemeCache;
|
|
||||||
import org.tasks.themes.ThemeColor;
|
|
||||||
import org.tasks.ui.SingleCheckedArrayAdapter;
|
|
||||||
import org.tasks.ui.Toaster;
|
|
||||||
|
|
||||||
public class BasicPreferences extends InjectingPreferenceActivity
|
|
||||||
implements LocalePickerDialog.LocaleSelectionHandler, NativeSeekBarDialog.SeekBarCallback {
|
|
||||||
|
|
||||||
private static final String FRAG_TAG_LOCALE_PICKER = "frag_tag_locale_picker";
|
|
||||||
private static final String FRAG_TAG_IMPORT_TASKS = "frag_tag_import_tasks";
|
|
||||||
private static final String FRAG_TAG_EXPORT_TASKS = "frag_tag_export_tasks";
|
|
||||||
private static final String FRAG_TAG_ROW_PADDING_SEEKBAR = "frag_tag_row_padding_seekbar";
|
|
||||||
private static final String FRAG_TAG_FONT_SIZE_SEEKBAR = "frag_tag_font_size_seekbar";
|
|
||||||
private static final int RC_PREFS = 10001;
|
|
||||||
private static final int REQUEST_THEME_PICKER = 10002;
|
|
||||||
private static final int REQUEST_COLOR_PICKER = 10003;
|
|
||||||
private static final int REQUEST_ACCENT_PICKER = 10004;
|
|
||||||
private static final int REQUEST_CODE_BACKUP_DIR = 10005;
|
|
||||||
private static final int REQUEST_PICKER = 10006;
|
|
||||||
private static final int REQUEST_LAUNCHER_PICKER = 10007;
|
|
||||||
private static final int REQUEST_DRIVE_BACKUP = 10008;
|
|
||||||
private static final int REQUEST_DEFAULT_LIST = 10009;
|
|
||||||
private static final int REQUEST_ROW_PADDING = 10010;
|
|
||||||
private static final int REQUEST_FONT_SIZE = 10011;
|
|
||||||
private static final int REQUEST_CUSTOMIZE = 10012;
|
|
||||||
public static final int REQUEST_CALDAV_SETTINGS = 10013;
|
|
||||||
public static final int REQUEST_GOOGLE_TASKS = 10014;
|
|
||||||
|
|
||||||
@Inject Preferences preferences;
|
|
||||||
@Inject ThemeBase themeBase;
|
|
||||||
@Inject ThemeColor themeColor;
|
|
||||||
@Inject ThemeAccent themeAccent;
|
|
||||||
@Inject DialogBuilder dialogBuilder;
|
|
||||||
@Inject Locale locale;
|
|
||||||
@Inject ThemeCache themeCache;
|
|
||||||
@Inject Inventory inventory;
|
|
||||||
@Inject PlayServices playServices;
|
|
||||||
@Inject Toaster toaster;
|
|
||||||
@Inject ActivityPermissionRequestor permissionRequestor;
|
|
||||||
@Inject GoogleAccountManager googleAccountManager;
|
|
||||||
@Inject DefaultFilterProvider defaultFilterProvider;
|
|
||||||
@Inject LocalBroadcastManager localBroadcastManager;
|
|
||||||
@Inject WorkManager workManager;
|
|
||||||
@Inject GoogleTaskListDao googleTaskListDao;
|
|
||||||
@Inject CaldavDao caldavDao;
|
|
||||||
@Inject TaskDeleter taskDeleter;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
|
|
||||||
addPreferencesFromResource(R.xml.preferences);
|
|
||||||
|
|
||||||
setExtraOnChange(
|
|
||||||
EXTRA_RESTART,
|
|
||||||
R.string.p_fontSize,
|
|
||||||
R.string.p_rowPadding,
|
|
||||||
R.string.p_fullTaskTitle,
|
|
||||||
R.string.p_show_description,
|
|
||||||
R.string.p_show_full_description,
|
|
||||||
R.string.p_linkify_task_list,
|
|
||||||
R.string.p_show_list_indicators);
|
|
||||||
|
|
||||||
findPreference(R.string.p_show_subtasks)
|
|
||||||
.setOnPreferenceChangeListener((preference, newValue) -> {
|
|
||||||
forceRestart();
|
|
||||||
localBroadcastManager.broadcastRefresh();
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
|
|
||||||
findPreference(R.string.customize_edit_screen)
|
|
||||||
.setOnPreferenceClickListener(
|
|
||||||
preference -> {
|
|
||||||
startActivityForResult(
|
|
||||||
new Intent(BasicPreferences.this, BeastModePreferences.class),
|
|
||||||
REQUEST_CUSTOMIZE);
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
|
|
||||||
findPreference(R.string.p_fontSize)
|
|
||||||
.setOnPreferenceClickListener(
|
|
||||||
preference -> {
|
|
||||||
newSeekBarDialog(
|
|
||||||
R.layout.dialog_font_size_seekbar,
|
|
||||||
10,
|
|
||||||
48,
|
|
||||||
preferences.getFontSize(),
|
|
||||||
REQUEST_FONT_SIZE)
|
|
||||||
.show(getFragmentManager(), FRAG_TAG_FONT_SIZE_SEEKBAR);
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
updateFontSize();
|
|
||||||
|
|
||||||
findPreference(R.string.p_rowPadding)
|
|
||||||
.setOnPreferenceClickListener(
|
|
||||||
preference -> {
|
|
||||||
newSeekBarDialog(
|
|
||||||
R.layout.dialog_font_size_seekbar,
|
|
||||||
0,
|
|
||||||
16,
|
|
||||||
preferences.getRowPadding(),
|
|
||||||
REQUEST_ROW_PADDING)
|
|
||||||
.show(getFragmentManager(), FRAG_TAG_ROW_PADDING_SEEKBAR);
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
updateRowPadding();
|
|
||||||
Preference defaultList = findPreference(getString(R.string.p_default_list));
|
|
||||||
Filter filter = defaultFilterProvider.getDefaultFilter();
|
|
||||||
defaultList.setSummary(filter.listingTitle);
|
|
||||||
defaultList.setOnPreferenceClickListener(
|
|
||||||
preference -> {
|
|
||||||
Intent intent = new Intent(BasicPreferences.this, FilterSelectionActivity.class);
|
|
||||||
intent.putExtra(
|
|
||||||
FilterSelectionActivity.EXTRA_FILTER, defaultFilterProvider.getDefaultFilter());
|
|
||||||
intent.putExtra(FilterSelectionActivity.EXTRA_RETURN_FILTER, true);
|
|
||||||
startActivityForResult(intent, REQUEST_DEFAULT_LIST);
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
|
|
||||||
setupActivity(R.string.notifications, ReminderPreferences.class);
|
|
||||||
setupActivity(R.string.EPr_manage_header, OldTaskPreferences.class);
|
|
||||||
setupActivity(R.string.debug, DebugPreferences.class);
|
|
||||||
|
|
||||||
Preference themePreference = findPreference(getString(R.string.p_theme));
|
|
||||||
themePreference.setSummary(themeBase.getName());
|
|
||||||
themePreference.setOnPreferenceClickListener(
|
|
||||||
preference -> {
|
|
||||||
Intent intent = new Intent(BasicPreferences.this, ColorPickerActivity.class);
|
|
||||||
intent.putExtra(ColorPickerActivity.EXTRA_PALETTE, ColorPalette.THEMES);
|
|
||||||
startActivityForResult(intent, REQUEST_THEME_PICKER);
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
Preference colorPreference = findPreference(getString(R.string.p_theme_color));
|
|
||||||
colorPreference.setSummary(themeColor.getName());
|
|
||||||
colorPreference.setOnPreferenceClickListener(
|
|
||||||
preference -> {
|
|
||||||
Intent intent = new Intent(BasicPreferences.this, ColorPickerActivity.class);
|
|
||||||
intent.putExtra(ColorPickerActivity.EXTRA_PALETTE, ColorPalette.COLORS);
|
|
||||||
startActivityForResult(intent, REQUEST_COLOR_PICKER);
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
Preference accentPreference = findPreference(getString(R.string.p_theme_accent));
|
|
||||||
accentPreference.setSummary(themeAccent.getName());
|
|
||||||
accentPreference.setOnPreferenceClickListener(
|
|
||||||
preference -> {
|
|
||||||
Intent intent = new Intent(BasicPreferences.this, ColorPickerActivity.class);
|
|
||||||
intent.putExtra(ColorPickerActivity.EXTRA_PALETTE, ColorPalette.ACCENTS);
|
|
||||||
startActivityForResult(intent, REQUEST_ACCENT_PICKER);
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
Preference launcherPreference = findPreference(getString(R.string.p_theme_launcher));
|
|
||||||
ThemeColor launcherColor =
|
|
||||||
themeCache.getThemeColor(preferences.getInt(R.string.p_theme_launcher, 7));
|
|
||||||
launcherPreference.setSummary(launcherColor.getName());
|
|
||||||
launcherPreference.setOnPreferenceClickListener(
|
|
||||||
preference -> {
|
|
||||||
Intent intent = new Intent(BasicPreferences.this, ColorPickerActivity.class);
|
|
||||||
intent.putExtra(ColorPickerActivity.EXTRA_PALETTE, ColorPalette.LAUNCHER);
|
|
||||||
startActivityForResult(intent, REQUEST_LAUNCHER_PICKER);
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
Preference languagePreference = findPreference(getString(R.string.p_language));
|
|
||||||
updateLocale();
|
|
||||||
languagePreference.setOnPreferenceClickListener(
|
|
||||||
preference -> {
|
|
||||||
newLocalePickerDialog().show(getFragmentManager(), FRAG_TAG_LOCALE_PICKER);
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
findPreference(getString(R.string.p_layout_direction))
|
|
||||||
.setOnPreferenceChangeListener(
|
|
||||||
(preference, o) -> {
|
|
||||||
int newValue = Integer.parseInt((String) o);
|
|
||||||
if (locale.getDirectionality()
|
|
||||||
!= locale.withDirectionality(newValue).getDirectionality()) {
|
|
||||||
showRestartDialog();
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
|
|
||||||
findPreference(R.string.backup_BAc_import)
|
|
||||||
.setOnPreferenceClickListener(
|
|
||||||
preference -> {
|
|
||||||
startActivityForResult(
|
|
||||||
newFilePickerIntent(BasicPreferences.this, preferences.getBackupDirectory()),
|
|
||||||
REQUEST_PICKER);
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
|
|
||||||
findPreference(R.string.backup_BAc_export)
|
|
||||||
.setOnPreferenceClickListener(
|
|
||||||
preference -> {
|
|
||||||
newExportTasksDialog().show(getFragmentManager(), FRAG_TAG_EXPORT_TASKS);
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
|
|
||||||
initializeBackupDirectory();
|
|
||||||
|
|
||||||
CheckBoxPreference googleDriveBackup =
|
|
||||||
(CheckBoxPreference) findPreference(R.string.p_google_drive_backup);
|
|
||||||
googleDriveBackup.setOnPreferenceChangeListener(
|
|
||||||
(preference, newValue) -> {
|
|
||||||
if (newValue == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((Boolean) newValue) {
|
|
||||||
if (permissionRequestor.requestAccountPermissions()) {
|
|
||||||
requestGoogleDriveLogin();
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
preference.setSummary(null);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
findPreference(getString(R.string.p_background_sync_unmetered_only))
|
|
||||||
.setOnPreferenceChangeListener(
|
|
||||||
(preference, o) -> {
|
|
||||||
workManager.updateBackgroundSync(null, null, (Boolean) o);
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
findPreference(getString(R.string.p_background_sync))
|
|
||||||
.setOnPreferenceChangeListener(
|
|
||||||
(preference, o) -> {
|
|
||||||
workManager.updateBackgroundSync(null, (Boolean) o, null);
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
CheckBoxPreference positionHack =
|
|
||||||
(CheckBoxPreference) findPreference(R.string.google_tasks_position_hack);
|
|
||||||
positionHack.setChecked(preferences.isPositionHackEnabled());
|
|
||||||
positionHack.setOnPreferenceChangeListener(
|
|
||||||
(preference, newValue) -> {
|
|
||||||
if (newValue == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
preferences.setLong(
|
|
||||||
R.string.p_google_tasks_position_hack, ((Boolean) newValue) ? now() : 0);
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
findPreference(R.string.add_account)
|
|
||||||
.setOnPreferenceClickListener(
|
|
||||||
preference -> {
|
|
||||||
AddAccountDialog.showAddAccountDialog(BasicPreferences.this, dialogBuilder);
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
|
|
||||||
requires(
|
|
||||||
R.string.settings_localization,
|
|
||||||
atLeastJellybeanMR1(),
|
|
||||||
R.string.p_language,
|
|
||||||
R.string.p_layout_direction);
|
|
||||||
|
|
||||||
requires(R.string.task_list_options, atLeastLollipop(), R.string.p_show_subtasks);
|
|
||||||
|
|
||||||
requires(BuildConfig.DEBUG, R.string.debug);
|
|
||||||
|
|
||||||
//noinspection ConstantConditions
|
|
||||||
if (!BuildConfig.FLAVOR.equals("googleplay")) {
|
|
||||||
removeGroup(R.string.TEA_control_location);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void removeGroup(int key) {
|
|
||||||
Preference preference = findPreference(key);
|
|
||||||
if (preference != null) {
|
|
||||||
((PreferenceScreen) findPreference(R.string.preference_screen)).removePreference(preference);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onResume() {
|
|
||||||
super.onResume();
|
|
||||||
|
|
||||||
CheckBoxPreference googleDriveBackup =
|
|
||||||
(CheckBoxPreference) findPreference(R.string.p_google_drive_backup);
|
|
||||||
String account = preferences.getStringValue(R.string.p_google_drive_backup_account);
|
|
||||||
if (preferences.getBoolean(R.string.p_google_drive_backup, false)
|
|
||||||
&& googleAccountManager.canAccessAccount(account)) {
|
|
||||||
googleDriveBackup.setChecked(true);
|
|
||||||
googleDriveBackup.setSummary(account);
|
|
||||||
} else {
|
|
||||||
googleDriveBackup.setChecked(false);
|
|
||||||
}
|
|
||||||
googleDriveBackup.setChecked(preferences.getBoolean(R.string.p_google_drive_backup, false));
|
|
||||||
|
|
||||||
PreferenceCategory synchronizationPreferences =
|
|
||||||
(PreferenceCategory) findPreference(R.string.synchronization);
|
|
||||||
synchronizationPreferences.removeAll();
|
|
||||||
|
|
||||||
boolean hasGoogleAccounts = addGoogleTasksAccounts(synchronizationPreferences);
|
|
||||||
boolean hasCaldavAccounts = addCaldavAccounts(synchronizationPreferences);
|
|
||||||
if (!hasGoogleAccounts) {
|
|
||||||
removeGroup(R.string.gtasks_GPr_header);
|
|
||||||
}
|
|
||||||
if (!(hasGoogleAccounts || hasCaldavAccounts)) {
|
|
||||||
removeGroup(R.string.sync_SPr_interval_title);
|
|
||||||
}
|
|
||||||
|
|
||||||
//noinspection ConstantConditions
|
|
||||||
if (!BuildConfig.FLAVOR.equals("googleplay")) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
List<String> choices =
|
|
||||||
asList(getString(R.string.map_provider_mapbox), getString(R.string.map_provider_google));
|
|
||||||
SingleCheckedArrayAdapter singleCheckedArrayAdapter =
|
|
||||||
new SingleCheckedArrayAdapter(this, choices, themeAccent);
|
|
||||||
Preference mapProviderPreference = findPreference(R.string.p_map_provider);
|
|
||||||
mapProviderPreference.setOnPreferenceClickListener(
|
|
||||||
preference -> {
|
|
||||||
dialogBuilder
|
|
||||||
.newDialog()
|
|
||||||
.setSingleChoiceItems(
|
|
||||||
singleCheckedArrayAdapter,
|
|
||||||
getMapProvider(),
|
|
||||||
(dialog, which) -> {
|
|
||||||
if (which == 1) {
|
|
||||||
if (!playServices.refreshAndCheck()) {
|
|
||||||
playServices.resolve(this);
|
|
||||||
dialog.dismiss();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
preferences.setInt(R.string.p_map_provider, which);
|
|
||||||
mapProviderPreference.setSummary(choices.get(which));
|
|
||||||
dialog.dismiss();
|
|
||||||
})
|
|
||||||
.setNegativeButton(android.R.string.cancel, null)
|
|
||||||
.showThemedListView();
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
int mapProvider = getMapProvider();
|
|
||||||
mapProviderPreference.setSummary(
|
|
||||||
mapProvider == -1 ? getString(R.string.none) : choices.get(mapProvider));
|
|
||||||
|
|
||||||
Preference placeProviderPreference = findPreference(R.string.p_place_provider);
|
|
||||||
placeProviderPreference.setOnPreferenceClickListener(
|
|
||||||
preference -> {
|
|
||||||
dialogBuilder
|
|
||||||
.newDialog()
|
|
||||||
.setSingleChoiceItems(
|
|
||||||
singleCheckedArrayAdapter,
|
|
||||||
getPlaceProvider(),
|
|
||||||
(dialog, which) -> {
|
|
||||||
if (which == 1) {
|
|
||||||
if (!playServices.refreshAndCheck()) {
|
|
||||||
playServices.resolve(this);
|
|
||||||
dialog.dismiss();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!inventory.hasPro()) {
|
|
||||||
toaster.longToast(R.string.requires_pro_subscription);
|
|
||||||
dialog.dismiss();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
preferences.setInt(R.string.p_place_provider, which);
|
|
||||||
placeProviderPreference.setSummary(choices.get(which));
|
|
||||||
dialog.dismiss();
|
|
||||||
})
|
|
||||||
.setNegativeButton(android.R.string.cancel, null)
|
|
||||||
.showThemedListView();
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
int placeProvider = getPlaceProvider();
|
|
||||||
placeProviderPreference.setSummary(choices.get(placeProvider));
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean addGoogleTasksAccounts(PreferenceCategory category) {
|
|
||||||
List<GoogleTaskAccount> accounts = googleTaskListDao.getAccounts();
|
|
||||||
for (GoogleTaskAccount googleTaskAccount : accounts) {
|
|
||||||
String account = googleTaskAccount.getAccount();
|
|
||||||
Preference preference = new Preference(this);
|
|
||||||
preference.setTitle(account);
|
|
||||||
String error = googleTaskAccount.getError();
|
|
||||||
if (Strings.isNullOrEmpty(error)) {
|
|
||||||
preference.setSummary(R.string.gtasks_GPr_header);
|
|
||||||
} else {
|
|
||||||
preference.setSummary(error);
|
|
||||||
}
|
|
||||||
preference.setOnPreferenceClickListener(
|
|
||||||
p -> {
|
|
||||||
dialogBuilder
|
|
||||||
.newDialog(account)
|
|
||||||
.setItems(
|
|
||||||
asList(getString(R.string.reinitialize_account), getString(R.string.logout)),
|
|
||||||
(dialog, which) -> {
|
|
||||||
if (which == 0) {
|
|
||||||
startActivityForResult(
|
|
||||||
new Intent(this, GtasksLoginActivity.class),
|
|
||||||
BasicPreferences.REQUEST_GOOGLE_TASKS);
|
|
||||||
} else {
|
|
||||||
logoutConfirmation(googleTaskAccount);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.showThemedListView();
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
category.addPreference(preference);
|
|
||||||
}
|
|
||||||
return !accounts.isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean addCaldavAccounts(PreferenceCategory category) {
|
|
||||||
List<CaldavAccount> accounts = caldavDao.getAccounts();
|
|
||||||
for (CaldavAccount account : accounts) {
|
|
||||||
Preference preference = new Preference(this);
|
|
||||||
preference.setTitle(account.getName());
|
|
||||||
String error = account.getError();
|
|
||||||
if (Strings.isNullOrEmpty(error)) {
|
|
||||||
preference.setSummary(
|
|
||||||
account.isCaldavAccount() ? R.string.caldav : R.string.etesync);
|
|
||||||
} else {
|
|
||||||
preference.setSummary(error);
|
|
||||||
}
|
|
||||||
preference.setOnPreferenceClickListener(
|
|
||||||
p -> {
|
|
||||||
Intent intent =
|
|
||||||
new Intent(
|
|
||||||
this,
|
|
||||||
account.isCaldavAccount()
|
|
||||||
? CaldavAccountSettingsActivity.class
|
|
||||||
: EteSyncAccountSettingsActivity.class);
|
|
||||||
intent.putExtra(CaldavAccountSettingsActivity.EXTRA_CALDAV_DATA, account);
|
|
||||||
startActivityForResult(intent, REQUEST_CALDAV_SETTINGS);
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
category.addPreference(preference);
|
|
||||||
}
|
|
||||||
return !accounts.isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void logoutConfirmation(GoogleTaskAccount account) {
|
|
||||||
String name = account.getAccount();
|
|
||||||
AlertDialog alertDialog =
|
|
||||||
dialogBuilder
|
|
||||||
.newDialog()
|
|
||||||
.setMessage(R.string.logout_warning, name)
|
|
||||||
.setPositiveButton(
|
|
||||||
R.string.logout,
|
|
||||||
(dialog, which) -> {
|
|
||||||
taskDeleter.delete(account);
|
|
||||||
restart();
|
|
||||||
})
|
|
||||||
.setNegativeButton(android.R.string.cancel, null)
|
|
||||||
.create();
|
|
||||||
alertDialog.setCanceledOnTouchOutside(false);
|
|
||||||
alertDialog.setCancelable(false);
|
|
||||||
alertDialog.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
private int getPlaceProvider() {
|
|
||||||
return playServices.isPlayServicesAvailable() && inventory.hasPro()
|
|
||||||
? preferences.getInt(R.string.p_place_provider, 0)
|
|
||||||
: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int getMapProvider() {
|
|
||||||
return playServices.isPlayServicesAvailable()
|
|
||||||
? preferences.getInt(R.string.p_map_provider, 0)
|
|
||||||
: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void requestGoogleDriveLogin() {
|
|
||||||
startActivityForResult(new Intent(this, DriveLoginActivity.class), REQUEST_DRIVE_BACKUP);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setupActivity(int key, final Class<?> target) {
|
|
||||||
findPreference(getString(key))
|
|
||||||
.setOnPreferenceClickListener(
|
|
||||||
preference -> {
|
|
||||||
startActivityForResult(new Intent(BasicPreferences.this, target), RC_PREFS);
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onRequestPermissionsResult(
|
|
||||||
int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
|
||||||
if (requestCode == PermissionRequestor.REQUEST_GOOGLE_ACCOUNTS) {
|
|
||||||
if (verifyPermissions(grantResults)) {
|
|
||||||
requestGoogleDriveLogin();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
|
||||||
if (requestCode == REQUEST_THEME_PICKER) {
|
|
||||||
if (resultCode == RESULT_OK) {
|
|
||||||
int index = data.getIntExtra(ColorPickerActivity.EXTRA_THEME_INDEX, 0);
|
|
||||||
preferences.setInt(R.string.p_theme, index);
|
|
||||||
themeCache.getThemeBase(index).setDefaultNightMode();
|
|
||||||
forceRestart();
|
|
||||||
recreate();
|
|
||||||
}
|
|
||||||
} else if (requestCode == REQUEST_COLOR_PICKER) {
|
|
||||||
if (resultCode == RESULT_OK) {
|
|
||||||
int index = data.getIntExtra(ColorPickerActivity.EXTRA_THEME_INDEX, 0);
|
|
||||||
preferences.setInt(R.string.p_theme_color, index);
|
|
||||||
forceRestart();
|
|
||||||
recreate();
|
|
||||||
}
|
|
||||||
} else if (requestCode == REQUEST_ACCENT_PICKER) {
|
|
||||||
if (resultCode == RESULT_OK) {
|
|
||||||
int index = data.getIntExtra(ColorPickerActivity.EXTRA_THEME_INDEX, 0);
|
|
||||||
preferences.setInt(R.string.p_theme_accent, index);
|
|
||||||
forceRestart();
|
|
||||||
recreate();
|
|
||||||
}
|
|
||||||
} else if (requestCode == REQUEST_LAUNCHER_PICKER) {
|
|
||||||
if (resultCode == RESULT_OK) {
|
|
||||||
int index = data.getIntExtra(ColorPickerActivity.EXTRA_THEME_INDEX, 0);
|
|
||||||
setLauncherIcon(index);
|
|
||||||
preferences.setInt(R.string.p_theme_launcher, index);
|
|
||||||
recreate();
|
|
||||||
}
|
|
||||||
} else if (requestCode == RC_PREFS) {
|
|
||||||
if (resultCode == Activity.RESULT_OK && data != null) {
|
|
||||||
mergeResults(data.getExtras());
|
|
||||||
}
|
|
||||||
} else if (requestCode == REQUEST_CODE_BACKUP_DIR) {
|
|
||||||
if (resultCode == RESULT_OK && data != null) {
|
|
||||||
Uri uri = data.getData();
|
|
||||||
if (atLeastLollipop()) {
|
|
||||||
getContentResolver()
|
|
||||||
.takePersistableUriPermission(
|
|
||||||
uri,
|
|
||||||
Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
|
|
||||||
}
|
|
||||||
preferences.setUri(R.string.p_backup_dir, uri);
|
|
||||||
updateBackupDirectory();
|
|
||||||
}
|
|
||||||
} else if (requestCode == REQUEST_PICKER) {
|
|
||||||
if (resultCode == RESULT_OK) {
|
|
||||||
Uri uri = data.getData();
|
|
||||||
String extension = FileHelper.getExtension(this, uri);
|
|
||||||
if (!("json".equalsIgnoreCase(extension) || "xml".equalsIgnoreCase(extension))) {
|
|
||||||
toaster.longToast(R.string.invalid_backup_file);
|
|
||||||
} else {
|
|
||||||
newImportTasksDialog(uri, extension).show(getFragmentManager(), FRAG_TAG_IMPORT_TASKS);
|
|
||||||
forceRestart();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (requestCode == REQUEST_DRIVE_BACKUP) {
|
|
||||||
boolean success = resultCode == RESULT_OK;
|
|
||||||
((CheckBoxPreference) findPreference(R.string.p_google_drive_backup)).setChecked(success);
|
|
||||||
if (!success && data != null) {
|
|
||||||
toaster.longToast(data.getStringExtra(GtasksLoginActivity.EXTRA_ERROR));
|
|
||||||
}
|
|
||||||
} else if (requestCode == REQUEST_DEFAULT_LIST) {
|
|
||||||
if (resultCode == RESULT_OK) {
|
|
||||||
Filter filter = data.getParcelableExtra(FilterSelectionActivity.EXTRA_FILTER);
|
|
||||||
defaultFilterProvider.setDefaultFilter(filter);
|
|
||||||
findPreference(getString(R.string.p_default_list)).setSummary(filter.listingTitle);
|
|
||||||
localBroadcastManager.broadcastRefresh();
|
|
||||||
}
|
|
||||||
} else if (requestCode == REQUEST_CUSTOMIZE) {
|
|
||||||
if (resultCode == RESULT_OK) {
|
|
||||||
forceRestart();
|
|
||||||
}
|
|
||||||
} else if (requestCode == REQUEST_CALDAV_SETTINGS) {
|
|
||||||
if (resultCode == RESULT_OK) {
|
|
||||||
workManager.updateBackgroundSync();
|
|
||||||
restart();
|
|
||||||
}
|
|
||||||
} else if (requestCode == REQUEST_GOOGLE_TASKS) {
|
|
||||||
if (resultCode == RESULT_OK) {
|
|
||||||
workManager.updateBackgroundSync();
|
|
||||||
restart();
|
|
||||||
} else if (data != null) {
|
|
||||||
toaster.longToast(data.getStringExtra(GtasksLoginActivity.EXTRA_ERROR));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
super.onActivityResult(requestCode, resultCode, data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onLocaleSelected(Locale newValue) {
|
|
||||||
String override = newValue.getLanguageOverride();
|
|
||||||
if (Strings.isNullOrEmpty(override)) {
|
|
||||||
preferences.remove(R.string.p_language);
|
|
||||||
} else {
|
|
||||||
preferences.setString(R.string.p_language, override);
|
|
||||||
}
|
|
||||||
updateLocale();
|
|
||||||
if (!locale.equals(newValue)) {
|
|
||||||
showRestartDialog();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateLocale() {
|
|
||||||
Preference languagePreference = findPreference(getString(R.string.p_language));
|
|
||||||
String preference = preferences.getStringValue(R.string.p_language);
|
|
||||||
languagePreference.setSummary(locale.withLanguage(preference).getDisplayName());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initializeBackupDirectory() {
|
|
||||||
findPreference(getString(R.string.p_backup_dir))
|
|
||||||
.setOnPreferenceClickListener(
|
|
||||||
p -> {
|
|
||||||
FileHelper.newDirectoryPicker(
|
|
||||||
this, REQUEST_CODE_BACKUP_DIR, preferences.getBackupDirectory());
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
updateBackupDirectory();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateBackupDirectory() {
|
|
||||||
findPreference(getString(R.string.p_backup_dir))
|
|
||||||
.setSummary(uri2String(preferences.getBackupDirectory()));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setLauncherIcon(int index) {
|
|
||||||
PackageManager packageManager = getPackageManager();
|
|
||||||
for (int i = 0; i < LAUNCHERS.length; i++) {
|
|
||||||
ComponentName componentName =
|
|
||||||
new ComponentName(this, "com.todoroo.astrid.activity.TaskListActivity" + LAUNCHERS[i]);
|
|
||||||
packageManager.setComponentEnabledSetting(
|
|
||||||
componentName,
|
|
||||||
index == i
|
|
||||||
? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
|
|
||||||
: PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
|
|
||||||
PackageManager.DONT_KILL_APP);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateFontSize() {
|
|
||||||
findPreference(R.string.p_fontSize).setSummary(locale.formatNumber(preferences.getFontSize()));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateRowPadding() {
|
|
||||||
findPreference(R.string.p_rowPadding)
|
|
||||||
.setSummary(locale.formatNumber(preferences.getRowPadding()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void valueSelected(int value, int requestCode) {
|
|
||||||
int resId = 0;
|
|
||||||
if (requestCode == REQUEST_ROW_PADDING) {
|
|
||||||
preferences.setInt(R.string.p_rowPadding, value);
|
|
||||||
updateRowPadding();
|
|
||||||
resId = R.string.p_rowPadding;
|
|
||||||
} else if (requestCode == REQUEST_FONT_SIZE) {
|
|
||||||
preferences.setInt(R.string.p_fontSize, value);
|
|
||||||
updateFontSize();
|
|
||||||
resId = R.string.p_fontSize;
|
|
||||||
}
|
|
||||||
if (resId > 0) {
|
|
||||||
forceRestart();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void inject(ActivityComponent component) {
|
|
||||||
component.inject(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,183 +0,0 @@
|
|||||||
package org.tasks.preferences;
|
|
||||||
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.preference.ListPreference;
|
|
||||||
import android.preference.Preference;
|
|
||||||
import android.widget.Toast;
|
|
||||||
import javax.inject.Inject;
|
|
||||||
import org.tasks.R;
|
|
||||||
import org.tasks.activities.TimePickerActivity;
|
|
||||||
import org.tasks.injection.ActivityComponent;
|
|
||||||
import org.tasks.injection.InjectingPreferenceActivity;
|
|
||||||
import org.tasks.locale.Locale;
|
|
||||||
import org.tasks.time.DateTime;
|
|
||||||
import org.tasks.ui.TimePreference;
|
|
||||||
import org.threeten.bp.DayOfWeek;
|
|
||||||
import org.threeten.bp.format.TextStyle;
|
|
||||||
|
|
||||||
public class DateTimePreferences extends InjectingPreferenceActivity
|
|
||||||
implements Preference.OnPreferenceChangeListener {
|
|
||||||
|
|
||||||
private static final int REQUEST_MORNING = 10001;
|
|
||||||
private static final int REQUEST_AFTERNOON = 10002;
|
|
||||||
private static final int REQUEST_EVENING = 10003;
|
|
||||||
private static final int REQUEST_NIGHT = 10004;
|
|
||||||
|
|
||||||
@Inject Locale locale;
|
|
||||||
@Inject Preferences preferences;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
|
|
||||||
addPreferencesFromResource(R.xml.preferences_date_time);
|
|
||||||
|
|
||||||
ListPreference startOfWeekPreference = getStartOfWeekPreference();
|
|
||||||
startOfWeekPreference.setEntries(getWeekdayEntries());
|
|
||||||
startOfWeekPreference.setOnPreferenceChangeListener(this);
|
|
||||||
|
|
||||||
initializeTimePreference(getMorningPreference(), REQUEST_MORNING);
|
|
||||||
initializeTimePreference(getAfternoonPreference(), REQUEST_AFTERNOON);
|
|
||||||
initializeTimePreference(getEveningPreference(), REQUEST_EVENING);
|
|
||||||
initializeTimePreference(getNightPreference(), REQUEST_NIGHT);
|
|
||||||
|
|
||||||
updateStartOfWeek(preferences.getStringValue(R.string.p_start_of_week));
|
|
||||||
}
|
|
||||||
|
|
||||||
private String[] getWeekdayEntries() {
|
|
||||||
return new String[] {
|
|
||||||
getString(R.string.use_locale_default),
|
|
||||||
getWeekdayDisplayName(DayOfWeek.SUNDAY),
|
|
||||||
getWeekdayDisplayName(DayOfWeek.MONDAY)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getWeekdayDisplayName(DayOfWeek dayOfWeek) {
|
|
||||||
return dayOfWeek.getDisplayName(TextStyle.FULL, locale.getLocale());
|
|
||||||
}
|
|
||||||
|
|
||||||
private TimePreference getMorningPreference() {
|
|
||||||
return getTimePreference(R.string.p_date_shortcut_morning);
|
|
||||||
}
|
|
||||||
|
|
||||||
private TimePreference getAfternoonPreference() {
|
|
||||||
return getTimePreference(R.string.p_date_shortcut_afternoon);
|
|
||||||
}
|
|
||||||
|
|
||||||
private TimePreference getEveningPreference() {
|
|
||||||
return getTimePreference(R.string.p_date_shortcut_evening);
|
|
||||||
}
|
|
||||||
|
|
||||||
private TimePreference getNightPreference() {
|
|
||||||
return getTimePreference(R.string.p_date_shortcut_night);
|
|
||||||
}
|
|
||||||
|
|
||||||
private TimePreference getTimePreference(int resId) {
|
|
||||||
return (TimePreference) findPreference(getString(resId));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initializeTimePreference(final TimePreference preference, final int requestCode) {
|
|
||||||
preference.setOnPreferenceChangeListener(this);
|
|
||||||
preference.setOnPreferenceClickListener(
|
|
||||||
ignored -> {
|
|
||||||
final DateTime current = new DateTime().withMillisOfDay(preference.getMillisOfDay());
|
|
||||||
Intent intent = new Intent(DateTimePreferences.this, TimePickerActivity.class);
|
|
||||||
intent.putExtra(TimePickerActivity.EXTRA_TIMESTAMP, current.getMillis());
|
|
||||||
startActivityForResult(intent, requestCode);
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
|
||||||
if (resultCode == RESULT_OK) {
|
|
||||||
switch (requestCode) {
|
|
||||||
case REQUEST_MORNING:
|
|
||||||
getMorningPreference().handleTimePickerActivityIntent(data);
|
|
||||||
return;
|
|
||||||
case REQUEST_AFTERNOON:
|
|
||||||
getAfternoonPreference().handleTimePickerActivityIntent(data);
|
|
||||||
return;
|
|
||||||
case REQUEST_EVENING:
|
|
||||||
getEveningPreference().handleTimePickerActivityIntent(data);
|
|
||||||
return;
|
|
||||||
case REQUEST_NIGHT:
|
|
||||||
getNightPreference().handleTimePickerActivityIntent(data);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
super.onActivityResult(requestCode, resultCode, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
|
||||||
if (preference.equals(getStartOfWeekPreference())) {
|
|
||||||
updateStartOfWeek(newValue.toString());
|
|
||||||
} else {
|
|
||||||
int millisOfDay = (int) newValue;
|
|
||||||
|
|
||||||
if (preference.equals(getMorningPreference())) {
|
|
||||||
if (millisOfDay >= getAfternoonPreference().getMillisOfDay()) {
|
|
||||||
mustComeBefore(R.string.date_shortcut_morning, R.string.date_shortcut_afternoon);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else if (preference.equals(getAfternoonPreference())) {
|
|
||||||
if (millisOfDay <= getMorningPreference().getMillisOfDay()) {
|
|
||||||
mustComeAfter(R.string.date_shortcut_afternoon, R.string.date_shortcut_morning);
|
|
||||||
return false;
|
|
||||||
} else if (millisOfDay >= getEveningPreference().getMillisOfDay()) {
|
|
||||||
mustComeBefore(R.string.date_shortcut_afternoon, R.string.date_shortcut_evening);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else if (preference.equals(getEveningPreference())) {
|
|
||||||
if (millisOfDay <= getAfternoonPreference().getMillisOfDay()) {
|
|
||||||
mustComeAfter(R.string.date_shortcut_evening, R.string.date_shortcut_afternoon);
|
|
||||||
return false;
|
|
||||||
} else if (millisOfDay >= getNightPreference().getMillisOfDay()) {
|
|
||||||
mustComeBefore(R.string.date_shortcut_evening, R.string.date_shortcut_night);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else if (preference.equals(getNightPreference())) {
|
|
||||||
if (millisOfDay <= getEveningPreference().getMillisOfDay()) {
|
|
||||||
mustComeAfter(R.string.date_shortcut_night, R.string.date_shortcut_evening);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void mustComeBefore(int settingResId, int relativeResId) {
|
|
||||||
invalidSetting(R.string.date_shortcut_must_come_before, settingResId, relativeResId);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void mustComeAfter(int settingResId, int relativeResId) {
|
|
||||||
invalidSetting(R.string.date_shortcut_must_come_after, settingResId, relativeResId);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void invalidSetting(int errorResId, int settingResId, int relativeResId) {
|
|
||||||
Toast.makeText(
|
|
||||||
this,
|
|
||||||
getString(errorResId, getString(settingResId), getString(relativeResId)),
|
|
||||||
Toast.LENGTH_SHORT)
|
|
||||||
.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateStartOfWeek(String value) {
|
|
||||||
ListPreference preference = getStartOfWeekPreference();
|
|
||||||
int index = preference.findIndexOfValue(value);
|
|
||||||
String summary = getWeekdayEntries()[index];
|
|
||||||
preference.setSummary(summary);
|
|
||||||
}
|
|
||||||
|
|
||||||
private ListPreference getStartOfWeekPreference() {
|
|
||||||
return (ListPreference) findPreference(R.string.p_start_of_week);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void inject(ActivityComponent component) {
|
|
||||||
component.inject(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -0,0 +1,33 @@
|
|||||||
|
package org.tasks.preferences
|
||||||
|
|
||||||
|
import android.content.Intent
|
||||||
|
import android.view.MenuItem
|
||||||
|
import androidx.appcompat.widget.Toolbar
|
||||||
|
import org.tasks.R
|
||||||
|
import org.tasks.injection.ActivityComponent
|
||||||
|
import org.tasks.preferences.fragments.MainSettingsFragment
|
||||||
|
|
||||||
|
class MainPreferences : BasePreferences(), Toolbar.OnMenuItemClickListener {
|
||||||
|
|
||||||
|
override fun setupMenu() {
|
||||||
|
toolbar.inflateMenu(R.menu.menu_preferences)
|
||||||
|
toolbar.setOnMenuItemClickListener(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getRootTitle() = R.string.TLA_menu_settings
|
||||||
|
|
||||||
|
override fun getRootPreference() = MainSettingsFragment()
|
||||||
|
|
||||||
|
override fun inject(component: ActivityComponent) {
|
||||||
|
component.inject(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onMenuItemClick(item: MenuItem?): Boolean {
|
||||||
|
return if (item?.itemId == R.id.menu_help_and_feedback) {
|
||||||
|
startActivity(Intent(this, HelpAndFeedback::class.java))
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,16 @@
|
|||||||
|
package org.tasks.preferences
|
||||||
|
|
||||||
|
import org.tasks.R
|
||||||
|
import org.tasks.injection.ActivityComponent
|
||||||
|
import org.tasks.preferences.fragments.Advanced
|
||||||
|
import org.tasks.preferences.fragments.HelpAndFeedback
|
||||||
|
import org.tasks.preferences.fragments.Notifications
|
||||||
|
|
||||||
|
class ManageSpaceActivity : BasePreferences() {
|
||||||
|
|
||||||
|
override fun getRootTitle() = R.string.preferences_advanced
|
||||||
|
|
||||||
|
override fun getRootPreference() = Advanced()
|
||||||
|
|
||||||
|
override fun inject(component: ActivityComponent) = component.inject(this)
|
||||||
|
}
|
||||||
@ -1,165 +0,0 @@
|
|||||||
package org.tasks.preferences;
|
|
||||||
|
|
||||||
import static com.todoroo.andlib.utility.AndroidUtilities.atLeastLollipop;
|
|
||||||
import static org.tasks.PermissionUtil.verifyPermissions;
|
|
||||||
import static org.tasks.files.FileHelper.uri2String;
|
|
||||||
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.preference.CheckBoxPreference;
|
|
||||||
import android.speech.tts.TextToSpeech;
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import com.todoroo.astrid.voice.VoiceOutputAssistant;
|
|
||||||
import javax.inject.Inject;
|
|
||||||
import org.tasks.R;
|
|
||||||
import org.tasks.files.FileHelper;
|
|
||||||
import org.tasks.injection.ActivityComponent;
|
|
||||||
import org.tasks.injection.InjectingPreferenceActivity;
|
|
||||||
import org.tasks.scheduling.CalendarNotificationIntentService;
|
|
||||||
import timber.log.Timber;
|
|
||||||
|
|
||||||
public class MiscellaneousPreferences extends InjectingPreferenceActivity {
|
|
||||||
|
|
||||||
private static final int REQUEST_CODE_FILES_DIR = 2;
|
|
||||||
private static final int REQUEST_CODE_TTS_CHECK = 2534;
|
|
||||||
|
|
||||||
@Inject Preferences preferences;
|
|
||||||
@Inject VoiceOutputAssistant voiceOutputAssistant;
|
|
||||||
@Inject ActivityPermissionRequestor permissionRequestor;
|
|
||||||
@Inject PermissionChecker permissionChecker;
|
|
||||||
|
|
||||||
private CheckBoxPreference calendarReminderPreference;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
|
|
||||||
addPreferencesFromResource(R.xml.preferences_misc);
|
|
||||||
|
|
||||||
calendarReminderPreference =
|
|
||||||
(CheckBoxPreference) findPreference(getString(R.string.p_calendar_reminders));
|
|
||||||
|
|
||||||
initializeAttachmentDirectoryPreference();
|
|
||||||
initializeCalendarReminderPreference();
|
|
||||||
initializeVoiceReminderPreference();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
|
||||||
if (requestCode == REQUEST_CODE_FILES_DIR) {
|
|
||||||
if (resultCode == RESULT_OK) {
|
|
||||||
Uri uri = data.getData();
|
|
||||||
if (atLeastLollipop()) {
|
|
||||||
getContentResolver()
|
|
||||||
.takePersistableUriPermission(
|
|
||||||
uri,
|
|
||||||
Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
|
|
||||||
}
|
|
||||||
preferences.setUri(R.string.p_attachment_dir, uri);
|
|
||||||
updateAttachmentDirectory();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
if (requestCode == REQUEST_CODE_TTS_CHECK) {
|
|
||||||
if (resultCode == TextToSpeech.Engine.CHECK_VOICE_DATA_PASS) {
|
|
||||||
// success, create the TTS instance
|
|
||||||
voiceOutputAssistant.initTTS();
|
|
||||||
} else {
|
|
||||||
// missing data, install it
|
|
||||||
Intent installIntent = new Intent();
|
|
||||||
installIntent.setAction(TextToSpeech.Engine.ACTION_INSTALL_TTS_DATA);
|
|
||||||
startActivity(installIntent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (VerifyError e) {
|
|
||||||
// unavailable
|
|
||||||
Timber.e(e);
|
|
||||||
}
|
|
||||||
super.onActivityResult(requestCode, resultCode, data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onDestroy() {
|
|
||||||
super.onDestroy();
|
|
||||||
|
|
||||||
voiceOutputAssistant.shutdown();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initializeAttachmentDirectoryPreference() {
|
|
||||||
findPreference(getString(R.string.p_attachment_dir))
|
|
||||||
.setOnPreferenceClickListener(
|
|
||||||
p -> {
|
|
||||||
FileHelper.newDirectoryPicker(
|
|
||||||
this, REQUEST_CODE_FILES_DIR, preferences.getAttachmentsDirectory());
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
updateAttachmentDirectory();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateAttachmentDirectory() {
|
|
||||||
findPreference(getString(R.string.p_attachment_dir))
|
|
||||||
.setSummary(uri2String(preferences.getAttachmentsDirectory()));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initializeCalendarReminderPreference() {
|
|
||||||
CheckBoxPreference calendarReminderPreference =
|
|
||||||
(CheckBoxPreference) findPreference(getString(R.string.p_calendar_reminders));
|
|
||||||
calendarReminderPreference.setOnPreferenceChangeListener(
|
|
||||||
(preference, newValue) -> {
|
|
||||||
if (newValue == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!(Boolean) newValue) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (permissionRequestor.requestCalendarPermissions()) {
|
|
||||||
CalendarNotificationIntentService.enqueueWork(this);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
calendarReminderPreference.setChecked(
|
|
||||||
calendarReminderPreference.isChecked() && permissionChecker.canAccessCalendars());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initializeVoiceReminderPreference() {
|
|
||||||
findPreference(getString(R.string.p_voiceRemindersEnabled))
|
|
||||||
.setOnPreferenceChangeListener(
|
|
||||||
(preference, newValue) -> {
|
|
||||||
boolean enabled = (boolean) newValue;
|
|
||||||
try {
|
|
||||||
if (enabled && !voiceOutputAssistant.isTTSInitialized()) {
|
|
||||||
Intent checkIntent = new Intent();
|
|
||||||
checkIntent.setAction(TextToSpeech.Engine.ACTION_CHECK_TTS_DATA);
|
|
||||||
startActivityForResult(checkIntent, REQUEST_CODE_TTS_CHECK);
|
|
||||||
} else if (!enabled && voiceOutputAssistant.isTTSInitialized()) {
|
|
||||||
voiceOutputAssistant.shutdown();
|
|
||||||
}
|
|
||||||
} catch (VerifyError e) {
|
|
||||||
Timber.e(e);
|
|
||||||
preference.setEnabled(false);
|
|
||||||
preferences.setBoolean(preference.getKey(), false);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onRequestPermissionsResult(
|
|
||||||
int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
|
||||||
if (requestCode == PermissionRequestor.REQUEST_CALENDAR) {
|
|
||||||
if (verifyPermissions(grantResults)) {
|
|
||||||
calendarReminderPreference.setChecked(true);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void inject(ActivityComponent component) {
|
|
||||||
component.inject(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -0,0 +1,15 @@
|
|||||||
|
package org.tasks.preferences
|
||||||
|
|
||||||
|
import org.tasks.R
|
||||||
|
import org.tasks.injection.ActivityComponent
|
||||||
|
import org.tasks.preferences.fragments.HelpAndFeedback
|
||||||
|
import org.tasks.preferences.fragments.Notifications
|
||||||
|
|
||||||
|
class NotificationPreferences : BasePreferences() {
|
||||||
|
|
||||||
|
override fun getRootTitle() = R.string.notifications
|
||||||
|
|
||||||
|
override fun getRootPreference() = Notifications()
|
||||||
|
|
||||||
|
override fun inject(component: ActivityComponent) = component.inject(this)
|
||||||
|
}
|
||||||
@ -0,0 +1,14 @@
|
|||||||
|
package org.tasks.preferences
|
||||||
|
|
||||||
|
import org.tasks.R
|
||||||
|
import org.tasks.injection.ActivityComponent
|
||||||
|
import org.tasks.preferences.fragments.Synchronization
|
||||||
|
|
||||||
|
class SyncPreferences : BasePreferences() {
|
||||||
|
|
||||||
|
override fun getRootTitle() = R.string.synchronization
|
||||||
|
|
||||||
|
override fun getRootPreference() = Synchronization()
|
||||||
|
|
||||||
|
override fun inject(component: ActivityComponent) = component.inject(this)
|
||||||
|
}
|
||||||
@ -0,0 +1,234 @@
|
|||||||
|
package org.tasks.preferences.fragments
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Bundle
|
||||||
|
import androidx.annotation.StringRes
|
||||||
|
import androidx.preference.Preference
|
||||||
|
import androidx.preference.SwitchPreferenceCompat
|
||||||
|
import com.todoroo.andlib.utility.AndroidUtilities
|
||||||
|
import com.todoroo.astrid.dao.Database
|
||||||
|
import com.todoroo.astrid.dao.TaskDao
|
||||||
|
import com.todoroo.astrid.service.TaskDeleter
|
||||||
|
import io.reactivex.Single
|
||||||
|
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||||
|
import io.reactivex.disposables.CompositeDisposable
|
||||||
|
import io.reactivex.schedulers.Schedulers
|
||||||
|
import org.tasks.PermissionUtil
|
||||||
|
import org.tasks.R
|
||||||
|
import org.tasks.calendars.CalendarEventProvider
|
||||||
|
import org.tasks.files.FileHelper
|
||||||
|
import org.tasks.injection.FragmentComponent
|
||||||
|
import org.tasks.injection.InjectingPreferenceFragment
|
||||||
|
import org.tasks.preferences.FragmentPermissionRequestor
|
||||||
|
import org.tasks.preferences.PermissionChecker
|
||||||
|
import org.tasks.preferences.PermissionRequestor
|
||||||
|
import org.tasks.preferences.Preferences
|
||||||
|
import org.tasks.scheduling.CalendarNotificationIntentService
|
||||||
|
import org.tasks.ui.Toaster
|
||||||
|
import java.util.concurrent.Callable
|
||||||
|
import javax.inject.Inject
|
||||||
|
import kotlin.system.exitProcess
|
||||||
|
|
||||||
|
private const val REQUEST_CODE_FILES_DIR = 10000
|
||||||
|
|
||||||
|
class Advanced : InjectingPreferenceFragment() {
|
||||||
|
|
||||||
|
@Inject lateinit var preferences: Preferences
|
||||||
|
@Inject lateinit var database: Database
|
||||||
|
@Inject lateinit var taskDao: TaskDao
|
||||||
|
@Inject lateinit var calendarEventProvider: CalendarEventProvider
|
||||||
|
@Inject lateinit var taskDeleter: TaskDeleter
|
||||||
|
@Inject lateinit var toaster: Toaster
|
||||||
|
@Inject lateinit var permissionRequester: FragmentPermissionRequestor
|
||||||
|
@Inject lateinit var permissionChecker: PermissionChecker
|
||||||
|
|
||||||
|
private lateinit var disposables: CompositeDisposable
|
||||||
|
private lateinit var calendarReminderPreference: SwitchPreferenceCompat
|
||||||
|
|
||||||
|
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||||
|
setPreferencesFromResource(R.xml.preferences_advanced, rootKey)
|
||||||
|
|
||||||
|
findPreference(R.string.EPr_manage_purge_deleted)
|
||||||
|
.setOnPreferenceClickListener {
|
||||||
|
purgeDeletedTasks()
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
findPreference(R.string.EPr_manage_delete_completed_gcal)
|
||||||
|
.setOnPreferenceClickListener {
|
||||||
|
deleteCompletedEvents()
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
findPreference(R.string.EPr_manage_delete_all_gcal)
|
||||||
|
.setOnPreferenceClickListener {
|
||||||
|
deleteAllCalendarEvents()
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
findPreference(R.string.EPr_reset_preferences)
|
||||||
|
.setOnPreferenceClickListener {
|
||||||
|
resetPreferences()
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
findPreference(R.string.EPr_delete_task_data)
|
||||||
|
.setOnPreferenceClickListener {
|
||||||
|
deleteTaskData()
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
findPreference(R.string.p_attachment_dir)
|
||||||
|
.setOnPreferenceClickListener {
|
||||||
|
FileHelper.newDirectoryPicker(this, REQUEST_CODE_FILES_DIR, preferences.attachmentsDirectory)
|
||||||
|
false
|
||||||
|
}
|
||||||
|
updateAttachmentDirectory()
|
||||||
|
|
||||||
|
calendarReminderPreference = findPreference(R.string.p_calendar_reminders) as SwitchPreferenceCompat
|
||||||
|
initializeCalendarReminderPreference()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||||
|
if (requestCode == REQUEST_CODE_FILES_DIR) {
|
||||||
|
if (resultCode == Activity.RESULT_OK) {
|
||||||
|
val uri = data!!.data!!
|
||||||
|
if (AndroidUtilities.atLeastLollipop()) {
|
||||||
|
context!!.contentResolver
|
||||||
|
.takePersistableUriPermission(
|
||||||
|
uri,
|
||||||
|
Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
|
||||||
|
}
|
||||||
|
preferences.setUri(R.string.p_attachment_dir, uri)
|
||||||
|
updateAttachmentDirectory()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
super.onActivityResult(requestCode, resultCode, data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onRequestPermissionsResult(
|
||||||
|
requestCode: Int, permissions: Array<String?>, grantResults: IntArray) {
|
||||||
|
if (requestCode == PermissionRequestor.REQUEST_CALENDAR) {
|
||||||
|
if (PermissionUtil.verifyPermissions(grantResults)) {
|
||||||
|
calendarReminderPreference.isChecked = true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
|
||||||
|
disposables = CompositeDisposable()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPause() {
|
||||||
|
super.onPause()
|
||||||
|
|
||||||
|
disposables.dispose()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun initializeCalendarReminderPreference() {
|
||||||
|
calendarReminderPreference.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue ->
|
||||||
|
if (newValue == null) {
|
||||||
|
false
|
||||||
|
} else if (!(newValue as Boolean)) {
|
||||||
|
true
|
||||||
|
} else if (permissionRequester.requestCalendarPermissions()) {
|
||||||
|
CalendarNotificationIntentService.enqueueWork(context)
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
calendarReminderPreference.isChecked = calendarReminderPreference.isChecked && permissionChecker.canAccessCalendars()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateAttachmentDirectory() {
|
||||||
|
findPreference(R.string.p_attachment_dir).summary =
|
||||||
|
FileHelper.uri2String(preferences.attachmentsDirectory)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun purgeDeletedTasks() {
|
||||||
|
dialogBuilder
|
||||||
|
.newDialog()
|
||||||
|
.setMessage(R.string.EPr_manage_purge_deleted_message)
|
||||||
|
.setPositiveButton(android.R.string.ok) { _, _ ->
|
||||||
|
performAction(
|
||||||
|
R.string.EPr_manage_purge_deleted_status, Callable { taskDeleter.purgeDeleted() })
|
||||||
|
}
|
||||||
|
.setNegativeButton(android.R.string.cancel, null)
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun deleteCompletedEvents() {
|
||||||
|
dialogBuilder
|
||||||
|
.newDialog()
|
||||||
|
.setMessage(R.string.EPr_manage_delete_completed_gcal_message)
|
||||||
|
.setPositiveButton(android.R.string.ok) { _, _ ->
|
||||||
|
performAction(
|
||||||
|
R.string.EPr_manage_delete_completed_gcal_status,
|
||||||
|
Callable {
|
||||||
|
calendarEventProvider.deleteEvents(taskDao.completedCalendarEvents)
|
||||||
|
taskDao.clearCompletedCalendarEvents()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
.setNegativeButton(android.R.string.cancel, null)
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun deleteAllCalendarEvents() {
|
||||||
|
dialogBuilder
|
||||||
|
.newDialog()
|
||||||
|
.setMessage(R.string.EPr_manage_delete_all_gcal_message)
|
||||||
|
.setPositiveButton(android.R.string.ok) { _, _ ->
|
||||||
|
performAction(
|
||||||
|
R.string.EPr_manage_delete_all_gcal_status,
|
||||||
|
Callable {
|
||||||
|
calendarEventProvider.deleteEvents(taskDao.allCalendarEvents)
|
||||||
|
taskDao.clearAllCalendarEvents()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
.setNegativeButton(android.R.string.cancel, null)
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun performAction(@StringRes message: Int, callable: Callable<Int>) {
|
||||||
|
disposables.add(
|
||||||
|
Single.fromCallable(callable)
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe { c: Int? -> toaster.longToastUnformatted(message, c!!) })
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun resetPreferences() {
|
||||||
|
dialogBuilder
|
||||||
|
.newDialog()
|
||||||
|
.setMessage(R.string.EPr_reset_preferences_warning)
|
||||||
|
.setPositiveButton(R.string.EPr_reset_preferences) { _, _ ->
|
||||||
|
preferences.reset()
|
||||||
|
exitProcess(0)
|
||||||
|
}
|
||||||
|
.setNegativeButton(android.R.string.cancel, null)
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun deleteTaskData() {
|
||||||
|
dialogBuilder
|
||||||
|
.newDialog()
|
||||||
|
.setMessage(R.string.EPr_delete_task_data_warning)
|
||||||
|
.setPositiveButton(R.string.EPr_delete_task_data) { _, _ ->
|
||||||
|
context!!.deleteDatabase(database.name)
|
||||||
|
exitProcess(0)
|
||||||
|
}
|
||||||
|
.setNegativeButton(android.R.string.cancel, null)
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun inject(component: FragmentComponent) {
|
||||||
|
component.inject(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,159 @@
|
|||||||
|
package org.tasks.preferences.fragments
|
||||||
|
|
||||||
|
import android.app.Activity.RESULT_OK
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Bundle
|
||||||
|
import androidx.preference.Preference
|
||||||
|
import androidx.preference.SwitchPreferenceCompat
|
||||||
|
import com.todoroo.andlib.utility.AndroidUtilities
|
||||||
|
import com.todoroo.astrid.gtasks.auth.GtasksLoginActivity
|
||||||
|
import org.tasks.PermissionUtil
|
||||||
|
import org.tasks.R
|
||||||
|
import org.tasks.dialogs.ExportTasksDialog
|
||||||
|
import org.tasks.dialogs.ImportTasksDialog
|
||||||
|
import org.tasks.drive.DriveLoginActivity
|
||||||
|
import org.tasks.files.FileHelper
|
||||||
|
import org.tasks.gtasks.GoogleAccountManager
|
||||||
|
import org.tasks.injection.FragmentComponent
|
||||||
|
import org.tasks.injection.InjectingPreferenceFragment
|
||||||
|
import org.tasks.preferences.FragmentPermissionRequestor
|
||||||
|
import org.tasks.preferences.PermissionRequestor
|
||||||
|
import org.tasks.preferences.Preferences
|
||||||
|
import org.tasks.ui.Toaster
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
private const val REQUEST_CODE_BACKUP_DIR = 10001
|
||||||
|
private const val REQUEST_DRIVE_BACKUP = 10002
|
||||||
|
private const val REQUEST_PICKER = 10003
|
||||||
|
private const val FRAG_TAG_EXPORT_TASKS = "frag_tag_export_tasks"
|
||||||
|
private const val FRAG_TAG_IMPORT_TASKS = "frag_tag_import_tasks"
|
||||||
|
|
||||||
|
class Backups : InjectingPreferenceFragment() {
|
||||||
|
|
||||||
|
@Inject lateinit var preferences: Preferences
|
||||||
|
@Inject lateinit var permissionRequestor: FragmentPermissionRequestor
|
||||||
|
@Inject lateinit var toaster: Toaster
|
||||||
|
@Inject lateinit var googleAccountManager: GoogleAccountManager
|
||||||
|
|
||||||
|
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||||
|
setPreferencesFromResource(R.xml.preferences_backups, rootKey)
|
||||||
|
|
||||||
|
initializeBackupDirectory()
|
||||||
|
|
||||||
|
findPreference(R.string.backup_BAc_import)
|
||||||
|
.setOnPreferenceClickListener {
|
||||||
|
startActivityForResult(
|
||||||
|
FileHelper.newFilePickerIntent(activity, preferences.backupDirectory),
|
||||||
|
REQUEST_PICKER)
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
findPreference(R.string.backup_BAc_export)
|
||||||
|
.setOnPreferenceClickListener {
|
||||||
|
ExportTasksDialog.newExportTasksDialog()
|
||||||
|
.show(fragmentManager!!, FRAG_TAG_EXPORT_TASKS)
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
val googleDriveBackup = findPreference(R.string.p_google_drive_backup) as SwitchPreferenceCompat
|
||||||
|
googleDriveBackup.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { preference: Preference, newValue: Any? ->
|
||||||
|
when {
|
||||||
|
newValue == null -> {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
newValue as Boolean -> {
|
||||||
|
if (permissionRequestor.requestAccountPermissions()) {
|
||||||
|
requestGoogleDriveLogin()
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
preference.summary = null
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
|
||||||
|
val googleDriveBackup = findPreference(R.string.p_google_drive_backup) as SwitchPreferenceCompat
|
||||||
|
val account = preferences.getStringValue(R.string.p_google_drive_backup_account)
|
||||||
|
if (preferences.getBoolean(R.string.p_google_drive_backup, false)
|
||||||
|
&& googleAccountManager.canAccessAccount(account)) {
|
||||||
|
googleDriveBackup.isChecked = true
|
||||||
|
googleDriveBackup.summary = account
|
||||||
|
} else {
|
||||||
|
googleDriveBackup.isChecked = false
|
||||||
|
googleDriveBackup.summary = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
|
||||||
|
if (requestCode == PermissionRequestor.REQUEST_GOOGLE_ACCOUNTS) {
|
||||||
|
if (PermissionUtil.verifyPermissions(grantResults)) {
|
||||||
|
requestGoogleDriveLogin()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||||
|
if (requestCode == REQUEST_CODE_BACKUP_DIR) {
|
||||||
|
if (resultCode == RESULT_OK && data != null) {
|
||||||
|
val uri = data.data!!
|
||||||
|
if (AndroidUtilities.atLeastLollipop()) {
|
||||||
|
context?.contentResolver
|
||||||
|
?.takePersistableUriPermission(
|
||||||
|
uri,
|
||||||
|
Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
|
||||||
|
}
|
||||||
|
preferences.setUri(R.string.p_backup_dir, uri)
|
||||||
|
updateBackupDirectory()
|
||||||
|
}
|
||||||
|
} else if (requestCode == REQUEST_PICKER) {
|
||||||
|
if (resultCode == RESULT_OK) {
|
||||||
|
val uri = data!!.data
|
||||||
|
val extension = FileHelper.getExtension(activity, uri)
|
||||||
|
if (!("json".equals(extension, ignoreCase = true) || "xml".equals(extension, ignoreCase = true))) {
|
||||||
|
toaster.longToast(R.string.invalid_backup_file)
|
||||||
|
} else {
|
||||||
|
ImportTasksDialog.newImportTasksDialog(uri, extension).show(fragmentManager!!, FRAG_TAG_IMPORT_TASKS)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (requestCode == REQUEST_DRIVE_BACKUP) {
|
||||||
|
val success = resultCode == RESULT_OK
|
||||||
|
(findPreference(R.string.p_google_drive_backup) as SwitchPreferenceCompat).isChecked = success
|
||||||
|
if (!success && data != null) {
|
||||||
|
toaster.longToast(data.getStringExtra(GtasksLoginActivity.EXTRA_ERROR))
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
super.onActivityResult(requestCode, resultCode, data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun requestGoogleDriveLogin() {
|
||||||
|
startActivityForResult(Intent(context, DriveLoginActivity::class.java), REQUEST_DRIVE_BACKUP)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun initializeBackupDirectory() {
|
||||||
|
findPreference(R.string.p_backup_dir)
|
||||||
|
.setOnPreferenceClickListener {
|
||||||
|
FileHelper.newDirectoryPicker(
|
||||||
|
this, REQUEST_CODE_BACKUP_DIR, preferences.backupDirectory)
|
||||||
|
false
|
||||||
|
}
|
||||||
|
updateBackupDirectory()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateBackupDirectory() {
|
||||||
|
findPreference(R.string.p_backup_dir).summary = FileHelper.uri2String(preferences.backupDirectory)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun inject(component: FragmentComponent) {
|
||||||
|
component.inject(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,431 @@
|
|||||||
|
package org.tasks.preferences.fragments
|
||||||
|
|
||||||
|
import android.app.Activity.RESULT_OK
|
||||||
|
import android.content.ComponentName
|
||||||
|
import android.content.DialogInterface
|
||||||
|
import android.content.Intent
|
||||||
|
import android.content.pm.PackageManager
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.os.Handler
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.annotation.StringRes
|
||||||
|
import androidx.preference.ListPreference
|
||||||
|
import androidx.preference.Preference
|
||||||
|
import com.google.common.base.Strings
|
||||||
|
import com.todoroo.andlib.utility.AndroidUtilities.atLeastJellybeanMR1
|
||||||
|
import com.todoroo.andlib.utility.AndroidUtilities.atLeastLollipop
|
||||||
|
import com.todoroo.astrid.api.Filter
|
||||||
|
import org.tasks.BuildConfig
|
||||||
|
import org.tasks.LocalBroadcastManager
|
||||||
|
import org.tasks.R
|
||||||
|
import org.tasks.activities.ColorPickerActivity
|
||||||
|
import org.tasks.activities.ColorPickerActivity.ColorPalette.*
|
||||||
|
import org.tasks.activities.FilterSelectionActivity
|
||||||
|
import org.tasks.activities.TimePickerActivity
|
||||||
|
import org.tasks.billing.Inventory
|
||||||
|
import org.tasks.gtasks.PlayServices
|
||||||
|
import org.tasks.injection.FragmentComponent
|
||||||
|
import org.tasks.injection.InjectingPreferenceFragment
|
||||||
|
import org.tasks.locale.Locale
|
||||||
|
import org.tasks.locale.LocalePickerDialog
|
||||||
|
import org.tasks.preferences.DefaultFilterProvider
|
||||||
|
import org.tasks.preferences.Preferences
|
||||||
|
import org.tasks.themes.ThemeAccent
|
||||||
|
import org.tasks.themes.ThemeBase
|
||||||
|
import org.tasks.themes.ThemeCache
|
||||||
|
import org.tasks.themes.ThemeColor
|
||||||
|
import org.tasks.time.DateTime
|
||||||
|
import org.tasks.ui.SingleCheckedArrayAdapter
|
||||||
|
import org.tasks.ui.TimePreference
|
||||||
|
import org.tasks.ui.Toaster
|
||||||
|
import org.threeten.bp.DayOfWeek
|
||||||
|
import org.threeten.bp.format.TextStyle
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
private const val REQUEST_THEME_PICKER = 10001
|
||||||
|
private const val REQUEST_COLOR_PICKER = 10002
|
||||||
|
private const val REQUEST_ACCENT_PICKER = 10003
|
||||||
|
private const val REQUEST_LAUNCHER_PICKER = 10004
|
||||||
|
private const val REQUEST_DEFAULT_LIST = 10005
|
||||||
|
private const val REQUEST_LOCALE = 10006
|
||||||
|
private const val REQUEST_MORNING = 10007
|
||||||
|
private const val REQUEST_AFTERNOON = 10008
|
||||||
|
private const val REQUEST_EVENING = 10009
|
||||||
|
private const val REQUEST_NIGHT = 10010
|
||||||
|
private const val FRAG_TAG_LOCALE_PICKER = "frag_tag_locale_picker"
|
||||||
|
|
||||||
|
class LookAndFeel : InjectingPreferenceFragment(), Preference.OnPreferenceChangeListener {
|
||||||
|
|
||||||
|
@Inject lateinit var themeCache: ThemeCache
|
||||||
|
@Inject lateinit var themeBase: ThemeBase
|
||||||
|
@Inject lateinit var themeColor: ThemeColor
|
||||||
|
@Inject lateinit var themeAccent: ThemeAccent
|
||||||
|
@Inject lateinit var preferences: Preferences
|
||||||
|
@Inject lateinit var localBroadcastManager: LocalBroadcastManager
|
||||||
|
@Inject lateinit var locale: Locale
|
||||||
|
@Inject lateinit var defaultFilterProvider: DefaultFilterProvider
|
||||||
|
@Inject lateinit var playServices: PlayServices
|
||||||
|
@Inject lateinit var inventory: Inventory
|
||||||
|
@Inject lateinit var toaster: Toaster
|
||||||
|
|
||||||
|
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||||
|
setPreferencesFromResource(R.xml.preferences_look_and_feel, rootKey)
|
||||||
|
|
||||||
|
setupColorPreference(R.string.p_theme, themeBase.name, THEMES, REQUEST_THEME_PICKER)
|
||||||
|
setupColorPreference(R.string.p_theme_color, themeColor.name, COLORS, REQUEST_COLOR_PICKER)
|
||||||
|
setupColorPreference(R.string.p_theme_accent, themeAccent.name, ACCENTS, REQUEST_ACCENT_PICKER)
|
||||||
|
updateLauncherPreference()
|
||||||
|
|
||||||
|
findPreference(R.string.p_show_subtasks)
|
||||||
|
.setOnPreferenceChangeListener { _: Preference?, _: Any? ->
|
||||||
|
localBroadcastManager.broadcastRefresh()
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
val defaultList = findPreference(R.string.p_default_list)
|
||||||
|
val filter: Filter = defaultFilterProvider.defaultFilter
|
||||||
|
defaultList.summary = filter.listingTitle
|
||||||
|
defaultList.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||||
|
val intent = Intent(context, FilterSelectionActivity::class.java)
|
||||||
|
intent.putExtra(FilterSelectionActivity.EXTRA_FILTER, defaultFilterProvider.defaultFilter)
|
||||||
|
intent.putExtra(FilterSelectionActivity.EXTRA_RETURN_FILTER, true)
|
||||||
|
startActivityForResult(intent, REQUEST_DEFAULT_LIST)
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
val languagePreference = findPreference(R.string.p_language)
|
||||||
|
updateLocale()
|
||||||
|
languagePreference.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||||
|
val dialog = LocalePickerDialog.newLocalePickerDialog()
|
||||||
|
dialog.setTargetFragment(this, REQUEST_LOCALE)
|
||||||
|
dialog.show(fragmentManager!!, FRAG_TAG_LOCALE_PICKER)
|
||||||
|
false
|
||||||
|
}
|
||||||
|
findPreference(R.string.p_layout_direction)
|
||||||
|
.setOnPreferenceChangeListener { _: Preference?, o: Any ->
|
||||||
|
val newValue: Int = o as Int
|
||||||
|
if (locale.directionality
|
||||||
|
!= locale.withDirectionality(newValue).directionality) {
|
||||||
|
showRestartDialog()
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
val startOfWeekPreference: ListPreference = getStartOfWeekPreference()
|
||||||
|
startOfWeekPreference.entries = getWeekdayEntries()
|
||||||
|
startOfWeekPreference.onPreferenceChangeListener = this
|
||||||
|
|
||||||
|
initializeTimePreference(getMorningPreference(), REQUEST_MORNING)
|
||||||
|
initializeTimePreference(getAfternoonPreference(), REQUEST_AFTERNOON)
|
||||||
|
initializeTimePreference(getEveningPreference(), REQUEST_EVENING)
|
||||||
|
initializeTimePreference(getNightPreference(), REQUEST_NIGHT)
|
||||||
|
|
||||||
|
updateStartOfWeek(preferences.getStringValue(R.string.p_start_of_week)!!)
|
||||||
|
|
||||||
|
requires(R.string.task_list_options, atLeastLollipop(), R.string.p_show_subtasks)
|
||||||
|
|
||||||
|
requires(R.string.settings_localization,
|
||||||
|
atLeastJellybeanMR1(),
|
||||||
|
R.string.p_language,
|
||||||
|
R.string.p_layout_direction)
|
||||||
|
|
||||||
|
@Suppress("ConstantConditionIf")
|
||||||
|
if (BuildConfig.FLAVOR != "googleplay") {
|
||||||
|
removeGroup(R.string.TEA_control_location)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
|
||||||
|
@Suppress("ConstantConditionIf")
|
||||||
|
if (BuildConfig.FLAVOR == "googleplay") {
|
||||||
|
setupLocationPickers()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateLauncherPreference() =
|
||||||
|
setupColorPreference(
|
||||||
|
R.string.p_theme_launcher,
|
||||||
|
themeCache.getThemeColor(preferences.getInt(R.string.p_theme_launcher, 7)).name,
|
||||||
|
LAUNCHER,
|
||||||
|
REQUEST_LAUNCHER_PICKER)
|
||||||
|
|
||||||
|
private fun setupLocationPickers() {
|
||||||
|
val choices = listOf(getString(R.string.map_provider_mapbox), getString(R.string.map_provider_google))
|
||||||
|
val singleCheckedArrayAdapter = SingleCheckedArrayAdapter(context!!, choices, themeAccent)
|
||||||
|
val mapProviderPreference = findPreference(R.string.p_map_provider)
|
||||||
|
mapProviderPreference.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||||
|
dialogBuilder
|
||||||
|
.newDialog()
|
||||||
|
.setSingleChoiceItems(
|
||||||
|
singleCheckedArrayAdapter,
|
||||||
|
getMapProvider()
|
||||||
|
) { dialog: DialogInterface, which: Int ->
|
||||||
|
if (which == 1) {
|
||||||
|
if (!playServices.refreshAndCheck()) {
|
||||||
|
playServices.resolve(activity)
|
||||||
|
dialog.dismiss()
|
||||||
|
return@setSingleChoiceItems
|
||||||
|
}
|
||||||
|
}
|
||||||
|
preferences.setInt(R.string.p_map_provider, which)
|
||||||
|
mapProviderPreference.summary = choices[which]
|
||||||
|
dialog.dismiss()
|
||||||
|
}
|
||||||
|
.setNegativeButton(android.R.string.cancel, null)
|
||||||
|
.showThemedListView()
|
||||||
|
false
|
||||||
|
}
|
||||||
|
val mapProvider: Int = getMapProvider()
|
||||||
|
mapProviderPreference.summary = if (mapProvider == -1) getString(R.string.none) else choices[mapProvider]
|
||||||
|
|
||||||
|
val placeProviderPreference = findPreference(R.string.p_place_provider)
|
||||||
|
placeProviderPreference.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||||
|
dialogBuilder
|
||||||
|
.newDialog()
|
||||||
|
.setSingleChoiceItems(
|
||||||
|
singleCheckedArrayAdapter,
|
||||||
|
getPlaceProvider()
|
||||||
|
) { dialog: DialogInterface, which: Int ->
|
||||||
|
if (which == 1) {
|
||||||
|
if (!playServices.refreshAndCheck()) {
|
||||||
|
playServices.resolve(activity)
|
||||||
|
dialog.dismiss()
|
||||||
|
return@setSingleChoiceItems
|
||||||
|
}
|
||||||
|
if (!inventory.hasPro()) {
|
||||||
|
toaster.longToast(R.string.requires_pro_subscription)
|
||||||
|
dialog.dismiss()
|
||||||
|
return@setSingleChoiceItems
|
||||||
|
}
|
||||||
|
}
|
||||||
|
preferences.setInt(R.string.p_place_provider, which)
|
||||||
|
placeProviderPreference.summary = choices[which]
|
||||||
|
dialog.dismiss()
|
||||||
|
}
|
||||||
|
.setNegativeButton(android.R.string.cancel, null)
|
||||||
|
.showThemedListView()
|
||||||
|
false
|
||||||
|
}
|
||||||
|
val placeProvider: Int = getPlaceProvider()
|
||||||
|
placeProviderPreference.summary = choices[placeProvider]
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getPlaceProvider(): Int {
|
||||||
|
return if (playServices.isPlayServicesAvailable && inventory.hasPro()) preferences.getInt(R.string.p_place_provider, 0) else 0
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getMapProvider(): Int {
|
||||||
|
return if (playServices.isPlayServicesAvailable) preferences.getInt(R.string.p_map_provider, 0) else 0
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||||
|
if (requestCode == REQUEST_THEME_PICKER) {
|
||||||
|
if (resultCode == RESULT_OK) {
|
||||||
|
val index = data!!.getIntExtra(ColorPickerActivity.EXTRA_THEME_INDEX, 0)
|
||||||
|
preferences.setInt(R.string.p_theme, index)
|
||||||
|
Handler().post {
|
||||||
|
themeCache.getThemeBase(index).setDefaultNightMode()
|
||||||
|
recreate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (requestCode == REQUEST_COLOR_PICKER) {
|
||||||
|
if (resultCode == RESULT_OK) {
|
||||||
|
val index = data!!.getIntExtra(ColorPickerActivity.EXTRA_THEME_INDEX, 0)
|
||||||
|
preferences.setInt(R.string.p_theme_color, index)
|
||||||
|
recreate()
|
||||||
|
}
|
||||||
|
} else if (requestCode == REQUEST_ACCENT_PICKER) {
|
||||||
|
if (resultCode == RESULT_OK) {
|
||||||
|
val index = data!!.getIntExtra(ColorPickerActivity.EXTRA_THEME_INDEX, 0)
|
||||||
|
preferences.setInt(R.string.p_theme_accent, index)
|
||||||
|
recreate()
|
||||||
|
}
|
||||||
|
} else if (requestCode == REQUEST_LAUNCHER_PICKER) {
|
||||||
|
if (resultCode == RESULT_OK) {
|
||||||
|
val index = data!!.getIntExtra(ColorPickerActivity.EXTRA_THEME_INDEX, 0)
|
||||||
|
setLauncherIcon(index)
|
||||||
|
preferences.setInt(R.string.p_theme_launcher, index)
|
||||||
|
updateLauncherPreference()
|
||||||
|
}
|
||||||
|
} else if (requestCode == REQUEST_DEFAULT_LIST) {
|
||||||
|
if (resultCode == RESULT_OK) {
|
||||||
|
val filter: Filter = data!!.getParcelableExtra(FilterSelectionActivity.EXTRA_FILTER)!!
|
||||||
|
defaultFilterProvider.defaultFilter = filter
|
||||||
|
findPreference(R.string.p_default_list).summary = filter.listingTitle
|
||||||
|
localBroadcastManager.broadcastRefresh()
|
||||||
|
}
|
||||||
|
} else if (requestCode == REQUEST_LOCALE) {
|
||||||
|
if (resultCode == RESULT_OK) {
|
||||||
|
val newValue: Locale = data!!.getSerializableExtra(LocalePickerDialog.EXTRA_LOCALE) as Locale
|
||||||
|
val override: String? = newValue.languageOverride
|
||||||
|
if (Strings.isNullOrEmpty(override)) {
|
||||||
|
preferences.remove(R.string.p_language)
|
||||||
|
} else {
|
||||||
|
preferences.setString(R.string.p_language, override)
|
||||||
|
}
|
||||||
|
updateLocale()
|
||||||
|
if (locale != newValue) {
|
||||||
|
showRestartDialog()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (requestCode == REQUEST_MORNING) {
|
||||||
|
if (resultCode == RESULT_OK) {
|
||||||
|
getMorningPreference().handleTimePickerActivityIntent(data)
|
||||||
|
}
|
||||||
|
} else if (requestCode == REQUEST_AFTERNOON) {
|
||||||
|
if (resultCode == RESULT_OK) {
|
||||||
|
getAfternoonPreference().handleTimePickerActivityIntent(data)
|
||||||
|
}
|
||||||
|
} else if (requestCode == REQUEST_EVENING) {
|
||||||
|
if (resultCode == RESULT_OK) {
|
||||||
|
getEveningPreference().handleTimePickerActivityIntent(data)
|
||||||
|
}
|
||||||
|
} else if (requestCode == REQUEST_NIGHT) {
|
||||||
|
if (resultCode == RESULT_OK) {
|
||||||
|
getNightPreference().handleTimePickerActivityIntent(data)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
super.onActivityResult(requestCode, resultCode, data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateLocale() {
|
||||||
|
val languagePreference = findPreference(R.string.p_language)
|
||||||
|
val preference = preferences.getStringValue(R.string.p_language)
|
||||||
|
languagePreference.summary = locale.withLanguage(preference).displayName
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setLauncherIcon(index: Int) {
|
||||||
|
val packageManager: PackageManager? = context?.packageManager
|
||||||
|
for (i in ThemeColor.LAUNCHERS.indices) {
|
||||||
|
val componentName = ComponentName(context!!, "com.todoroo.astrid.activity.TaskListActivity" + ThemeColor.LAUNCHERS[i])
|
||||||
|
packageManager?.setComponentEnabledSetting(
|
||||||
|
componentName,
|
||||||
|
if (index == i) PackageManager.COMPONENT_ENABLED_STATE_ENABLED else PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
|
||||||
|
PackageManager.DONT_KILL_APP)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun inject(component: FragmentComponent) {
|
||||||
|
component.inject(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupColorPreference(@StringRes prefId: Int, summary: String, palette: ColorPickerActivity.ColorPalette, requestCode: Int) {
|
||||||
|
val themePref: Preference = findPreference(prefId)
|
||||||
|
themePref.summary = summary
|
||||||
|
themePref.setOnPreferenceClickListener {
|
||||||
|
val intent = Intent(context, ColorPickerActivity::class.java)
|
||||||
|
intent.putExtra(ColorPickerActivity.EXTRA_PALETTE, palette)
|
||||||
|
startActivityForResult(intent, requestCode)
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun initializeTimePreference(preference: TimePreference, requestCode: Int) {
|
||||||
|
preference.onPreferenceChangeListener = this
|
||||||
|
preference.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||||
|
val current = DateTime().withMillisOfDay(preference.millisOfDay)
|
||||||
|
val intent = Intent(context, TimePickerActivity::class.java)
|
||||||
|
intent.putExtra(TimePickerActivity.EXTRA_TIMESTAMP, current.millis)
|
||||||
|
startActivityForResult(intent, requestCode)
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPreferenceChange(preference: Preference?, newValue: Any?): Boolean {
|
||||||
|
if (preference == getStartOfWeekPreference()) {
|
||||||
|
updateStartOfWeek(newValue.toString())
|
||||||
|
} else {
|
||||||
|
val millisOfDay = newValue as Int
|
||||||
|
if (preference == getMorningPreference()) {
|
||||||
|
if (millisOfDay >= getAfternoonPreference().millisOfDay) {
|
||||||
|
mustComeBefore(R.string.date_shortcut_morning, R.string.date_shortcut_afternoon)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
} else if (preference == getAfternoonPreference()) {
|
||||||
|
if (millisOfDay <= getMorningPreference().millisOfDay) {
|
||||||
|
mustComeAfter(R.string.date_shortcut_afternoon, R.string.date_shortcut_morning)
|
||||||
|
return false
|
||||||
|
} else if (millisOfDay >= getEveningPreference().millisOfDay) {
|
||||||
|
mustComeBefore(R.string.date_shortcut_afternoon, R.string.date_shortcut_evening)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
} else if (preference == getEveningPreference()) {
|
||||||
|
if (millisOfDay <= getAfternoonPreference().millisOfDay) {
|
||||||
|
mustComeAfter(R.string.date_shortcut_evening, R.string.date_shortcut_afternoon)
|
||||||
|
return false
|
||||||
|
} else if (millisOfDay >= getNightPreference().millisOfDay) {
|
||||||
|
mustComeBefore(R.string.date_shortcut_evening, R.string.date_shortcut_night)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
} else if (preference == getNightPreference()) {
|
||||||
|
if (millisOfDay <= getEveningPreference().millisOfDay) {
|
||||||
|
mustComeAfter(R.string.date_shortcut_night, R.string.date_shortcut_evening)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun mustComeBefore(settingResId: Int, relativeResId: Int) {
|
||||||
|
invalidSetting(R.string.date_shortcut_must_come_before, settingResId, relativeResId)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun mustComeAfter(settingResId: Int, relativeResId: Int) {
|
||||||
|
invalidSetting(R.string.date_shortcut_must_come_after, settingResId, relativeResId)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun invalidSetting(errorResId: Int, settingResId: Int, relativeResId: Int) {
|
||||||
|
Toast.makeText(
|
||||||
|
context,
|
||||||
|
getString(errorResId, getString(settingResId), getString(relativeResId)),
|
||||||
|
Toast.LENGTH_SHORT)
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateStartOfWeek(value: String) {
|
||||||
|
val preference = getStartOfWeekPreference()
|
||||||
|
val index = preference.findIndexOfValue(value)
|
||||||
|
val summary: String? = getWeekdayEntries()?.get(index)
|
||||||
|
preference.summary = summary
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getStartOfWeekPreference(): ListPreference {
|
||||||
|
return findPreference(R.string.p_start_of_week) as ListPreference
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getWeekdayDisplayName(dayOfWeek: DayOfWeek): String {
|
||||||
|
return dayOfWeek.getDisplayName(TextStyle.FULL, locale.locale)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getMorningPreference(): TimePreference {
|
||||||
|
return getTimePreference(R.string.p_date_shortcut_morning)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getAfternoonPreference(): TimePreference {
|
||||||
|
return getTimePreference(R.string.p_date_shortcut_afternoon)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getEveningPreference(): TimePreference {
|
||||||
|
return getTimePreference(R.string.p_date_shortcut_evening)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getNightPreference(): TimePreference {
|
||||||
|
return getTimePreference(R.string.p_date_shortcut_night)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getTimePreference(resId: Int): TimePreference {
|
||||||
|
return findPreference(resId) as TimePreference
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getWeekdayEntries(): Array<String?>? {
|
||||||
|
return arrayOf(
|
||||||
|
getString(R.string.use_locale_default),
|
||||||
|
getWeekdayDisplayName(DayOfWeek.SUNDAY),
|
||||||
|
getWeekdayDisplayName(DayOfWeek.MONDAY)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,17 @@
|
|||||||
|
package org.tasks.preferences.fragments
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import org.tasks.BuildConfig
|
||||||
|
import org.tasks.R
|
||||||
|
import org.tasks.injection.FragmentComponent
|
||||||
|
import org.tasks.injection.InjectingPreferenceFragment
|
||||||
|
|
||||||
|
class MainSettingsFragment : InjectingPreferenceFragment() {
|
||||||
|
override fun inject(component: FragmentComponent) = component.inject(this)
|
||||||
|
|
||||||
|
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||||
|
setPreferencesFromResource(R.xml.preferences, rootKey)
|
||||||
|
|
||||||
|
requires(BuildConfig.DEBUG, R.string.debug)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,270 @@
|
|||||||
|
package org.tasks.preferences.fragments
|
||||||
|
|
||||||
|
import android.annotation.TargetApi
|
||||||
|
import android.app.Activity.RESULT_OK
|
||||||
|
import android.content.Intent
|
||||||
|
import android.media.RingtoneManager
|
||||||
|
import android.net.Uri
|
||||||
|
import android.os.Build
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.provider.Settings
|
||||||
|
import android.speech.tts.TextToSpeech
|
||||||
|
import androidx.preference.Preference
|
||||||
|
import com.todoroo.andlib.utility.AndroidUtilities
|
||||||
|
import com.todoroo.astrid.api.Filter
|
||||||
|
import com.todoroo.astrid.voice.VoiceOutputAssistant
|
||||||
|
import org.tasks.LocalBroadcastManager
|
||||||
|
import org.tasks.R
|
||||||
|
import org.tasks.activities.FilterSelectionActivity
|
||||||
|
import org.tasks.activities.TimePickerActivity
|
||||||
|
import org.tasks.injection.FragmentComponent
|
||||||
|
import org.tasks.injection.InjectingPreferenceFragment
|
||||||
|
import org.tasks.preferences.DefaultFilterProvider
|
||||||
|
import org.tasks.preferences.Preferences
|
||||||
|
import org.tasks.receivers.ShortcutBadger
|
||||||
|
import org.tasks.scheduling.NotificationSchedulerIntentService
|
||||||
|
import org.tasks.time.DateTime
|
||||||
|
import org.tasks.ui.TimePreference
|
||||||
|
import timber.log.Timber
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
private const val REQUEST_QUIET_START = 10001
|
||||||
|
private const val REQUEST_QUIET_END = 10002
|
||||||
|
private const val REQUEST_DEFAULT_REMIND = 10003
|
||||||
|
private const val REQUEST_BADGE_LIST = 10004
|
||||||
|
private const val REQUEST_CODE_ALERT_RINGTONE = 10005
|
||||||
|
private const val REQUEST_CODE_TTS_CHECK = 10006
|
||||||
|
|
||||||
|
class Notifications : InjectingPreferenceFragment() {
|
||||||
|
|
||||||
|
@Inject lateinit var preferences: Preferences
|
||||||
|
@Inject lateinit var defaultFilterProvider: DefaultFilterProvider
|
||||||
|
@Inject lateinit var localBroadcastManager: LocalBroadcastManager
|
||||||
|
@Inject lateinit var voiceOutputAssistant: VoiceOutputAssistant
|
||||||
|
|
||||||
|
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||||
|
setPreferencesFromResource(R.xml.preferences_notifications, rootKey)
|
||||||
|
|
||||||
|
rescheduleNotificationsOnChange(
|
||||||
|
R.string.p_rmd_time,
|
||||||
|
R.string.p_rmd_enable_quiet,
|
||||||
|
R.string.p_rmd_quietStart,
|
||||||
|
R.string.p_rmd_quietEnd,
|
||||||
|
R.string.p_rmd_persistent)
|
||||||
|
|
||||||
|
initializeRingtonePreference()
|
||||||
|
initializeTimePreference(getDefaultRemindTimePreference()!!, REQUEST_DEFAULT_REMIND)
|
||||||
|
initializeTimePreference(getQuietStartPreference()!!, REQUEST_QUIET_START)
|
||||||
|
initializeTimePreference(getQuietEndPreference()!!, REQUEST_QUIET_END)
|
||||||
|
|
||||||
|
findPreference(R.string.notification_channel_settings)
|
||||||
|
.setOnPreferenceClickListener(::openNotificationChannelSettings)
|
||||||
|
findPreference(R.string.battery_optimization_settings)
|
||||||
|
.setOnPreferenceClickListener(::openBatteryOptimizationSettings)
|
||||||
|
|
||||||
|
findPreference(R.string.p_bundle_notifications)
|
||||||
|
.setOnPreferenceChangeListener { _: Preference?, _: Any? ->
|
||||||
|
NotificationSchedulerIntentService.enqueueWork(context, true)
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
findPreference(R.string.p_badges_enabled)
|
||||||
|
.setOnPreferenceChangeListener { _: Preference?, newValue: Any? ->
|
||||||
|
if (newValue != null) {
|
||||||
|
if (newValue as Boolean) {
|
||||||
|
showRestartDialog()
|
||||||
|
} else {
|
||||||
|
ShortcutBadger.removeCount(context)
|
||||||
|
}
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val badgePreference: Preference = findPreference(R.string.p_badge_list)
|
||||||
|
val filter = defaultFilterProvider.badgeFilter
|
||||||
|
badgePreference.summary = filter.listingTitle
|
||||||
|
badgePreference.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||||
|
val intent = Intent(context, FilterSelectionActivity::class.java)
|
||||||
|
intent.putExtra(
|
||||||
|
FilterSelectionActivity.EXTRA_FILTER, defaultFilterProvider.badgeFilter)
|
||||||
|
intent.putExtra(FilterSelectionActivity.EXTRA_RETURN_FILTER, true)
|
||||||
|
startActivityForResult(intent, REQUEST_BADGE_LIST)
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
findPreference(R.string.p_voiceRemindersEnabled)
|
||||||
|
.setOnPreferenceChangeListener { preference: Preference, newValue: Any ->
|
||||||
|
val enabled = newValue as Boolean
|
||||||
|
try {
|
||||||
|
if (enabled && !voiceOutputAssistant.isTTSInitialized) {
|
||||||
|
val checkIntent = Intent()
|
||||||
|
checkIntent.action = TextToSpeech.Engine.ACTION_CHECK_TTS_DATA
|
||||||
|
startActivityForResult(checkIntent, REQUEST_CODE_TTS_CHECK)
|
||||||
|
} else if (!enabled && voiceOutputAssistant.isTTSInitialized) {
|
||||||
|
voiceOutputAssistant.shutdown()
|
||||||
|
}
|
||||||
|
} catch (e: VerifyError) {
|
||||||
|
Timber.e(e)
|
||||||
|
preference.isEnabled = false
|
||||||
|
preferences.setBoolean(preference.key, false)
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
requires(AndroidUtilities.atLeastOreo(), R.string.notification_channel_settings)
|
||||||
|
requires(AndroidUtilities.atLeastMarshmallow(), R.string.battery_optimization_settings)
|
||||||
|
requires(
|
||||||
|
AndroidUtilities.preOreo(), R.string.p_rmd_ringtone, R.string.p_rmd_vibrate, R.string.p_led_notification)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
super.onDestroy()
|
||||||
|
|
||||||
|
voiceOutputAssistant.shutdown()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun inject(component: FragmentComponent) {
|
||||||
|
component.inject(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun rescheduleNotificationsOnChange(vararg resIds: Int) {
|
||||||
|
for (resId in resIds) {
|
||||||
|
findPreference(resId)
|
||||||
|
.setOnPreferenceChangeListener { _: Preference?, _: Any? ->
|
||||||
|
NotificationSchedulerIntentService.enqueueWork(context, false)
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPreferenceTreeClick(preference: Preference?): Boolean {
|
||||||
|
return if (preference!!.key == getString(R.string.p_rmd_ringtone)) {
|
||||||
|
val intent = Intent(RingtoneManager.ACTION_RINGTONE_PICKER)
|
||||||
|
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, RingtoneManager.TYPE_NOTIFICATION)
|
||||||
|
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_DEFAULT, true)
|
||||||
|
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_SILENT, true)
|
||||||
|
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_DEFAULT_URI, Settings.System.DEFAULT_NOTIFICATION_URI)
|
||||||
|
val existingValue: String? = preferences.getStringValue(R.string.p_rmd_ringtone)
|
||||||
|
if (existingValue != null) {
|
||||||
|
if (existingValue.isEmpty()) {
|
||||||
|
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, null as Uri?)
|
||||||
|
} else {
|
||||||
|
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, Uri.parse(existingValue))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, Settings.System.DEFAULT_NOTIFICATION_URI)
|
||||||
|
}
|
||||||
|
startActivityForResult(intent, REQUEST_CODE_ALERT_RINGTONE)
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
super.onPreferenceTreeClick(preference)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getQuietStartPreference(): TimePreference? {
|
||||||
|
return getTimePreference(R.string.p_rmd_quietStart)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getQuietEndPreference(): TimePreference? {
|
||||||
|
return getTimePreference(R.string.p_rmd_quietEnd)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getDefaultRemindTimePreference(): TimePreference? {
|
||||||
|
return getTimePreference(R.string.p_rmd_time)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getTimePreference(resId: Int): TimePreference? {
|
||||||
|
return findPreference(getString(resId)) as TimePreference?
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun initializeTimePreference(preference: TimePreference, requestCode: Int) {
|
||||||
|
preference.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||||
|
val current = DateTime().withMillisOfDay(preference.millisOfDay)
|
||||||
|
val intent = Intent(context, TimePickerActivity::class.java)
|
||||||
|
intent.putExtra(TimePickerActivity.EXTRA_TIMESTAMP, current.millis)
|
||||||
|
startActivityForResult(intent, requestCode)
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun initializeRingtonePreference() {
|
||||||
|
val ringtoneChangedListener = Preference.OnPreferenceChangeListener { preference: Preference, value: Any? ->
|
||||||
|
if ("" == value) {
|
||||||
|
preference.setSummary(R.string.silent)
|
||||||
|
} else {
|
||||||
|
val ringtone = RingtoneManager.getRingtone(
|
||||||
|
context,
|
||||||
|
if (value == null) Settings.System.DEFAULT_NOTIFICATION_URI else Uri.parse(value as String?))
|
||||||
|
preference.summary = if (ringtone == null) "" else ringtone.getTitle(context)
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
val ringtoneKey = R.string.p_rmd_ringtone
|
||||||
|
val ringtonePreference: Preference = findPreference(ringtoneKey)
|
||||||
|
ringtonePreference.onPreferenceChangeListener = ringtoneChangedListener
|
||||||
|
ringtoneChangedListener.onPreferenceChange(
|
||||||
|
ringtonePreference,
|
||||||
|
preferences.getStringValue(ringtoneKey))
|
||||||
|
}
|
||||||
|
|
||||||
|
@TargetApi(Build.VERSION_CODES.O)
|
||||||
|
private fun openNotificationChannelSettings(@Suppress("UNUSED_PARAMETER") ignored: Preference): Boolean {
|
||||||
|
val intent = Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS)
|
||||||
|
intent.putExtra(Settings.EXTRA_APP_PACKAGE, activity!!.packageName)
|
||||||
|
startActivity(intent)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
@TargetApi(Build.VERSION_CODES.M)
|
||||||
|
private fun openBatteryOptimizationSettings(@Suppress("UNUSED_PARAMETER") ignored: Preference): Boolean {
|
||||||
|
val intent = Intent()
|
||||||
|
intent.action = Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS
|
||||||
|
startActivity(intent)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||||
|
if (requestCode == REQUEST_CODE_ALERT_RINGTONE) {
|
||||||
|
if (resultCode == RESULT_OK && data != null) {
|
||||||
|
val ringtone: Uri? = data.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI)
|
||||||
|
if (ringtone != null) {
|
||||||
|
preferences.setString(R.string.p_rmd_ringtone, ringtone.toString())
|
||||||
|
} else {
|
||||||
|
preferences.setString(R.string.p_rmd_ringtone, "")
|
||||||
|
}
|
||||||
|
initializeRingtonePreference()
|
||||||
|
}
|
||||||
|
} else if (requestCode == REQUEST_QUIET_START) {
|
||||||
|
if (resultCode == RESULT_OK) {
|
||||||
|
getQuietStartPreference()!!.handleTimePickerActivityIntent(data)
|
||||||
|
}
|
||||||
|
} else if (requestCode == REQUEST_QUIET_END) {
|
||||||
|
if (resultCode == RESULT_OK) {
|
||||||
|
getQuietEndPreference()!!.handleTimePickerActivityIntent(data)
|
||||||
|
}
|
||||||
|
} else if (requestCode == REQUEST_DEFAULT_REMIND) {
|
||||||
|
if (resultCode == RESULT_OK) {
|
||||||
|
getDefaultRemindTimePreference()!!.handleTimePickerActivityIntent(data)
|
||||||
|
}
|
||||||
|
} else if (requestCode == REQUEST_BADGE_LIST) {
|
||||||
|
if (resultCode == RESULT_OK) {
|
||||||
|
val filter: Filter = data!!.getParcelableExtra(FilterSelectionActivity.EXTRA_FILTER)!!
|
||||||
|
defaultFilterProvider.badgeFilter = filter
|
||||||
|
findPreference(R.string.p_badge_list).summary = filter.listingTitle
|
||||||
|
localBroadcastManager.broadcastRefresh()
|
||||||
|
}
|
||||||
|
} else if (requestCode == REQUEST_CODE_TTS_CHECK) {
|
||||||
|
if (resultCode == TextToSpeech.Engine.CHECK_VOICE_DATA_PASS) { // success, create the TTS instance
|
||||||
|
voiceOutputAssistant.initTTS()
|
||||||
|
} else { // missing data, install it
|
||||||
|
val installIntent = Intent()
|
||||||
|
installIntent.action = TextToSpeech.Engine.ACTION_INSTALL_TTS_DATA
|
||||||
|
startActivity(installIntent)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
super.onActivityResult(requestCode, resultCode, data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,183 @@
|
|||||||
|
package org.tasks.preferences.fragments
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Bundle
|
||||||
|
import androidx.preference.Preference
|
||||||
|
import androidx.preference.PreferenceCategory
|
||||||
|
import androidx.preference.SwitchPreferenceCompat
|
||||||
|
import com.google.common.base.Strings
|
||||||
|
import com.todoroo.andlib.utility.DateUtilities
|
||||||
|
import com.todoroo.astrid.gtasks.auth.GtasksLoginActivity
|
||||||
|
import com.todoroo.astrid.service.TaskDeleter
|
||||||
|
import org.tasks.R
|
||||||
|
import org.tasks.caldav.CaldavAccountSettingsActivity
|
||||||
|
import org.tasks.data.CaldavAccount
|
||||||
|
import org.tasks.data.CaldavDao
|
||||||
|
import org.tasks.data.GoogleTaskAccount
|
||||||
|
import org.tasks.data.GoogleTaskListDao
|
||||||
|
import org.tasks.etesync.EteSyncAccountSettingsActivity
|
||||||
|
import org.tasks.injection.FragmentComponent
|
||||||
|
import org.tasks.injection.InjectingPreferenceFragment
|
||||||
|
import org.tasks.jobs.WorkManager
|
||||||
|
import org.tasks.preferences.Preferences
|
||||||
|
import org.tasks.sync.AddAccountDialog
|
||||||
|
import org.tasks.ui.Toaster
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
const val REQUEST_CALDAV_SETTINGS = 10013
|
||||||
|
const val REQUEST_GOOGLE_TASKS = 10014
|
||||||
|
|
||||||
|
class Synchronization : InjectingPreferenceFragment() {
|
||||||
|
|
||||||
|
@Inject lateinit var workManager: WorkManager
|
||||||
|
@Inject lateinit var preferences: Preferences
|
||||||
|
@Inject lateinit var toaster: Toaster
|
||||||
|
@Inject lateinit var caldavDao: CaldavDao
|
||||||
|
@Inject lateinit var googleTaskListDao: GoogleTaskListDao
|
||||||
|
@Inject lateinit var taskDeleter: TaskDeleter
|
||||||
|
|
||||||
|
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||||
|
setPreferencesFromResource(R.xml.preferences_synchronization, rootKey)
|
||||||
|
|
||||||
|
findPreference(R.string.p_background_sync_unmetered_only)
|
||||||
|
.setOnPreferenceChangeListener { _: Preference?, o: Any? ->
|
||||||
|
workManager.updateBackgroundSync(null, null, o as Boolean?)
|
||||||
|
true
|
||||||
|
}
|
||||||
|
findPreference(R.string.p_background_sync)
|
||||||
|
.setOnPreferenceChangeListener { _: Preference?, o: Any? ->
|
||||||
|
workManager.updateBackgroundSync(null, o as Boolean?, null)
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
val positionHack = findPreference(R.string.google_tasks_position_hack) as SwitchPreferenceCompat
|
||||||
|
positionHack.isChecked = preferences.isPositionHackEnabled
|
||||||
|
positionHack.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _: Preference?, newValue: Any? ->
|
||||||
|
if (newValue == null) {
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
preferences.setLong(
|
||||||
|
R.string.p_google_tasks_position_hack, if (newValue as Boolean) DateUtilities.now() else 0)
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
findPreference(R.string.add_account)
|
||||||
|
.setOnPreferenceClickListener {
|
||||||
|
AddAccountDialog.showAddAccountDialog(activity, dialogBuilder)
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
|
||||||
|
refresh()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||||
|
if (requestCode == REQUEST_CALDAV_SETTINGS) {
|
||||||
|
if (resultCode == Activity.RESULT_OK) {
|
||||||
|
workManager.updateBackgroundSync()
|
||||||
|
}
|
||||||
|
} else if (requestCode == REQUEST_GOOGLE_TASKS) {
|
||||||
|
if (resultCode == Activity.RESULT_OK) {
|
||||||
|
workManager.updateBackgroundSync()
|
||||||
|
} else if (data != null) {
|
||||||
|
toaster.longToast(data.getStringExtra(GtasksLoginActivity.EXTRA_ERROR))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
super.onActivityResult(requestCode, resultCode, data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun addGoogleTasksAccounts(category: PreferenceCategory): Boolean {
|
||||||
|
val accounts: List<GoogleTaskAccount> = googleTaskListDao.accounts
|
||||||
|
for (googleTaskAccount in accounts) {
|
||||||
|
val account = googleTaskAccount.account
|
||||||
|
val preference = Preference(context)
|
||||||
|
preference.title = account
|
||||||
|
val error = googleTaskAccount.error
|
||||||
|
if (Strings.isNullOrEmpty(error)) {
|
||||||
|
preference.setSummary(R.string.gtasks_GPr_header)
|
||||||
|
} else {
|
||||||
|
preference.summary = error
|
||||||
|
}
|
||||||
|
preference.setOnPreferenceClickListener {
|
||||||
|
dialogBuilder
|
||||||
|
.newDialog(account)
|
||||||
|
.setItems(listOf(getString(R.string.reinitialize_account), getString(R.string.logout))) { _, which ->
|
||||||
|
if (which == 0) {
|
||||||
|
startActivityForResult(
|
||||||
|
Intent(context, GtasksLoginActivity::class.java),
|
||||||
|
REQUEST_GOOGLE_TASKS)
|
||||||
|
} else {
|
||||||
|
logoutConfirmation(googleTaskAccount)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.showThemedListView()
|
||||||
|
false
|
||||||
|
}
|
||||||
|
category.addPreference(preference)
|
||||||
|
}
|
||||||
|
return accounts.isNotEmpty()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun addCaldavAccounts(category: PreferenceCategory): Boolean {
|
||||||
|
val accounts: List<CaldavAccount> = caldavDao.accounts
|
||||||
|
for (account in accounts) {
|
||||||
|
val preference = Preference(context)
|
||||||
|
preference.title = account.name
|
||||||
|
val error = account.error
|
||||||
|
if (Strings.isNullOrEmpty(error)) {
|
||||||
|
preference.setSummary(
|
||||||
|
if (account.isCaldavAccount) R.string.caldav else R.string.etesync)
|
||||||
|
} else {
|
||||||
|
preference.summary = error
|
||||||
|
}
|
||||||
|
preference.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||||
|
val intent = Intent(
|
||||||
|
context,
|
||||||
|
if (account.isCaldavAccount) CaldavAccountSettingsActivity::class.java
|
||||||
|
else EteSyncAccountSettingsActivity::class.java)
|
||||||
|
intent.putExtra(CaldavAccountSettingsActivity.EXTRA_CALDAV_DATA, account)
|
||||||
|
startActivityForResult(intent, REQUEST_CALDAV_SETTINGS)
|
||||||
|
false
|
||||||
|
}
|
||||||
|
category.addPreference(preference)
|
||||||
|
}
|
||||||
|
return accounts.isNotEmpty()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun logoutConfirmation(account: GoogleTaskAccount) {
|
||||||
|
val name = account.account
|
||||||
|
val alertDialog = dialogBuilder
|
||||||
|
.newDialog()
|
||||||
|
.setMessage(R.string.logout_warning, name)
|
||||||
|
.setPositiveButton(R.string.logout) { _, _ ->
|
||||||
|
taskDeleter.delete(account)
|
||||||
|
refresh()
|
||||||
|
}
|
||||||
|
.setNegativeButton(android.R.string.cancel, null)
|
||||||
|
.create()
|
||||||
|
alertDialog.setCanceledOnTouchOutside(false)
|
||||||
|
alertDialog.setCancelable(false)
|
||||||
|
alertDialog.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun refresh() {
|
||||||
|
val synchronizationPreferences = findPreference(R.string.accounts) as PreferenceCategory
|
||||||
|
synchronizationPreferences.removeAll()
|
||||||
|
|
||||||
|
val hasGoogleAccounts: Boolean = addGoogleTasksAccounts(synchronizationPreferences)
|
||||||
|
val hasCaldavAccounts = addCaldavAccounts(synchronizationPreferences)
|
||||||
|
findPreference(R.string.gtasks_GPr_header).isVisible = hasGoogleAccounts
|
||||||
|
findPreference(R.string.accounts).isVisible = hasGoogleAccounts || hasCaldavAccounts
|
||||||
|
findPreference(R.string.sync_SPr_interval_title).isVisible = hasGoogleAccounts || hasCaldavAccounts
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun inject(component: FragmentComponent) {
|
||||||
|
component.inject(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,115 @@
|
|||||||
|
package org.tasks.preferences.fragments
|
||||||
|
|
||||||
|
import android.app.Activity.RESULT_OK
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Bundle
|
||||||
|
import androidx.preference.Preference
|
||||||
|
import com.todoroo.astrid.api.CaldavFilter
|
||||||
|
import com.todoroo.astrid.api.Filter
|
||||||
|
import com.todoroo.astrid.api.GtasksFilter
|
||||||
|
import org.tasks.PermissionUtil
|
||||||
|
import org.tasks.R
|
||||||
|
import org.tasks.activities.CalendarSelectionActivity
|
||||||
|
import org.tasks.activities.RemoteListPicker
|
||||||
|
import org.tasks.calendars.CalendarProvider
|
||||||
|
import org.tasks.injection.FragmentComponent
|
||||||
|
import org.tasks.injection.InjectingPreferenceFragment
|
||||||
|
import org.tasks.preferences.DefaultFilterProvider
|
||||||
|
import org.tasks.preferences.FragmentPermissionRequestor
|
||||||
|
import org.tasks.preferences.PermissionRequestor
|
||||||
|
import org.tasks.preferences.Preferences
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
private const val FRAG_TAG_REMOTE_LIST_SELECTION = "frag_tag_remote_list_selection"
|
||||||
|
private const val REQUEST_REMOTE_LIST = 10010
|
||||||
|
private const val REQUEST_CALENDAR_SELECTION = 10011
|
||||||
|
|
||||||
|
class TaskDefaults : InjectingPreferenceFragment() {
|
||||||
|
|
||||||
|
@Inject lateinit var permissionRequester: FragmentPermissionRequestor
|
||||||
|
@Inject lateinit var defaultFilterProvider: DefaultFilterProvider
|
||||||
|
@Inject lateinit var preferences: Preferences
|
||||||
|
@Inject lateinit var calendarProvider: CalendarProvider
|
||||||
|
|
||||||
|
private lateinit var defaultCalendarPref: Preference
|
||||||
|
|
||||||
|
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||||
|
setPreferencesFromResource(R.xml.preferences_task_defaults, rootKey)
|
||||||
|
|
||||||
|
defaultCalendarPref = findPreference(R.string.gcal_p_default)
|
||||||
|
defaultCalendarPref.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||||
|
if (permissionRequester.requestCalendarPermissions()) {
|
||||||
|
startCalendarSelectionActivity()
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
val defaultCalendarName: String? = getDefaultCalendarName()
|
||||||
|
defaultCalendarPref.summary = defaultCalendarName
|
||||||
|
?: getString(R.string.dont_add_to_calendar)
|
||||||
|
|
||||||
|
findPreference(R.string.p_default_remote_list)
|
||||||
|
.setOnPreferenceClickListener {
|
||||||
|
RemoteListPicker.newRemoteListSupportPicker(defaultFilterProvider.defaultRemoteList, this, REQUEST_REMOTE_LIST)
|
||||||
|
.show(fragmentManager!!, FRAG_TAG_REMOTE_LIST_SELECTION)
|
||||||
|
false
|
||||||
|
}
|
||||||
|
updateRemoteListSummary()
|
||||||
|
|
||||||
|
requires(device.supportsGeofences(), R.string.p_default_location_reminder_key)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
|
||||||
|
if (requestCode == PermissionRequestor.REQUEST_CALENDAR) {
|
||||||
|
if (PermissionUtil.verifyPermissions(grantResults)) {
|
||||||
|
startCalendarSelectionActivity()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||||
|
if (requestCode == REQUEST_REMOTE_LIST) {
|
||||||
|
val list: Filter? = data!!.getParcelableExtra(RemoteListPicker.EXTRA_SELECTED_FILTER)
|
||||||
|
if (list == null) {
|
||||||
|
preferences.setString(R.string.p_default_remote_list, null)
|
||||||
|
} else if (list is GtasksFilter || list is CaldavFilter) {
|
||||||
|
defaultFilterProvider.defaultRemoteList = list
|
||||||
|
} else {
|
||||||
|
throw RuntimeException("Unhandled filter type")
|
||||||
|
}
|
||||||
|
updateRemoteListSummary()
|
||||||
|
} else if (requestCode == REQUEST_CALENDAR_SELECTION) {
|
||||||
|
if (resultCode == RESULT_OK) {
|
||||||
|
preferences.setString(
|
||||||
|
R.string.gcal_p_default,
|
||||||
|
data!!.getStringExtra(CalendarSelectionActivity.EXTRA_CALENDAR_ID))
|
||||||
|
defaultCalendarPref.summary = data.getStringExtra(CalendarSelectionActivity.EXTRA_CALENDAR_NAME)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
super.onActivityResult(requestCode, resultCode, data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getDefaultCalendarName(): String? {
|
||||||
|
val calendarId = preferences.getStringValue(R.string.gcal_p_default)
|
||||||
|
return calendarProvider.getCalendar(calendarId)?.name
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun startCalendarSelectionActivity() {
|
||||||
|
val intent = Intent(context, CalendarSelectionActivity::class.java)
|
||||||
|
intent.putExtra(CalendarSelectionActivity.EXTRA_CALENDAR_NAME, getDefaultCalendarName())
|
||||||
|
startActivityForResult(intent, REQUEST_CALENDAR_SELECTION)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateRemoteListSummary() {
|
||||||
|
val defaultFilter = defaultFilterProvider.defaultRemoteList
|
||||||
|
findPreference(R.string.p_default_remote_list).summary =
|
||||||
|
if (defaultFilter == null) getString(R.string.dont_sync)
|
||||||
|
else defaultFilter.listingTitle
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun inject(component: FragmentComponent) {
|
||||||
|
component.inject(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
<vector android:autoMirrored="true" android:height="24dp"
|
||||||
|
android:viewportHeight="24" android:viewportWidth="24"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="#FF000000" android:pathData="M19,19H5V5h7V3H5c-1.11,0 -2,0.9 -2,2v14c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2v-7h-2v7zM14,3v2h3.59l-9.83,9.83 1.41,1.41L19,6.41V10h2V3h-7z"/>
|
||||||
|
</vector>
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
<vector android:autoMirrored="true" android:height="24dp"
|
||||||
|
android:viewportHeight="24" android:viewportWidth="24"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="#FF000000" android:pathData="M14.06,9.02l0.92,0.92L5.92,19L5,19v-0.92l9.06,-9.06M17.66,3c-0.25,0 -0.51,0.1 -0.7,0.29l-1.83,1.83 3.75,3.75 1.83,-1.83c0.39,-0.39 0.39,-1.02 0,-1.41l-2.34,-2.34c-0.2,-0.2 -0.45,-0.29 -0.71,-0.29zM14.06,6.19L3,17.25L3,21h3.75L17.81,9.94l-3.75,-3.75z"/>
|
||||||
|
</vector>
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
<vector android:autoMirrored="true" android:height="24dp"
|
||||||
|
android:viewportHeight="24" android:viewportWidth="24"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="#FF000000" android:pathData="M11,7h2v2h-2zM11,11h2v6h-2zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8z"/>
|
||||||
|
</vector>
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
<vector android:autoMirrored="true" android:height="24dp"
|
||||||
|
android:viewportHeight="24" android:viewportWidth="24"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="#FF000000" android:pathData="M12,22C6.49,22 2,17.51 2,12S6.49,2 12,2s10,4.04 10,9c0,3.31 -2.69,6 -6,6h-1.77c-0.28,0 -0.5,0.22 -0.5,0.5 0,0.12 0.05,0.23 0.13,0.33 0.41,0.47 0.64,1.06 0.64,1.67 0,1.38 -1.12,2.5 -2.5,2.5zM12,4c-4.41,0 -8,3.59 -8,8s3.59,8 8,8c0.28,0 0.5,-0.22 0.5,-0.5 0,-0.16 -0.08,-0.28 -0.14,-0.35 -0.41,-0.46 -0.63,-1.05 -0.63,-1.65 0,-1.38 1.12,-2.5 2.5,-2.5L16,15c2.21,0 4,-1.79 4,-4 0,-3.86 -3.59,-7 -8,-7z"/>
|
||||||
|
<path android:fillColor="#FF000000" android:pathData="M6.5,11.5m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0"/>
|
||||||
|
<path android:fillColor="#FF000000" android:pathData="M9.5,7.5m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0"/>
|
||||||
|
<path android:fillColor="#FF000000" android:pathData="M14.5,7.5m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0"/>
|
||||||
|
<path android:fillColor="#FF000000" android:pathData="M17.5,11.5m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0"/>
|
||||||
|
</vector>
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
<vector android:autoMirrored="true" android:height="24dp"
|
||||||
|
android:viewportHeight="24" android:viewportWidth="24"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="#FF000000" android:pathData="M18,4v16L6,20L6,8.83L10.83,4L18,4m0,-2h-8L4,8v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L20,4c0,-1.1 -0.9,-2 -2,-2zM9,7h2v4L9,11zM12,7h2v4h-2zM15,7h2v4h-2z"/>
|
||||||
|
</vector>
|
||||||
@ -1,9 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<include layout="@layout/toolbar"/>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
@ -1,47 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content">
|
|
||||||
|
|
||||||
<com.rey.material.widget.Slider xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
android:id="@+id/slider"
|
|
||||||
style="@style/Material.Widget.Slider.Discrete"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:paddingStart="@dimen/keyline_first"
|
|
||||||
android:paddingEnd="@dimen/keyline_first"
|
|
||||||
android:paddingLeft="@dimen/keyline_first"
|
|
||||||
android:paddingRight="@dimen/keyline_first"
|
|
||||||
android:gravity="center"
|
|
||||||
android:minHeight="?attr/listPreferredItemHeight"
|
|
||||||
app:sl_discreteMode="true"
|
|
||||||
app:sl_stepValue="2"
|
|
||||||
app:sl_travelAnimDuration="100"/>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/min"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_alignParentLeft="true"
|
|
||||||
android:layout_alignParentStart="true"
|
|
||||||
android:layout_below="@id/slider"
|
|
||||||
android:paddingTop="5dp"
|
|
||||||
android:paddingStart="@dimen/keyline_first"
|
|
||||||
android:paddingEnd="@dimen/keyline_first"
|
|
||||||
android:paddingLeft="@dimen/keyline_first"
|
|
||||||
android:paddingRight="@dimen/keyline_first"/>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/max"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_alignParentEnd="true"
|
|
||||||
android:layout_alignParentRight="true"
|
|
||||||
android:layout_below="@id/slider"
|
|
||||||
android:paddingTop="5dp"
|
|
||||||
android:paddingStart="@dimen/keyline_first"
|
|
||||||
android:paddingEnd="@dimen/keyline_first"
|
|
||||||
android:paddingLeft="@dimen/keyline_first"
|
|
||||||
android:paddingRight="@dimen/keyline_first"/>
|
|
||||||
|
|
||||||
</RelativeLayout>
|
|
||||||
@ -1,47 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content">
|
|
||||||
|
|
||||||
<com.rey.material.widget.Slider xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
android:id="@+id/slider"
|
|
||||||
style="@style/Material.Widget.Slider.Discrete"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:paddingStart="@dimen/keyline_first"
|
|
||||||
android:paddingEnd="@dimen/keyline_first"
|
|
||||||
android:paddingLeft="@dimen/keyline_first"
|
|
||||||
android:paddingRight="@dimen/keyline_first"
|
|
||||||
android:gravity="center"
|
|
||||||
android:minHeight="?attr/listPreferredItemHeight"
|
|
||||||
app:sl_discreteMode="true"
|
|
||||||
app:sl_stepValue="5"
|
|
||||||
app:sl_travelAnimDuration="100"/>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/min"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_alignParentLeft="true"
|
|
||||||
android:layout_alignParentStart="true"
|
|
||||||
android:layout_below="@id/slider"
|
|
||||||
android:paddingTop="5dp"
|
|
||||||
android:paddingStart="@dimen/keyline_first"
|
|
||||||
android:paddingEnd="@dimen/keyline_first"
|
|
||||||
android:paddingLeft="@dimen/keyline_first"
|
|
||||||
android:paddingRight="@dimen/keyline_first"/>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/max"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_alignParentEnd="true"
|
|
||||||
android:layout_alignParentRight="true"
|
|
||||||
android:layout_below="@id/slider"
|
|
||||||
android:paddingTop="5dp"
|
|
||||||
android:paddingStart="@dimen/keyline_first"
|
|
||||||
android:paddingEnd="@dimen/keyline_first"
|
|
||||||
android:paddingLeft="@dimen/keyline_first"
|
|
||||||
android:paddingRight="@dimen/keyline_first"/>
|
|
||||||
|
|
||||||
</RelativeLayout>
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue