diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index a9b45902e..eaa03eb08 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -153,11 +153,6 @@ android:name=".activities.CameraActivity" android:theme="@style/TranslucentDialog"/> - - diff --git a/app/src/main/java/com/todoroo/astrid/adapter/FilterViewHolder.java b/app/src/main/java/com/todoroo/astrid/adapter/FilterViewHolder.java index 7deb81fe5..56aaf23d8 100644 --- a/app/src/main/java/com/todoroo/astrid/adapter/FilterViewHolder.java +++ b/app/src/main/java/com/todoroo/astrid/adapter/FilterViewHolder.java @@ -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.sync.SynchronizationPreferences; +import org.tasks.preferences.BasicPreferences; 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, SynchronizationPreferences.class))); + v -> activity.startActivity(new Intent(activity, BasicPreferences.class))); } FilterViewHolder(@NonNull View itemView) { diff --git a/app/src/main/java/com/todoroo/astrid/core/DefaultsPreferences.java b/app/src/main/java/com/todoroo/astrid/core/DefaultsPreferences.java index 47c127d2c..ebd6ee673 100644 --- a/app/src/main/java/com/todoroo/astrid/core/DefaultsPreferences.java +++ b/app/src/main/java/com/todoroo/astrid/core/DefaultsPreferences.java @@ -24,6 +24,7 @@ import org.tasks.analytics.Tracker; import org.tasks.analytics.Tracking; 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; @@ -34,7 +35,7 @@ import org.tasks.preferences.DefaultFilterProvider; import org.tasks.preferences.Device; import org.tasks.preferences.PermissionRequestor; import org.tasks.preferences.Preferences; -import org.tasks.sync.SynchronizationPreferences; +import org.tasks.sync.AddAccountDialog; public class DefaultsPreferences extends InjectingPreferenceActivity implements RemoteListSelectionHandler, NativeSeekBarDialog.SeekBarCallback { @@ -51,6 +52,7 @@ public class DefaultsPreferences extends InjectingPreferenceActivity @Inject DefaultFilterProvider defaultFilterProvider; @Inject Locale locale; @Inject Device device; + @Inject DialogBuilder dialogBuilder; private Preference defaultCalendarPref; private Preference defaultRadiusPref; @@ -139,7 +141,7 @@ public class DefaultsPreferences extends InjectingPreferenceActivity @Override public void addAccount() { - startActivity(new Intent(this, SynchronizationPreferences.class)); + AddAccountDialog.showAddAccountDialog(this, dialogBuilder); } @Override diff --git a/app/src/main/java/com/todoroo/astrid/gtasks/auth/GtasksLoginActivity.java b/app/src/main/java/com/todoroo/astrid/gtasks/auth/GtasksLoginActivity.java index dcc5cc1ff..93d935fec 100644 --- a/app/src/main/java/com/todoroo/astrid/gtasks/auth/GtasksLoginActivity.java +++ b/app/src/main/java/com/todoroo/astrid/gtasks/auth/GtasksLoginActivity.java @@ -6,9 +6,12 @@ package com.todoroo.astrid.gtasks.auth; +import static org.tasks.PermissionUtil.verifyPermissions; + import android.app.ProgressDialog; import android.content.Intent; import android.os.Bundle; +import androidx.annotation.NonNull; import com.todoroo.andlib.utility.DialogUtilities; import javax.inject.Inject; import org.tasks.R; @@ -19,6 +22,8 @@ import org.tasks.gtasks.GoogleAccountManager; import org.tasks.injection.ActivityComponent; import org.tasks.injection.InjectingAppCompatActivity; import org.tasks.play.AuthResultHandler; +import org.tasks.preferences.ActivityPermissionRequestor; +import org.tasks.preferences.PermissionRequestor; /** * This activity allows users to sign in or log in to Google Tasks through the Android account @@ -33,15 +38,15 @@ public class GtasksLoginActivity extends InjectingAppCompatActivity { @Inject DialogBuilder dialogBuilder; @Inject GoogleAccountManager googleAccountManager; @Inject GoogleTaskListDao googleTaskListDao; + @Inject ActivityPermissionRequestor permissionRequestor; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - Intent chooseAccountIntent = - android.accounts.AccountManager.newChooseAccountIntent( - null, null, new String[] {"com.google"}, false, null, null, null, null); - startActivityForResult(chooseAccountIntent, RC_CHOOSE_ACCOUNT); + if (permissionRequestor.requestAccountPermissions()) { + chooseAccount(); + } } @Override @@ -49,6 +54,13 @@ public class GtasksLoginActivity extends InjectingAppCompatActivity { component.inject(this); } + private void chooseAccount() { + Intent chooseAccountIntent = + android.accounts.AccountManager.newChooseAccountIntent( + null, null, new String[] {"com.google"}, false, null, null, null, null); + startActivityForResult(chooseAccountIntent, RC_CHOOSE_ACCOUNT); + } + private void getAuthToken(String account) { final ProgressDialog pd = dialogBuilder.newProgressDialog(R.string.gtasks_GLA_authenticating); pd.show(); @@ -99,4 +111,16 @@ public class GtasksLoginActivity extends InjectingAppCompatActivity { super.onActivityResult(requestCode, resultCode, data); } } + + @Override + public void onRequestPermissionsResult( + int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + if (requestCode == PermissionRequestor.REQUEST_GOOGLE_ACCOUNTS) { + if (verifyPermissions(grantResults)) { + chooseAccount(); + } + } else { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + } + } } diff --git a/app/src/main/java/org/tasks/activities/RemoteListSupportPicker.java b/app/src/main/java/org/tasks/activities/RemoteListSupportPicker.java index a03be8b7a..b7718a0da 100644 --- a/app/src/main/java/org/tasks/activities/RemoteListSupportPicker.java +++ b/app/src/main/java/org/tasks/activities/RemoteListSupportPicker.java @@ -24,8 +24,8 @@ import org.tasks.filters.FilterProvider; import org.tasks.gtasks.RemoteListSelectionHandler; import org.tasks.injection.DialogFragmentComponent; import org.tasks.injection.InjectingDialogFragment; +import org.tasks.sync.AddAccountDialog; import org.tasks.sync.SyncAdapters; -import org.tasks.sync.SynchronizationPreferences; public class RemoteListSupportPicker extends InjectingDialogFragment implements RemoteListSelectionHandler { @@ -136,7 +136,7 @@ public class RemoteListSupportPicker extends InjectingDialogFragment @Override public void addAccount() { - startActivity(new Intent(getContext(), SynchronizationPreferences.class)); + AddAccountDialog.showAddAccountDialog(getActivity(), dialogBuilder); } @Override diff --git a/app/src/main/java/org/tasks/caldav/BaseCaldavAccountSettingsActivity.java b/app/src/main/java/org/tasks/caldav/BaseCaldavAccountSettingsActivity.java index 0a367a851..c67adb67f 100644 --- a/app/src/main/java/org/tasks/caldav/BaseCaldavAccountSettingsActivity.java +++ b/app/src/main/java/org/tasks/caldav/BaseCaldavAccountSettingsActivity.java @@ -1,6 +1,7 @@ package org.tasks.caldav; import static android.text.TextUtils.isEmpty; +import static org.tasks.billing.PurchaseDialog.newPurchaseDialog; import android.content.Context; import android.content.Intent; @@ -9,12 +10,14 @@ import android.os.Bundle; import android.view.MenuItem; import android.view.View; import android.view.inputmethod.InputMethodManager; +import androidx.annotation.StringRes; import androidx.appcompat.widget.Toolbar; import androidx.core.content.ContextCompat; import at.bitfire.dav4jvm.exception.HttpException; import butterknife.ButterKnife; import butterknife.OnFocusChange; import butterknife.OnTextChanged; +import com.google.android.material.snackbar.BaseTransientBottomBar; import com.google.android.material.snackbar.Snackbar; import com.google.android.material.textfield.TextInputEditText; import com.todoroo.astrid.service.TaskDeleter; @@ -26,6 +29,7 @@ import javax.inject.Inject; import org.tasks.R; import org.tasks.analytics.Tracker; import org.tasks.analytics.Tracking.Events; +import org.tasks.billing.Inventory; import org.tasks.data.CaldavAccount; import org.tasks.data.CaldavDao; import org.tasks.databinding.ActivityCaldavAccountSettingsBinding; @@ -47,6 +51,7 @@ public abstract class BaseCaldavAccountSettingsActivity extends ThemedInjectingA @Inject protected Encryption encryption; @Inject DialogBuilder dialogBuilder; @Inject TaskDeleter taskDeleter; + @Inject Inventory inventory; protected CaldavAccount caldavAccount; @@ -94,6 +99,15 @@ public abstract class BaseCaldavAccountSettingsActivity extends ThemedInjectingA InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); imm.showSoftInput(binding.name, InputMethodManager.SHOW_IMPLICIT); } + + if (!inventory.hasPro()) { + newSnackbar(R.string.this_feature_requires_a_subscription) + .setDuration(BaseTransientBottomBar.LENGTH_INDEFINITE) + .setAction( + R.string.button_subscribe, + v -> newPurchaseDialog().show(getSupportFragmentManager(), null)) + .show(); + } } private void showProgressIndicator() { @@ -291,6 +305,14 @@ public abstract class BaseCaldavAccountSettingsActivity extends ThemedInjectingA } private void showSnackbar(String message) { + newSnackbar(message).show(); + } + + private Snackbar newSnackbar(@StringRes int resId) { + return newSnackbar(getString(resId)); + } + + private Snackbar newSnackbar(String message) { Snackbar snackbar = Snackbar.make(binding.rootLayout, message, 8000) .setTextColor(ContextCompat.getColor(this, R.color.snackbar_text_color)) @@ -298,7 +320,7 @@ public abstract class BaseCaldavAccountSettingsActivity extends ThemedInjectingA snackbar .getView() .setBackgroundColor(ContextCompat.getColor(this, R.color.snackbar_background)); - snackbar.show(); + return snackbar; } private boolean hasChanges() { diff --git a/app/src/main/java/org/tasks/dialogs/AlertDialogBuilder.java b/app/src/main/java/org/tasks/dialogs/AlertDialogBuilder.java index da4b888cc..d131be05d 100644 --- a/app/src/main/java/org/tasks/dialogs/AlertDialogBuilder.java +++ b/app/src/main/java/org/tasks/dialogs/AlertDialogBuilder.java @@ -50,7 +50,7 @@ public class AlertDialogBuilder { return this; } - AlertDialogBuilder setTitle(int title) { + public AlertDialogBuilder setTitle(int title) { builder.setTitle(title); return this; } @@ -62,7 +62,7 @@ public class AlertDialogBuilder { public AlertDialogBuilder setItems( List strings, DialogInterface.OnClickListener onClickListener) { - return setItems(strings.toArray(new String[strings.size()]), onClickListener); + return setItems(strings.toArray(new String[0]), onClickListener); } public AlertDialogBuilder setItems( @@ -86,10 +86,10 @@ public class AlertDialogBuilder { return this; } - public AlertDialogBuilder setSingleChoiceItems( + AlertDialogBuilder setSingleChoiceItems( List strings, int selectedIndex, DialogInterface.OnClickListener onClickListener) { builder.setSingleChoiceItems( - addDirectionality(strings.toArray(new String[strings.size()])), + addDirectionality(strings.toArray(new String[0])), selectedIndex, onClickListener); return this; diff --git a/app/src/main/java/org/tasks/injection/ActivityComponent.java b/app/src/main/java/org/tasks/injection/ActivityComponent.java index 34c2fcbcb..e080218d3 100644 --- a/app/src/main/java/org/tasks/injection/ActivityComponent.java +++ b/app/src/main/java/org/tasks/injection/ActivityComponent.java @@ -41,7 +41,6 @@ import org.tasks.preferences.DebugPreferences; import org.tasks.preferences.MiscellaneousPreferences; import org.tasks.reminders.NotificationActivity; import org.tasks.reminders.SnoozeActivity; -import org.tasks.sync.SynchronizationPreferences; import org.tasks.tags.TagPickerViewModel; import org.tasks.themes.Theme; import org.tasks.ui.TaskListViewModel; @@ -54,8 +53,6 @@ import org.tasks.widget.WidgetConfigActivity; @Subcomponent(modules = {ActivityModule.class, LocationModule.class}) public interface ActivityComponent { - void inject(SynchronizationPreferences synchronizationPreferences); - void inject(GtasksLoginActivity gtasksLoginActivity); Theme getTheme(); diff --git a/app/src/main/java/org/tasks/injection/InjectingPreferenceActivity.java b/app/src/main/java/org/tasks/injection/InjectingPreferenceActivity.java index bb93b7c61..333769830 100644 --- a/app/src/main/java/org/tasks/injection/InjectingPreferenceActivity.java +++ b/app/src/main/java/org/tasks/injection/InjectingPreferenceActivity.java @@ -174,6 +174,12 @@ public abstract class InjectingPreferenceActivity extends AppCompatPreferenceAct super.finish(); } + protected void restart() { + Intent intent = getIntent(); + finish(); + startActivity(intent); + } + protected void emailSupport() { startActivity( new Intent( diff --git a/app/src/main/java/org/tasks/preferences/BasicPreferences.java b/app/src/main/java/org/tasks/preferences/BasicPreferences.java index 84700db47..e4045c92e 100644 --- a/app/src/main/java/org/tasks/preferences/BasicPreferences.java +++ b/app/src/main/java/org/tasks/preferences/BasicPreferences.java @@ -2,7 +2,7 @@ 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.AndroidUtilities.atLeastMarshmallow; +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; @@ -21,14 +21,17 @@ 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; @@ -43,16 +46,24 @@ import org.tasks.analytics.Tracking.Events; import org.tasks.billing.BillingClient; import org.tasks.billing.Inventory; import org.tasks.billing.PurchaseActivity; +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; @@ -75,11 +86,13 @@ public class BasicPreferences extends InjectingPreferenceActivity 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 RC_DRIVE_BACKUP = 10008; + 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 Tracker tracker; @Inject Preferences preferences; @@ -97,6 +110,10 @@ public class BasicPreferences extends InjectingPreferenceActivity @Inject BillingClient billingClient; @Inject DefaultFilterProvider defaultFilterProvider; @Inject LocalBroadcastManager localBroadcastManager; + @Inject WorkManager workManager; + @Inject GoogleTaskListDao googleTaskListDao; + @Inject CaldavDao caldavDao; + @Inject TaskDeleter taskDeleter; @Override public void onCreate(Bundle savedInstanceState) { @@ -266,7 +283,7 @@ public class BasicPreferences extends InjectingPreferenceActivity if ((Boolean) newValue) { if (permissionRequestor.requestAccountPermissions()) { - requestLogin(); + requestGoogleDriveLogin(); } return false; } else { @@ -314,6 +331,37 @@ public class BasicPreferences extends InjectingPreferenceActivity return false; }); + 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; + }); + findPreference(R.string.changelog) .setSummary(getString(R.string.version_string, BuildConfig.VERSION_NAME)); @@ -340,8 +388,14 @@ public class BasicPreferences extends InjectingPreferenceActivity //noinspection ConstantConditions if (!BuildConfig.FLAVOR.equals("googleplay")) { - ((PreferenceScreen) findPreference(getString(R.string.preference_screen))) - .removePreference(findPreference(getString(R.string.TEA_control_location))); + 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); } } @@ -428,6 +482,102 @@ public class BasicPreferences extends InjectingPreferenceActivity }); int placeProvider = getPlaceProvider(); placeProviderPreference.setSummary(choices.get(placeProvider)); + + 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); + } + } + + private boolean addGoogleTasksAccounts(PreferenceCategory category) { + List 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 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() { @@ -442,8 +592,8 @@ public class BasicPreferences extends InjectingPreferenceActivity : 0; } - private void requestLogin() { - startActivityForResult(new Intent(this, DriveLoginActivity.class), RC_DRIVE_BACKUP); + private void requestGoogleDriveLogin() { + startActivityForResult(new Intent(this, DriveLoginActivity.class), REQUEST_DRIVE_BACKUP); } private void setupActivity(int key, final Class target) { @@ -460,7 +610,7 @@ public class BasicPreferences extends InjectingPreferenceActivity int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { if (requestCode == PermissionRequestor.REQUEST_GOOGLE_ACCOUNTS) { if (verifyPermissions(grantResults)) { - requestLogin(); + requestGoogleDriveLogin(); } } else { super.onRequestPermissionsResult(requestCode, permissions, grantResults); @@ -529,7 +679,7 @@ public class BasicPreferences extends InjectingPreferenceActivity forceRestart(); } } - } else if (requestCode == RC_DRIVE_BACKUP) { + } 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) { @@ -546,6 +696,18 @@ public class BasicPreferences extends InjectingPreferenceActivity 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); } diff --git a/app/src/main/java/org/tasks/preferences/Preferences.java b/app/src/main/java/org/tasks/preferences/Preferences.java index bf8eeb8c2..2f26548c6 100644 --- a/app/src/main/java/org/tasks/preferences/Preferences.java +++ b/app/src/main/java/org/tasks/preferences/Preferences.java @@ -207,7 +207,6 @@ public class Preferences { 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_synchronization, true); PreferenceManager.setDefaultValues(context, R.xml.preferences_misc, true); PreferenceManager.setDefaultValues(context, R.xml.preferences_reminders, true); diff --git a/app/src/main/java/org/tasks/sync/AddAccountDialog.java b/app/src/main/java/org/tasks/sync/AddAccountDialog.java new file mode 100644 index 000000000..e1a7f0b05 --- /dev/null +++ b/app/src/main/java/org/tasks/sync/AddAccountDialog.java @@ -0,0 +1,82 @@ +package org.tasks.sync; + +import android.app.Activity; +import android.content.Intent; +import android.content.res.TypedArray; +import android.net.Uri; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.ImageView; +import android.widget.TextView; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import com.todoroo.astrid.gtasks.auth.GtasksLoginActivity; +import org.tasks.R; +import org.tasks.caldav.CaldavAccountSettingsActivity; +import org.tasks.dialogs.DialogBuilder; +import org.tasks.etesync.EteSyncAccountSettingsActivity; +import org.tasks.preferences.BasicPreferences; + +public class AddAccountDialog { + public static void showAddAccountDialog(Activity activity, DialogBuilder dialogBuilder) { + String[] services = activity.getResources().getStringArray(R.array.synchronization_services); + String[] descriptions = + activity.getResources().getStringArray(R.array.synchronization_services_description); + TypedArray typedArray = + activity.getResources().obtainTypedArray(R.array.synchronization_services_icons); + int[] icons = new int[typedArray.length()]; + for (int i = 0; i < icons.length; i++) { + icons[i] = typedArray.getResourceId(i, 0); + } + typedArray.recycle(); + ArrayAdapter adapter = + new ArrayAdapter( + activity, R.layout.simple_list_item_2_themed, R.id.text1, services) { + @NonNull + @Override + public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) { + View view = super.getView(position, convertView, parent); + view.findViewById(R.id.text1).setText(services[position]); + view.findViewById(R.id.text2).setText(descriptions[position]); + view.findViewById(R.id.image_view).setImageResource(icons[position]); + return view; + } + }; + + dialogBuilder + .newDialog() + .setTitle(R.string.choose_synchronization_service) + .setSingleChoiceItems( + adapter, + -1, + (dialog, which) -> { + switch (which) { + case 0: + activity.startActivityForResult( + new Intent(activity, GtasksLoginActivity.class), + BasicPreferences.REQUEST_GOOGLE_TASKS); + break; + case 1: + activity.startActivityForResult( + new Intent(activity, CaldavAccountSettingsActivity.class), + BasicPreferences.REQUEST_CALDAV_SETTINGS); + break; + case 2: + activity.startActivityForResult( + new Intent(activity, EteSyncAccountSettingsActivity.class), + BasicPreferences.REQUEST_CALDAV_SETTINGS); + break; + } + dialog.dismiss(); + }) + .setNeutralButton( + R.string.help, + (dialog, which) -> + activity.startActivity( + new Intent( + Intent.ACTION_VIEW, Uri.parse(activity.getString(R.string.help_url_sync))))) + .setNegativeButton(android.R.string.cancel, null) + .showThemedListView(); + } +} diff --git a/app/src/main/java/org/tasks/sync/SynchronizationPreferences.java b/app/src/main/java/org/tasks/sync/SynchronizationPreferences.java deleted file mode 100644 index 42cad66fd..000000000 --- a/app/src/main/java/org/tasks/sync/SynchronizationPreferences.java +++ /dev/null @@ -1,326 +0,0 @@ -/* - * Copyright (c) 2012 Todoroo Inc - * - * See the file "LICENSE" for the full license governing this code. - */ - -package org.tasks.sync; - -import static com.todoroo.andlib.utility.DateUtilities.now; -import static java.util.Arrays.asList; -import static org.tasks.PermissionUtil.verifyPermissions; - -import android.content.Intent; -import android.os.Bundle; -import android.preference.CheckBoxPreference; -import android.preference.Preference; -import android.preference.PreferenceCategory; -import androidx.annotation.NonNull; -import androidx.appcompat.app.AlertDialog; -import com.google.common.base.Strings; -import com.todoroo.astrid.gtasks.auth.GtasksLoginActivity; -import com.todoroo.astrid.service.TaskDeleter; -import javax.inject.Inject; -import org.tasks.R; -import org.tasks.analytics.Tracker; -import org.tasks.analytics.Tracking; -import org.tasks.billing.Inventory; -import org.tasks.billing.PurchaseActivity; -import org.tasks.caldav.CaldavAccountSettingsActivity; -import org.tasks.etesync.EteSyncAccountSettingsActivity; -import org.tasks.data.CaldavAccount; -import org.tasks.data.CaldavDao; -import org.tasks.data.GoogleTaskAccount; -import org.tasks.data.GoogleTaskDao; -import org.tasks.data.GoogleTaskListDao; -import org.tasks.dialogs.DialogBuilder; -import org.tasks.gtasks.GoogleAccountManager; -import org.tasks.injection.ActivityComponent; -import org.tasks.injection.InjectingPreferenceActivity; -import org.tasks.jobs.WorkManager; -import org.tasks.preferences.ActivityPermissionRequestor; -import org.tasks.preferences.PermissionChecker; -import org.tasks.preferences.PermissionRequestor; -import org.tasks.preferences.Preferences; -import org.tasks.ui.Toaster; - -public class SynchronizationPreferences extends InjectingPreferenceActivity { - - private static final int REQUEST_LOGIN = 0; - private static final int REQUEST_CALDAV_SETTINGS = 101; - private static final int REQUEST_CALDAV_SUBSCRIBE = 102; - private static final int REQUEST_GOOGLE_TASKS_SUBSCRIBE = 103; - private static final int REQUEST_ETESYNC_SETTINGS = 104; - private static final int REQUEST_ETESYNC_SUBSCRIBE = 105; - - @Inject ActivityPermissionRequestor permissionRequestor; - @Inject PermissionChecker permissionChecker; - @Inject Tracker tracker; - @Inject DialogBuilder dialogBuilder; - @Inject SyncAdapters syncAdapters; - @Inject GoogleTaskDao googleTaskDao; - @Inject GoogleTaskListDao googleTaskListDao; - @Inject GoogleAccountManager googleAccountManager; - @Inject Preferences preferences; - @Inject WorkManager workManager; - @Inject CaldavDao caldavDao; - @Inject Inventory inventory; - @Inject TaskDeleter taskDeleter; - @Inject Toaster toaster; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - setTitle(R.string.synchronization); - - addPreferencesFromResource(R.xml.preferences_synchronization); - - 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; - }); - Preference addGoogleTaskAccount = findPreference(R.string.p_add_google_task_account); - if (inventory.hasPro() || googleTaskListDao.getAccounts().isEmpty()) { - addGoogleTaskAccount.setOnPreferenceClickListener( - preference -> { - addGoogleTaskAccount(); - return false; - }); - } else { - addGoogleTaskAccount.setSummary(R.string.requires_pro_subscription); - addGoogleTaskAccount.setOnPreferenceClickListener( - preference -> { - startActivityForResult( - new Intent(this, PurchaseActivity.class), REQUEST_GOOGLE_TASKS_SUBSCRIBE); - return false; - }); - } - - 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; - }); - - Preference addCaldavAccount = findPreference(R.string.p_add_caldav_account); - if (inventory.hasPro()) { - addCaldavAccount.setOnPreferenceClickListener( - preference -> { - addCaldavAccount(); - return false; - }); - } else { - addCaldavAccount.setSummary(R.string.requires_pro_subscription); - addCaldavAccount.setOnPreferenceClickListener( - preference -> { - startActivityForResult( - new Intent(this, PurchaseActivity.class), REQUEST_CALDAV_SUBSCRIBE); - return false; - }); - } - - Preference addEteSyncAccount = findPreference(R.string.p_add_etesync_account); - if (inventory.hasPro()) { - addEteSyncAccount.setOnPreferenceClickListener( - preference -> { - addEteSyncAccount(); - return false; - }); - } else { - addEteSyncAccount.setSummary(R.string.requires_pro_subscription); - addEteSyncAccount.setOnPreferenceClickListener( - preference -> { - startActivityForResult( - new Intent(this, PurchaseActivity.class), REQUEST_ETESYNC_SUBSCRIBE); - return false; - }); - } - } - - 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 void requestLogin() { - startActivityForResult(new Intent(this, GtasksLoginActivity.class), REQUEST_LOGIN); - } - - @Override - protected void onResume() { - super.onResume(); - - addGoogleTasksAccounts(); - addCaldavAccounts(); - } - - private void addGoogleTasksAccounts() { - PreferenceCategory googleTaskPreferences = - (PreferenceCategory) findPreference(getString(R.string.gtasks_GPr_header)); - googleTaskPreferences.removeAll(); - for (GoogleTaskAccount googleTaskAccount : googleTaskListDao.getAccounts()) { - String account = googleTaskAccount.getAccount(); - Preference accountPreferences = new Preference(this); - accountPreferences.setTitle(account); - accountPreferences.setSummary(googleTaskAccount.getError()); - accountPreferences.setOnPreferenceClickListener( - preference -> { - dialogBuilder - .newDialog(account) - .setItems( - asList(getString(R.string.reinitialize_account), getString(R.string.logout)), - (dialog, which) -> { - if (which == 0) { - addGoogleTaskAccount(); - } else { - logoutConfirmation(googleTaskAccount); - } - }) - .showThemedListView(); - return false; - }); - googleTaskPreferences.addPreference(accountPreferences); - } - } - - private void addGoogleTaskAccount() { - if (permissionRequestor.requestAccountPermissions()) { - requestLogin(); - } - } - - private void addCaldavAccounts() { - PreferenceCategory caldavPreferences = - (PreferenceCategory) findPreference(getString(R.string.CalDAV)); - PreferenceCategory eteSyncPreferences = - (PreferenceCategory) findPreference(R.string.etesync); - caldavPreferences.removeAll(); - eteSyncPreferences.removeAll(); - for (CaldavAccount caldavAccount : caldavDao.getAccounts()) { - Preference accountPreferences = new Preference(this); - accountPreferences.setTitle(caldavAccount.getName()); - accountPreferences.setSummary(caldavAccount.getError()); - if (caldavAccount.isCaldavAccount()) { - accountPreferences.setOnPreferenceClickListener( - preference -> { - Intent intent = new Intent(this, CaldavAccountSettingsActivity.class); - intent.putExtra(CaldavAccountSettingsActivity.EXTRA_CALDAV_DATA, caldavAccount); - startActivityForResult(intent, REQUEST_CALDAV_SETTINGS); - return false; - }); - caldavPreferences.addPreference(accountPreferences); - } else if (caldavAccount.isEteSyncAccount()) { - accountPreferences.setOnPreferenceClickListener( - preference -> { - Intent intent = new Intent(this, EteSyncAccountSettingsActivity.class); - intent.putExtra(CaldavAccountSettingsActivity.EXTRA_CALDAV_DATA, caldavAccount); - startActivityForResult(intent, REQUEST_ETESYNC_SETTINGS); - return false; - } - ); - eteSyncPreferences.addPreference(accountPreferences); - } - } - } - - private void addCaldavAccount() { - startActivityForResult( - new Intent(this, CaldavAccountSettingsActivity.class), REQUEST_CALDAV_SETTINGS); - } - - private void addEteSyncAccount() { - startActivityForResult( - new Intent(this, EteSyncAccountSettingsActivity.class), REQUEST_ETESYNC_SETTINGS); - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - if (requestCode == REQUEST_LOGIN) { - boolean enabled = resultCode == RESULT_OK; - if (enabled) { - tracker.reportEvent(Tracking.Events.GTASK_ENABLED); - workManager.updateBackgroundSync(); - restart(); - } else if (data != null) { - toaster.longToast(data.getStringExtra(GtasksLoginActivity.EXTRA_ERROR)); - } - } else if (requestCode == REQUEST_CALDAV_SETTINGS || requestCode == REQUEST_ETESYNC_SETTINGS) { - if (resultCode == RESULT_OK) { - workManager.updateBackgroundSync(); - restart(); - } - } else if (requestCode == REQUEST_CALDAV_SUBSCRIBE) { - if (inventory.hasPro()) { - addCaldavAccount(); - } - } else if (requestCode == REQUEST_GOOGLE_TASKS_SUBSCRIBE) { - if (inventory.hasPro()) { - requestLogin(); - } - } else if (requestCode == REQUEST_ETESYNC_SUBSCRIBE) { - if (inventory.hasPro()) { - addEteSyncAccount(); - } - } else { - super.onActivityResult(requestCode, resultCode, data); - } - } - - private void restart() { - Intent intent = getIntent(); - finish(); - startActivity(intent); - } - - @Override - public void onRequestPermissionsResult( - int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { - if (requestCode == PermissionRequestor.REQUEST_GOOGLE_ACCOUNTS) { - if (verifyPermissions(grantResults)) { - requestLogin(); - } - } else { - super.onRequestPermissionsResult(requestCode, permissions, grantResults); - } - } - - @Override - protected String getHelpUrl() { - return "http://tasks.org/subscribe"; - } - - @Override - public void inject(ActivityComponent component) { - component.inject(this); - } -} diff --git a/app/src/main/res/drawable/ic_etesync.xml b/app/src/main/res/drawable/ic_etesync.xml new file mode 100644 index 000000000..a85697ad5 --- /dev/null +++ b/app/src/main/res/drawable/ic_etesync.xml @@ -0,0 +1,13 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_google.xml b/app/src/main/res/drawable/ic_google.xml new file mode 100644 index 000000000..7e59e53d4 --- /dev/null +++ b/app/src/main/res/drawable/ic_google.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/app/src/main/res/drawable/ic_webdav_logo.xml b/app/src/main/res/drawable/ic_webdav_logo.xml new file mode 100644 index 000000000..bb664dac7 --- /dev/null +++ b/app/src/main/res/drawable/ic_webdav_logo.xml @@ -0,0 +1,8 @@ + + + + diff --git a/app/src/main/res/layout/activity_caldav_account_settings.xml b/app/src/main/res/layout/activity_caldav_account_settings.xml index 7a6459d6e..d7687d823 100644 --- a/app/src/main/res/layout/activity_caldav_account_settings.xml +++ b/app/src/main/res/layout/activity_caldav_account_settings.xml @@ -1,110 +1,119 @@ - - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + android:descendantFocusability="beforeDescendants" + android:focusableInTouchMode="true" + android:orientation="vertical"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + + \ No newline at end of file diff --git a/app/src/main/res/layout/simple_list_item_2_themed.xml b/app/src/main/res/layout/simple_list_item_2_themed.xml new file mode 100644 index 000000000..020a4e8c8 --- /dev/null +++ b/app/src/main/res/layout/simple_list_item_2_themed.xml @@ -0,0 +1,57 @@ + + + + + + + + + + + diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index 63f3571b2..2d1409add 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -224,4 +224,22 @@ 3 + + @string/gtasks_GPr_header + @string/caldav + @string/etesync + + + + @string/google_tasks_selection_description + @string/caldav_selection_description + @string/etesync_selection_description + + + + @drawable/ic_google + @drawable/ic_webdav_logo + @drawable/ic_etesync + + \ No newline at end of file diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index adb0eba24..3dca22a20 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -42,5 +42,5 @@ 4dp 48dp - + 8dp \ No newline at end of file diff --git a/app/src/main/res/values/keys.xml b/app/src/main/res/values/keys.xml index 136b867a5..43683d7ba 100644 --- a/app/src/main/res/values/keys.xml +++ b/app/src/main/res/values/keys.xml @@ -9,6 +9,7 @@ CalDAV EteSync https://api.etesync.com + https://tasks.org/sync date_shortcut_morning date_shortcut_afternoon @@ -304,9 +305,6 @@ map_provider place_provider preference_screen - add_google_task_account - add_caldav_account - add_etesync_account google_tasks_add_to_top google_tasks_position_hack Custom order synchronization fix diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 37ecd8ca4..05dbff7a2 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -523,6 +523,7 @@ File %1$s contained %2$s.\n\n Tasker plugins Dashclock extension Requires pro subscription + This feature requires a subscription Log out Log out of %s? All data for this account will be removed from your device Cannot access account @@ -566,4 +567,8 @@ File %1$s contained %2$s.\n\n Displaying subtasks will degrade app performance Enter tag name Create \"%s\" + Select a platform + Basic service that synchronizes with your Google account + Synchronization based on open internet standards + Open source, end-to-end encrypted synchronization diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index f67706696..b78c6a375 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -98,6 +98,45 @@ + + + + + + + + + + + + + + + + + + @@ -112,14 +151,6 @@ android:targetPackage="@string/app_package"/> - - - - diff --git a/app/src/main/res/xml/preferences_synchronization.xml b/app/src/main/res/xml/preferences_synchronization.xml deleted file mode 100644 index 436388f44..000000000 --- a/app/src/main/res/xml/preferences_synchronization.xml +++ /dev/null @@ -1,54 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - -