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