diff --git a/app/src/main/java/com/nextcloud/talk/application/NextcloudTalkApplication.java b/app/src/main/java/com/nextcloud/talk/application/NextcloudTalkApplication.java index 44c6d3052..567c6cd2f 100644 --- a/app/src/main/java/com/nextcloud/talk/application/NextcloudTalkApplication.java +++ b/app/src/main/java/com/nextcloud/talk/application/NextcloudTalkApplication.java @@ -32,6 +32,7 @@ import com.nextcloud.talk.dagger.modules.BusModule; import com.nextcloud.talk.dagger.modules.ContextModule; import com.nextcloud.talk.dagger.modules.DatabaseModule; import com.nextcloud.talk.dagger.modules.RestModule; +import com.nextcloud.talk.jobs.AccountRemovalJob; import com.nextcloud.talk.jobs.PushRegistrationJob; import com.nextcloud.talk.jobs.creator.MagicJobCreator; import com.nextcloud.talk.utils.database.user.UserModule; @@ -96,7 +97,7 @@ public class NextcloudTalkApplication extends MultiDexApplication { refWatcher = LeakCanary.install(this); new JobRequest.Builder(PushRegistrationJob.TAG).setUpdateCurrent(true).startNow().build().schedule(); - + new JobRequest.Builder(AccountRemovalJob.TAG).setUpdateCurrent(true).startNow().build().schedule(); } diff --git a/app/src/main/java/com/nextcloud/talk/controllers/ServerSelectionController.java b/app/src/main/java/com/nextcloud/talk/controllers/ServerSelectionController.java index d34bd8765..2efdde8a3 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/ServerSelectionController.java +++ b/app/src/main/java/com/nextcloud/talk/controllers/ServerSelectionController.java @@ -35,6 +35,7 @@ import com.nextcloud.talk.api.NcApi; import com.nextcloud.talk.api.helpers.api.ApiHelper; import com.nextcloud.talk.application.NextcloudTalkApplication; import com.nextcloud.talk.controllers.base.BaseController; +import com.nextcloud.talk.utils.ErrorMessageHolder; import java.security.cert.CertificateException; @@ -170,6 +171,18 @@ public class ServerSelectionController extends BaseController { }); } + @Override + protected void onAttach(@NonNull View view) { + super.onAttach(view); + if (ErrorMessageHolder.getInstance().getMessageType() != null && + ErrorMessageHolder.getInstance().getMessageType() + .equals(ErrorMessageHolder.ErrorMessageType.ACCOUNT_SCHEDULED_FOR_DELETION)) { + textFieldBoxes.setError(getResources().getString(R.string.nc_account_scheduled_for_deletion), + false); + ErrorMessageHolder.getInstance().setMessageType(null); + } + } + @Override protected void onDestroyView(@NonNull View view) { super.onDestroyView(view); diff --git a/app/src/main/java/com/nextcloud/talk/controllers/SettingsController.java b/app/src/main/java/com/nextcloud/talk/controllers/SettingsController.java index 6506288ec..d6bea0f05 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/SettingsController.java +++ b/app/src/main/java/com/nextcloud/talk/controllers/SettingsController.java @@ -33,18 +33,21 @@ import android.view.ViewGroup; import android.widget.TextView; import com.bluelinelabs.conductor.RouterTransaction; +import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler; import com.bluelinelabs.conductor.changehandler.VerticalChangeHandler; import com.bumptech.glide.load.model.GlideUrl; import com.bumptech.glide.load.model.LazyHeaders; +import com.evernote.android.job.JobRequest; import com.nextcloud.talk.BuildConfig; import com.nextcloud.talk.R; import com.nextcloud.talk.api.NcApi; import com.nextcloud.talk.api.helpers.api.ApiHelper; import com.nextcloud.talk.application.NextcloudTalkApplication; import com.nextcloud.talk.controllers.base.BaseController; +import com.nextcloud.talk.jobs.AccountRemovalJob; import com.nextcloud.talk.persistence.entities.UserEntity; import com.nextcloud.talk.utils.ColorUtils; -import com.nextcloud.talk.utils.SettingsMessageHolder; +import com.nextcloud.talk.utils.ErrorMessageHolder; import com.nextcloud.talk.utils.database.user.UserUtils; import com.nextcloud.talk.utils.glide.GlideApp; import com.nextcloud.talk.utils.preferences.AppPreferences; @@ -306,14 +309,31 @@ public class SettingsController extends BaseController { dispose(profileQueryDisposable); }, () -> dispose(profileQueryDisposable)); + removeAccountButton.setOnClickListener(view1 -> { + boolean otherUserExists = userUtils.scheduleUserForDeletionWithId(userEntity.getId()); + if (otherUserExists && getView() != null) { + onViewBound(getView()); + onAttach(getView()); + } else if (!otherUserExists) { + getParentController().getRouter().setRoot(RouterTransaction.with( + new ServerSelectionController()) + .pushChangeHandler(new HorizontalChangeHandler()) + .popChangeHandler(new HorizontalChangeHandler())); + } + + new JobRequest.Builder(AccountRemovalJob.TAG).setUpdateCurrent(true) + .startNow().build().schedule(); + + }); + } if (userUtils.getUsers().size() <= 1) { switchAccountButton.setVisibility(View.GONE); } - if (SettingsMessageHolder.getInstance().getMessageType() != null) { - switch (SettingsMessageHolder.getInstance().getMessageType()) { + if (ErrorMessageHolder.getInstance().getMessageType() != null) { + switch (ErrorMessageHolder.getInstance().getMessageType()) { case ACCOUNT_UPDATED_NOT_ADDED: messageText.setTextColor(getResources().getColor(R.color.colorPrimary)); messageText.setText(getResources().getString(R.string.nc_settings_account_updated)); @@ -328,7 +348,7 @@ public class SettingsController extends BaseController { messageView.setVisibility(View.GONE); break; } - SettingsMessageHolder.getInstance().setMessageType(null); + ErrorMessageHolder.getInstance().setMessageType(null); messageView.animate() .translationY(0) diff --git a/app/src/main/java/com/nextcloud/talk/controllers/WebViewLoginController.java b/app/src/main/java/com/nextcloud/talk/controllers/WebViewLoginController.java index a615e78ff..841f1a6a2 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/WebViewLoginController.java +++ b/app/src/main/java/com/nextcloud/talk/controllers/WebViewLoginController.java @@ -45,7 +45,7 @@ import com.nextcloud.talk.controllers.base.BaseController; import com.nextcloud.talk.events.CertificateEvent; import com.nextcloud.talk.models.LoginData; import com.nextcloud.talk.persistence.entities.UserEntity; -import com.nextcloud.talk.utils.SettingsMessageHolder; +import com.nextcloud.talk.utils.ErrorMessageHolder; import com.nextcloud.talk.utils.bundle.BundleBuilder; import com.nextcloud.talk.utils.bundle.BundleKeys; import com.nextcloud.talk.utils.database.user.UserUtils; @@ -221,24 +221,30 @@ public class WebViewLoginController extends BaseController { UserEntity currentUser = userUtils.getCurrentUser(); - SettingsMessageHolder.SettingsMessageType settingsMessageType = null; + ErrorMessageHolder.ErrorMessageType errorMessageType = null; if (currentUser != null && isPasswordUpdate && !currentUser.getUsername().equals(loginData.getUsername())) { - SettingsMessageHolder.getInstance().setMessageType( - SettingsMessageHolder.SettingsMessageType.WRONG_ACCOUNT); + ErrorMessageHolder.getInstance().setMessageType( + ErrorMessageHolder.ErrorMessageType.WRONG_ACCOUNT); getRouter().popToRoot(); } else { if (!isPasswordUpdate && userUtils.getIfUserWithUsernameAndServer(loginData.getUsername(), baseUrl)) { - settingsMessageType = SettingsMessageHolder.SettingsMessageType.ACCOUNT_UPDATED_NOT_ADDED; + errorMessageType = ErrorMessageHolder.ErrorMessageType.ACCOUNT_UPDATED_NOT_ADDED; + } + + if (userUtils.checkIfUserIsScheduledForDeletion(loginData.getUsername(), baseUrl)) { + ErrorMessageHolder.getInstance().setMessageType( + ErrorMessageHolder.ErrorMessageType.ACCOUNT_SCHEDULED_FOR_DELETION); + getRouter().popToRoot(); } // We use the URL user entered because one provided by the server is NOT reliable - SettingsMessageHolder.SettingsMessageType finalSettingsMessageType = settingsMessageType; + ErrorMessageHolder.ErrorMessageType finalErrorMessageType = errorMessageType; userQueryDisposable = userUtils.createOrUpdateUser(loginData.getUsername(), loginData.getToken(), baseUrl, null, null, true). subscribe(userEntity -> { - if (!isPasswordUpdate && finalSettingsMessageType == null) { + if (!isPasswordUpdate && finalErrorMessageType == null) { BundleBuilder bundleBuilder = new BundleBuilder(new Bundle()); bundleBuilder.putString(BundleKeys.KEY_USERNAME, userEntity.getUsername()); bundleBuilder.putString(BundleKeys.KEY_TOKEN, userEntity.getToken()); @@ -247,8 +253,8 @@ public class WebViewLoginController extends BaseController { (bundleBuilder.build())).pushChangeHandler(new HorizontalChangeHandler()) .popChangeHandler(new HorizontalChangeHandler())); } else { - if (finalSettingsMessageType != null) { - SettingsMessageHolder.getInstance().setMessageType(finalSettingsMessageType); + if (finalErrorMessageType != null) { + ErrorMessageHolder.getInstance().setMessageType(finalErrorMessageType); } getRouter().popToRoot(); } diff --git a/app/src/main/java/com/nextcloud/talk/persistence/entities/User.java b/app/src/main/java/com/nextcloud/talk/persistence/entities/User.java index 8eefbb193..a590c604c 100644 --- a/app/src/main/java/com/nextcloud/talk/persistence/entities/User.java +++ b/app/src/main/java/com/nextcloud/talk/persistence/entities/User.java @@ -46,4 +46,6 @@ public interface User extends Parcelable, Persistable, Serializable { String getPushConfigurationState(); boolean getCurrent(); + + boolean getScheduledForDeletion(); } diff --git a/app/src/main/java/com/nextcloud/talk/utils/SettingsMessageHolder.java b/app/src/main/java/com/nextcloud/talk/utils/ErrorMessageHolder.java similarity index 62% rename from app/src/main/java/com/nextcloud/talk/utils/SettingsMessageHolder.java rename to app/src/main/java/com/nextcloud/talk/utils/ErrorMessageHolder.java index 62ec5e6d8..2b50844a1 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/SettingsMessageHolder.java +++ b/app/src/main/java/com/nextcloud/talk/utils/ErrorMessageHolder.java @@ -22,24 +22,24 @@ package com.nextcloud.talk.utils; import android.support.annotation.Nullable; -public class SettingsMessageHolder { - public enum SettingsMessageType { - WRONG_ACCOUNT, ACCOUNT_UPDATED_NOT_ADDED +public class ErrorMessageHolder { + public enum ErrorMessageType { + WRONG_ACCOUNT, ACCOUNT_UPDATED_NOT_ADDED, ACCOUNT_SCHEDULED_FOR_DELETION } - private SettingsMessageType settingsMessageType; + private ErrorMessageType errorMessageType; - private static final SettingsMessageHolder holder = new SettingsMessageHolder(); - public static SettingsMessageHolder getInstance() { + private static final ErrorMessageHolder holder = new ErrorMessageHolder(); + public static ErrorMessageHolder getInstance() { return holder; } - public SettingsMessageType getMessageType() { - return settingsMessageType; + public ErrorMessageType getMessageType() { + return errorMessageType; } - public void setMessageType(@Nullable SettingsMessageType settingsMessageType) { - this.settingsMessageType = settingsMessageType; + public void setMessageType(@Nullable ErrorMessageType errorMessageType) { + this.errorMessageType = errorMessageType; } diff --git a/app/src/main/java/com/nextcloud/talk/utils/database/user/UserUtils.java b/app/src/main/java/com/nextcloud/talk/utils/database/user/UserUtils.java index ec43eae0f..89170bfc3 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/database/user/UserUtils.java +++ b/app/src/main/java/com/nextcloud/talk/utils/database/user/UserUtils.java @@ -46,18 +46,36 @@ public class UserUtils { } public boolean anyUserExists() { - return (dataStore.count(User.class).limit(1).get().value() > 0); + return (dataStore.count(User.class).where(UserEntity.SCHEDULED_FOR_DELETION.eq(false)). + limit(1).get().value() > 0); } public List getUsers() { - Result findUsersQueryResult = dataStore.select(User.class).get(); + Result findUsersQueryResult = dataStore.select(User.class).where(UserEntity.SCHEDULED_FOR_DELETION.eq(false)) + .get(); return findUsersQueryResult.toList(); } - // temporary method while we only support 1 user + + public UserEntity getAnyUserAndSetAsActive() { + Result findUserQueryResult = dataStore.select(User.class) + .where(UserEntity.SCHEDULED_FOR_DELETION.eq(false)) + .limit(1).get(); + + UserEntity userEntity; + if ((userEntity = (UserEntity) findUserQueryResult.firstOrNull()) != null) { + userEntity.setCurrent(true); + dataStore.update(userEntity).blockingGet(); + return userEntity; + } + + return null; + } + public UserEntity getCurrentUser() { - Result findUserQueryResult = dataStore.select(User.class).where(UserEntity.CURRENT.eq(true)) + Result findUserQueryResult = dataStore.select(User.class).where(UserEntity.CURRENT.eq(true) + .and(UserEntity.SCHEDULED_FOR_DELETION.eq(false))) .limit(1).get(); return (UserEntity) findUserQueryResult.firstOrNull(); @@ -86,6 +104,19 @@ public class UserUtils { } } + public boolean checkIfUserIsScheduledForDeletion(String username, String server) { + Result findUserQueryResult = dataStore.select(User.class).where(UserEntity.USERNAME.eq(username)) + .and(UserEntity.BASE_URL.eq(server)) + .limit(1).get(); + + UserEntity userEntity; + if ((userEntity = (UserEntity) findUserQueryResult.firstOrNull()) != null) { + return userEntity.getScheduledForDeletion(); + } + + return false; + + } public boolean getIfUserWithUsernameAndServer(String username, String server) { Result findUserQueryResult = dataStore.select(User.class).where(UserEntity.USERNAME.eq(username) .and(UserEntity.BASE_URL.eq(server.toLowerCase()))) @@ -94,6 +125,21 @@ public class UserUtils { return findUserQueryResult.firstOrNull() != null; } + public boolean scheduleUserForDeletionWithId(long id) { + Result findUserQueryResult = dataStore.select(User.class).where(UserEntity.ID.eq(id)) + .limit(1).get(); + + UserEntity userEntity; + if ((userEntity = (UserEntity) findUserQueryResult.firstOrNull()) != null) { + userEntity.setScheduledForDeletion(true); + userEntity.setCurrent(false); + dataStore.update(userEntity).blockingGet(); + } + + return getAnyUserAndSetAsActive() != null; + + } + public Observable createOrUpdateUser(String username, String token, String serverUrl, @Nullable String displayName, @Nullable String pushConfigurationState, diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 1d4cd5e03..aadd1c6e6 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -49,6 +49,7 @@ Add a new account Only current account can be reauthorized We updated your existing account instead of adding a new one since it already exists + Account is scheduled for deletion, and cannot be operated on No proxy Username