Migrate settings to androidx preferences

pull/935/head
Alex Baker 5 years ago
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,23 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<CheckBoxPreference
<SwitchPreferenceCompat
android:key="@string/p_leakcanary"
android:title="@string/debug_leakcanary" />
<CheckBoxPreference
<SwitchPreferenceCompat
android:key="@string/p_flipper"
android:title="@string/debug_flipper"/>
<CheckBoxPreference
<SwitchPreferenceCompat
android:key="@string/p_strict_mode_thread"
android:title="@string/debug_strict_mode_thread"/>
<CheckBoxPreference
<SwitchPreferenceCompat
android:key="@string/p_strict_mode_vm"
android:title="@string/debug_strict_mode_vm"/>
<CheckBoxPreference
<SwitchPreferenceCompat
android:key="@string/p_debug_pro"
android:title="@string/debug_pro"/>

@ -104,7 +104,7 @@
android:networkSecurityConfig="@xml/network_security_config"
android:icon="@mipmap/ic_launcher_blue"
android:label="@string/app_name"
android:manageSpaceActivity="com.todoroo.astrid.core.OldTaskPreferences"
android:manageSpaceActivity="org.tasks.preferences.ManageSpaceActivity"
android:name=".Tasks"
android:roundIcon="@mipmap/ic_launcher_blue"
android:supportsRtl="true"
@ -213,16 +213,6 @@
<!-- Activity for preferences -->
<activity
android:label="@string/TLA_menu_settings"
android:name=".preferences.BasicPreferences"
android:theme="@style/Tasks"/>
<activity
android:label="@string/miscellaneous"
android:name=".preferences.MiscellaneousPreferences"
android:theme="@style/Tasks"/>
<activity
android:excludeFromRecents="true"
android:exported="true"
@ -288,16 +278,6 @@
<!-- ========================================================= Plugins = -->
<activity
android:label="@string/date_and_time"
android:name=".preferences.DateTimePreferences"
android:theme="@style/Tasks"/>
<activity
android:label="@string/task_defaults"
android:name="com.todoroo.astrid.core.DefaultsPreferences"
android:theme="@style/Tasks"/>
<activity
android:name="com.todoroo.astrid.activity.BeastModePreferences"
android:theme="@style/Tasks"/>
@ -362,10 +342,6 @@
android:theme="@style/TranslucentDialog" />
<!-- old tasks -->
<activity
android:label="@string/EPr_manage_header"
android:name="com.todoroo.astrid.core.OldTaskPreferences"
android:theme="@style/Tasks"/>
<activity
android:label="@string/app_name"
@ -382,18 +358,6 @@
android:theme="@style/TranslucentDialog"/>
<!-- reminders -->
<activity
android:exported="false"
android:label="@string/notifications"
android:name="com.todoroo.astrid.reminders.ReminderPreferences"
android:theme="@style/Tasks">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.NOTIFICATION_PREFERENCES"/>
</intent-filter>
</activity>
<activity
android:name=".voice.VoiceCommandActivity"
@ -550,11 +514,6 @@
</activity>
<activity
android:label="@string/debug"
android:name=".preferences.DebugPreferences"
android:theme="@style/Tasks"/>
<activity
android:name=".widget.WidgetClickActivity"
android:excludeFromRecents="true"
@ -574,10 +533,31 @@
android:name=".etesync.EncryptionSettingsActivity"
android:theme="@style/Tasks" />
<activity
android:name=".preferences.MainPreferences"
android:theme="@style/Tasks" />
<activity
android:name=".preferences.HelpAndFeedback"
android:theme="@style/Tasks" />
<activity
android:name=".preferences.NotificationPreferences"
android:theme="@style/Tasks">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.NOTIFICATION_PREFERENCES" />
</intent-filter>
</activity>
<activity
android:name=".preferences.ManageSpaceActivity"
android:theme="@style/Tasks" />
<activity
android:name=".preferences.SyncPreferences"
android:theme="@style/Tasks" />
<!-- launcher icons -->
<activity-alias

@ -9,6 +9,7 @@ package com.todoroo.astrid.activity;
import static com.google.common.base.Strings.isNullOrEmpty;
import static com.todoroo.andlib.utility.AndroidUtilities.assertMainThread;
import static com.todoroo.andlib.utility.AndroidUtilities.atLeastLollipop;
import static com.todoroo.andlib.utility.AndroidUtilities.atLeastNougat;
import static com.todoroo.astrid.activity.TaskEditFragment.newTaskEditFragment;
import static com.todoroo.astrid.activity.TaskListFragment.newTaskListFragment;
import static org.tasks.tasklist.ActionUtils.applySupportActionModeColor;
@ -48,6 +49,7 @@ import org.tasks.fragments.CommentBarFragment;
import org.tasks.gtasks.PlayServices;
import org.tasks.injection.ActivityComponent;
import org.tasks.injection.InjectingAppCompatActivity;
import org.tasks.intents.TaskIntents;
import org.tasks.preferences.DefaultFilterProvider;
import org.tasks.preferences.Preferences;
import org.tasks.receivers.RepeatConfirmationReceiver;
@ -133,6 +135,27 @@ public class MainActivity extends InjectingAppCompatActivity
});
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == NavigationDrawerFragment.REQUEST_SETTINGS) {
if (atLeastNougat()) {
recreate();
} else {
finish();
startActivity(TaskIntents.getTaskListIntent(this, filter));
}
} else if (requestCode == REQUEST_NEW_LIST) {
if (resultCode == RESULT_OK && data != null) {
Filter filter = data.getParcelableExtra(MainActivity.OPEN_FILTER);
if (filter != null) {
startActivity(TaskIntents.getTaskListIntent(this, filter));
}
}
} else {
super.onActivityResult(requestCode, resultCode, data);
}
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);

@ -10,7 +10,7 @@ import static android.app.Activity.RESULT_OK;
import static androidx.core.content.ContextCompat.getColor;
import static com.google.common.collect.Lists.newArrayList;
import static com.todoroo.andlib.utility.AndroidUtilities.assertMainThread;
import static org.tasks.activities.RemoteListSupportPicker.newRemoteListSupportPicker;
import static org.tasks.activities.RemoteListPicker.newRemoteListSupportPicker;
import static org.tasks.caldav.CaldavCalendarSettingsActivity.EXTRA_CALDAV_CALENDAR;
import static org.tasks.ui.CheckBoxes.getPriorityColor;
@ -80,7 +80,7 @@ import org.tasks.LocalBroadcastManager;
import org.tasks.R;
import org.tasks.activities.FilterSettingsActivity;
import org.tasks.activities.GoogleTaskListSettingsActivity;
import org.tasks.activities.RemoteListSupportPicker;
import org.tasks.activities.RemoteListPicker;
import org.tasks.activities.TagSettingsActivity;
import org.tasks.caldav.CaldavCalendarSettingsActivity;
import org.tasks.data.CaldavAccount;
@ -586,7 +586,7 @@ public final class TaskListFragment extends InjectingFragment
if (resultCode == RESULT_OK) {
taskMover.move(
taskAdapter.getSelected(),
data.getParcelableExtra(RemoteListSupportPicker.EXTRA_SELECTED_FILTER));
data.getParcelableExtra(RemoteListPicker.EXTRA_SELECTED_FILTER));
finishActionMode();
}
break;

@ -27,7 +27,7 @@ import org.tasks.R;
import org.tasks.billing.Inventory;
import org.tasks.filters.NavigationDrawerSubheader;
import org.tasks.locale.Locale;
import org.tasks.preferences.BasicPreferences;
import org.tasks.preferences.SyncPreferences;
import org.tasks.themes.CustomIcons;
import org.tasks.themes.ThemeAccent;
import org.tasks.themes.ThemeCache;
@ -104,7 +104,7 @@ public class FilterViewHolder extends RecyclerView.ViewHolder {
ButterKnife.bind(this, itemView);
icon.setOnClickListener(
v -> activity.startActivity(new Intent(activity, BasicPreferences.class)));
v -> activity.startActivity(new Intent(activity, SyncPreferences.class)));
}
FilterViewHolder(@NonNull View itemView) {

@ -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);
}
}

@ -14,7 +14,7 @@ import org.tasks.R;
import org.tasks.dialogs.DialogBuilder;
import org.tasks.injection.ActivityComponent;
import org.tasks.injection.ThemedInjectingAppCompatActivity;
import org.tasks.preferences.BasicPreferences;
import org.tasks.preferences.MainPreferences;
import org.tasks.preferences.Preferences;
import org.tasks.scheduling.AlarmManager;
import org.tasks.scheduling.CalendarNotificationIntentService;
@ -129,7 +129,7 @@ public class CalendarReminderActivity extends ThemedInjectingAppCompatActivity {
ignoreSettingsButton.setOnClickListener(
v -> {
Intent editPreferences =
new Intent(CalendarReminderActivity.this, BasicPreferences.class);
new Intent(CalendarReminderActivity.this, MainPreferences.class);
startActivity(editPreferences);
dismissListener.onClick(v);
});

@ -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,17 +1,13 @@
package org.tasks.activities;
import static org.tasks.dialogs.NativeDatePickerDialog.newNativeDatePickerDialog;
import static org.tasks.time.DateTimeUtils.currentTimeMillis;
import android.app.FragmentManager;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import com.wdullaer.materialdatetimepicker.date.DatePickerDialog;
import javax.inject.Inject;
import org.tasks.R;
import org.tasks.dialogs.MyDatePickerDialog;
import org.tasks.dialogs.NativeDatePickerDialog;
import org.tasks.injection.ActivityComponent;
import org.tasks.injection.InjectingAppCompatActivity;
import org.tasks.preferences.Preferences;
@ -21,8 +17,7 @@ import org.tasks.time.DateTime;
public class DateAndTimePickerActivity extends InjectingAppCompatActivity
implements DatePickerDialog.OnDateSetListener,
DialogInterface.OnCancelListener,
NativeDatePickerDialog.NativeDatePickerDialogCallback {
DialogInterface.OnCancelListener {
public static final String EXTRA_TIMESTAMP = "extra_timestamp";
private static final String FRAG_TAG_DATE_PICKER = "frag_tag_date_picker";
@ -47,30 +42,23 @@ public class DateAndTimePickerActivity extends InjectingAppCompatActivity
}
}
if (preferences.getBoolean(R.string.p_use_native_datetime_pickers, false)) {
FragmentManager fragmentManager = getFragmentManager();
if (fragmentManager.findFragmentByTag(FRAG_TAG_DATE_PICKER) == null) {
newNativeDatePickerDialog(initial).show(fragmentManager, FRAG_TAG_DATE_PICKER);
androidx.fragment.app.FragmentManager fragmentManager = getSupportFragmentManager();
MyDatePickerDialog datePickerDialog =
(MyDatePickerDialog) fragmentManager.findFragmentByTag(FRAG_TAG_DATE_PICKER);
if (datePickerDialog == null) {
datePickerDialog = new MyDatePickerDialog();
datePickerDialog.initialize(
null, initial.getYear(), initial.getMonthOfYear() - 1, initial.getDayOfMonth());
datePickerDialog.setThemeDark(themeBase.isDarkTheme(this));
datePickerDialog.setAccentColor(themeAccent.getAccentColor());
int firstDayOfWeek = preferences.getFirstDayOfWeek();
if (firstDayOfWeek >= 1 && firstDayOfWeek <= 7) {
datePickerDialog.setFirstDayOfWeek(firstDayOfWeek);
}
} else {
androidx.fragment.app.FragmentManager fragmentManager = getSupportFragmentManager();
MyDatePickerDialog datePickerDialog =
(MyDatePickerDialog) fragmentManager.findFragmentByTag(FRAG_TAG_DATE_PICKER);
if (datePickerDialog == null) {
datePickerDialog = new MyDatePickerDialog();
datePickerDialog.initialize(
null, initial.getYear(), initial.getMonthOfYear() - 1, initial.getDayOfMonth());
datePickerDialog.setThemeDark(themeBase.isDarkTheme(this));
datePickerDialog.setAccentColor(themeAccent.getAccentColor());
int firstDayOfWeek = preferences.getFirstDayOfWeek();
if (firstDayOfWeek >= 1 && firstDayOfWeek <= 7) {
datePickerDialog.setFirstDayOfWeek(firstDayOfWeek);
}
datePickerDialog.show(fragmentManager, FRAG_TAG_DATE_PICKER);
}
datePickerDialog.setOnCancelListener(this);
datePickerDialog.setOnDateSetListener(this);
datePickerDialog.show(fragmentManager, FRAG_TAG_DATE_PICKER);
}
datePickerDialog.setOnCancelListener(this);
datePickerDialog.setOnDateSetListener(this);
}
@Override
@ -87,25 +75,6 @@ public class DateAndTimePickerActivity extends InjectingAppCompatActivity
@Override
public void onDateSet(DatePickerDialog datePickerDialog, int year, int month, int day) {
datePickerDialog.dismiss();
dateSet(year, month, day);
}
@Override
public void onCancel(DialogInterface dialog) {
finish();
}
@Override
public void cancel() {
finish();
}
@Override
public void onDateSet(int year, int month, int day) {
dateSet(year, month, day);
}
private void dateSet(int year, int month, int day) {
dateSelected = true;
final long timestamp =
new DateTime(year, month + 1, day).withMillisOfDay(initial.getMillisOfDay()).getMillis();
@ -115,4 +84,10 @@ public class DateAndTimePickerActivity extends InjectingAppCompatActivity
startActivity(intent);
finish();
}
@Override
public void onCancel(DialogInterface dialog) {
finish();
}
}

@ -1,6 +1,5 @@
package org.tasks.activities;
import static org.tasks.dialogs.NativeDatePickerDialog.newNativeDatePickerDialog;
import static org.tasks.time.DateTimeUtils.currentTimeMillis;
import android.content.Intent;
@ -8,9 +7,7 @@ import android.os.Bundle;
import androidx.fragment.app.FragmentManager;
import com.wdullaer.materialdatetimepicker.date.DatePickerDialog;
import javax.inject.Inject;
import org.tasks.R;
import org.tasks.dialogs.MyDatePickerDialog;
import org.tasks.dialogs.NativeDatePickerDialog.NativeDatePickerDialogCallback;
import org.tasks.injection.ActivityComponent;
import org.tasks.injection.InjectingAppCompatActivity;
import org.tasks.preferences.Preferences;
@ -19,7 +16,7 @@ import org.tasks.themes.ThemeBase;
import org.tasks.time.DateTime;
public class DatePickerActivity extends InjectingAppCompatActivity
implements DatePickerDialog.OnDateSetListener, NativeDatePickerDialogCallback {
implements DatePickerDialog.OnDateSetListener {
public static final String EXTRA_TIMESTAMP = "extra_timestamp";
private static final String FRAG_TAG_DATE_PICKER = "frag_tag_date_picker";
@ -33,31 +30,24 @@ public class DatePickerActivity extends InjectingAppCompatActivity
long timestamp = getIntent().getLongExtra(EXTRA_TIMESTAMP, currentTimeMillis());
DateTime initial = (timestamp > 0 ? new DateTime(timestamp) : new DateTime()).startOfDay();
if (preferences.getBoolean(R.string.p_use_native_datetime_pickers, false)) {
android.app.FragmentManager fragmentManager = getFragmentManager();
if (fragmentManager.findFragmentByTag(FRAG_TAG_DATE_PICKER) == null) {
newNativeDatePickerDialog(initial).show(fragmentManager, FRAG_TAG_DATE_PICKER);
FragmentManager fragmentManager = getSupportFragmentManager();
MyDatePickerDialog dialog =
(MyDatePickerDialog) fragmentManager.findFragmentByTag(FRAG_TAG_DATE_PICKER);
if (dialog == null) {
dialog = new MyDatePickerDialog();
dialog.initialize(
null, initial.getYear(), initial.getMonthOfYear() - 1, initial.getDayOfMonth());
dialog.setVersion(DatePickerDialog.Version.VERSION_2);
dialog.setThemeDark(themeBase.isDarkTheme(this));
dialog.setAccentColor(themeAccent.getAccentColor());
int firstDayOfWeek = preferences.getFirstDayOfWeek();
if (firstDayOfWeek >= 1 && firstDayOfWeek <= 7) {
dialog.setFirstDayOfWeek(firstDayOfWeek);
}
} else {
FragmentManager fragmentManager = getSupportFragmentManager();
MyDatePickerDialog dialog =
(MyDatePickerDialog) fragmentManager.findFragmentByTag(FRAG_TAG_DATE_PICKER);
if (dialog == null) {
dialog = new MyDatePickerDialog();
dialog.initialize(
null, initial.getYear(), initial.getMonthOfYear() - 1, initial.getDayOfMonth());
dialog.setVersion(DatePickerDialog.Version.VERSION_2);
dialog.setThemeDark(themeBase.isDarkTheme(this));
dialog.setAccentColor(themeAccent.getAccentColor());
int firstDayOfWeek = preferences.getFirstDayOfWeek();
if (firstDayOfWeek >= 1 && firstDayOfWeek <= 7) {
dialog.setFirstDayOfWeek(firstDayOfWeek);
}
dialog.show(fragmentManager, FRAG_TAG_DATE_PICKER);
}
dialog.setOnCancelListener(dialogInterface -> finish());
dialog.setOnDateSetListener(this);
dialog.show(fragmentManager, FRAG_TAG_DATE_PICKER);
}
dialog.setOnCancelListener(dialogInterface -> finish());
dialog.setOnDateSetListener(this);
}
@Override
@ -68,22 +58,8 @@ public class DatePickerActivity extends InjectingAppCompatActivity
@Override
public void onDateSet(
DatePickerDialog view, final int year, final int monthOfYear, final int dayOfMonth) {
dateSet(year, monthOfYear, dayOfMonth);
}
@Override
public void cancel() {
finish();
}
@Override
public void onDateSet(final int year, final int month, final int day) {
dateSet(year, month, day);
}
private void dateSet(final int year, final int month, final int day) {
Intent data = new Intent();
data.putExtra(EXTRA_TIMESTAMP, new DateTime(year, month + 1, day).getMillis());
data.putExtra(EXTRA_TIMESTAMP, new DateTime(year, monthOfYear + 1, dayOfMonth).getMillis());
setResult(RESULT_OK, data);
finish();
}

@ -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);
}
}

@ -27,7 +27,7 @@ import org.tasks.injection.InjectingDialogFragment;
import org.tasks.sync.AddAccountDialog;
import org.tasks.sync.SyncAdapters;
public class RemoteListSupportPicker extends InjectingDialogFragment
public class RemoteListPicker extends InjectingDialogFragment
implements RemoteListSelectionHandler {
public static final String EXTRA_SELECTED_FILTER = "extra_selected_filter";
@ -40,9 +40,9 @@ public class RemoteListSupportPicker extends InjectingDialogFragment
private CompositeDisposable disposables;
public static RemoteListSupportPicker newRemoteListSupportPicker(
public static RemoteListPicker newRemoteListSupportPicker(
Filter selected, Fragment targetFragment, int requestCode) {
RemoteListSupportPicker dialog = new RemoteListSupportPicker();
RemoteListPicker dialog = new RemoteListPicker();
Bundle arguments = new Bundle();
arguments.putParcelable(EXTRA_SELECTED_FILTER, selected);
dialog.setArguments(arguments);
@ -50,9 +50,9 @@ public class RemoteListSupportPicker extends InjectingDialogFragment
return dialog;
}
public static RemoteListSupportPicker newRemoteListSupportPicker(
public static RemoteListPicker newRemoteListSupportPicker(
Fragment targetFragment, int requestCode) {
RemoteListSupportPicker dialog = new RemoteListSupportPicker();
RemoteListPicker dialog = new RemoteListPicker();
Bundle arguments = new Bundle();
arguments.putBoolean(EXTRA_NO_SELECTION, true);
dialog.setArguments(arguments);
@ -60,7 +60,7 @@ public class RemoteListSupportPicker extends InjectingDialogFragment
return dialog;
}
static AlertDialog createDialog(
private static AlertDialog createDialog(
FilterAdapter filterAdapter,
DialogBuilder dialogBuilder,
SyncAdapters syncAdapters,

@ -1,33 +1,26 @@
package org.tasks.activities;
import static org.tasks.dialogs.NativeTimePickerDialog.newNativeTimePickerDialog;
import static org.tasks.time.DateTimeUtils.currentTimeMillis;
import android.app.FragmentManager;
import android.content.Intent;
import android.os.Bundle;
import android.text.format.DateFormat;
import com.wdullaer.materialdatetimepicker.time.TimePickerDialog;
import javax.inject.Inject;
import org.tasks.R;
import org.tasks.dialogs.MyTimePickerDialog;
import org.tasks.dialogs.NativeTimePickerDialog;
import org.tasks.injection.ActivityComponent;
import org.tasks.injection.InjectingAppCompatActivity;
import org.tasks.preferences.Preferences;
import org.tasks.themes.ThemeAccent;
import org.tasks.themes.ThemeBase;
import org.tasks.time.DateTime;
public class TimePickerActivity extends InjectingAppCompatActivity
implements TimePickerDialog.OnTimeSetListener,
NativeTimePickerDialog.NativeTimePickerDialogCallback {
implements TimePickerDialog.OnTimeSetListener {
public static final String EXTRA_TIMESTAMP = "extra_timestamp";
private static final String FRAG_TAG_TIME_PICKER = "frag_tag_time_picker";
@Inject ThemeBase themeBase;
@Inject ThemeAccent themeAccent;
@Inject Preferences preferences;
private DateTime initial;
@ -37,30 +30,23 @@ public class TimePickerActivity extends InjectingAppCompatActivity
initial = new DateTime(getIntent().getLongExtra(EXTRA_TIMESTAMP, currentTimeMillis()));
if (preferences.getBoolean(R.string.p_use_native_datetime_pickers, false)) {
FragmentManager fragmentManager = getFragmentManager();
if (fragmentManager.findFragmentByTag(FRAG_TAG_TIME_PICKER) == null) {
newNativeTimePickerDialog(initial).show(fragmentManager, FRAG_TAG_TIME_PICKER);
}
} else {
androidx.fragment.app.FragmentManager fragmentManager = getSupportFragmentManager();
MyTimePickerDialog dialog =
(MyTimePickerDialog) fragmentManager.findFragmentByTag(FRAG_TAG_TIME_PICKER);
if (dialog == null) {
dialog = new MyTimePickerDialog();
dialog.initialize(
null,
initial.getHourOfDay(),
initial.getMinuteOfHour(),
0,
DateFormat.is24HourFormat(this));
dialog.setThemeDark(themeBase.isDarkTheme(this));
dialog.setAccentColor(themeAccent.getAccentColor());
dialog.show(fragmentManager, FRAG_TAG_TIME_PICKER);
}
dialog.setOnCancelListener(dialogInterface -> finish());
dialog.setOnTimeSetListener(this);
androidx.fragment.app.FragmentManager fragmentManager = getSupportFragmentManager();
MyTimePickerDialog dialog =
(MyTimePickerDialog) fragmentManager.findFragmentByTag(FRAG_TAG_TIME_PICKER);
if (dialog == null) {
dialog = new MyTimePickerDialog();
dialog.initialize(
null,
initial.getHourOfDay(),
initial.getMinuteOfHour(),
0,
DateFormat.is24HourFormat(this));
dialog.setThemeDark(themeBase.isDarkTheme(this));
dialog.setAccentColor(themeAccent.getAccentColor());
dialog.show(fragmentManager, FRAG_TAG_TIME_PICKER);
}
dialog.setOnCancelListener(dialogInterface -> finish());
dialog.setOnTimeSetListener(this);
}
@Override
@ -71,24 +57,10 @@ public class TimePickerActivity extends InjectingAppCompatActivity
@Override
public void onTimeSet(
TimePickerDialog timePickerDialog, final int hours, final int minutes, int seconds) {
timeSet(hours, minutes);
}
@Override
public void cancel() {
finish();
}
@Override
public void onTimeSet(final int hour, final int minute) {
timeSet(hour, minute);
}
private void timeSet(final int hour, final int minute) {
Intent data = new Intent();
data.putExtra(
EXTRA_TIMESTAMP,
initial.startOfDay().withHourOfDay(hour).withMinuteOfHour(minute).getMillis());
initial.startOfDay().withHourOfDay(hours).withMinuteOfHour(minutes).getMillis());
setResult(RESULT_OK, data);
finish();
}

@ -6,10 +6,10 @@ import android.os.Bundle;
import androidx.annotation.NonNull;
import javax.inject.Inject;
import org.tasks.backup.TasksJsonExporter;
import org.tasks.injection.InjectingNativeDialogFragment;
import org.tasks.injection.NativeDialogFragmentComponent;
import org.tasks.injection.DialogFragmentComponent;
import org.tasks.injection.InjectingDialogFragment;
public class ExportTasksDialog extends InjectingNativeDialogFragment {
public class ExportTasksDialog extends InjectingDialogFragment {
@Inject DialogBuilder dialogBuilder;
@Inject TasksJsonExporter tasksJsonExporter;
@ -35,7 +35,7 @@ public class ExportTasksDialog extends InjectingNativeDialogFragment {
}
@Override
protected void inject(NativeDialogFragmentComponent component) {
protected void inject(DialogFragmentComponent component) {
component.inject(this);
}
}

@ -134,10 +134,9 @@ public class GeofenceDialog extends InjectingDialogFragment {
@OnClick(R.id.location_radius)
void selectRadius() {
SeekBarDialog seekBarDialog =
newSeekBarDialog(R.layout.dialog_radius_seekbar, 75, 1000, toGeofence().getRadius());
seekBarDialog.setTargetFragment(this, REQUEST_RADIUS);
seekBarDialog.show(getFragmentManager(), FRAG_TAG_SEEKBAR);
newSeekBarDialog(
R.layout.dialog_radius_seekbar, 75, 1000, toGeofence().getRadius(), this, REQUEST_RADIUS)
.show(getFragmentManager(), FRAG_TAG_SEEKBAR);
}
private void updateRadius(int radius) {

@ -14,12 +14,12 @@ import javax.inject.Inject;
import org.tasks.R;
import org.tasks.backup.TasksJsonImporter;
import org.tasks.backup.TasksJsonImporter.ImportResult;
import org.tasks.injection.DialogFragmentComponent;
import org.tasks.injection.ForActivity;
import org.tasks.injection.InjectingNativeDialogFragment;
import org.tasks.injection.NativeDialogFragmentComponent;
import org.tasks.injection.InjectingDialogFragment;
import org.tasks.ui.Toaster;
public class ImportTasksDialog extends InjectingNativeDialogFragment {
public class ImportTasksDialog extends InjectingDialogFragment {
private static final String EXTRA_URI = "extra_uri";
private static final String EXTRA_EXTENSION = "extra_extension";
@ -92,7 +92,7 @@ public class ImportTasksDialog extends InjectingNativeDialogFragment {
}
@Override
protected void inject(NativeDialogFragmentComponent component) {
protected void inject(DialogFragmentComponent 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);
}
}

@ -9,6 +9,7 @@ import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import butterknife.BindView;
import butterknife.ButterKnife;
import com.rey.material.widget.Slider;
@ -21,7 +22,7 @@ import org.tasks.themes.Theme;
public class SeekBarDialog extends InjectingDialogFragment {
public static final String EXTRA_VALUE = "extra_value";
static final String EXTRA_VALUE = "extra_value";
private static final String EXTRA_LAYOUT = "extra_layout";
private static final String EXTRA_MIN = "extra_min";
private static final String EXTRA_MAX = "extra_max";
@ -39,14 +40,15 @@ public class SeekBarDialog extends InjectingDialogFragment {
@Inject Theme theme;
@Inject Locale locale;
static SeekBarDialog newSeekBarDialog(int layout, int min, int max, int initial) {
SeekBarDialog dialog = new SeekBarDialog();
static SeekBarDialog newSeekBarDialog(int layout, int min, int max, int initial, Fragment target, int requestCode) {
Bundle args = new Bundle();
args.putInt(EXTRA_LAYOUT, layout);
args.putInt(EXTRA_MIN, min);
args.putInt(EXTRA_MAX, max);
args.putInt(EXTRA_VALUE, initial);
SeekBarDialog dialog = new SeekBarDialog();
dialog.setArguments(args);
dialog.setTargetFragment(target, requestCode);
return dialog;
}

@ -24,6 +24,7 @@ import android.webkit.MimeTypeMap;
import android.widget.Toast;
import androidx.annotation.Nullable;
import androidx.documentfile.provider.DocumentFile;
import androidx.fragment.app.Fragment;
import com.google.common.base.Strings;
import com.google.common.io.ByteStreams;
import com.google.common.io.Files;
@ -67,7 +68,7 @@ public class FileHelper {
}
}
public static void newDirectoryPicker(Activity activity, int rc, @Nullable Uri initial) {
public static void newDirectoryPicker(Fragment fragment, int rc, @Nullable Uri initial) {
if (atLeastLollipop()) {
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
intent.addFlags(
@ -78,15 +79,15 @@ public class FileHelper {
intent.putExtra("android.content.extra.SHOW_ADVANCED", true);
intent.putExtra("android.content.extra.FANCY", true);
intent.putExtra("android.content.extra.SHOW_FILESIZE", true);
setInitialUri(activity, intent, initial);
activity.startActivityForResult(intent, rc);
setInitialUri(fragment.getContext(), intent, initial);
fragment.startActivityForResult(intent, rc);
} else {
Intent intent = new Intent(activity, FileExplore.class);
Intent intent = new Intent(fragment.getContext(), FileExplore.class);
intent.putExtra(FileExplore.EXTRA_DIRECTORY_MODE, true);
if (initial != null) {
intent.putExtra(FileExplore.EXTRA_START_PATH, initial.getPath());
}
activity.startActivityForResult(intent, rc);
fragment.startActivityForResult(intent, rc);
}
}

@ -1,7 +1,5 @@
package org.tasks.files;
import static org.tasks.preferences.ResourceResolver.getData;
import android.os.Bundle;
import com.nononsenseapps.filepicker.FilePickerActivity;
import javax.inject.Inject;
@ -19,7 +17,7 @@ public class MyFilePickerActivity extends FilePickerActivity {
.getComponent()
.plus(new ActivityModule(this))
.inject(this);
theme.applyThemeAndStatusBarColor(this, getDelegate());
theme.applyThemeAndStatusBarColor(this);
setTitle(null);
super.onCreate(savedInstanceState);
}

@ -37,8 +37,8 @@ import org.tasks.data.CaldavAccount;
import org.tasks.data.GoogleTaskAccount;
import org.tasks.etesync.EteSyncCalendarSettingsActivity;
import org.tasks.injection.ForApplication;
import org.tasks.preferences.BasicPreferences;
import org.tasks.preferences.HelpAndFeedback;
import org.tasks.preferences.MainPreferences;
import org.tasks.ui.NavigationDrawerFragment;
public class FilterProvider {
@ -113,7 +113,7 @@ public class FilterProvider {
context.getString(R.string.FLA_new_filter),
R.drawable.ic_outline_add_24px,
new Intent(context, CustomFilterActivity.class),
NavigationDrawerFragment.ACTIVITY_REQUEST_NEW_FILTER));
NavigationDrawerFragment.REQUEST_NEW_LIST));
}
items.addAll(getSubmenu(R.string.tags, tagFilterExposer.getFilters()));
@ -143,7 +143,7 @@ public class FilterProvider {
R.drawable.ic_outline_add_24px,
new Intent(context, GoogleTaskListSettingsActivity.class)
.putExtra(GoogleTaskListSettingsActivity.EXTRA_ACCOUNT, account),
NavigationDrawerFragment.REQUEST_NEW_GTASK_LIST));
NavigationDrawerFragment.REQUEST_NEW_LIST));
}
}
@ -167,7 +167,7 @@ public class FilterProvider {
? CaldavCalendarSettingsActivity.class
: EteSyncCalendarSettingsActivity.class)
.putExtra(EXTRA_CALDAV_ACCOUNT, account),
NavigationDrawerFragment.REQUEST_NEW_CALDAV_COLLECTION));
NavigationDrawerFragment.REQUEST_NEW_LIST));
}
}
@ -193,7 +193,7 @@ public class FilterProvider {
new NavigationDrawerAction(
context.getString(R.string.TLA_menu_settings),
R.drawable.ic_outline_settings_24px,
new Intent(context, BasicPreferences.class),
new Intent(context, MainPreferences.class),
REQUEST_SETTINGS));
items.add(

@ -5,11 +5,8 @@ import com.todoroo.astrid.activity.MainActivity;
import com.todoroo.astrid.activity.ShareLinkActivity;
import com.todoroo.astrid.activity.TaskEditActivity;
import com.todoroo.astrid.core.CustomFilterActivity;
import com.todoroo.astrid.core.DefaultsPreferences;
import com.todoroo.astrid.core.OldTaskPreferences;
import com.todoroo.astrid.gcal.CalendarReminderActivity;
import com.todoroo.astrid.gtasks.auth.GtasksLoginActivity;
import com.todoroo.astrid.reminders.ReminderPreferences;
import dagger.Subcomponent;
import org.jetbrains.annotations.NotNull;
import org.tasks.activities.CalendarSelectionActivity;
@ -20,11 +17,6 @@ import org.tasks.activities.DatePickerActivity;
import org.tasks.activities.FilterSelectionActivity;
import org.tasks.activities.FilterSettingsActivity;
import org.tasks.activities.GoogleTaskListSettingsActivity;
import org.tasks.etesync.EncryptionSettingsActivity;
import org.tasks.etesync.EteSyncAccountSettingsActivity;
import org.tasks.etesync.EteSyncCalendarSettingsActivity;
import org.tasks.preferences.HelpAndFeedback;
import org.tasks.tags.TagPickerActivity;
import org.tasks.activities.TagSettingsActivity;
import org.tasks.activities.TimePickerActivity;
import org.tasks.billing.PurchaseActivity;
@ -32,18 +24,23 @@ import org.tasks.caldav.CaldavAccountSettingsActivity;
import org.tasks.caldav.CaldavCalendarSettingsActivity;
import org.tasks.dashclock.DashClockSettings;
import org.tasks.drive.DriveLoginActivity;
import org.tasks.etesync.EncryptionSettingsActivity;
import org.tasks.etesync.EteSyncAccountSettingsActivity;
import org.tasks.etesync.EteSyncCalendarSettingsActivity;
import org.tasks.files.FileExplore;
import org.tasks.files.MyFilePickerActivity;
import org.tasks.locale.ui.activity.TaskerCreateTaskActivity;
import org.tasks.locale.ui.activity.TaskerSettingsActivity;
import org.tasks.location.LocationPickerActivity;
import org.tasks.preferences.ManageSpaceActivity;
import org.tasks.preferences.AttributionActivity;
import org.tasks.preferences.BasicPreferences;
import org.tasks.preferences.DateTimePreferences;
import org.tasks.preferences.DebugPreferences;
import org.tasks.preferences.MiscellaneousPreferences;
import org.tasks.preferences.HelpAndFeedback;
import org.tasks.preferences.MainPreferences;
import org.tasks.preferences.NotificationPreferences;
import org.tasks.preferences.SyncPreferences;
import org.tasks.reminders.NotificationActivity;
import org.tasks.reminders.SnoozeActivity;
import org.tasks.tags.TagPickerActivity;
import org.tasks.tags.TagPickerViewModel;
import org.tasks.themes.Theme;
import org.tasks.ui.TaskListViewModel;
@ -64,8 +61,6 @@ public interface ActivityComponent {
DialogFragmentComponent plus(DialogFragmentModule dialogFragmentModule);
NativeDialogFragmentComponent plus(NativeDialogFragmentModule nativeDialogFragmentModule);
void inject(TaskerSettingsActivity taskerSettingsActivity);
void inject(DashClockSettings dashClockSettings);
@ -104,26 +99,14 @@ public interface ActivityComponent {
void inject(VoiceCommandActivity voiceCommandActivity);
void inject(ReminderPreferences reminderPreferences);
void inject(@NotNull WidgetConfigActivity widgetConfigActivity);
void inject(OldTaskPreferences oldTaskPreferences);
void inject(DefaultsPreferences defaultsPreferences);
void inject(ShortcutConfigActivity shortcutConfigActivity);
void inject(MiscellaneousPreferences miscellaneousPreferences);
void inject(DateTimePreferences dateTimePreferences);
void inject(MyFilePickerActivity myFilePickerActivity);
void inject(ColorPickerActivity colorPickerActivity);
void inject(BasicPreferences basicPreferences);
void inject(GoogleTaskListSettingsActivity googleTaskListSettingsActivity);
void inject(CaldavCalendarSettingsActivity caldavCalendarSettingsActivity);
@ -140,8 +123,6 @@ public interface ActivityComponent {
void inject(DriveLoginActivity driveLoginActivity);
void inject(DebugPreferences debugPreferences);
void inject(TaskEditActivity taskEditActivity);
void inject(WidgetClickActivity widgetActivity);
@ -158,5 +139,13 @@ public interface ActivityComponent {
void inject(EncryptionSettingsActivity encryptionSettingsActivity);
void inject(MainPreferences mainPreferences);
void inject(@NotNull HelpAndFeedback helpAndFeedback);
void inject(@NotNull NotificationPreferences notificationPreferences);
void inject(@NotNull ManageSpaceActivity manageSpaceActivity);
void inject(@NotNull SyncPreferences syncPreferences);
}

@ -2,16 +2,19 @@ package org.tasks.injection;
import dagger.Subcomponent;
import org.tasks.activities.CalendarSelectionDialog;
import org.tasks.activities.RemoteListSupportPicker;
import org.tasks.activities.RemoteListPicker;
import org.tasks.billing.NameYourPriceDialog;
import org.tasks.billing.PurchaseDialog;
import org.tasks.dialogs.AddAttachmentDialog;
import org.tasks.dialogs.ColorPickerDialog;
import org.tasks.dialogs.ExportTasksDialog;
import org.tasks.dialogs.GeofenceDialog;
import org.tasks.dialogs.IconPickerDialog;
import org.tasks.dialogs.ImportTasksDialog;
import org.tasks.dialogs.RecordAudioDialog;
import org.tasks.dialogs.SeekBarDialog;
import org.tasks.dialogs.SortDialog;
import org.tasks.locale.LocalePickerDialog;
import org.tasks.reminders.NotificationDialog;
import org.tasks.reminders.SnoozeDialog;
import org.tasks.repeats.BasicRecurrenceDialog;
@ -20,7 +23,7 @@ import org.tasks.repeats.CustomRecurrenceDialog;
@Subcomponent(modules = DialogFragmentModule.class)
public interface DialogFragmentComponent {
void inject(RemoteListSupportPicker remoteListSupportPicker);
void inject(RemoteListPicker remoteListPicker);
void inject(NotificationDialog notificationDialog);
@ -49,4 +52,10 @@ public interface DialogFragmentComponent {
void inject(PurchaseDialog purchaseDialog);
void inject(NameYourPriceDialog nameYourPriceDialog);
void inject(ExportTasksDialog exportTasksDialog);
void inject(ImportTasksDialog importTasksDialog);
void inject(LocalePickerDialog localePickerDialog);
}

@ -12,9 +12,17 @@ import com.todoroo.astrid.ui.ReminderControlSet;
import dagger.Subcomponent;
import org.jetbrains.annotations.NotNull;
import org.tasks.fragments.CommentBarFragment;
import org.tasks.preferences.fragments.Advanced;
import org.tasks.preferences.fragments.Backups;
import org.tasks.preferences.fragments.DashClock;
import org.tasks.preferences.fragments.Debug;
import org.tasks.preferences.fragments.HelpAndFeedback;
import org.tasks.preferences.fragments.LookAndFeel;
import org.tasks.preferences.fragments.MainSettingsFragment;
import org.tasks.preferences.fragments.Notifications;
import org.tasks.preferences.fragments.ScrollableWidget;
import org.tasks.preferences.fragments.Synchronization;
import org.tasks.preferences.fragments.TaskDefaults;
import org.tasks.preferences.fragments.TaskerListNotification;
import org.tasks.ui.CalendarControlSet;
import org.tasks.ui.DeadlineControlSet;
@ -69,6 +77,22 @@ public interface FragmentComponent {
void inject(@NotNull HelpAndFeedback helpAndFeedback);
void inject(@NotNull LookAndFeel lookAndFeel);
void inject(@NotNull Synchronization synchronization);
void inject(@NotNull Debug debug);
void inject(@NotNull MainSettingsFragment mainSettingsFragment);
void inject(@NotNull Backups backups);
void inject(@NotNull Advanced advanced);
void inject(@NotNull Notifications notifications);
void inject(@NotNull TaskDefaults taskDefaults);
void inject(@NotNull ScrollableWidget scrollableWidget);
void inject(@NotNull DashClock dashClock);

@ -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;
});
}
}

@ -3,11 +3,11 @@ package org.tasks.injection
import android.app.Activity
import android.content.DialogInterface
import android.content.Intent
import android.net.Uri
import androidx.annotation.StringRes
import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat
import androidx.preference.PreferenceGroup
import androidx.preference.PreferenceScreen
import com.jakewharton.processphoenix.ProcessPhoenix
import com.todoroo.astrid.activity.MainActivity
import com.todoroo.astrid.api.Filter
@ -50,6 +50,17 @@ abstract class InjectingPreferenceFragment : PreferenceFragmentCompat() {
}
}
protected fun requires(check: Boolean, vararg resIds: Int) {
if (!check) {
remove(preferenceScreen as PreferenceGroup, resIds)
}
}
protected fun removeGroup(key: Int) {
val preference = findPreference(key)
(findPreference(R.string.preference_screen) as PreferenceScreen).removePreference(preference)
}
protected fun remove(vararg resIds: Int) {
remove(preferenceScreen, resIds)
}

@ -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();
}
}

@ -22,7 +22,7 @@ public abstract class ThemedInjectingAppCompatActivity extends AppCompatActivity
((InjectingApplication) getApplication()).getComponent().plus(new ActivityModule(this));
inject(activityComponent);
setTitle(null);
theme.applyThemeAndStatusBarColor(this, getDelegate());
theme.applyThemeAndStatusBarColor(this);
super.onCreate(savedInstanceState);
}

@ -9,17 +9,19 @@ import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.os.Build;
import android.preference.PreferenceManager;
import android.view.ContextThemeWrapper;
import android.view.View;
import android.view.ViewParent;
import androidx.annotation.Nullable;
import androidx.core.text.TextUtilsCompat;
import androidx.preference.PreferenceManager;
import com.google.common.base.Strings;
import java.io.Serializable;
import java.text.NumberFormat;
import java.text.ParseException;
import org.tasks.R;
public class Locale {
public class Locale implements Serializable {
private static final Locale DEFAULT = new Locale(java.util.Locale.getDefault(), null, -1);
private static final int[] sDialogButtons =
@ -125,7 +127,7 @@ public class Locale {
return appDirectionality;
}
public String getLanguageOverride() {
public @Nullable String getLanguageOverride() {
return languageOverride;
}

@ -1,29 +1,31 @@
package org.tasks.locale;
import static android.app.Activity.RESULT_OK;
import static com.google.common.collect.Lists.transform;
import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import java.util.ArrayList;
import java.util.List;
import javax.inject.Inject;
import org.tasks.R;
import org.tasks.dialogs.DialogBuilder;
import org.tasks.injection.DialogFragmentComponent;
import org.tasks.injection.ForActivity;
import org.tasks.injection.InjectingNativeDialogFragment;
import org.tasks.injection.NativeDialogFragmentComponent;
import org.tasks.injection.InjectingDialogFragment;
import org.tasks.themes.ThemeAccent;
import org.tasks.ui.SingleCheckedArrayAdapter;
public class LocalePickerDialog extends InjectingNativeDialogFragment {
public class LocalePickerDialog extends InjectingDialogFragment {
public static final String EXTRA_LOCALE = "extra_locale";
@Inject @ForActivity Context context;
@Inject DialogBuilder dialogBuilder;
@Inject ThemeAccent themeAccent;
@Inject Locale locale;
private LocaleSelectionHandler callback;
public static LocalePickerDialog newLocalePickerDialog() {
return new LocalePickerDialog();
@ -45,26 +47,16 @@ public class LocalePickerDialog extends InjectingNativeDialogFragment {
adapter,
display.indexOf(locale.getDisplayName()),
(dialogInterface, i) -> {
callback.onLocaleSelected(locales.get(i));
Locale locale = locales.get(i);
Intent data = new Intent().putExtra(EXTRA_LOCALE, locale);
getTargetFragment().onActivityResult(getTargetRequestCode(), RESULT_OK, data);
dialogInterface.dismiss();
})
.show();
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
callback = (LocaleSelectionHandler) activity;
}
@Override
protected void inject(NativeDialogFragmentComponent component) {
protected void inject(DialogFragmentComponent component) {
component.inject(this);
}
public interface LocaleSelectionHandler {
void onLocaleSelected(Locale locale);
}
}

@ -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);
}
}

@ -83,7 +83,7 @@ public class DefaultFilterProvider {
return getFilterFromPreference(R.string.p_default_list);
}
void setDefaultFilter(Filter filter) {
public void setDefaultFilter(Filter filter) {
setFilterPreference(filter, R.string.p_default_list);
}

@ -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)
}

@ -1,6 +1,7 @@
package org.tasks.preferences;
import static android.content.SharedPreferences.Editor;
import static androidx.preference.PreferenceManager.setDefaultValues;
import static com.google.common.collect.Iterables.filter;
import static com.google.common.collect.Iterables.transform;
import static com.google.common.collect.Sets.newHashSet;
@ -17,7 +18,6 @@ import android.content.res.Resources;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Binder;
import android.preference.PreferenceManager;
import android.text.TextUtils;
import androidx.annotation.Nullable;
import androidx.core.app.NotificationCompat;
@ -204,11 +204,13 @@ public class Preferences {
}
public void setDefaults() {
PreferenceManager.setDefaultValues(context, R.xml.preferences, true);
PreferenceManager.setDefaultValues(context, R.xml.preferences_date_time, true);
PreferenceManager.setDefaultValues(context, R.xml.preferences_defaults, true);
PreferenceManager.setDefaultValues(context, R.xml.preferences_misc, true);
PreferenceManager.setDefaultValues(context, R.xml.preferences_reminders, true);
setDefaultValues(context, R.xml.preferences, true);
setDefaultValues(context, R.xml.preferences_task_defaults, true);
setDefaultValues(context, R.xml.preferences_synchronization, true);
setDefaultValues(context, R.xml.preferences_notifications, true);
setDefaultValues(context, R.xml.preferences_look_and_feel, true);
setDefaultValues(context, R.xml.preferences_backups, true);
setDefaultValues(context, R.xml.preferences_advanced, true);
BeastModePreferences.setDefaultOrder(this, context);
}
@ -222,7 +224,7 @@ public class Preferences {
return prefs.getString(key, null);
}
public String getStringValue(int keyResource) {
public @Nullable String getStringValue(int keyResource) {
return prefs.getString(context.getResources().getString(keyResource), null);
}
@ -239,7 +241,7 @@ public class Preferences {
return getIntegerFromString(R.string.p_default_reminders_mode_key, 0);
}
int getRowPadding() {
public int getRowPadding() {
return getInt(R.string.p_rowPadding, 16);
}

@ -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);
}
}

@ -16,7 +16,7 @@ import org.tasks.R;
import org.tasks.caldav.CaldavAccountSettingsActivity;
import org.tasks.dialogs.DialogBuilder;
import org.tasks.etesync.EteSyncAccountSettingsActivity;
import org.tasks.preferences.BasicPreferences;
import org.tasks.preferences.fragments.SynchronizationKt;
public class AddAccountDialog {
public static void showAddAccountDialog(Activity activity, DialogBuilder dialogBuilder) {
@ -55,17 +55,17 @@ public class AddAccountDialog {
case 0:
activity.startActivityForResult(
new Intent(activity, GtasksLoginActivity.class),
BasicPreferences.REQUEST_GOOGLE_TASKS);
SynchronizationKt.REQUEST_GOOGLE_TASKS);
break;
case 1:
activity.startActivityForResult(
new Intent(activity, CaldavAccountSettingsActivity.class),
BasicPreferences.REQUEST_CALDAV_SETTINGS);
SynchronizationKt.REQUEST_CALDAV_SETTINGS);
break;
case 2:
activity.startActivityForResult(
new Intent(activity, EteSyncAccountSettingsActivity.class),
BasicPreferences.REQUEST_CALDAV_SETTINGS);
SynchronizationKt.REQUEST_CALDAV_SETTINGS);
break;
}
dialog.dismiss();

@ -20,9 +20,7 @@ import butterknife.OnClick;
import butterknife.OnLongClick;
import com.google.android.material.chip.Chip;
import com.google.android.material.chip.ChipGroup;
import com.todoroo.astrid.api.CaldavFilter;
import com.todoroo.astrid.api.Filter;
import com.todoroo.astrid.api.GtasksFilter;
import com.todoroo.astrid.service.TaskCompleter;
import com.todoroo.astrid.ui.CheckableImageView;
import java.util.List;

@ -156,7 +156,12 @@ object CustomIcons {
1119 to R.drawable.ic_cached_24px,
1120 to R.drawable.ic_octocat,
1121 to R.drawable.ic_outline_perm_identity_24px,
1122 to R.drawable.ic_track_changes_24px
1122 to R.drawable.ic_track_changes_24px,
1123 to R.drawable.ic_open_in_new_24px,
1124 to R.drawable.ic_outline_edit_24px,
1125 to R.drawable.ic_outline_info_24px,
1126 to R.drawable.ic_outline_palette_24px,
1127 to R.drawable.ic_outline_sd_storage_24px
)
@kotlin.jvm.JvmStatic

@ -6,8 +6,6 @@ import android.content.res.Resources;
import android.graphics.PixelFormat;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.app.AppCompatDelegate;
import javax.inject.Inject;
import org.tasks.R;
@ -48,18 +46,13 @@ public class Theme {
return new ContextThemeWrapper(context, themeBase.getAlertDialogStyle());
}
public void applyThemeAndStatusBarColor(Activity activity, AppCompatDelegate delegate) {
applyTheme(activity, delegate);
public void applyThemeAndStatusBarColor(Activity activity) {
applyTheme(activity);
themeColor.applyToSystemBars(activity);
themeColor.applyTaskDescription(activity, activity.getString(R.string.app_name));
}
public void applyTheme(AppCompatActivity activity) {
applyTheme(activity, activity.getDelegate());
}
private void applyTheme(Activity activity, AppCompatDelegate delegate) {
delegate.applyDayNight();
public void applyTheme(Activity activity) {
themeBase.set(activity);
applyToContext(activity);
activity.getWindow().setFormat(PixelFormat.RGBA_8888);

@ -1,6 +1,5 @@
package org.tasks.ui;
import static android.app.Activity.RESULT_OK;
import static com.google.common.collect.Iterables.filter;
import static com.todoroo.andlib.utility.AndroidUtilities.assertNotMainThread;
import static com.todoroo.andlib.utility.AndroidUtilities.atLeastLollipop;
@ -27,7 +26,6 @@ import androidx.fragment.app.FragmentActivity;
import androidx.lifecycle.ViewModelProviders;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.todoroo.astrid.activity.MainActivity;
import com.todoroo.astrid.adapter.NavigationDrawerAdapter;
import com.todoroo.astrid.api.Filter;
import com.todoroo.astrid.api.FilterListItem;
@ -48,18 +46,14 @@ import org.tasks.filters.NavigationDrawerAction;
import org.tasks.injection.FragmentComponent;
import org.tasks.injection.InjectingFragment;
import org.tasks.intents.TaskIntents;
import org.tasks.preferences.BasicPreferences;
public class NavigationDrawerFragment extends InjectingFragment {
public static final int FRAGMENT_NAVIGATION_DRAWER = R.id.navigation_drawer;
public static final int REQUEST_NEW_LIST = 10100;
public static final int ACTIVITY_REQUEST_NEW_FILTER = 10101;
public static final int REQUEST_NEW_GTASK_LIST = 10102;
public static final int REQUEST_NEW_CALDAV_COLLECTION = 10103;
public static final int REQUEST_SETTINGS = 10104;
public static final int REQUEST_PURCHASE = 10105;
public static final int REQUEST_DONATE = 10106;
public static final int REQUEST_SETTINGS = 10101;
public static final int REQUEST_PURCHASE = 10102;
public static final int REQUEST_DONATE = 10103;
private static final String FRAG_TAG_PURCHASE_DIALOG = "frag_tag_purchase_dialog";
private final RefreshReceiver refreshReceiver = new RefreshReceiver();
@ -92,36 +86,6 @@ public class NavigationDrawerFragment extends InjectingFragment {
setUpList();
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_SETTINGS) {
if (resultCode == Activity.RESULT_OK) {
if (data != null && data.getBooleanExtra(BasicPreferences.EXTRA_RESTART, false)) {
getActivity().recreate();
}
}
} else if (requestCode == REQUEST_NEW_LIST
|| requestCode == ACTIVITY_REQUEST_NEW_FILTER
|| requestCode == REQUEST_NEW_GTASK_LIST
|| requestCode == REQUEST_NEW_CALDAV_COLLECTION) {
if (resultCode == RESULT_OK && data != null) {
Filter filter = data.getParcelableExtra(MainActivity.OPEN_FILTER);
if (filter != null) {
openFilter(filter);
}
}
} else {
super.onActivityResult(requestCode, resultCode, data);
}
}
private void openFilter(@NonNull Filter filter) {
FragmentActivity activity = getActivity();
if (activity != null) {
activity.startActivity(TaskIntents.getTaskListIntent(activity, filter));
}
}
@Override
public View onCreateView(
@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
@ -147,7 +111,10 @@ public class NavigationDrawerFragment extends InjectingFragment {
public void onDrawerClosed(View drawerView) {
mDrawerLayout.removeDrawerListener(this);
if (item instanceof Filter) {
openFilter((Filter) item);
FragmentActivity activity = getActivity();
if (activity != null) {
activity.startActivity(TaskIntents.getTaskListIntent(activity, (Filter) item));
}
} else if (item instanceof NavigationDrawerAction) {
NavigationDrawerAction action = (NavigationDrawerAction) item;
if (action.requestCode == REQUEST_PURCHASE) {
@ -155,7 +122,7 @@ public class NavigationDrawerFragment extends InjectingFragment {
} else if (action.requestCode == REQUEST_DONATE) {
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://tasks.org/donate")));
} else {
startActivityForResult(action.intent, action.requestCode);
getActivity().startActivityForResult(action.intent, action.requestCode);
}
}
}

@ -1,7 +1,7 @@
package org.tasks.ui;
import static android.app.Activity.RESULT_OK;
import static org.tasks.activities.RemoteListSupportPicker.newRemoteListSupportPicker;
import static org.tasks.activities.RemoteListPicker.newRemoteListSupportPicker;
import android.app.Activity;
import android.content.Intent;
@ -24,7 +24,7 @@ import com.todoroo.astrid.gtasks.GtasksListService;
import com.todoroo.astrid.service.TaskMover;
import javax.inject.Inject;
import org.tasks.R;
import org.tasks.activities.RemoteListSupportPicker;
import org.tasks.activities.RemoteListPicker;
import org.tasks.data.CaldavCalendar;
import org.tasks.data.CaldavDao;
import org.tasks.data.CaldavTask;
@ -190,7 +190,7 @@ public class RemoteListFragment extends TaskEditControlFragment {
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_CODE_SELECT_LIST) {
if (resultCode == RESULT_OK) {
setList(data.getParcelableExtra(RemoteListSupportPicker.EXTRA_SELECTED_FILTER));
setList(data.getParcelableExtra(RemoteListPicker.EXTRA_SELECTED_FILTER));
}
} else {
super.onActivityResult(requestCode, resultCode, data);

@ -3,8 +3,8 @@ package org.tasks.ui;
import android.content.Context;
import android.content.Intent;
import android.content.res.TypedArray;
import android.preference.Preference;
import android.util.AttributeSet;
import androidx.preference.Preference;
import com.todoroo.andlib.utility.DateUtilities;
import org.tasks.R;
import org.tasks.activities.TimePickerActivity;
@ -19,7 +19,7 @@ public class TimePreference extends Preference {
super(context, attrs);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TimePreference);
summary = a.getString(R.styleable.TimePreference_summary);
summary = a.getString(R.styleable.TimePreference_time_summary);
a.recycle();
}

@ -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>

@ -1,18 +1,4 @@
<?xml version="1.0" encoding="utf-8"?><!-- Copyright (C) 2006 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.
-->
<?xml version="1.0" encoding="utf-8"?>
<TwoLineListItem xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@ -34,7 +20,7 @@
android:layout_alignParentLeft="true"
android:layout_marginEnd="@dimen/keyline_first"
android:layout_marginRight="@dimen/keyline_first"
android:src="@drawable/ic_etesync" />
android:tint="@null" />
<TextView
android:id="@id/text1"

@ -2,12 +2,7 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tasks="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/menu_help"
android:icon="@drawable/ic_outline_help_outline_24px"
android:title="@string/help"
tasks:showAsAction="ifRoom"/>
<item
android:id="@+id/menu_contact"
android:title="@string/contact_developer"
tasks:showAsAction="never"/>
android:id="@+id/menu_help_and_feedback"
android:title="@string/help_and_feedback"
tasks:showAsAction="never" />
</menu>

@ -49,7 +49,6 @@
<string name="EPr_beastMode_reset">الإعادة إلى الإفتراضي</string>
<string name="EPr_fullTask_title">إظهار عنوان المهمه</string>
<string name="task_list_options">خيارات قائمة المهام</string>
<string name="EPr_manage_header"> إدارة المهام القديمة</string>
<string name="EPr_manage_delete_completed_gcal">حذف أحداث التقويم للمهام المُتَممه</string>
<string name="EPr_manage_delete_all_gcal">حذف جميع نشاطات التقويم للمهام</string>
<string name="EPr_manage_delete_all_gcal_message">هل فعلا تريد حذف جميع الأحداث للمهام ؟</string>

@ -88,7 +88,6 @@
<string name="EPr_cal_end_or_start_at_due_time">Време на събитие в календара</string>
<string name="EPr_cal_end_at_due_time">Приключване на събития в календара на крайния срок</string>
<string name="EPr_cal_start_at_due_time">Започване на събития в календара на крайния срок</string>
<string name="EPr_manage_header">Управление на стари задачи</string>
<string name="EPr_manage_purge_deleted">Изчистване на изтритите задачи</string>
<string name="EPr_manage_purge_deleted_message">Наистина ли искате да изчистите всичките си приключени задачи?\n\nТези задачи ще изчезнат завинаги!</string>
<string name="EPr_manage_purge_deleted_status">Изчистени %d задачи!</string>
@ -354,12 +353,10 @@
<string name="take_a_picture">Заснемане</string>
<string name="pick_from_gallery">Изберете от галерия</string>
<string name="pick_from_storage">Изберете от паметта</string>
<string name="privacy">Поверителност</string>
<string name="privacy_policy">Декларация за поверителност</string>
<string name="send_anonymous_statistics">Подобряване на Tasks</string>
<string name="send_anonymous_statistics_summary">Изпращане на анонимна статистика за използването и отчети за грешки, за да се подпомогне подобряването на Tasks. Няма да бъдат събирани персонални данни.</string>
<string name="tag_already_exists">Този таг вече съществува</string>
<string name="duplicate_name">Дублирано име</string>
<string name="name_cannot_be_empty">Името не може да е празно</string>
<string name="username_required">Потребителското име е задължително</string>
<string name="password_required">Паролата е задължителна</string>
@ -402,7 +399,6 @@
<string name="theme_dark">Тъмна</string>
<string name="theme_wallpaper">Тапет</string>
<string name="theme_day_night">Ден/Нощ</string>
<string name="settings_general">Общи</string>
<string name="language">Език</string>
<string name="restart_required">Tasks трябва да бъде рестартиран за да влязат промените в сила</string>
<string name="restart_now">Рестартирай сега</string>
@ -426,7 +422,6 @@
<string name="date_and_time">Дата и време</string>
<string name="start_of_week">Начало на седмицата</string>
<string name="use_locale_default">Локализация по подразбиране</string>
<string name="use_native_datetime_pickers">Контроли за избор на дата и време по подразбиране </string>
<string name="add_account">Добави акаунт</string>
<string name="user">Потребител</string>
<string name="password">Парола</string>

@ -73,7 +73,6 @@
<string name="EPr_cal_end_or_start_at_due_time">Čas události v kalendáři</string>
<string name="EPr_cal_end_at_due_time">Událost v kalendáři končí splněním úkolu</string>
<string name="EPr_cal_start_at_due_time">Událost v kalendáři začíná splněním úkolu</string>
<string name="EPr_manage_header">Spravovat staré úkoly</string>
<string name="EPr_manage_purge_deleted">Vymazat smazané úkoly</string>
<string name="EPr_manage_purge_deleted_message">Opravdu chcete vymazat vaše smazané úkoly?\n\nTyto úkoly budou vymazány navždy!</string>
<string name="EPr_manage_purge_deleted_status">Vymyzáno %d úkolů!</string>
@ -223,7 +222,6 @@
<string name="reverse">Obrácené třídění</string>
<string name="no_application_found">K otevření přílohy nebyla nalezena aplikace</string>
<string name="add_attachment">Přidat přílohu</string>
<string name="privacy">Soukromí</string>
<string name="privacy_policy">Zásady ochrany osobních údajů</string>
<string name="send_anonymous_statistics">Vylepšit Úkoly</string>
<string name="send_anonymous_statistics_summary">Odesílat anonymní statistiky využití a zprávy o selhání ke zlepšení Úkolů. Žádné osobní údaje nebudou shromažďovány.</string>
@ -256,7 +254,6 @@
<string name="theme_dark">Tmavý</string>
<string name="theme_wallpaper">Tapeta</string>
<string name="theme_day_night">Den/Noc</string>
<string name="settings_general">Všeobecný</string>
<string name="language">Jazyk</string>
<string name="restart_required">Úkoly musí být restartovány, aby se změny projevily</string>
<string name="restart_now">Restartovat nyní</string>

@ -83,7 +83,6 @@
<string name="EPr_cal_end_or_start_at_due_time">Zeitpunkt Kalendertermin</string>
<string name="EPr_cal_end_at_due_time">Kalendereintrag endet zur Fälligkeits-Uhrzeit</string>
<string name="EPr_cal_start_at_due_time">Kalendereintrag Startet zur Fälligkeits-Uhrzeit</string>
<string name="EPr_manage_header">Alte Aufgaben verwalten</string>
<string name="EPr_manage_purge_deleted">Gelöschte Aufgaben endgültig löschen</string>
<string name="EPr_manage_purge_deleted_message">Willst du wirklich alle gelöschten Aufgaben bereinigen?\n\nDiese Aufgaben werden für immer gelöscht bleiben!</string>
<string name="EPr_manage_purge_deleted_status">%d Aufgaben bereinigt!</string>
@ -346,12 +345,10 @@
<string name="take_a_picture">Bild aufnehmen</string>
<string name="pick_from_gallery">Aus Galerie wählen</string>
<string name="pick_from_storage">Von Speicher auswählen</string>
<string name="privacy">Datenschutz</string>
<string name="privacy_policy">Datenschutzerklärung</string>
<string name="send_anonymous_statistics">Tasks verbessern</string>
<string name="send_anonymous_statistics_summary">Anonyme Nutzungsstatistiken und Absturzberichte zur Verbesserung von Tasks senden. Es werden keine persönlichen Daten gesammelt.</string>
<string name="tag_already_exists">Schlagwort existiert bereits</string>
<string name="duplicate_name">Doppelter Name</string>
<string name="name_cannot_be_empty">Name darf nicht leer sein</string>
<string name="username_required">Benutzername benötigt</string>
<string name="password_required">Passwort benötigt</string>
@ -389,7 +386,6 @@
<string name="theme_dark">Dunkel</string>
<string name="theme_wallpaper">Hintergrundbild</string>
<string name="theme_day_night">Tag/Nacht</string>
<string name="settings_general">Allgemein</string>
<string name="language">Sprache</string>
<string name="restart_required">Tasks muss neugestartet werden um die Änderungen zu übernehmen</string>
<string name="restart_now">Jetzt neustarten</string>
@ -413,7 +409,6 @@
<string name="date_and_time">Datum und Uhrzeit</string>
<string name="start_of_week">Beginn der Woche</string>
<string name="use_locale_default">Aus Systemeinstellungen</string>
<string name="use_native_datetime_pickers">Datum- und Zeitauswahl des Systems benutzen</string>
<string name="add_account">Account hinzufügen</string>
<string name="user">Benutzer</string>
<string name="password">Passwort</string>

@ -71,7 +71,6 @@
<string name="EPr_cal_end_or_start_at_due_time">Ώρα γεγονότος ημερολογίου</string>
<string name="EPr_cal_end_at_due_time">Τερματισμός γεγονότων ημερολογίου στην ώρα λήξης τους</string>
<string name="EPr_cal_start_at_due_time">Εκκίνηση γεγονότων ημερολογίου στην ώρα λήξης τους</string>
<string name="EPr_manage_header">Διαχείριση παλιών εργασιών</string>
<string name="EPr_manage_purge_deleted">Εκκαθάριση διεγραμμένων εργασιών</string>
<string name="EPr_manage_purge_deleted_message">Θέλετε πραγματικά να καθαρίσετε όλες τις διαγραμμένες εργασίες;\n\nΑυτές οι εργασίες θα χαθούν για πάντα!</string>
<string name="EPr_manage_purge_deleted_status">Εκκαθαρίστηκαν %d εργασίες!</string>

@ -88,7 +88,6 @@
<string name="EPr_cal_end_or_start_at_due_time">Momento del evento en calendario</string>
<string name="EPr_cal_end_at_due_time">Finalizar eventos del calendario al vencimiento</string>
<string name="EPr_cal_start_at_due_time">Iniciar eventos del calendario al vencimiento</string>
<string name="EPr_manage_header">Administrar tareas antiguas</string>
<string name="EPr_manage_purge_deleted">Limpiar tareas eliminadas</string>
<string name="EPr_manage_purge_deleted_message">¿Seguro que desea limpiar todas las tareas eliminadas?\n\n¡Estas tareas se perderán por siempre!</string>
<string name="EPr_manage_purge_deleted_status">¡%d tareas purgadas!</string>
@ -353,12 +352,10 @@
<string name="take_a_picture">Tomar fotografía</string>
<string name="pick_from_gallery">Elegir desde la galería</string>
<string name="pick_from_storage">Elegir desde almacenamiento</string>
<string name="privacy">Privacidad</string>
<string name="privacy_policy">Política de privacidad</string>
<string name="send_anonymous_statistics">Mejorar Tasks</string>
<string name="send_anonymous_statistics_summary">Enviar de forma anónima estadísticas de uso e informes de error para ayudar a mejorar Task. No se recogerán datos personales.</string>
<string name="tag_already_exists">La etiqueta ya existe</string>
<string name="duplicate_name">Nombre duplicado</string>
<string name="name_cannot_be_empty">El nombre no puede estar vacío</string>
<string name="username_required">Nombre de usuario requerido</string>
<string name="password_required">Contraseña requerida</string>
@ -423,7 +420,6 @@
<string name="date_and_time">Fecha y hora</string>
<string name="start_of_week">Inicio de semana</string>
<string name="use_locale_default">Usar configuración regional</string>
<string name="use_native_datetime_pickers">Usar fecha y hora nativas</string>
<string name="add_account">Añadir cuenta</string>
<string name="user">Usuario</string>
<string name="password">Contraseña</string>
@ -523,7 +519,6 @@
<string name="gtasks_GPr_header">Google Tasks</string>
<string name="location_radius_meters">%s m</string>
<string name="color">Color</string>
<string name="settings_general">General</string>
<string name="url">URL</string>
<string name="error_adding_account">Error : %s</string>
<string name="list_separator_with_space">", "</string>

@ -62,7 +62,6 @@
<string name="EPr_cal_end_or_start_at_due_time">Kalendri sündmuse aeg</string>
<string name="EPr_cal_end_at_due_time">Lõpeta kalendri sündmus tähtajal</string>
<string name="EPr_cal_start_at_due_time">Alusta kalendri sündmust tähtajal</string>
<string name="EPr_manage_header">Halda vanu ülesandeid</string>
<string name="EPr_manage_purge_deleted">Eemalda kustutatud ülesanded</string>
<string name="EPr_manage_purge_deleted_status">Eemaldati %d ülesannet!</string>
<string name="EPr_reset_preferences">Taasta eelistused</string>
@ -216,10 +215,8 @@
<string name="take_a_picture">Tee pilt</string>
<string name="pick_from_gallery">Vali galeriist</string>
<string name="pick_from_storage">Vali seadmest</string>
<string name="privacy">Privaatsus</string>
<string name="privacy_policy">Privaatsus</string>
<string name="tag_already_exists">Silt on juba olemas</string>
<string name="duplicate_name">Topelt nimi</string>
<string name="name_cannot_be_empty">Nimi ei saa olla tühi</string>
<string name="username_required">Kasutajanimi on nõutud</string>
<string name="password_required">Parool on nõutud</string>
@ -257,7 +254,6 @@
<string name="theme_dark">Tume</string>
<string name="theme_wallpaper">Taustapilt</string>
<string name="theme_day_night">Päev/Öö</string>
<string name="settings_general">Üldine</string>
<string name="language">Keel</string>
<string name="restart_now">Taaskäivita kohe</string>
<string name="restart_later">Hiljem</string>

@ -89,7 +89,6 @@
<string name="EPr_cal_end_or_start_at_due_time">Egutegiko gertaeraren ordua</string>
<string name="EPr_cal_end_at_due_time">Amaitu egutegiko gertaerak epemuga-orduan</string>
<string name="EPr_cal_start_at_due_time">Hasi egutegiko gertaerak epemuga-orduan</string>
<string name="EPr_manage_header">Kudeatu zeregin zaharrak</string>
<string name="EPr_manage_purge_deleted">Purgatu ezabatutako zereginak</string>
<string name="EPr_manage_purge_deleted_message">Ziur ezabatutako zereginak purgatu nahi dituzula\?
\n
@ -358,12 +357,10 @@
<string name="take_a_picture">Atera argazkia</string>
<string name="pick_from_gallery">Hautatu galeriatik</string>
<string name="pick_from_storage">Hautatu biltegiratzetik</string>
<string name="privacy">Pribatutasuna</string>
<string name="privacy_policy">pribatutasun politika</string>
<string name="send_anonymous_statistics">Hobetu Tasks</string>
<string name="send_anonymous_statistics_summary">Bidali erabilera estatistika anonimoak eta kraskatze txostenak Tasks hobetzen laguntzeko. Ez da datu pertsonalik jasoko.</string>
<string name="tag_already_exists">Etiketa hau badago aurretik</string>
<string name="duplicate_name">Bikoiztutako izena</string>
<string name="name_cannot_be_empty">Izena ezin da hutsik egon</string>
<string name="username_required">Erabiltzaile-izena ezinbestekoa da</string>
<string name="password_required">Pasahitza ezinbestekoa da</string>
@ -406,7 +403,6 @@
<string name="theme_dark">Iluna</string>
<string name="theme_wallpaper">Horma-papera</string>
<string name="theme_day_night">Eguna/Gaua</string>
<string name="settings_general">Orokorra</string>
<string name="language">Hizkuntza</string>
<string name="restart_required">Tasks aplikazioa berrabiarazi behar da aldaketak aplikatzeko</string>
<string name="restart_now">Berrabiarazi orain</string>
@ -430,7 +426,6 @@
<string name="date_and_time">Data eta ordua</string>
<string name="start_of_week">Astearen hasiera</string>
<string name="use_locale_default">Erabili hizkuntzak lehenetsitakoa</string>
<string name="use_native_datetime_pickers">Erabili sistemaren data eta ordu hautatzaileak</string>
<string name="add_account">Gehitu kontua</string>
<string name="user">Erabiltzailea</string>
<string name="password">Pasahitza</string>

@ -64,7 +64,6 @@
<string name="EPr_cal_end_or_start_at_due_time">زمان رویداد تقویم</string>
<string name="EPr_cal_end_at_due_time">اتمام رویدادهای تقویم در موعود</string>
<string name="EPr_cal_start_at_due_time">شروع رویدادهای تقویم در موعود</string>
<string name="EPr_manage_header">مدیریت وظایف قدیمی</string>
<string name="EPr_delete_task_data">حذف داده وظیفه</string>
<string name="task_defaults">پیش فرض های وظیفه</string>
<string name="EPr_default_urgency_title">موعود پیش فرض</string>
@ -245,7 +244,6 @@
<string name="theme_white">سفید</string>
<string name="theme_light">روشن</string>
<string name="theme_dark">تیره</string>
<string name="settings_general">عمومی</string>
<string name="language">زبان</string>
<string name="restart_now">اکنون ریست کن</string>
<string name="restart_later">بعدا</string>

@ -81,7 +81,6 @@
<string name="EPr_cal_end_or_start_at_due_time">Kalenteritapahtuman aika</string>
<string name="EPr_cal_end_at_due_time">Lopeta kalenteritapahtuma määräaikana</string>
<string name="EPr_cal_start_at_due_time">Aloita kalenteritapahtumat määräaikana</string>
<string name="EPr_manage_header">Hallinnoi vanhoja tehtäviä</string>
<string name="EPr_manage_purge_deleted">Tyjennä poistetut tehtävät</string>
<string name="EPr_manage_purge_deleted_message">Haluatko todella tyhjentää kaikki poistetut tehtävät?\n\n Nämä tehtävät häviävät lopullisesti!</string>
<string name="EPr_manage_purge_deleted_status">Tyhjennettu %d tehtävää!</string>
@ -335,7 +334,6 @@
<string name="take_a_picture">Ota kuva</string>
<string name="pick_from_gallery">Valitse galleriasta</string>
<string name="pick_from_storage">Valitse muistista</string>
<string name="privacy">Yksityisyys</string>
<string name="privacy_policy">Rekisteriseloste</string>
<string name="send_anonymous_statistics">Paranna tehtäviä</string>
<string name="send_anonymous_statistics_summary">Lähetä nimettömästi käyttäjätilastoja ja virheilmoituksia Tasks -ohjelman parantamiseksi. Mitään henkilökohtaisia tietoja ei kerätä.</string>
@ -376,7 +374,6 @@
<string name="theme_dark">Tumma</string>
<string name="theme_wallpaper">Taustakuva</string>
<string name="theme_day_night">Päivä/Yö</string>
<string name="settings_general">Yleinen</string>
<string name="language">Kieli</string>
<string name="restart_required">Tasks on uudelleen käynnistettävä muutoksien käyttöönottamiseksi</string>
<string name="restart_now">Käynnistä uudelleen nyt</string>
@ -400,7 +397,6 @@
<string name="date_and_time">Päivä ja aika</string>
<string name="start_of_week">Viikon alku</string>
<string name="use_locale_default">Käytä paikallista oletusta</string>
<string name="use_native_datetime_pickers">Käytä kotimaisia päivämäärä- ja aikapoimijoita</string>
<string name="notification_channel_settings">Hallinnoi ilmoituksia</string>
<string name="battery_optimization_settings">Hallinnoi akun optimointia</string>
<string name="notification_disable_battery_optimizations_description">Akun optimointi voi viivästyttää ilmoituksia</string>

@ -82,7 +82,6 @@
<string name="EPr_cal_end_or_start_at_due_time">Heure de l\'évenement dans le calendrier</string>
<string name="EPr_cal_end_at_due_time">Terminer les événements dans le calendrier à l\'échéance</string>
<string name="EPr_cal_start_at_due_time">Commencer les événements dans le calendrier à l\'échéance</string>
<string name="EPr_manage_header">Gérer les anciennes tâches</string>
<string name="EPr_manage_purge_deleted">Supprimer définitivement les tâches supprimées</string>
<string name="EPr_manage_purge_deleted_message">Voulez-vous vraiment supprimer définitivement toutes les tâches supprimées ?\n\nCes tâches seront perdues à jamais !</string>
<string name="EPr_manage_purge_deleted_status">%d tâche(s) supprimée(s) définitivement !</string>
@ -335,12 +334,10 @@
<string name="take_a_picture">Prendre une photo</string>
<string name="pick_from_gallery">Choisir depuis la galerie</string>
<string name="pick_from_storage">Choisir depuis le stockage</string>
<string name="privacy">Vie privée</string>
<string name="privacy_policy">Politique de vie privée</string>
<string name="send_anonymous_statistics">Améliorer Tasks</string>
<string name="send_anonymous_statistics_summary">Envoyer des statistiques anonymes d\'usage et les rapports de plantage afin d\'aider à l\'amélioration de Tasks. Aucune donnée personnelle ne sera collectée.</string>
<string name="tag_already_exists">Le tag existe déjà</string>
<string name="duplicate_name">Nom dupliqué</string>
<string name="name_cannot_be_empty">Le nom doit être renseigné</string>
<string name="username_required">Nom d\'utilisateur requis</string>
<string name="password_required">Mot de passe requis</string>
@ -379,7 +376,6 @@
<string name="theme_dark">Sombre</string>
<string name="theme_wallpaper">Fond d\'écran</string>
<string name="theme_day_night">Jour/Nuit</string>
<string name="settings_general">Général</string>
<string name="language">Langage</string>
<string name="restart_required">Tasks doit être redémarré pour que les changements prennent effet</string>
<string name="restart_now">Redémarrer maintenant</string>
@ -403,7 +399,6 @@
<string name="date_and_time">Date et heure</string>
<string name="start_of_week">Début de la semaine</string>
<string name="use_locale_default">Utiliser les paramètres de langue par défaut</string>
<string name="use_native_datetime_pickers">Utiliser le sélecteur de date et d\'heure natif</string>
<string name="add_account">Ajouter un compte</string>
<string name="user">Utilisateur</string>
<string name="password">Mot de passe</string>

@ -77,7 +77,6 @@
<string name="EPr_cal_end_or_start_at_due_time">Momento del evento en calendario</string>
<string name="EPr_cal_end_at_due_time">Finalizar eventos del calendario al vencimiento</string>
<string name="EPr_cal_start_at_due_time">Iniciar eventos del calendario al vencimiento</string>
<string name="EPr_manage_header">Administrar tareas antiguas</string>
<string name="EPr_manage_purge_deleted">Limpiar tareas eliminadas</string>
<string name="EPr_manage_purge_deleted_message">¿Seguro que desea limpiar todas las tareas eliminadas?\n\n¡Estas tareas se perderán por siempre!</string>
<string name="EPr_manage_purge_deleted_status">¡%d tareas purgadas!</string>
@ -257,7 +256,6 @@
<string name="take_a_picture">Tomar fotografía</string>
<string name="pick_from_gallery">Elegir desde la galería</string>
<string name="pick_from_storage">Elegir desde almacenamiento</string>
<string name="privacy">Privacidad</string>
<string name="privacy_policy">Política de privacidad</string>
<string name="send_anonymous_statistics">Mejorar Tasks</string>
<string name="send_anonymous_statistics_summary">Enviar de forma anónima estadísticas de uso e informes de error para ayudar a mejorar Tasks. No se recogerán datos personales.</string>
@ -297,7 +295,6 @@
<string name="theme_dark">Oscuro</string>
<string name="theme_wallpaper">Fondo de pantalla</string>
<string name="theme_day_night">Día/Noche</string>
<string name="settings_general">Xeneral</string>
<string name="language">Idioma</string>
<string name="restart_required">Debe reiniciar Tasks para que los cambios tengan efecto</string>
<string name="restart_now">Reiniciar ahora</string>
@ -318,6 +315,5 @@
<string name="delete_multiple_tasks_confirmation">%s borradas</string>
<string name="delete_selected_tasks">¿Borrar tareas seleccionadas?</string>
<string name="copy_selected_tasks">¿Copiar tareas seleccionadas?</string>
<string name="use_native_datetime_pickers">Escoller data e hora</string>
<string name="themes">Temas adicionales</string>
</resources>

@ -87,7 +87,6 @@
<string name="EPr_cal_end_or_start_at_due_time">Naptáresemény időzítése</string>
<string name="EPr_cal_end_at_due_time">Naptáresemények befejezése határidőkor</string>
<string name="EPr_cal_start_at_due_time">Naptáresemények kezdése határidőkor</string>
<string name="EPr_manage_header">Régi feladatok kezelése</string>
<string name="EPr_manage_purge_deleted">Törölt feladatok elvetése</string>
<string name="EPr_manage_purge_deleted_message">Biztosan el akarja vetni az összes törölt feladatot?\n\nEzek a feladatok többé nem lesznek visszaállíthatóak!</string>
<string name="EPr_manage_purge_deleted_status">%d feladat elvetve!</string>
@ -352,12 +351,10 @@
<string name="take_a_picture">Kép készítése</string>
<string name="pick_from_gallery">Kiválasztás a galériából</string>
<string name="pick_from_storage">Kiválasztás a tárhelyről</string>
<string name="privacy">Adatvédelem</string>
<string name="privacy_policy">Adatvédelmi irányelv</string>
<string name="send_anonymous_statistics">Tasks fejlesztése</string>
<string name="send_anonymous_statistics_summary">Anonim felhasználási statisztikák és hibajelentések küldése a Tasks fejlesztése érdekében. Személyes adatok gyűjtése nem történik.</string>
<string name="tag_already_exists">A címke már létezik</string>
<string name="duplicate_name">Duplikált név</string>
<string name="name_cannot_be_empty">A cím nem lehet üres</string>
<string name="username_required">Felhasználónév szükséges</string>
<string name="password_required">Jelszó szükséges</string>
@ -400,7 +397,6 @@
<string name="theme_dark">Sötét</string>
<string name="theme_wallpaper">Háttérkép</string>
<string name="theme_day_night">Nappal/Éjszaka</string>
<string name="settings_general">Általános</string>
<string name="language">Nyelv</string>
<string name="restart_required">A változás érvényesítéséhez újra kell indítani a Tasks appot</string>
<string name="restart_now">Újraindítás most</string>
@ -424,7 +420,6 @@
<string name="date_and_time">Dátum és időpont</string>
<string name="start_of_week">Hét kezdőnapja</string>
<string name="use_locale_default">Beállított nyelv alapján</string>
<string name="use_native_datetime_pickers">Natív dátum és időpont kijelölő használata</string>
<string name="add_account">Felhasználói fiók hozzáadása</string>
<string name="user">Felhasználónév</string>
<string name="password">Jelszó</string>

@ -61,7 +61,6 @@
<string name="EPr_show_task_edit_comments">Tampilkan komentar di penyunting tugas</string>
<string name="task_list_options">Opsi daftar tugas</string>
<string name="EPr_cal_end_or_start_at_due_time">Waktu acara kalender</string>
<string name="EPr_manage_header">Kelola tugas lama</string>
<string name="EPr_manage_purge_deleted">Buang tugas yang dihapus</string>
<string name="EPr_manage_purge_deleted_message">Apakah anda benar-benar ingin membuang tugas yang dihapus\?
\n
@ -267,7 +266,6 @@
<string name="take_a_picture">Ambil gambar</string>
<string name="pick_from_gallery">Pilih dari galeri</string>
<string name="pick_from_storage">Pilih dari penyimpanan</string>
<string name="privacy">Privasi</string>
<string name="privacy_policy">Kebijakan privasi</string>
<string name="send_anonymous_statistics">Buat Tasks lebih baik</string>
<string name="send_anonymous_statistics_summary">Kirim statistik penggunaan dan laporan kerusakan secara anonim untuk membantu membuat Tasks menjadi lebih baik. Tidak ada data personal yang dikumpulkan.</string>
@ -311,7 +309,6 @@
<string name="theme_light">Cerah</string>
<string name="theme_dark">Gelap</string>
<string name="theme_day_night">Siang/Malam</string>
<string name="settings_general">Umum</string>
<string name="language">Bahasa</string>
<string name="restart_required">Tasks harus dimulai ulang agar perubahan terdampak</string>
<string name="restart_now">Mulai ulang sekarang</string>
@ -334,7 +331,6 @@
<string name="date_and_time">Tanggal dan waktu</string>
<string name="start_of_week">Awal minggu</string>
<string name="use_locale_default">Gunakan bahasa default</string>
<string name="use_native_datetime_pickers">Gunakan pemilih tanggal dan waktu bawaan</string>
<string name="add_account">Tambah akun</string>
<string name="user">Pengguna</string>
<string name="password">Kata sandi</string>

@ -85,7 +85,6 @@
<string name="EPr_cal_end_or_start_at_due_time">Ora calendario eventi</string>
<string name="EPr_cal_end_at_due_time">Calendario eventi fino alla scadenza</string>
<string name="EPr_cal_start_at_due_time">Calendario eventi dalla scadenza</string>
<string name="EPr_manage_header">Gestisci attività passate</string>
<string name="EPr_manage_purge_deleted">Rimuovi le attività eliminate</string>
<string name="EPr_manage_purge_deleted_message">Sicuro di voler rimuovere le attività eliminate?\n\nQueste attività saranno perse per sempre!</string>
<string name="EPr_manage_purge_deleted_status">Rimosse %d attività!</string>
@ -350,12 +349,10 @@
<string name="take_a_picture">Scatta un foto</string>
<string name="pick_from_gallery">Scegli dalla libreria</string>
<string name="pick_from_storage">Scegli dalla memoria</string>
<string name="privacy">Riservatezza</string>
<string name="privacy_policy">Norme Riservatezza</string>
<string name="send_anonymous_statistics">Migliora Attività</string>
<string name="send_anonymous_statistics_summary">Invio anonimo di statistiche e problemi di funzionamento atti a migliorare \"Tasks\". Non verrà inviato nessun dato personale.</string>
<string name="tag_already_exists">Etichetta già presente</string>
<string name="duplicate_name">Nome già presente</string>
<string name="name_cannot_be_empty">Il nome non può essere omesso</string>
<string name="username_required">Necessario nome utente</string>
<string name="password_required">Necessaria password</string>
@ -398,7 +395,6 @@
<string name="theme_dark">Scuro</string>
<string name="theme_wallpaper">Sfondo</string>
<string name="theme_day_night">Giorno/Notte</string>
<string name="settings_general">Generale</string>
<string name="language">Lingua</string>
<string name="restart_required">Per rendere attive le modifiche l\'attività va riavviata</string>
<string name="restart_now">Riavvia ora</string>
@ -422,7 +418,6 @@
<string name="date_and_time">Data e ora</string>
<string name="start_of_week">Inizio settimana</string>
<string name="use_locale_default">Usa default locale</string>
<string name="use_native_datetime_pickers">Usa data e ora locali</string>
<string name="add_account">Aggiungi account</string>
<string name="user">Utente</string>
<string name="calendar_settings">Impostazioni calendario

@ -90,7 +90,6 @@
<string name="EPr_cal_end_or_start_at_due_time">משך אירוע יומן</string>
<string name="EPr_cal_end_at_due_time">סיים את אירועי היומן במועד היעד</string>
<string name="EPr_cal_start_at_due_time">התחל את מאורעות היומן במועד היעד</string>
<string name="EPr_manage_header">נהל משימות ישנות</string>
<string name="EPr_manage_purge_deleted">מחק לצמיתות משימות שנמחקו</string>
<string name="EPr_manage_purge_deleted_message">למחוק לצמיתות את כל המשימות שנמחקו\?
\n
@ -389,12 +388,10 @@
<string name="take_a_picture">צלם תמונה</string>
<string name="pick_from_gallery">בחירה מהגלריה</string>
<string name="pick_from_storage">בחירה מאחסון</string>
<string name="privacy">פרטיות</string>
<string name="privacy_policy">מדיניות פרטיות</string>
<string name="send_anonymous_statistics">שיפור Tasks</string>
<string name="send_anonymous_statistics_summary">שליחת סטסיטיקות ודיווחי קריסה של האפליקציה באופן אנונימי. מידע אישי לא נאסף כלל.</string>
<string name="tag_already_exists">תגית כבר קיימת</string>
<string name="duplicate_name">שכפל שם</string>
<string name="name_cannot_be_empty">השם לא יכול להיות ריק</string>
<string name="username_required">נדרש שם משתמש</string>
<string name="password_required">נדרשת סיסמא</string>
@ -437,7 +434,6 @@
<string name="theme_dark">כהה</string>
<string name="theme_wallpaper">תמונת רקע</string>
<string name="theme_day_night">יום / לילה</string>
<string name="settings_general">כללי</string>
<string name="language">שפה</string>
<string name="restart_required">יש לאתחל את האפליקציה כדי להחיל את השינוי</string>
<string name="restart_now">אתחל כעת</string>
@ -461,7 +457,6 @@
<string name="date_and_time">תאריך וושעה</string>
<string name="start_of_week">תחילת השבוע</string>
<string name="use_locale_default">השתמש באזור גיאוגרפי ברירת מחדל</string>
<string name="use_native_datetime_pickers">השתמש בממשק תאריך ושעה של המערכת</string>
<string name="add_account">הוסף חשבון</string>
<string name="user">משתמש</string>
<string name="password">סיסמא</string>

@ -85,7 +85,6 @@
<string name="EPr_cal_end_or_start_at_due_time">カレンダーイベント時間</string>
<string name="EPr_cal_end_at_due_time">カレンダーイベント終了時間</string>
<string name="EPr_cal_start_at_due_time">カレンダーイベント開始時間</string>
<string name="EPr_manage_header">古いタスクを管理</string>
<string name="EPr_manage_purge_deleted">削除済のタスクを消去</string>
<string name="EPr_manage_purge_deleted_message">削除済のタスクをすべて消去してもよろしいですか?\n\nこれらのタスクは永久になくなります!</string>
<string name="EPr_manage_purge_deleted_status">%d タスクを消去しました!</string>
@ -351,12 +350,10 @@
<string name="take_a_picture">写真を撮影</string>
<string name="pick_from_gallery">ギャラリーから選択</string>
<string name="pick_from_storage">ストレージから選択</string>
<string name="privacy">プライバシー</string>
<string name="privacy_policy">プライバシーポリシー</string>
<string name="send_anonymous_statistics">Tasks を改善</string>
<string name="send_anonymous_statistics_summary">Tasks を改善するために、匿名で使用状況データとクラッシュレポートを送信します。個人情報は収集されません。</string>
<string name="tag_already_exists">タグは既に存在します</string>
<string name="duplicate_name">名前を複製</string>
<string name="name_cannot_be_empty">名前は空にできません。</string>
<string name="username_required">ユーザー名が必要です</string>
<string name="password_required">パスワードが必要です</string>
@ -399,7 +396,6 @@
<string name="theme_dark">ダーク</string>
<string name="theme_wallpaper">壁紙</string>
<string name="theme_day_night">デイナイト</string>
<string name="settings_general">全般</string>
<string name="language">言語</string>
<string name="restart_required">Tasks は、変更を有効にするために再起動する必要があります</string>
<string name="restart_now">今すぐ再起動</string>
@ -423,7 +419,6 @@
<string name="date_and_time">日付と時刻</string>
<string name="start_of_week">週の始まり</string>
<string name="use_locale_default">ロケールのデフォルトを使用する</string>
<string name="use_native_datetime_pickers">ネイティブの日付と時刻選択を使用する</string>
<string name="add_account">アカウントを追加</string>
<string name="user">ユーザー</string>
<string name="password">パスワード</string>

@ -87,7 +87,6 @@
<string name="EPr_cal_end_or_start_at_due_time">달력 이벤트 시간</string>
<string name="EPr_cal_end_at_due_time">설정한 시간에 달력 이벤트 종료</string>
<string name="EPr_cal_start_at_due_time">설정한 시간에 달력 이벤트 시작</string>
<string name="EPr_manage_header">오래된 할일 관리하기</string>
<string name="EPr_manage_purge_deleted">삭제한 할일을 비우기</string>
<string name="EPr_manage_purge_deleted_message">삭제한 할일을 모두 비울까요?
비운 할일은 되돌릴 수 없습니다!</string>
@ -353,12 +352,10 @@
<string name="take_a_picture">사진 촬영</string>
<string name="pick_from_gallery">갤러리에서 선택</string>
<string name="pick_from_storage">저장소에서 가져오기</string>
<string name="privacy">프라이버시</string>
<string name="privacy_policy">프라이버시 정책</string>
<string name="send_anonymous_statistics">Tasks 향상</string>
<string name="send_anonymous_statistics_summary">Tasks를 향상시키기 위해 사용 기록과 충돌 보고서를 익명으로 전송합니다. 개인 정보는 수집되지 않습니다.</string>
<string name="tag_already_exists">태그가 이미 존재합니다</string>
<string name="duplicate_name">중복된 이름</string>
<string name="name_cannot_be_empty">이름은 필수 입력항목입니다</string>
<string name="username_required">계정명 필수</string>
<string name="password_required">비밀번호 필수</string>
@ -401,7 +398,6 @@
<string name="theme_dark">어둡게</string>
<string name="theme_wallpaper">바탕화면</string>
<string name="theme_day_night">주간/야간</string>
<string name="settings_general">일반</string>
<string name="language">언어</string>
<string name="restart_required">이 변경을 적용하려면 Tasks 앱을 재시작해야 합니다</string>
<string name="restart_now">지금 재시작하기</string>
@ -425,7 +421,6 @@
<string name="date_and_time">날짜와 시간</string>
<string name="start_of_week">한 주의 시작</string>
<string name="use_locale_default">기본으로 설정된 언어 사용하기</string>
<string name="use_native_datetime_pickers">시스템 날짜와 시간 입력창 사용하기</string>
<string name="add_account">계정 추가</string>
<string name="user">사용자</string>
<string name="password">비밀번호</string>

@ -85,7 +85,6 @@
<string name="EPr_cal_end_or_start_at_due_time">Kalendoriaus įvykio laikas</string>
<string name="EPr_cal_end_at_due_time">Baigti kalendoriaus įvykius atėjus terminui</string>
<string name="EPr_cal_start_at_due_time">Baigti kalendoriaus įvykius atėjus terminui</string>
<string name="EPr_manage_header">Valdyti senas užduotis</string>
<string name="EPr_manage_purge_deleted">Išvalyti ištrintas užduotis</string>
<string name="EPr_manage_purge_deleted_message">Ar tikrai norite išvalyti visas ištrintas užduotis?\n\nŠios užduotys pradings negrįžtamai!</string>
<string name="EPr_manage_purge_deleted_status">Išvalyta %d užduočių!</string>
@ -350,12 +349,10 @@
<string name="take_a_picture">Nufotografuoti</string>
<string name="pick_from_gallery">Pasirinkti iš galerijos</string>
<string name="pick_from_storage">Pasirinkti iš įrenginio</string>
<string name="privacy">Privatumas</string>
<string name="privacy_policy">Privatumo politika</string>
<string name="send_anonymous_statistics">Pagerinti Tasks</string>
<string name="send_anonymous_statistics_summary">Siųsti anoniminę naudojimo statistikos ir gedimų ataskaitas, kad pagerinti Tasks programą. Jokia asmeninė informacija nebus renkama.</string>
<string name="tag_already_exists">Etiketė jau egzistuoja</string>
<string name="duplicate_name">Besidubliuojantis pavadinimas</string>
<string name="name_cannot_be_empty">Pavadinimas negali būti tuščias</string>
<string name="username_required">Reikalingas vartotojo vardas</string>
<string name="password_required">Reikalingas slaptažodis</string>
@ -397,7 +394,6 @@
<string name="theme_dark">Tamsi</string>
<string name="theme_wallpaper">Fono vaizdas</string>
<string name="theme_day_night">Diena/Naktis</string>
<string name="settings_general">Pagrindiniai</string>
<string name="language">Kalba</string>
<string name="restart_required">Kad nustatymai įsigaliotų, Tasks turi būti perkrauta</string>
<string name="restart_now">Perkrauti dabar</string>
@ -421,7 +417,6 @@
<string name="date_and_time">Data ir laikas</string>
<string name="start_of_week">Savaitės pradžia</string>
<string name="use_locale_default">Naudoti įprastą vietovę</string>
<string name="use_native_datetime_pickers">Naudoti įprastą datos ir laiko pasirinkimą</string>
<string name="add_account">Pridėti paskyrą</string>
<string name="user">Vartotojas</string>
<string name="password">Slaptažodis</string>

@ -215,7 +215,6 @@
<string name="EPr_cal_end_or_start_at_due_time">Kalenderhendelsestid</string>
<string name="EPr_cal_end_at_due_time">Sluttfør kalenderhendelser ved tidsfrist</string>
<string name="EPr_cal_start_at_due_time">Start kalenderhendelser ved tidsfrist</string>
<string name="EPr_manage_header">Håndter gamle oppgaver</string>
<string name="EPr_manage_purge_deleted">Tøm slettede oppgaver</string>
<string name="EPr_manage_purge_deleted_message">Ønsker du virkelig å tømme alle dine slettede oppgaver\?
\n
@ -388,11 +387,9 @@
<string name="take_a_picture">Ta et bilde</string>
<string name="pick_from_gallery">Velg fra galleri</string>
<string name="pick_from_storage">Velg fra lagring</string>
<string name="privacy">Personvern</string>
<string name="privacy_policy">Personvernspraksis</string>
<string name="send_anonymous_statistics">Forbedre Tasks</string>
<string name="send_anonymous_statistics_summary">Send anonym bruksstatistkk og kræsjrapporter for å hjelpe til å forbedre Tasks. Ingen personlig data vil bli samlet inn.</string>
<string name="duplicate_name">Duplikatnavn</string>
<string name="name_cannot_be_empty">Navn kan ikke stå tomt</string>
<string name="username_required">Brukernavn kreves</string>
<string name="password_required">Passord kreves</string>
@ -434,7 +431,6 @@
<string name="theme_dark">Mørk</string>
<string name="theme_wallpaper">Bakgrunnsbilde</string>
<string name="theme_day_night">Dag/natt</string>
<string name="settings_general">Generelt</string>
<string name="layout_direction">Sideretning</string>
<string name="hardware_support_required">Maskinvarestøtte kreves</string>
<string name="no_calendars_found">Fant ingen kalendre</string>
@ -450,7 +446,6 @@
<string name="date_and_time">Dato og tid</string>
<string name="start_of_week">Ukestart</string>
<string name="use_locale_default">Bruk forvalgt lokalitet</string>
<string name="use_native_datetime_pickers">Bruk systemets dato og tider</string>
<string name="add_account">Legg til konto</string>
<string name="user">Bruker</string>
<string name="password">Passord</string>

@ -83,7 +83,6 @@
<string name="EPr_cal_end_or_start_at_due_time">Agenda item tijd</string>
<string name="EPr_cal_end_at_due_time">Agenda item op tijd afronden</string>
<string name="EPr_cal_start_at_due_time">Agenda item op tijd starten</string>
<string name="EPr_manage_header">Oude taken beheren</string>
<string name="EPr_manage_purge_deleted">Verwijderde taken opruimen</string>
<string name="EPr_manage_purge_deleted_message">Alle verwijderde taken werkelijk opschonen?\n\nDeze taken zijn dan definitief verwijderd!</string>
<string name="EPr_manage_purge_deleted_status">%d verwijderde taken opgeruimd!</string>
@ -350,7 +349,6 @@
<string name="send_anonymous_statistics">Tasks verbeteren</string>
<string name="send_anonymous_statistics_summary">Verstuur anoniem gebruikersstatistieken en crash rapporten om Tasks te verbeteren. Er worden geen persoonlijke gegevens verzameld.</string>
<string name="tag_already_exists">Label bestaat reeds</string>
<string name="duplicate_name">Dubbele naam</string>
<string name="name_cannot_be_empty">Naam mag niet leeg zijn</string>
<string name="username_required">Gebruikersnaam verplicht</string>
<string name="password_required">Wachtwoord verplicht</string>
@ -390,7 +388,6 @@
<string name="theme_dark">Donker</string>
<string name="theme_wallpaper">Achtergrond</string>
<string name="theme_day_night">Dag/Nacht</string>
<string name="settings_general">Globaal</string>
<string name="language">Taal</string>
<string name="restart_required">Tasks moet opnieuw gestart worden om de nieuwe wijzingen te activeren</string>
<string name="restart_now">Herstart nu</string>
@ -413,7 +410,6 @@
<string name="date_and_time">Datum en tijd</string>
<string name="start_of_week">Begin van de week</string>
<string name="use_locale_default">Gebruik lokale instellingen</string>
<string name="use_native_datetime_pickers">Gebruik standaard datum- en tijd selectie</string>
<string name="add_account">Account toevoegen</string>
<string name="user">Gebruiker</string>
<string name="password">Wachtwoord</string>
@ -512,7 +508,6 @@
<string name="backup_directory">Backup locatie</string>
<string name="location_radius_meters">%s m</string>
<string name="filters">Filters</string>
<string name="privacy">Privacy</string>
<string name="filter">Filter</string>
<string name="accent">Accent</string>
<string name="pro_tasker_plugins">Tasker plugins</string>

@ -84,7 +84,6 @@
<string name="EPr_cal_end_or_start_at_due_time">Czas zdarzenia kalendarza</string>
<string name="EPr_cal_end_at_due_time">Zakończ zadania kalendarza w ustalonym czasie</string>
<string name="EPr_cal_start_at_due_time">Rozpocznij zadania kalendarza w ustalonym czasie</string>
<string name="EPr_manage_header">Zarządzaj starymi zadaniami</string>
<string name="EPr_manage_purge_deleted">Skasuj usunięte zadania</string>
<string name="EPr_manage_purge_deleted_message">Czy na pewno chcesz, aby oczyścić wszystkie usunięte zadania?\n\n Te zadania znikną na zawsze!</string>
<string name="EPr_manage_purge_deleted_status">Oczyszczone %d zadań!</string>
@ -364,12 +363,10 @@
<string name="take_a_picture">Wybierz obrazek</string>
<string name="pick_from_gallery">Wybierz z galerii</string>
<string name="pick_from_storage">Wybierz z pamięci</string>
<string name="privacy">Prywatność</string>
<string name="privacy_policy">Polityka prywatności</string>
<string name="send_anonymous_statistics">Ulepsz Tasks</string>
<string name="send_anonymous_statistics_summary">Wyślij anonimowe statyki użycia i raporty o awariach celem ulepszenia Tasks. Żadne prywatne dane nie będą gromadzone.</string>
<string name="tag_already_exists">Tag już istnieje</string>
<string name="duplicate_name">Duplikuj nazwę</string>
<string name="name_cannot_be_empty">Nazwa nie może być pusta</string>
<string name="username_required">Wymagana nazwa użytkownika</string>
<string name="password_required">Wymagane hasło</string>
@ -412,7 +409,6 @@
<string name="theme_dark">Ciemny</string>
<string name="theme_wallpaper">Tapeta</string>
<string name="theme_day_night">Dzień/noc</string>
<string name="settings_general">Podstawowe</string>
<string name="language">Język</string>
<string name="restart_required">Tasks muszą zostać zrestartowane aby zmiany zostały wprowadzone</string>
<string name="restart_now">Zrestartuj teraz</string>
@ -436,7 +432,6 @@
<string name="date_and_time">Data i czas</string>
<string name="start_of_week">Początek tygodnia</string>
<string name="use_locale_default">Użyj domyślnych</string>
<string name="use_native_datetime_pickers">Użyj natywnych narzędzi wyboru daty i czasu</string>
<string name="add_account">Dodaj konto</string>
<string name="user">Użytkownik</string>
<string name="password">Hasło</string>

@ -86,7 +86,6 @@
<string name="EPr_cal_end_or_start_at_due_time">Hora do evento do calendário</string>
<string name="EPr_cal_end_at_due_time">Finalizar eventos do calendário no horário de vencimento</string>
<string name="EPr_cal_start_at_due_time">Iniciar eventos do calendário no horário de vencimento</string>
<string name="EPr_manage_header">Gerenciar tarefas antigas</string>
<string name="EPr_manage_purge_deleted">Limpar tarefas excluídas</string>
<string name="EPr_manage_purge_deleted_message">Você realmente deseja limpar todas as suas tarefas excluídas?\n\nEstas tarefas irão desaparecer para sempre!</string>
<string name="EPr_manage_purge_deleted_status">%d tarefas removidas!</string>
@ -351,12 +350,10 @@
<string name="take_a_picture">Tirar uma foto</string>
<string name="pick_from_gallery">Selecionar da galeria</string>
<string name="pick_from_storage">Selecionar do armazenamento</string>
<string name="privacy">Privacidade</string>
<string name="privacy_policy">Política de privacidade</string>
<string name="send_anonymous_statistics">Melhorar o Tasks</string>
<string name="send_anonymous_statistics_summary">Enviar estatísticas de uso e relatórios de falha anonimamente para ajudar a melhorar o Tasks. Nenhuma informação pessoal será coletada.</string>
<string name="tag_already_exists">Etiqueta já existe</string>
<string name="duplicate_name">Duplicar nome</string>
<string name="name_cannot_be_empty">Nome não pode ser vazio</string>
<string name="username_required">Nome de usuário necessário</string>
<string name="password_required">Senha necessária</string>
@ -399,7 +396,6 @@
<string name="theme_dark">Escuro</string>
<string name="theme_wallpaper">Plano de fundo</string>
<string name="theme_day_night">Dia/Noite</string>
<string name="settings_general">Geral</string>
<string name="language">Idioma</string>
<string name="restart_required">Você deve reiniciar seu aplicativo para que as alterações sejam aplicadas.</string>
<string name="restart_now">Reiniciar agora</string>
@ -423,7 +419,6 @@
<string name="date_and_time">Hora e data</string>
<string name="start_of_week">Começo da semana</string>
<string name="use_locale_default">Usar padrão do aparelho</string>
<string name="use_native_datetime_pickers">Usar calendário nativo</string>
<string name="add_account">Adicionar conta</string>
<string name="user">Usuário</string>
<string name="password">Senha</string>

@ -79,7 +79,6 @@
<string name="EPr_cal_end_or_start_at_due_time">Hora do evento de calendário</string>
<string name="EPr_cal_end_at_due_time">Terminar evento do calendário na hora limite</string>
<string name="EPr_cal_start_at_due_time">Iniciar eventos de calendário na hora limite</string>
<string name="EPr_manage_header">Gerir tarefas antigas</string>
<string name="EPr_manage_purge_deleted">Remover tarefas eliminadas</string>
<string name="EPr_manage_purge_deleted_message">Quer mesmo remover todas as tarefas eliminadas?\n\nNunca mais as conseguirá recuperar!</string>
<string name="EPr_manage_purge_deleted_status">%d tarefas removidas!</string>
@ -332,7 +331,6 @@
<string name="take_a_picture">Tirar uma foto</string>
<string name="pick_from_gallery">Escolher da galeria</string>
<string name="pick_from_storage">Escolher do armazenamento</string>
<string name="privacy">Privacidade</string>
<string name="privacy_policy">Política de privacidade</string>
<string name="send_anonymous_statistics">Melhorar o Tasks</string>
<string name="send_anonymous_statistics_summary">Envie estatísticas de uso anónimo e relatórios de falhas para ajudar a melhorar o Tasks. Não serão recolhidos dados pessoais.</string>
@ -362,7 +360,6 @@
<string name="theme_dark">Escuro</string>
<string name="theme_wallpaper">Fundo</string>
<string name="theme_day_night">Dia/Noite</string>
<string name="settings_general">Geral</string>
<string name="language">Linguagem</string>
<string name="restart_required">O Tasks precisa ser reiniciado para que a mudança entre em vigor</string>
<string name="restart_now">Reiniciar agora</string>
@ -385,7 +382,6 @@
<string name="date_and_time">Data e hora</string>
<string name="start_of_week">Início da semana</string>
<string name="use_locale_default">Usar o idioma padrão</string>
<string name="use_native_datetime_pickers">Usar seletores de data e hora padrão</string>
<string name="notification_channel_settings">Gerir notificações</string>
<string name="battery_optimization_settings">Gerir optimizações de bateria</string>
<string name="notification_disable_battery_optimizations_description">Optimizações da bateria podem atrasar as notificações</string>

@ -89,7 +89,6 @@
<string name="EPr_cal_end_or_start_at_due_time">Время события в календаре</string>
<string name="EPr_cal_end_at_due_time">Завершать события в календаре при наступлении срока</string>
<string name="EPr_cal_start_at_due_time">Начинать события в календаре при наступлении срока</string>
<string name="EPr_manage_header">Управление старыми задачами</string>
<string name="EPr_manage_purge_deleted">Очистить удаленные задачи</string>
<string name="EPr_manage_purge_deleted_message">Действительно хотите навсегда удалить эти задачи?
Эта операция необратима!</string>
@ -371,12 +370,10 @@
<string name="take_a_picture">Сделать снимок</string>
<string name="pick_from_gallery">Выбрать изображение из галереи</string>
<string name="pick_from_storage">Выбрать файл с диска</string>
<string name="privacy">Конфиденциальность</string>
<string name="privacy_policy">Политика конфиденциальности</string>
<string name="send_anonymous_statistics">Содействовать улучшению Tasks</string>
<string name="send_anonymous_statistics_summary">Отправлять анонимную статистику и отчёты об ошибках для содействия улучшению программы. Персональная информация не собирается.</string>
<string name="tag_already_exists">Тег уже существует</string>
<string name="duplicate_name">Повторяющееся название</string>
<string name="name_cannot_be_empty">Необходимо задать имя</string>
<string name="username_required">Требуется имя пользователя</string>
<string name="password_required">Требуется пароль</string>
@ -419,7 +416,6 @@
<string name="theme_dark">Тёмная</string>
<string name="theme_wallpaper">Как обои</string>
<string name="theme_day_night">День / ночь</string>
<string name="settings_general">Общие</string>
<string name="language">Язык</string>
<string name="restart_required">Для применения изменений программа должна быть перезапущена</string>
<string name="restart_now">Перезапустить сейчас</string>
@ -443,7 +439,6 @@
<string name="date_and_time">Дата и время</string>
<string name="start_of_week">Начало недели</string>
<string name="use_locale_default">Как в системе</string>
<string name="use_native_datetime_pickers">Встроенные элементы даты/времени</string>
<string name="add_account">Добавить учётную запись</string>
<string name="user">Пользователь</string>
<string name="password">Пароль</string>

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save