diff --git a/app/build.gradle b/app/build.gradle index ab7830042..381e2d2c2 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -150,6 +150,10 @@ android { htmlOutput file("$project.buildDir/reports/lint/lint.html") disable 'MissingTranslation' } + + buildFeatures { + viewBinding true + } } ext { diff --git a/app/src/main/java/com/nextcloud/talk/activities/MainActivity.kt b/app/src/main/java/com/nextcloud/talk/activities/MainActivity.kt index 57088dc4b..cbed95d08 100644 --- a/app/src/main/java/com/nextcloud/talk/activities/MainActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/activities/MainActivity.kt @@ -50,6 +50,7 @@ import com.nextcloud.talk.controllers.CallNotificationController import com.nextcloud.talk.controllers.ConversationsListController import com.nextcloud.talk.controllers.LockedController import com.nextcloud.talk.controllers.ServerSelectionController +import com.nextcloud.talk.controllers.SettingsController import com.nextcloud.talk.controllers.WebViewLoginController import com.nextcloud.talk.controllers.base.providers.ActionBarProvider import com.nextcloud.talk.models.json.conversations.RoomOverall @@ -192,6 +193,32 @@ class MainActivity : BaseActivity(), ActionBarProvider { handleActionFromContact(intent) } + fun resetConversationsList() { + if (userUtils.anyUserExists()) { + router!!.setRoot( + RouterTransaction.with(ConversationsListController()) + .pushChangeHandler(HorizontalChangeHandler()) + .popChangeHandler(HorizontalChangeHandler()) + ) + } + } + + fun openSettings() { + router!!.pushController( + RouterTransaction.with(SettingsController()) + .pushChangeHandler(HorizontalChangeHandler()) + .popChangeHandler(HorizontalChangeHandler()) + ) + } + + fun addAccount() { + router!!.pushController( + RouterTransaction.with(ServerSelectionController()) + .pushChangeHandler(VerticalChangeHandler()) + .popChangeHandler(VerticalChangeHandler()) + ) + } + private fun handleActionFromContact(intent: Intent) { if (intent.action == Intent.ACTION_VIEW && intent.data != null) { diff --git a/app/src/main/java/com/nextcloud/talk/controllers/ConversationsListController.java b/app/src/main/java/com/nextcloud/talk/controllers/ConversationsListController.java index 1c23e6ab6..26839b2aa 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/ConversationsListController.java +++ b/app/src/main/java/com/nextcloud/talk/controllers/ConversationsListController.java @@ -79,6 +79,7 @@ import com.nextcloud.talk.jobs.DeleteConversationWorker; import com.nextcloud.talk.models.database.UserEntity; import com.nextcloud.talk.models.json.conversations.Conversation; import com.nextcloud.talk.models.json.participants.Participant; +import com.nextcloud.talk.ui.dialog.ChooseAccountDialogFragment; import com.nextcloud.talk.utils.ApiUtils; import com.nextcloud.talk.utils.ConductorRemapping; import com.nextcloud.talk.utils.DisplayUtils; @@ -108,6 +109,7 @@ import androidx.core.content.res.ResourcesCompat; import androidx.core.graphics.drawable.RoundedBitmapDrawable; import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory; import androidx.core.view.MenuItemCompat; +import androidx.fragment.app.DialogFragment; import androidx.recyclerview.widget.RecyclerView; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; import androidx.work.Data; @@ -565,11 +567,15 @@ public class ConversationsListController extends BaseController implements Searc if (activity.settingsButton != null) { activity.settingsButton.setOnClickListener(v -> { - ArrayList names = new ArrayList<>(); - names.add("userAvatar.transitionTag"); - getRouter().pushController((RouterTransaction.with(new SettingsController()) - .pushChangeHandler(new HorizontalChangeHandler()) - .popChangeHandler(new HorizontalChangeHandler()))); + if (getResources() != null && getResources().getBoolean(R.bool.multiaccount_support)) { + DialogFragment newFragment = ChooseAccountDialogFragment.newInstance(); + newFragment.show(((MainActivity) getActivity()).getSupportFragmentManager(), + "ChooseAccountDialogFragment"); + } else { + getRouter().pushController((RouterTransaction.with(new SettingsController()) + .pushChangeHandler(new HorizontalChangeHandler()) + .popChangeHandler(new HorizontalChangeHandler()))); + } }); } } 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 3af9b8cd8..eb4885642 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/SettingsController.java +++ b/app/src/main/java/com/nextcloud/talk/controllers/SettingsController.java @@ -160,12 +160,8 @@ public class SettingsController extends BaseController { MaterialStandardPreference settingsMessageSound; @BindView(R.id.settings_remove_account) MaterialStandardPreference removeAccountButton; - @BindView(R.id.settings_switch) - MaterialStandardPreference switchAccountButton; @BindView(R.id.settings_reauthorize) MaterialStandardPreference reauthorizeButton; - @BindView(R.id.settings_add_account) - MaterialStandardPreference addAccountButton; @BindView(R.id.message_view) MaterialPreferenceCategory messageView; @BindView(R.id.settings_client_cert) @@ -321,22 +317,6 @@ public class SettingsController extends BaseController { .popChangeHandler(new HorizontalChangeHandler())); }); - if (getResources().getBoolean(R.bool.multiaccount_support)) { - addAccountButton.addPreferenceClickListener(view15 -> { - getRouter().pushController(RouterTransaction.with(new - ServerSelectionController()).pushChangeHandler(new VerticalChangeHandler()) - .popChangeHandler(new VerticalChangeHandler())); - }); - } else { - addAccountButton.setVisibility(View.GONE); - } - - switchAccountButton.addPreferenceClickListener(view16 -> { - getRouter().pushController(RouterTransaction.with(new - SwitchAccountController()).pushChangeHandler(new VerticalChangeHandler()) - .popChangeHandler(new VerticalChangeHandler())); - }); - if (userUtils.getCurrentUser().isPhoneBookIntegrationAvailable()) { phoneBookIntegrationPreference.setVisibility(View.VISIBLE); } else { @@ -379,12 +359,8 @@ public class SettingsController extends BaseController { } private void showLovelyDialog(int dialogId, Bundle savedInstanceState) { - switch (dialogId) { - case ID_REMOVE_ACCOUNT_WARNING_DIALOG: - showRemoveAccountWarning(savedInstanceState); - break; - default: - break; + if (dialogId == ID_REMOVE_ACCOUNT_WARNING_DIALOG) { + showRemoveAccountWarning(savedInstanceState); } } @@ -632,11 +608,6 @@ public class SettingsController extends BaseController { }); } - - if (userUtils.getUsers().size() <= 1) { - switchAccountButton.setVisibility(View.GONE); - } - if (ApplicationWideMessageHolder.getInstance().getMessageType() != null) { switch (ApplicationWideMessageHolder.getInstance().getMessageType()) { case ACCOUNT_UPDATED_NOT_ADDED: diff --git a/app/src/main/java/com/nextcloud/talk/ui/dialog/ChooseAccountDialogFragment.java b/app/src/main/java/com/nextcloud/talk/ui/dialog/ChooseAccountDialogFragment.java new file mode 100644 index 000000000..391ccfb45 --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/ui/dialog/ChooseAccountDialogFragment.java @@ -0,0 +1,244 @@ +/* + * Nextcloud Talk application + * + * @author Andy Scherzinger + * @author Mario Danic + * Copyright (C) 2021 Andy Scherzinger + * Copyright (C) 2017 Mario Danic + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Parts related to account import were either copied from or inspired by the great work done by David Luhmer at: + * https://github.com/nextcloud/ownCloud-Account-Importer + */ + +package com.nextcloud.talk.ui.dialog; + +import android.annotation.SuppressLint; +import android.app.Dialog; +import android.net.Uri; +import android.os.Bundle; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import com.facebook.drawee.backends.pipeline.Fresco; +import com.facebook.drawee.interfaces.DraweeController; +import com.google.android.material.dialog.MaterialAlertDialogBuilder; +import com.nextcloud.talk.R; +import com.nextcloud.talk.activities.MainActivity; +import com.nextcloud.talk.adapters.items.AdvancedUserItem; +import com.nextcloud.talk.application.NextcloudTalkApplication; +import com.nextcloud.talk.databinding.DialogChooseAccountBinding; +import com.nextcloud.talk.models.database.User; +import com.nextcloud.talk.models.database.UserEntity; +import com.nextcloud.talk.models.json.participants.Participant; +import com.nextcloud.talk.utils.ApiUtils; +import com.nextcloud.talk.utils.DisplayUtils; +import com.nextcloud.talk.utils.database.user.UserUtils; + +import org.jetbrains.annotations.NotNull; + +import java.net.CookieManager; +import java.util.ArrayList; +import java.util.List; + +import javax.inject.Inject; + +import androidx.fragment.app.DialogFragment; +import androidx.recyclerview.widget.LinearLayoutManager; +import autodagger.AutoInjector; +import eu.davidea.flexibleadapter.FlexibleAdapter; +import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager; +import io.reactivex.Observer; +import io.reactivex.disposables.Disposable; + +@AutoInjector(NextcloudTalkApplication.class) +public class ChooseAccountDialogFragment extends DialogFragment { + private static final String TAG = ChooseAccountDialogFragment.class.getSimpleName(); + + @Inject + UserUtils userUtils; + + @Inject + CookieManager cookieManager; + + private DialogChooseAccountBinding binding; + private View dialogView; + + private FlexibleAdapter adapter; + private final List userItems = new ArrayList<>(); + + @SuppressLint("InflateParams") + @NotNull + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + binding = DialogChooseAccountBinding.inflate(LayoutInflater.from(requireContext())); + dialogView = binding.getRoot(); + + return new MaterialAlertDialogBuilder(requireContext()).setView(dialogView).create(); + } + + @Override + public void onViewCreated(@NotNull View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + NextcloudTalkApplication.Companion.getSharedApplication().getComponentApplication().inject(this); + + // Defining user picture + binding.currentAccount.userIcon.setTag(""); + + // Defining user texts, accounts, etc. + User user = userUtils.getCurrentUser(); + if (user != null) { + binding.currentAccount.userName.setText(user.getDisplayName()); + binding.currentAccount.ticker.setVisibility(View.GONE); + binding.currentAccount.account.setText((Uri.parse(user.getBaseUrl()).getHost())); + + if (user.getBaseUrl() != null && + (user.getBaseUrl().startsWith("http://") || user.getBaseUrl().startsWith("https://"))) { + binding.currentAccount.userIcon.setVisibility(View.VISIBLE); + + DraweeController draweeController = Fresco.newDraweeControllerBuilder() + .setOldController(binding.currentAccount.userIcon.getController()) + .setAutoPlayAnimations(true) + .setImageRequest(DisplayUtils.getImageRequestForUrl( + ApiUtils.getUrlForAvatarWithName(user.getBaseUrl(), user.getUserId(), R.dimen.avatar_size), + null)) + .build(); + binding.currentAccount.userIcon.setController(draweeController); + + } else { + binding.currentAccount.userIcon.setVisibility(View.INVISIBLE); + } + } + + // Creating listeners for quick-actions + binding.currentAccount.getRoot().setOnClickListener(v -> dismiss()); + + if (getActivity() instanceof MainActivity) { + binding.addAccount.setOnClickListener(v -> { + dismiss(); + ((MainActivity) getActivity()).addAccount(); + }); + binding.manageSettings.setOnClickListener(v -> { + dismiss(); + ((MainActivity) getActivity()).openSettings(); + }); + } + + if (adapter == null) { + adapter = new FlexibleAdapter<>(userItems, getActivity(), false); + + UserEntity userEntity; + Participant participant; + + for (Object userEntityObject : userUtils.getUsers()) { + userEntity = (UserEntity) userEntityObject; + if (!userEntity.getCurrent()) { + String userId; + if (userEntity.getUserId() != null) { + userId = userEntity.getUserId(); + } else { + userId = userEntity.getUsername(); + } + + participant = new Participant(); + participant.setActorType(Participant.ActorType.USERS); + participant.setActorId(userId); + participant.setDisplayName(userEntity.getDisplayName()); + userItems.add(new AdvancedUserItem(participant, userEntity, null)); + } + } + + adapter.addListener(onSwitchItemClickListener); + adapter.updateDataSet(userItems, false); + } + + prepareViews(); + } + + private void prepareViews() { + if (getActivity() != null) { + LinearLayoutManager layoutManager = new SmoothScrollLinearLayoutManager(getActivity()); + binding.accountsList.setLayoutManager(layoutManager); + } + binding.accountsList.setHasFixedSize(true); + binding.accountsList.setAdapter(adapter); + } + + public static ChooseAccountDialogFragment newInstance() { + return new ChooseAccountDialogFragment(); + } + + @Override + public View onCreateView(@NotNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + return dialogView; + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + binding = null; + } + + private final FlexibleAdapter.OnItemClickListener onSwitchItemClickListener = + new FlexibleAdapter.OnItemClickListener() { + @Override + public boolean onItemClick(View view, int position) { + if (userItems.size() > position) { + UserEntity userEntity = (userItems.get(position)).getEntity(); + userUtils.createOrUpdateUser(null, + null, + null, + null, + null, + true, + null, userEntity.getId(), + null, + null, + null) + .subscribe(new Observer() { + @Override + public void onSubscribe(@NotNull Disposable d) { + // unused at the moment + } + + @Override + public void onNext(@NotNull UserEntity userEntity) { + cookieManager.getCookieStore().removeAll(); + userUtils.disableAllUsersWithoutId(userEntity.getId()); + if (getActivity() != null) { + getActivity().runOnUiThread( + () -> ((MainActivity) getActivity()).resetConversationsList()); + } + dismiss(); + } + + @Override + public void onError(@NotNull Throwable e) { + Log.w(TAG, "Error updating user", e); + } + + @Override + public void onComplete() { + // DONE + } + }); + } + + return true; + } + }; +} diff --git a/app/src/main/res/drawable/ic_check_circle.xml b/app/src/main/res/drawable/ic_check_circle.xml new file mode 100644 index 000000000..7cdf90a82 --- /dev/null +++ b/app/src/main/res/drawable/ic_check_circle.xml @@ -0,0 +1,26 @@ + + + + diff --git a/app/src/main/res/drawable/ic_settings.xml b/app/src/main/res/drawable/ic_settings.xml new file mode 100644 index 000000000..26bf3926d --- /dev/null +++ b/app/src/main/res/drawable/ic_settings.xml @@ -0,0 +1,25 @@ + + + + diff --git a/app/src/main/res/layout/account_item.xml b/app/src/main/res/layout/account_item.xml new file mode 100644 index 000000000..545a23716 --- /dev/null +++ b/app/src/main/res/layout/account_item.xml @@ -0,0 +1,138 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/controller_settings.xml b/app/src/main/res/layout/controller_settings.xml index d459ef2f0..b8bc571de 100644 --- a/app/src/main/res/layout/controller_settings.xml +++ b/app/src/main/res/layout/controller_settings.xml @@ -122,19 +122,11 @@ apc:roundAsCircle="true" tools:src="@tools:sample/avatars[0]" /> - - - - diff --git a/app/src/main/res/layout/dialog_choose_account.xml b/app/src/main/res/layout/dialog_choose_account.xml new file mode 100644 index 000000000..3e84ff898 --- /dev/null +++ b/app/src/main/res/layout/dialog_choose_account.xml @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 0d6942d3b..ea9347a0c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -162,6 +162,8 @@ GNU General Public License, Version 3 Select an account + Add account + Active user Personal Info diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 36b21b75c..1a61c1e0c 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -159,4 +159,9 @@ @color/colorPrimary @color/colorPrimary + +