Explorar o código

remove conductor

- replace remaining controllers with activities
- remove conductor lib
- modify some code related to account management and conductor

Signed-off-by: Marcel Hibbe <dev@mhibbe.de>
Marcel Hibbe hai 1 ano
pai
achega
591d6dc3e8
Modificáronse 49 ficheiros con 831 adicións e 1401 borrados
  1. 0 1
      CONTRIBUTING.md
  2. 1 3
      app/build.gradle
  3. 0 1
      app/lint.xml
  4. 39 23
      app/src/main/AndroidManifest.xml
  5. 158 168
      app/src/main/java/com/nextcloud/talk/account/AccountVerificationActivity.kt
  6. 116 137
      app/src/main/java/com/nextcloud/talk/account/ServerSelectionActivity.kt
  7. 50 48
      app/src/main/java/com/nextcloud/talk/account/SwitchAccountActivity.kt
  8. 142 151
      app/src/main/java/com/nextcloud/talk/account/WebViewLoginActivity.kt
  9. 1 1
      app/src/main/java/com/nextcloud/talk/activities/ActionBarProvider.java
  10. 65 7
      app/src/main/java/com/nextcloud/talk/activities/BaseActivity.kt
  11. 1 1
      app/src/main/java/com/nextcloud/talk/activities/CallActivity.kt
  12. 18 66
      app/src/main/java/com/nextcloud/talk/activities/MainActivity.kt
  13. 1 1
      app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingPollMessageViewHolder.kt
  14. 1 1
      app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingPollMessageViewHolder.kt
  15. 1 1
      app/src/main/java/com/nextcloud/talk/bottomsheet/items/BasicListItemWithImage.kt
  16. 1 1
      app/src/main/java/com/nextcloud/talk/bottomsheet/items/BottomSheets.kt
  17. 1 1
      app/src/main/java/com/nextcloud/talk/bottomsheet/items/ListIconDialogAdapter.kt
  18. 1 1
      app/src/main/java/com/nextcloud/talk/callnotification/CallNotificationActivity.kt
  19. 3 3
      app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt
  20. 4 13
      app/src/main/java/com/nextcloud/talk/contacts/ContactsActivity.kt
  21. 0 256
      app/src/main/java/com/nextcloud/talk/controllers/RingtoneSelectionController.kt
  22. 0 309
      app/src/main/java/com/nextcloud/talk/controllers/base/BaseController.kt
  23. 0 52
      app/src/main/java/com/nextcloud/talk/controllers/util/ControllerViewBindingDelegate.kt
  24. 2 2
      app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt
  25. 120 73
      app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt
  26. 0 15
      app/src/main/java/com/nextcloud/talk/jobs/AccountRemovalWorker.java
  27. 1 1
      app/src/main/java/com/nextcloud/talk/location/GeocodingActivity.kt
  28. 9 9
      app/src/main/java/com/nextcloud/talk/profile/ProfileActivity.kt
  29. 0 2
      app/src/main/java/com/nextcloud/talk/receivers/ShareRecordingToChatReceiver.kt
  30. 42 9
      app/src/main/java/com/nextcloud/talk/settings/SettingsActivity.kt
  31. 2 2
      app/src/main/java/com/nextcloud/talk/ui/bottom/sheet/ProfileBottomSheet.kt
  32. 4 6
      app/src/main/java/com/nextcloud/talk/ui/dialog/ChooseAccountDialogFragment.java
  33. 3 1
      app/src/main/java/com/nextcloud/talk/utils/bundle/BundleKeys.kt
  34. 1 1
      app/src/main/java/com/nextcloud/talk/utils/singletons/ApplicationWideMessageHolder.java
  35. 0 0
      app/src/main/res/layout/activity_account_verification.xml
  36. 1 1
      app/src/main/res/layout/activity_chat.xml
  37. 11 3
      app/src/main/res/layout/activity_contacts.xml
  38. 0 0
      app/src/main/res/layout/activity_conversations.xml
  39. 0 9
      app/src/main/res/layout/activity_main.xml
  40. 0 0
      app/src/main/res/layout/activity_server_selection.xml
  41. 20 11
      app/src/main/res/layout/activity_switch_account.xml
  42. 0 0
      app/src/main/res/layout/activity_web_view_login.xml
  43. 2 2
      app/src/main/res/layout/call_activity.xml
  44. 3 3
      app/src/main/res/layout/call_notification_activity.xml
  45. 1 1
      app/src/main/res/values-night/colors.xml
  46. 2 2
      app/src/main/res/values/colors.xml
  47. 1 1
      app/src/main/res/values/setup.xml
  48. 1 0
      app/src/main/res/values/strings.xml
  49. 1 1
      app/src/test/java/com/nextcloud/talk/utils/BundleKeysTest.kt

+ 0 - 1
CONTRIBUTING.md

@@ -289,7 +289,6 @@ We are using [Dagger 2](https://dagger.dev/) to inject dependencies into major A
 
 
  * `Activity`
  * `Activity`
  * `Fragment`
  * `Fragment`
- * `Controller`
  * `Service`
  * `Service`
  * `BroadcastReceiver`
  * `BroadcastReceiver`
  * `ContentProvider`
  * `ContentProvider`

+ 1 - 3
app/build.gradle

@@ -7,7 +7,7 @@
  * @author Tim Krüger
  * @author Tim Krüger
  * Copyright (C) 2021 Andy Scherzinger <info@andy-scherzinger.de>
  * Copyright (C) 2021 Andy Scherzinger <info@andy-scherzinger.de>
  * Copyright (C) 2017-2019 Mario Danic <mario@lovelyhq.com>
  * Copyright (C) 2017-2019 Mario Danic <mario@lovelyhq.com>
- * Copyright (C) 2021 Marcel Hibbe <dev@mhibbe.de>
+ * Copyright (C) 2021-2023 Marcel Hibbe <dev@mhibbe.de>
  * Copyright (C) 2022 Tim Krüger <t@timkrueger.me>
  * Copyright (C) 2022 Tim Krüger <t@timkrueger.me>
  *
  *
  * This program is free software: you can redistribute it and/or modify
  * This program is free software: you can redistribute it and/or modify
@@ -210,8 +210,6 @@ dependencies {
     implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
     implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
     implementation "io.reactivex.rxjava2:rxjava:2.2.21"
     implementation "io.reactivex.rxjava2:rxjava:2.2.21"
 
 
-    implementation 'com.bluelinelabs:conductor:3.2.0'
-
     implementation "com.squareup.okhttp3:okhttp:${okhttpVersion}"
     implementation "com.squareup.okhttp3:okhttp:${okhttpVersion}"
     implementation "com.squareup.okhttp3:okhttp-urlconnection:${okhttpVersion}"
     implementation "com.squareup.okhttp3:okhttp-urlconnection:${okhttpVersion}"
     implementation "com.squareup.okhttp3:logging-interceptor:${okhttpVersion}"
     implementation "com.squareup.okhttp3:logging-interceptor:${okhttpVersion}"

+ 0 - 1
app/lint.xml

@@ -32,6 +32,5 @@
 
 
     <issue id="ObsoleteLintCustomCheck" severity="warning">
     <issue id="ObsoleteLintCustomCheck" severity="warning">
         <ignore path="**/jetified-annotation-experimental-1.**/**/lint.jar" />
         <ignore path="**/jetified-annotation-experimental-1.**/**/lint.jar" />
-        <ignore path="**/jetified-conductor-2.**/**/lint.jar" />
     </issue>
     </issue>
 </lint>
 </lint>

+ 39 - 23
app/src/main/AndroidManifest.xml

@@ -4,7 +4,7 @@
   ~ @author Mario Danic
   ~ @author Mario Danic
   ~ @author Marcel Hibbe
   ~ @author Marcel Hibbe
   ~ Copyright (C) 2017-2019 Mario Danic <mario@lovelyhq.com>
   ~ Copyright (C) 2017-2019 Mario Danic <mario@lovelyhq.com>
-  ~ Copyright (C) 2021-2022 Marcel Hibbe <dev@mhibbe.de>
+  ~ Copyright (C) 2021-2023 Marcel Hibbe <dev@mhibbe.de>
   ~
   ~
   ~ This program is free software: you can redistribute it and/or modify
   ~ 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
   ~ it under the terms of the GNU General Public License as published by
@@ -131,6 +131,44 @@
             </intent-filter>
             </intent-filter>
         </activity>
         </activity>
 
 
+        <activity
+            android:name=".account.ServerSelectionActivity"
+            android:theme="@style/AppTheme" />
+
+        <activity
+            android:name=".account.WebViewLoginActivity"
+            android:theme="@style/AppTheme" />
+
+        <activity
+            android:name=".account.AccountVerificationActivity"
+            android:theme="@style/AppTheme" />
+
+        <activity
+            android:name=".account.SwitchAccountActivity"
+            android:theme="@style/AppTheme" />
+
+        <activity
+            android:name=".conversationlist.ConversationsListActivity"
+            android:theme="@style/AppTheme"
+            android:exported="true">
+
+            <intent-filter>
+                <action android:name="android.intent.action.SEND" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <data android:mimeType="*/*" />
+            </intent-filter>
+
+            <intent-filter>
+                <action android:name="android.intent.action.SEND_MULTIPLE" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <data android:mimeType="*/*" />
+            </intent-filter>
+        </activity>
+
+        <activity
+            android:name=".chat.ChatActivity"
+            android:theme="@style/AppTheme" />
+
         <activity
         <activity
             android:name=".activities.CallActivity"
             android:name=".activities.CallActivity"
             android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"
             android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"
@@ -215,32 +253,10 @@
             android:name=".contacts.ContactsActivity"
             android:name=".contacts.ContactsActivity"
             android:theme="@style/AppTheme" />
             android:theme="@style/AppTheme" />
 
 
-        <activity
-            android:name=".chat.ChatActivity"
-            android:theme="@style/AppTheme" />
-
         <activity
         <activity
             android:name=".openconversations.ListOpenConversationsActivity"
             android:name=".openconversations.ListOpenConversationsActivity"
             android:theme="@style/AppTheme" />
             android:theme="@style/AppTheme" />
 
 
-        <activity
-            android:name=".conversationlist.ConversationsListActivity"
-            android:theme="@style/AppTheme"
-            android:exported="true">
-
-            <intent-filter>
-                <action android:name="android.intent.action.SEND" />
-                <category android:name="android.intent.category.DEFAULT" />
-                <data android:mimeType="*/*" />
-            </intent-filter>
-
-            <intent-filter>
-                <action android:name="android.intent.action.SEND_MULTIPLE" />
-                <category android:name="android.intent.category.DEFAULT" />
-                <data android:mimeType="*/*" />
-            </intent-filter>
-        </activity>
-
         <activity
         <activity
             android:name=".lock.LockedActivity"
             android:name=".lock.LockedActivity"
             android:theme="@style/AppTheme" />
             android:theme="@style/AppTheme" />

+ 158 - 168
app/src/main/java/com/nextcloud/talk/controllers/AccountVerificationController.kt → app/src/main/java/com/nextcloud/talk/account/AccountVerificationActivity.kt

@@ -3,6 +3,8 @@
  *
  *
  * @author Mario Danic
  * @author Mario Danic
  * @author Andy Scherzinger
  * @author Andy Scherzinger
+ * @author Marcel Hibbe
+ * Copyright (C) 2023 Marcel Hibbe <dev@mhibbe.de>
  * Copyright (C) 2022 Andy Scherzinger <info@andy-scherzinger.de>
  * Copyright (C) 2022 Andy Scherzinger <info@andy-scherzinger.de>
  * Copyright (C) 2017 Mario Danic (mario@lovelyhq.com)
  * Copyright (C) 2017 Mario Danic (mario@lovelyhq.com)
  *
  *
@@ -19,7 +21,7 @@
  * You should have received a copy of the GNU General Public License
  * You should have received a copy of the GNU General Public License
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
  */
-package com.nextcloud.talk.controllers
+package com.nextcloud.talk.account
 
 
 import android.annotation.SuppressLint
 import android.annotation.SuppressLint
 import android.content.Intent
 import android.content.Intent
@@ -28,25 +30,24 @@ import android.os.Bundle
 import android.os.Handler
 import android.os.Handler
 import android.text.TextUtils
 import android.text.TextUtils
 import android.util.Log
 import android.util.Log
-import android.view.View
+import android.widget.Toast
 import androidx.work.Data
 import androidx.work.Data
 import androidx.work.OneTimeWorkRequest
 import androidx.work.OneTimeWorkRequest
+import androidx.work.WorkInfo
 import androidx.work.WorkManager
 import androidx.work.WorkManager
 import autodagger.AutoInjector
 import autodagger.AutoInjector
-import com.bluelinelabs.conductor.RouterTransaction
-import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler
 import com.bluelinelabs.logansquare.LoganSquare
 import com.bluelinelabs.logansquare.LoganSquare
 import com.google.android.material.snackbar.Snackbar
 import com.google.android.material.snackbar.Snackbar
 import com.nextcloud.talk.R
 import com.nextcloud.talk.R
+import com.nextcloud.talk.activities.BaseActivity
 import com.nextcloud.talk.api.NcApi
 import com.nextcloud.talk.api.NcApi
 import com.nextcloud.talk.application.NextcloudTalkApplication
 import com.nextcloud.talk.application.NextcloudTalkApplication
 import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication
 import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication
-import com.nextcloud.talk.controllers.base.BaseController
-import com.nextcloud.talk.controllers.util.viewBinding
 import com.nextcloud.talk.conversationlist.ConversationsListActivity
 import com.nextcloud.talk.conversationlist.ConversationsListActivity
 import com.nextcloud.talk.data.user.model.User
 import com.nextcloud.talk.data.user.model.User
-import com.nextcloud.talk.databinding.ControllerAccountVerificationBinding
+import com.nextcloud.talk.databinding.ActivityAccountVerificationBinding
 import com.nextcloud.talk.events.EventStatus
 import com.nextcloud.talk.events.EventStatus
+import com.nextcloud.talk.jobs.AccountRemovalWorker
 import com.nextcloud.talk.jobs.CapabilitiesWorker
 import com.nextcloud.talk.jobs.CapabilitiesWorker
 import com.nextcloud.talk.jobs.PushRegistrationWorker
 import com.nextcloud.talk.jobs.PushRegistrationWorker
 import com.nextcloud.talk.jobs.SignalingSettingsWorker
 import com.nextcloud.talk.jobs.SignalingSettingsWorker
@@ -63,6 +64,7 @@ import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_BASE_URL
 import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_INTERNAL_USER_ID
 import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_INTERNAL_USER_ID
 import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_IS_ACCOUNT_IMPORT
 import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_IS_ACCOUNT_IMPORT
 import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ORIGINAL_PROTOCOL
 import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ORIGINAL_PROTOCOL
+import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_PASSWORD
 import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_TOKEN
 import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_TOKEN
 import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_USERNAME
 import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_USERNAME
 import com.nextcloud.talk.utils.singletons.ApplicationWideMessageHolder
 import com.nextcloud.talk.utils.singletons.ApplicationWideMessageHolder
@@ -71,20 +73,15 @@ import io.reactivex.Observer
 import io.reactivex.android.schedulers.AndroidSchedulers
 import io.reactivex.android.schedulers.AndroidSchedulers
 import io.reactivex.disposables.Disposable
 import io.reactivex.disposables.Disposable
 import io.reactivex.schedulers.Schedulers
 import io.reactivex.schedulers.Schedulers
-import org.greenrobot.eventbus.EventBus
 import org.greenrobot.eventbus.Subscribe
 import org.greenrobot.eventbus.Subscribe
 import org.greenrobot.eventbus.ThreadMode
 import org.greenrobot.eventbus.ThreadMode
 import java.net.CookieManager
 import java.net.CookieManager
 import javax.inject.Inject
 import javax.inject.Inject
 
 
 @AutoInjector(NextcloudTalkApplication::class)
 @AutoInjector(NextcloudTalkApplication::class)
-class AccountVerificationController(args: Bundle? = null) : BaseController(
-    R.layout.controller_account_verification,
-    args
-) {
-    private val binding: ControllerAccountVerificationBinding? by viewBinding(
-        ControllerAccountVerificationBinding::bind
-    )
+class AccountVerificationActivity : BaseActivity() {
+
+    private lateinit var binding: ActivityAccountVerificationBinding
 
 
     @Inject
     @Inject
     lateinit var ncApi: NcApi
     lateinit var ncApi: NcApi
@@ -95,9 +92,6 @@ class AccountVerificationController(args: Bundle? = null) : BaseController(
     @Inject
     @Inject
     lateinit var cookieManager: CookieManager
     lateinit var cookieManager: CookieManager
 
 
-    @Inject
-    lateinit var eventBus: EventBus
-
     private var internalAccountId: Long = -1
     private var internalAccountId: Long = -1
     private val disposables: MutableList<Disposable> = ArrayList()
     private val disposables: MutableList<Disposable> = ArrayList()
     private var baseUrl: String? = null
     private var baseUrl: String? = null
@@ -106,43 +100,53 @@ class AccountVerificationController(args: Bundle? = null) : BaseController(
     private var isAccountImport = false
     private var isAccountImport = false
     private var originalProtocol: String? = null
     private var originalProtocol: String? = null
 
 
-    override fun onAttach(view: View) {
-        super.onAttach(view)
-        eventBus.register(this)
-    }
+    @SuppressLint("SourceLockedOrientationActivity")
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        sharedApplication!!.componentApplication.inject(this)
+        binding = ActivityAccountVerificationBinding.inflate(layoutInflater)
+        requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
+        setContentView(binding.root)
+        actionBar?.hide()
+        setupPrimaryColors()
 
 
-    override fun onDetach(view: View) {
-        super.onDetach(view)
-        eventBus.unregister(this)
+        handleIntent()
     }
     }
 
 
-    override fun onViewBound(view: View) {
-        super.onViewBound(view)
-        activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
+    private fun handleIntent() {
+        val extras = intent.extras!!
+        baseUrl = extras.getString(KEY_BASE_URL)
+        username = extras.getString(KEY_USERNAME)
+        token = extras.getString(KEY_TOKEN)
+        if (extras.containsKey(KEY_IS_ACCOUNT_IMPORT)) {
+            isAccountImport = true
+        }
+        if (extras.containsKey(KEY_ORIGINAL_PROTOCOL)) {
+            originalProtocol = extras.getString(KEY_ORIGINAL_PROTOCOL)
+        }
+    }
 
 
-        actionBar?.hide()
+    override fun onResume() {
+        super.onResume()
 
 
         if (
         if (
             isAccountImport &&
             isAccountImport &&
             !UriUtils.hasHttpProtocolPrefixed(baseUrl!!) ||
             !UriUtils.hasHttpProtocolPrefixed(baseUrl!!) ||
-            isSameProtocol(baseUrl!!, originalProtocol!!)
+            isNotSameProtocol(baseUrl!!, originalProtocol)
         ) {
         ) {
             determineBaseUrlProtocol(true)
             determineBaseUrlProtocol(true)
         } else {
         } else {
-            checkEverything()
+            findServerTalkApp()
         }
         }
     }
     }
 
 
-    private fun isSameProtocol(baseUrl: String, originalProtocol: String): Boolean {
+    private fun isNotSameProtocol(baseUrl: String, originalProtocol: String?): Boolean {
+        if (originalProtocol == null) {
+            return true
+        }
         return !TextUtils.isEmpty(originalProtocol) && !baseUrl.startsWith(originalProtocol)
         return !TextUtils.isEmpty(originalProtocol) && !baseUrl.startsWith(originalProtocol)
     }
     }
 
 
-    private fun checkEverything() {
-        val credentials = ApiUtils.getCredentials(username, token)
-        cookieManager.cookieStore.removeAll()
-        findServerTalkApp(credentials)
-    }
-
     private fun determineBaseUrlProtocol(checkForcedHttps: Boolean) {
     private fun determineBaseUrlProtocol(checkForcedHttps: Boolean) {
         cookieManager.cookieStore.removeAll()
         cookieManager.cookieStore.removeAll()
         baseUrl = baseUrl!!.replace("http://", "").replace("https://", "")
         baseUrl = baseUrl!!.replace("http://", "").replace("https://", "")
@@ -166,20 +170,16 @@ class AccountVerificationController(args: Bundle? = null) : BaseController(
                         "http://$baseUrl"
                         "http://$baseUrl"
                     }
                     }
                     if (isAccountImport) {
                     if (isAccountImport) {
-                        router.replaceTopController(
-                            RouterTransaction.with(
-                                WebViewLoginController(
-                                    baseUrl,
-                                    false,
-                                    username,
-                                    ""
-                                )
-                            )
-                                .pushChangeHandler(HorizontalChangeHandler())
-                                .popChangeHandler(HorizontalChangeHandler())
-                        )
+                        val bundle = Bundle()
+                        bundle.putString(KEY_BASE_URL, baseUrl)
+                        bundle.putString(KEY_USERNAME, username)
+                        bundle.putString(KEY_PASSWORD, "")
+
+                        val intent = Intent(context, WebViewLoginActivity::class.java)
+                        intent.putExtras(bundle)
+                        startActivity(intent)
                     } else {
                     } else {
-                        checkEverything()
+                        findServerTalkApp()
                     }
                     }
                 }
                 }
 
 
@@ -197,7 +197,10 @@ class AccountVerificationController(args: Bundle? = null) : BaseController(
             })
             })
     }
     }
 
 
-    private fun findServerTalkApp(credentials: String) {
+    private fun findServerTalkApp() {
+        val credentials = ApiUtils.getCredentials(username, token)
+        cookieManager.cookieStore.removeAll()
+
         ncApi.getCapabilities(credentials, ApiUtils.getUrlForCapabilities(baseUrl))
         ncApi.getCapabilities(credentials, ApiUtils.getUrlForCapabilities(baseUrl))
             .subscribeOn(Schedulers.io())
             .subscribeOn(Schedulers.io())
             .subscribe(object : Observer<CapabilitiesOverall> {
             .subscribe(object : Observer<CapabilitiesOverall> {
@@ -214,27 +217,24 @@ class AccountVerificationController(args: Bundle? = null) : BaseController(
                     if (hasTalk) {
                     if (hasTalk) {
                         fetchProfile(credentials, capabilitiesOverall)
                         fetchProfile(credentials, capabilitiesOverall)
                     } else {
                     } else {
-                        if (activity != null && resources != null) {
-                            activity!!.runOnUiThread {
-                                binding?.progressText?.setText(
-                                    String.format(
-                                        resources!!.getString(R.string.nc_nextcloud_talk_app_not_installed),
-                                        resources!!.getString(R.string.nc_app_product_name)
-                                    )
+                        if (resources != null) {
+                            runOnUiThread {
+                                binding.progressText.text = String.format(
+                                    resources!!.getString(R.string.nc_nextcloud_talk_app_not_installed),
+                                    resources!!.getString(R.string.nc_app_product_name)
                                 )
                                 )
                             }
                             }
                         }
                         }
-                        ApplicationWideMessageHolder.getInstance().setMessageType(
+                        ApplicationWideMessageHolder.getInstance().messageType =
                             ApplicationWideMessageHolder.MessageType.SERVER_WITHOUT_TALK
                             ApplicationWideMessageHolder.MessageType.SERVER_WITHOUT_TALK
-                        )
                         abortVerification()
                         abortVerification()
                     }
                     }
                 }
                 }
 
 
                 override fun onError(e: Throwable) {
                 override fun onError(e: Throwable) {
-                    if (activity != null && resources != null) {
-                        activity!!.runOnUiThread {
-                            binding?.progressText?.text = String.format(
+                    if (resources != null) {
+                        runOnUiThread {
+                            binding.progressText.text = String.format(
                                 resources!!.getString(R.string.nc_nextcloud_talk_app_not_installed),
                                 resources!!.getString(R.string.nc_nextcloud_talk_app_not_installed),
                                 resources!!.getString(R.string.nc_app_product_name)
                                 resources!!.getString(R.string.nc_app_product_name)
                             )
                             )
@@ -263,7 +263,7 @@ class AccountVerificationController(args: Bundle? = null) : BaseController(
                 displayName = displayName,
                 displayName = displayName,
                 pushConfigurationState = null,
                 pushConfigurationState = null,
                 capabilities = LoganSquare.serialize(capabilities),
                 capabilities = LoganSquare.serialize(capabilities),
-                certificateAlias = appPreferences!!.temporaryClientCertAlias,
+                certificateAlias = appPreferences.temporaryClientCertAlias,
                 externalSignalingServer = null
                 externalSignalingServer = null
             )
             )
         )
         )
@@ -279,9 +279,9 @@ class AccountVerificationController(args: Bundle? = null) : BaseController(
                     if (ClosedInterfaceImpl().isGooglePlayServicesAvailable) {
                     if (ClosedInterfaceImpl().isGooglePlayServicesAvailable) {
                         registerForPush()
                         registerForPush()
                     } else {
                     } else {
-                        activity!!.runOnUiThread {
-                            binding?.progressText?.text =
-                                """ ${binding?.progressText?.text}
+                        runOnUiThread {
+                            binding.progressText.text =
+                                """ ${binding.progressText.text}
                                     ${resources!!.getString(R.string.nc_push_disabled)}
                                     ${resources!!.getString(R.string.nc_push_disabled)}
                                 """.trimIndent()
                                 """.trimIndent()
                         }
                         }
@@ -291,7 +291,7 @@ class AccountVerificationController(args: Bundle? = null) : BaseController(
 
 
                 @SuppressLint("SetTextI18n")
                 @SuppressLint("SetTextI18n")
                 override fun onError(e: Throwable) {
                 override fun onError(e: Throwable) {
-                    binding?.progressText?.text = """ ${binding?.progressText?.text}""".trimIndent() +
+                    binding.progressText.text = """ ${binding.progressText.text}""".trimIndent() +
                         resources!!.getString(R.string.nc_display_name_not_stored)
                         resources!!.getString(R.string.nc_display_name_not_stored)
                     abortVerification()
                     abortVerification()
                 }
                 }
@@ -328,14 +328,12 @@ class AccountVerificationController(args: Bundle? = null) : BaseController(
                             capabilities.ocs!!.data!!.capabilities!!
                             capabilities.ocs!!.data!!.capabilities!!
                         )
                         )
                     } else {
                     } else {
-                        if (activity != null) {
-                            activity!!.runOnUiThread {
-                                binding?.progressText?.text =
-                                    """
-                                        ${binding?.progressText?.text}
-                                        ${resources!!.getString(R.string.nc_display_name_not_fetched)}
-                                    """.trimIndent()
-                            }
+                        runOnUiThread {
+                            binding.progressText.text =
+                                """
+                                    ${binding.progressText.text}
+                                    ${resources!!.getString(R.string.nc_display_name_not_fetched)}
+                                """.trimIndent()
                         }
                         }
                         abortVerification()
                         abortVerification()
                     }
                     }
@@ -343,14 +341,12 @@ class AccountVerificationController(args: Bundle? = null) : BaseController(
 
 
                 @SuppressLint("SetTextI18n")
                 @SuppressLint("SetTextI18n")
                 override fun onError(e: Throwable) {
                 override fun onError(e: Throwable) {
-                    if (activity != null) {
-                        activity!!.runOnUiThread {
-                            binding?.progressText?.text =
-                                """
-                                    ${binding?.progressText?.text}
-                                    ${resources!!.getString(R.string.nc_display_name_not_fetched)}
-                                """.trimIndent()
-                        }
+                    runOnUiThread {
+                        binding.progressText.text =
+                            """
+                                ${binding.progressText.text}
+                                ${resources!!.getString(R.string.nc_display_name_not_fetched)}
+                            """.trimIndent()
                     }
                     }
                     abortVerification()
                     abortVerification()
                 }
                 }
@@ -364,7 +360,7 @@ class AccountVerificationController(args: Bundle? = null) : BaseController(
     private fun registerForPush() {
     private fun registerForPush() {
         val data =
         val data =
             Data.Builder()
             Data.Builder()
-                .putString(PushRegistrationWorker.ORIGIN, "AccountVerificationController#registerForPush")
+                .putString(PushRegistrationWorker.ORIGIN, "AccountVerificationActivity#registerForPush")
                 .build()
                 .build()
         val pushRegistrationWork =
         val pushRegistrationWork =
             OneTimeWorkRequest.Builder(PushRegistrationWorker::class.java)
             OneTimeWorkRequest.Builder(PushRegistrationWorker::class.java)
@@ -377,11 +373,11 @@ class AccountVerificationController(args: Bundle? = null) : BaseController(
     @Subscribe(threadMode = ThreadMode.BACKGROUND)
     @Subscribe(threadMode = ThreadMode.BACKGROUND)
     fun onMessageEvent(eventStatus: EventStatus) {
     fun onMessageEvent(eventStatus: EventStatus) {
         if (eventStatus.eventType == EventStatus.EventType.PUSH_REGISTRATION) {
         if (eventStatus.eventType == EventStatus.EventType.PUSH_REGISTRATION) {
-            if (internalAccountId == eventStatus.userId && !eventStatus.isAllGood && activity != null) {
-                activity!!.runOnUiThread {
-                    binding?.progressText?.text =
+            if (internalAccountId == eventStatus.userId && !eventStatus.isAllGood) {
+                runOnUiThread {
+                    binding.progressText.text =
                         """
                         """
-                            ${binding?.progressText?.text}
+                            ${binding.progressText.text}
                             ${resources!!.getString(R.string.nc_push_disabled)}
                             ${resources!!.getString(R.string.nc_push_disabled)}
                         """.trimIndent()
                         """.trimIndent()
                 }
                 }
@@ -389,14 +385,12 @@ class AccountVerificationController(args: Bundle? = null) : BaseController(
             fetchAndStoreCapabilities()
             fetchAndStoreCapabilities()
         } else if (eventStatus.eventType == EventStatus.EventType.CAPABILITIES_FETCH) {
         } else if (eventStatus.eventType == EventStatus.EventType.CAPABILITIES_FETCH) {
             if (internalAccountId == eventStatus.userId && !eventStatus.isAllGood) {
             if (internalAccountId == eventStatus.userId && !eventStatus.isAllGood) {
-                if (activity != null) {
-                    activity!!.runOnUiThread {
-                        binding?.progressText?.text =
-                            """
-                                ${binding?.progressText?.text}
-                                ${resources!!.getString(R.string.nc_capabilities_failed)}
-                            """.trimIndent()
-                    }
+                runOnUiThread {
+                    binding.progressText.text =
+                        """
+                            ${binding.progressText.text}
+                            ${resources!!.getString(R.string.nc_capabilities_failed)}
+                        """.trimIndent()
                 }
                 }
                 abortVerification()
                 abortVerification()
             } else if (internalAccountId == eventStatus.userId && eventStatus.isAllGood) {
             } else if (internalAccountId == eventStatus.userId && eventStatus.isAllGood) {
@@ -404,14 +398,12 @@ class AccountVerificationController(args: Bundle? = null) : BaseController(
             }
             }
         } else if (eventStatus.eventType == EventStatus.EventType.SIGNALING_SETTINGS) {
         } else if (eventStatus.eventType == EventStatus.EventType.SIGNALING_SETTINGS) {
             if (internalAccountId == eventStatus.userId && !eventStatus.isAllGood) {
             if (internalAccountId == eventStatus.userId && !eventStatus.isAllGood) {
-                if (activity != null) {
-                    activity!!.runOnUiThread {
-                        binding?.progressText?.text =
-                            """
-                                ${binding?.progressText?.text}
-                                ${resources!!.getString(R.string.nc_external_server_failed)}
-                            """.trimIndent()
-                    }
+                runOnUiThread {
+                    binding.progressText.text =
+                        """
+                            ${binding.progressText.text}
+                            ${resources!!.getString(R.string.nc_external_server_failed)}
+                        """.trimIndent()
                 }
                 }
             }
             }
             proceedWithLogin()
             proceedWithLogin()
@@ -457,24 +449,22 @@ class AccountVerificationController(args: Bundle? = null) : BaseController(
             Log.d(TAG, "userToSetAsActive: " + userToSetAsActive.username)
             Log.d(TAG, "userToSetAsActive: " + userToSetAsActive.username)
 
 
             if (userManager.setUserAsActive(userToSetAsActive).blockingGet()) {
             if (userManager.setUserAsActive(userToSetAsActive).blockingGet()) {
-                if (activity != null) {
-                    activity!!.runOnUiThread {
-                        if (userManager.users.blockingGet().size == 1) {
-                            val intent = Intent(context, ConversationsListActivity::class.java)
-                            startActivity(intent)
-                        } else {
-                            if (isAccountImport) {
-                                ApplicationWideMessageHolder.getInstance().messageType =
-                                    ApplicationWideMessageHolder.MessageType.ACCOUNT_WAS_IMPORTED
-                            }
-                            val intent = Intent(context, ConversationsListActivity::class.java)
-                            startActivity(intent)
+                runOnUiThread {
+                    if (userManager.users.blockingGet().size == 1) {
+                        val intent = Intent(context, ConversationsListActivity::class.java)
+                        startActivity(intent)
+                    } else {
+                        if (isAccountImport) {
+                            ApplicationWideMessageHolder.getInstance().messageType =
+                                ApplicationWideMessageHolder.MessageType.ACCOUNT_WAS_IMPORTED
                         }
                         }
+                        val intent = Intent(context, ConversationsListActivity::class.java)
+                        startActivity(intent)
                     }
                     }
                 }
                 }
             } else {
             } else {
                 Log.e(TAG, "failed to set active user")
                 Log.e(TAG, "failed to set active user")
-                Snackbar.make(binding!!.root, R.string.nc_common_error_sorry, Snackbar.LENGTH_LONG).show()
+                Snackbar.make(binding.root, R.string.nc_common_error_sorry, Snackbar.LENGTH_LONG).show()
             }
             }
         }
         }
     }
     }
@@ -487,70 +477,70 @@ class AccountVerificationController(args: Bundle? = null) : BaseController(
         }
         }
     }
     }
 
 
-    override fun onDestroyView(view: View) {
-        super.onDestroyView(view)
-        activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR
-    }
-
     public override fun onDestroy() {
     public override fun onDestroy() {
         dispose()
         dispose()
         super.onDestroy()
         super.onDestroy()
     }
     }
 
 
     private fun abortVerification() {
     private fun abortVerification() {
-        if (!isAccountImport) {
+        if (isAccountImport) {
+            ApplicationWideMessageHolder.getInstance().messageType = ApplicationWideMessageHolder.MessageType
+                .FAILED_TO_IMPORT_ACCOUNT
+            runOnUiThread {
+                Handler().postDelayed({
+                    val intent = Intent(this, ServerSelectionActivity::class.java)
+                    startActivity(intent)
+                }, DELAY_IN_MILLIS)
+            }
+        } else {
             if (internalAccountId != -1L) {
             if (internalAccountId != -1L) {
-                val count = userManager.deleteUser(internalAccountId)
-                if (count > 0) {
-                    activity?.runOnUiThread { Handler().postDelayed({ router.popToRoot() }, DELAY_IN_MILLIS) }
+                runOnUiThread {
+                    deleteUserAndStartServerSelection(internalAccountId)
                 }
                 }
             } else {
             } else {
-                activity?.runOnUiThread { Handler().postDelayed({ router.popToRoot() }, DELAY_IN_MILLIS) }
+                runOnUiThread {
+                    Handler().postDelayed({
+                        val intent = Intent(this, ServerSelectionActivity::class.java)
+                        startActivity(intent)
+                    }, DELAY_IN_MILLIS)
+                }
             }
             }
-        } else {
-            ApplicationWideMessageHolder.getInstance().setMessageType(
-                ApplicationWideMessageHolder.MessageType.FAILED_TO_IMPORT_ACCOUNT
-            )
-            activity?.runOnUiThread {
-                Handler().postDelayed({
-                    if (router.hasRootController()) {
-                        if (activity != null) {
-                            router.popToRoot()
-                        }
-                    } else {
-                        if (userManager.users.blockingGet().isNotEmpty()) {
-                            val intent = Intent(context, ConversationsListActivity::class.java)
-                            startActivity(intent)
-                        } else {
-                            router.setRoot(
-                                RouterTransaction.with(ServerSelectionController())
-                                    .pushChangeHandler(HorizontalChangeHandler())
-                                    .popChangeHandler(HorizontalChangeHandler())
-                            )
-                        }
+        }
+    }
+
+    @SuppressLint("CheckResult")
+    private fun deleteUserAndStartServerSelection(userId: Long) {
+        userManager.scheduleUserForDeletionWithId(userId).blockingGet()
+        val accountRemovalWork = OneTimeWorkRequest.Builder(AccountRemovalWorker::class.java).build()
+        WorkManager.getInstance(applicationContext).enqueue(accountRemovalWork)
+
+        WorkManager.getInstance(context).getWorkInfoByIdLiveData(accountRemovalWork.id)
+            .observeForever { workInfo: WorkInfo ->
+
+                when (workInfo.state) {
+                    WorkInfo.State.SUCCEEDED -> {
+                        val intent = Intent(this, ServerSelectionActivity::class.java)
+                        startActivity(intent)
                     }
                     }
-                }, DELAY_IN_MILLIS)
+
+                    WorkInfo.State.FAILED, WorkInfo.State.CANCELLED -> {
+                        Toast.makeText(
+                            context,
+                            context.resources.getString(R.string.nc_common_error_sorry),
+                            Toast.LENGTH_LONG
+                        ).show()
+                        Log.e(TAG, "something went wrong when deleting user with id $userId")
+                        val intent = Intent(this, ServerSelectionActivity::class.java)
+                        startActivity(intent)
+                    }
+
+                    else -> {}
+                }
             }
             }
-        }
     }
     }
 
 
     companion object {
     companion object {
-        const val TAG = "AccountVerification"
+        private val TAG = AccountVerificationActivity::class.java.simpleName
         const val DELAY_IN_MILLIS: Long = 7500
         const val DELAY_IN_MILLIS: Long = 7500
     }
     }
-
-    init {
-        sharedApplication!!.componentApplication.inject(this)
-        if (args != null) {
-            baseUrl = args.getString(KEY_BASE_URL)
-            username = args.getString(KEY_USERNAME)
-            token = args.getString(KEY_TOKEN)
-            if (args.containsKey(KEY_IS_ACCOUNT_IMPORT)) {
-                isAccountImport = true
-            }
-            if (args.containsKey(KEY_ORIGINAL_PROTOCOL)) {
-                originalProtocol = args.getString(KEY_ORIGINAL_PROTOCOL)
-            }
-        }
-    }
 }
 }

+ 116 - 137
app/src/main/java/com/nextcloud/talk/controllers/ServerSelectionController.kt → app/src/main/java/com/nextcloud/talk/account/ServerSelectionActivity.kt

@@ -3,6 +3,8 @@
  *
  *
  * @author Andy Scherzinger
  * @author Andy Scherzinger
  * @author Mario Danic
  * @author Mario Danic
+ * @author Marcel Hibbe
+ * Copyright (C) 2023 Marcel Hibbe <dev@mhibbe.de>
  * Copyright (C) 2021 Andy Scherzinger <info@andy-scherzinger.de>
  * Copyright (C) 2021 Andy Scherzinger <info@andy-scherzinger.de>
  * Copyright (C) 2017 Mario Danic <mario@lovelyhq.com>
  * Copyright (C) 2017 Mario Danic <mario@lovelyhq.com>
  *
  *
@@ -19,7 +21,7 @@
  * You should have received a copy of the GNU General Public License
  * You should have received a copy of the GNU General Public License
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
  */
-package com.nextcloud.talk.controllers
+package com.nextcloud.talk.account
 
 
 import android.accounts.Account
 import android.accounts.Account
 import android.annotation.SuppressLint
 import android.annotation.SuppressLint
@@ -34,24 +36,21 @@ import android.view.KeyEvent
 import android.view.View
 import android.view.View
 import android.view.inputmethod.EditorInfo
 import android.view.inputmethod.EditorInfo
 import android.widget.TextView
 import android.widget.TextView
-import androidx.core.content.res.ResourcesCompat
+import androidx.activity.OnBackPressedCallback
 import autodagger.AutoInjector
 import autodagger.AutoInjector
-import com.bluelinelabs.conductor.RouterTransaction
-import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler
 import com.nextcloud.talk.R
 import com.nextcloud.talk.R
+import com.nextcloud.talk.activities.BaseActivity
 import com.nextcloud.talk.api.NcApi
 import com.nextcloud.talk.api.NcApi
 import com.nextcloud.talk.application.NextcloudTalkApplication
 import com.nextcloud.talk.application.NextcloudTalkApplication
-import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication
-import com.nextcloud.talk.controllers.base.BaseController
-import com.nextcloud.talk.controllers.util.viewBinding
-import com.nextcloud.talk.databinding.ControllerServerSelectionBinding
+import com.nextcloud.talk.databinding.ActivityServerSelectionBinding
 import com.nextcloud.talk.models.json.capabilities.CapabilitiesOverall
 import com.nextcloud.talk.models.json.capabilities.CapabilitiesOverall
 import com.nextcloud.talk.models.json.generic.Status
 import com.nextcloud.talk.models.json.generic.Status
 import com.nextcloud.talk.users.UserManager
 import com.nextcloud.talk.users.UserManager
 import com.nextcloud.talk.utils.AccountUtils
 import com.nextcloud.talk.utils.AccountUtils
 import com.nextcloud.talk.utils.ApiUtils
 import com.nextcloud.talk.utils.ApiUtils
-import com.nextcloud.talk.utils.DisplayUtils
 import com.nextcloud.talk.utils.UriUtils
 import com.nextcloud.talk.utils.UriUtils
+import com.nextcloud.talk.utils.bundle.BundleKeys
+import com.nextcloud.talk.utils.bundle.BundleKeys.ADD_ADDITIONAL_ACCOUNT
 import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_IS_ACCOUNT_IMPORT
 import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_IS_ACCOUNT_IMPORT
 import com.nextcloud.talk.utils.database.user.CapabilitiesUtilNew
 import com.nextcloud.talk.utils.database.user.CapabilitiesUtilNew
 import com.nextcloud.talk.utils.singletons.ApplicationWideMessageHolder
 import com.nextcloud.talk.utils.singletons.ApplicationWideMessageHolder
@@ -61,12 +60,12 @@ import io.reactivex.disposables.Disposable
 import io.reactivex.schedulers.Schedulers
 import io.reactivex.schedulers.Schedulers
 import java.security.cert.CertificateException
 import java.security.cert.CertificateException
 import javax.inject.Inject
 import javax.inject.Inject
+import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication
 
 
 @AutoInjector(NextcloudTalkApplication::class)
 @AutoInjector(NextcloudTalkApplication::class)
-class ServerSelectionController :
-    BaseController(R.layout.controller_server_selection) {
+class ServerSelectionActivity : BaseActivity() {
 
 
-    private val binding: ControllerServerSelectionBinding? by viewBinding(ControllerServerSelectionBinding::bind)
+    private lateinit var binding: ActivityServerSelectionBinding
 
 
     @Inject
     @Inject
     lateinit var ncApi: NcApi
     lateinit var ncApi: NcApi
@@ -76,44 +75,40 @@ class ServerSelectionController :
 
 
     private var statusQueryDisposable: Disposable? = null
     private var statusQueryDisposable: Disposable? = null
 
 
-    fun onCertClick() {
-        if (activity != null) {
-            KeyChain.choosePrivateKeyAlias(
-                activity!!,
-                { alias: String? ->
-                    if (alias != null) {
-                        appPreferences!!.temporaryClientCertAlias = alias
-                    } else {
-                        appPreferences!!.removeTemporaryClientCertAlias()
-                    }
-                    setCertTextView()
-                },
-                arrayOf("RSA", "EC"),
-                null,
-                null,
-                -1,
-                null
-            )
+    private val onBackPressedCallback = object : OnBackPressedCallback(true) {
+        override fun handleOnBackPressed() {
+            if (intent.hasExtra(ADD_ADDITIONAL_ACCOUNT) && intent.getBooleanExtra(ADD_ADDITIONAL_ACCOUNT, false)) {
+                finish()
+            } else {
+                finishAffinity()
+            }
         }
         }
     }
     }
 
 
-    override fun onViewBound(view: View) {
-        super.onViewBound(view)
+    @SuppressLint("SourceLockedOrientationActivity")
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
         sharedApplication!!.componentApplication.inject(this)
         sharedApplication!!.componentApplication.inject(this)
-        if (activity != null) {
-            activity!!.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
-        }
-
+        binding = ActivityServerSelectionBinding.inflate(layoutInflater)
+        requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
+        setContentView(binding.root)
         actionBar?.hide()
         actionBar?.hide()
+        setupPrimaryColors()
+
+        onBackPressedDispatcher.addCallback(this, onBackPressedCallback)
+    }
 
 
-        binding?.hostUrlInputHelperText?.text = String.format(
+    override fun onResume() {
+        super.onResume()
+
+        binding.hostUrlInputHelperText.text = String.format(
             resources!!.getString(R.string.nc_server_helper_text),
             resources!!.getString(R.string.nc_server_helper_text),
             resources!!.getString(R.string.nc_server_product_name)
             resources!!.getString(R.string.nc_server_product_name)
         )
         )
-        binding?.serverEntryTextInputLayout?.setEndIconOnClickListener { checkServerAndProceed() }
+        binding.serverEntryTextInputLayout.setEndIconOnClickListener { checkServerAndProceed() }
 
 
         if (resources!!.getBoolean(R.bool.hide_auth_cert)) {
         if (resources!!.getBoolean(R.bool.hide_auth_cert)) {
-            binding?.certTextView?.visibility = View.GONE
+            binding.certTextView.visibility = View.GONE
         }
         }
 
 
         val loggedInUsers = userManager.users.blockingGet()
         val loggedInUsers = userManager.users.blockingGet()
@@ -124,21 +119,54 @@ class ServerSelectionController :
         } else if (isAbleToShowProviderLink() && loggedInUsers.isEmpty()) {
         } else if (isAbleToShowProviderLink() && loggedInUsers.isEmpty()) {
             showVisitProvidersInfo()
             showVisitProvidersInfo()
         } else {
         } else {
-            binding?.importOrChooseProviderText?.visibility = View.INVISIBLE
+            binding.importOrChooseProviderText.visibility = View.INVISIBLE
         }
         }
 
 
-        binding?.serverEntryTextInputEditText?.requestFocus()
+        binding.serverEntryTextInputEditText.requestFocus()
         if (!TextUtils.isEmpty(resources!!.getString(R.string.weblogin_url))) {
         if (!TextUtils.isEmpty(resources!!.getString(R.string.weblogin_url))) {
-            binding?.serverEntryTextInputEditText?.setText(resources!!.getString(R.string.weblogin_url))
+            binding.serverEntryTextInputEditText.setText(resources!!.getString(R.string.weblogin_url))
             checkServerAndProceed()
             checkServerAndProceed()
         }
         }
-        binding?.serverEntryTextInputEditText?.setOnEditorActionListener { _: TextView?, i: Int, _: KeyEvent? ->
+        binding.serverEntryTextInputEditText.setOnEditorActionListener { _: TextView?, i: Int, _: KeyEvent? ->
             if (i == EditorInfo.IME_ACTION_DONE) {
             if (i == EditorInfo.IME_ACTION_DONE) {
                 checkServerAndProceed()
                 checkServerAndProceed()
             }
             }
             false
             false
         }
         }
-        binding?.certTextView?.setOnClickListener { onCertClick() }
+        binding.certTextView.setOnClickListener { onCertClick() }
+
+        if (ApplicationWideMessageHolder.getInstance().messageType != null) {
+            if (ApplicationWideMessageHolder.getInstance().messageType
+                == ApplicationWideMessageHolder.MessageType.SERVER_WITHOUT_TALK
+            ) {
+                setErrorText(resources!!.getString(R.string.nc_settings_no_talk_installed))
+            } else if (ApplicationWideMessageHolder.getInstance().messageType
+                == ApplicationWideMessageHolder.MessageType.FAILED_TO_IMPORT_ACCOUNT
+            ) {
+                setErrorText(resources!!.getString(R.string.nc_server_failed_to_import_account))
+            }
+            ApplicationWideMessageHolder.getInstance().messageType = null
+        }
+        setCertTextView()
+    }
+
+    fun onCertClick() {
+        KeyChain.choosePrivateKeyAlias(
+            this,
+            { alias: String? ->
+                if (alias != null) {
+                    appPreferences.temporaryClientCertAlias = alias
+                } else {
+                    appPreferences.removeTemporaryClientCertAlias()
+                }
+                setCertTextView()
+            },
+            arrayOf("RSA", "EC"),
+            null,
+            null,
+            -1,
+            null
+        )
     }
     }
 
 
     private fun isAbleToShowProviderLink(): Boolean {
     private fun isAbleToShowProviderLink(): Boolean {
@@ -152,41 +180,37 @@ class ServerSelectionController :
             )
             )
         ) {
         ) {
             if (availableAccounts.size > 1) {
             if (availableAccounts.size > 1) {
-                binding?.importOrChooseProviderText?.text = String.format(
+                binding.importOrChooseProviderText.text = String.format(
                     resources!!.getString(R.string.nc_server_import_accounts),
                     resources!!.getString(R.string.nc_server_import_accounts),
                     AccountUtils.getAppNameBasedOnPackage(resources!!.getString(R.string.nc_import_accounts_from))
                     AccountUtils.getAppNameBasedOnPackage(resources!!.getString(R.string.nc_import_accounts_from))
                 )
                 )
             } else {
             } else {
-                binding?.importOrChooseProviderText?.text = String.format(
+                binding.importOrChooseProviderText.text = String.format(
                     resources!!.getString(R.string.nc_server_import_account),
                     resources!!.getString(R.string.nc_server_import_account),
                     AccountUtils.getAppNameBasedOnPackage(resources!!.getString(R.string.nc_import_accounts_from))
                     AccountUtils.getAppNameBasedOnPackage(resources!!.getString(R.string.nc_import_accounts_from))
                 )
                 )
             }
             }
         } else {
         } else {
             if (availableAccounts.size > 1) {
             if (availableAccounts.size > 1) {
-                binding?.importOrChooseProviderText?.text =
+                binding.importOrChooseProviderText.text =
                     resources!!.getString(R.string.nc_server_import_accounts_plain)
                     resources!!.getString(R.string.nc_server_import_accounts_plain)
             } else {
             } else {
-                binding?.importOrChooseProviderText?.text =
+                binding.importOrChooseProviderText.text =
                     resources!!.getString(R.string.nc_server_import_account_plain)
                     resources!!.getString(R.string.nc_server_import_account_plain)
             }
             }
         }
         }
-        binding?.importOrChooseProviderText?.setOnClickListener {
+        binding.importOrChooseProviderText.setOnClickListener {
             val bundle = Bundle()
             val bundle = Bundle()
             bundle.putBoolean(KEY_IS_ACCOUNT_IMPORT, true)
             bundle.putBoolean(KEY_IS_ACCOUNT_IMPORT, true)
-            router.pushController(
-                RouterTransaction.with(
-                    SwitchAccountController(bundle)
-                )
-                    .pushChangeHandler(HorizontalChangeHandler())
-                    .popChangeHandler(HorizontalChangeHandler())
-            )
+            val intent = Intent(context, SwitchAccountActivity::class.java)
+            intent.putExtras(bundle)
+            startActivity(intent)
         }
         }
     }
     }
 
 
     private fun showVisitProvidersInfo() {
     private fun showVisitProvidersInfo() {
-        binding?.importOrChooseProviderText?.setText(R.string.nc_get_from_provider)
-        binding?.importOrChooseProviderText?.setOnClickListener {
+        binding.importOrChooseProviderText.setText(R.string.nc_get_from_provider)
+        binding.importOrChooseProviderText.setOnClickListener {
             val browserIntent = Intent(
             val browserIntent = Intent(
                 Intent.ACTION_VIEW,
                 Intent.ACTION_VIEW,
                 Uri.parse(
                 Uri.parse(
@@ -206,11 +230,11 @@ class ServerSelectionController :
     @Suppress("Detekt.TooGenericExceptionCaught")
     @Suppress("Detekt.TooGenericExceptionCaught")
     private fun checkServerAndProceed() {
     private fun checkServerAndProceed() {
         dispose()
         dispose()
-        var url: String = binding?.serverEntryTextInputEditText?.text.toString().trim { it <= ' ' }
+        var url: String = binding.serverEntryTextInputEditText.text.toString().trim { it <= ' ' }
         showserverEntryProgressBar()
         showserverEntryProgressBar()
-        if (binding?.importOrChooseProviderText?.visibility != View.INVISIBLE) {
-            binding?.importOrChooseProviderText?.visibility = View.INVISIBLE
-            binding?.certTextView?.visibility = View.INVISIBLE
+        if (binding.importOrChooseProviderText.visibility != View.INVISIBLE) {
+            binding.importOrChooseProviderText.visibility = View.INVISIBLE
+            binding.certTextView.visibility = View.INVISIBLE
         }
         }
         if (url.endsWith("/")) {
         if (url.endsWith("/")) {
             url = url.substring(0, url.length - 1)
             url = url.substring(0, url.length - 1)
@@ -278,17 +302,17 @@ class ServerSelectionController :
                         hideserverEntryProgressBar()
                         hideserverEntryProgressBar()
                     }
                     }
 
 
-                    if (binding?.importOrChooseProviderText?.visibility != View.INVISIBLE) {
-                        binding?.importOrChooseProviderText?.visibility = View.VISIBLE
-                        binding?.certTextView?.visibility = View.VISIBLE
+                    if (binding.importOrChooseProviderText.visibility != View.INVISIBLE) {
+                        binding.importOrChooseProviderText.visibility = View.VISIBLE
+                        binding.certTextView.visibility = View.VISIBLE
                     }
                     }
                     dispose()
                     dispose()
                 }
                 }
             }) {
             }) {
                 hideserverEntryProgressBar()
                 hideserverEntryProgressBar()
-                if (binding?.importOrChooseProviderText?.visibility != View.INVISIBLE) {
-                    binding?.importOrChooseProviderText?.visibility = View.VISIBLE
-                    binding?.certTextView?.visibility = View.VISIBLE
+                if (binding.importOrChooseProviderText.visibility != View.INVISIBLE) {
+                    binding.importOrChooseProviderText.visibility = View.VISIBLE
+                    binding.certTextView.visibility = View.VISIBLE
                 }
                 }
                 dispose()
                 dispose()
             }
             }
@@ -311,29 +335,25 @@ class ServerSelectionController :
                             capabilities.spreedCapability?.features?.isNotEmpty() == true
                             capabilities.spreedCapability?.features?.isNotEmpty() == true
 
 
                     if (hasTalk) {
                     if (hasTalk) {
-                        activity?.runOnUiThread {
+                        runOnUiThread {
                             if (CapabilitiesUtilNew.isServerEOL(capabilities)) {
                             if (CapabilitiesUtilNew.isServerEOL(capabilities)) {
                                 if (resources != null) {
                                 if (resources != null) {
-                                    activity!!.runOnUiThread {
+                                    runOnUiThread {
                                         setErrorText(resources!!.getString(R.string.nc_settings_server_eol))
                                         setErrorText(resources!!.getString(R.string.nc_settings_server_eol))
                                     }
                                     }
                                 }
                                 }
                             } else {
                             } else {
-                                router.pushController(
-                                    RouterTransaction.with(
-                                        WebViewLoginController(
-                                            queryUrl.replace("/status.php", ""),
-                                            false
-                                        )
-                                    )
-                                        .pushChangeHandler(HorizontalChangeHandler())
-                                        .popChangeHandler(HorizontalChangeHandler())
-                                )
+                                val bundle = Bundle()
+                                bundle.putString(BundleKeys.KEY_BASE_URL, queryUrl.replace("/status.php", ""))
+
+                                val intent = Intent(context, WebViewLoginActivity::class.java)
+                                intent.putExtras(bundle)
+                                startActivity(intent)
                             }
                             }
                         }
                         }
                     } else {
                     } else {
-                        if (activity != null && resources != null) {
-                            activity!!.runOnUiThread {
+                        if (resources != null) {
+                            runOnUiThread {
                                 setErrorText(resources!!.getString(R.string.nc_server_unsupported))
                                 setErrorText(resources!!.getString(R.string.nc_server_unsupported))
                             }
                             }
                         }
                         }
@@ -342,8 +362,8 @@ class ServerSelectionController :
 
 
                 override fun onError(e: Throwable) {
                 override fun onError(e: Throwable) {
                     Log.e(TAG, "Error while checking capabilities", e)
                     Log.e(TAG, "Error while checking capabilities", e)
-                    if (activity != null && resources != null) {
-                        activity!!.runOnUiThread {
+                    if (resources != null) {
+                        runOnUiThread {
                             setErrorText(resources!!.getString(R.string.nc_common_error_sorry))
                             setErrorText(resources!!.getString(R.string.nc_common_error_sorry))
                         }
                         }
                     }
                     }
@@ -360,70 +380,29 @@ class ServerSelectionController :
     }
     }
 
 
     private fun setErrorText(text: String) {
     private fun setErrorText(text: String) {
-        binding?.errorWrapper?.visibility = View.VISIBLE
-        binding?.errorText?.text = text
+        binding.errorWrapper.visibility = View.VISIBLE
+        binding.errorText.text = text
         hideserverEntryProgressBar()
         hideserverEntryProgressBar()
     }
     }
 
 
     private fun showserverEntryProgressBar() {
     private fun showserverEntryProgressBar() {
-        binding?.errorWrapper?.visibility = View.INVISIBLE
-        binding?.serverEntryProgressBar?.visibility = View.VISIBLE
+        binding.errorWrapper.visibility = View.INVISIBLE
+        binding.serverEntryProgressBar.visibility = View.VISIBLE
     }
     }
 
 
     private fun hideserverEntryProgressBar() {
     private fun hideserverEntryProgressBar() {
-        binding?.serverEntryProgressBar?.visibility = View.INVISIBLE
-    }
-
-    override fun onAttach(view: View) {
-        super.onAttach(view)
-        if (ApplicationWideMessageHolder.getInstance().messageType != null) {
-            if (ApplicationWideMessageHolder.getInstance().messageType
-                == ApplicationWideMessageHolder.MessageType.ACCOUNT_SCHEDULED_FOR_DELETION
-            ) {
-                setErrorText(resources!!.getString(R.string.nc_account_scheduled_for_deletion))
-                ApplicationWideMessageHolder.getInstance().messageType = null
-            } else if (ApplicationWideMessageHolder.getInstance().messageType
-                == ApplicationWideMessageHolder.MessageType.SERVER_WITHOUT_TALK
-            ) {
-                setErrorText(resources!!.getString(R.string.nc_settings_no_talk_installed))
-            } else if (ApplicationWideMessageHolder.getInstance().messageType
-                == ApplicationWideMessageHolder.MessageType.FAILED_TO_IMPORT_ACCOUNT
-            ) {
-                setErrorText(resources!!.getString(R.string.nc_server_failed_to_import_account))
-            }
-            ApplicationWideMessageHolder.getInstance().messageType = null
-        }
-        if (activity != null && resources != null) {
-            DisplayUtils.applyColorToStatusBar(
-                activity,
-                ResourcesCompat.getColor(resources!!, R.color.colorPrimary, null)
-            )
-            DisplayUtils.applyColorToNavigationBar(
-                activity!!.window,
-                ResourcesCompat.getColor(resources!!, R.color.colorPrimary, null)
-            )
-        }
-        setCertTextView()
+        binding.serverEntryProgressBar.visibility = View.INVISIBLE
     }
     }
 
 
     @SuppressLint("LongLogTag")
     @SuppressLint("LongLogTag")
     private fun setCertTextView() {
     private fun setCertTextView() {
-        if (activity != null) {
-            activity!!.runOnUiThread {
-                if (!TextUtils.isEmpty(appPreferences!!.temporaryClientCertAlias)) {
-                    binding?.certTextView?.setText(R.string.nc_change_cert_auth)
-                } else {
-                    binding?.certTextView?.setText(R.string.nc_configure_cert_auth)
-                }
-                hideserverEntryProgressBar()
+        runOnUiThread {
+            if (!TextUtils.isEmpty(appPreferences.temporaryClientCertAlias)) {
+                binding.certTextView.setText(R.string.nc_change_cert_auth)
+            } else {
+                binding.certTextView.setText(R.string.nc_configure_cert_auth)
             }
             }
-        }
-    }
-
-    override fun onDestroyView(view: View) {
-        super.onDestroyView(view)
-        if (activity != null) {
-            activity!!.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR
+            hideserverEntryProgressBar()
         }
         }
     }
     }
 
 
@@ -443,7 +422,7 @@ class ServerSelectionController :
         get() = AppBarLayoutType.EMPTY
         get() = AppBarLayoutType.EMPTY
 
 
     companion object {
     companion object {
-        const val TAG = "ServerSelectionController"
+        private val TAG = ServerSelectionActivity::class.java.simpleName
         const val MIN_SERVER_MAJOR_VERSION = 13
         const val MIN_SERVER_MAJOR_VERSION = 13
     }
     }
 }
 }

+ 50 - 48
app/src/main/java/com/nextcloud/talk/controllers/SwitchAccountController.kt → app/src/main/java/com/nextcloud/talk/account/SwitchAccountActivity.kt

@@ -3,6 +3,8 @@
  *
  *
  * @author Mario Danic
  * @author Mario Danic
  * @author Andy Scherzinger
  * @author Andy Scherzinger
+ * @author Marcel Hibbe
+ * Copyright (C) 2023 Marcel Hibbe <dev@mhibbe.de>
  * Copyright (C) 2022 Andy Scherzinger <info@andy-scherzinger.de>
  * Copyright (C) 2022 Andy Scherzinger <info@andy-scherzinger.de>
  * Copyright (C) 2017 Mario Danic <mario@lovelyhq.com>
  * Copyright (C) 2017 Mario Danic <mario@lovelyhq.com>
  *
  *
@@ -22,25 +24,23 @@
  * Parts related to account import were either copied from or inspired by the great work done by David Luhmer at:
  * 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
  * https://github.com/nextcloud/ownCloud-Account-Importer
  */
  */
-package com.nextcloud.talk.controllers
+package com.nextcloud.talk.account
 
 
 import android.accounts.Account
 import android.accounts.Account
+import android.annotation.SuppressLint
+import android.content.Intent
+import android.content.pm.ActivityInfo
+import android.graphics.drawable.ColorDrawable
 import android.os.Bundle
 import android.os.Bundle
-import android.view.MenuItem
-import android.view.View
 import androidx.preference.PreferenceManager
 import androidx.preference.PreferenceManager
 import androidx.recyclerview.widget.LinearLayoutManager
 import androidx.recyclerview.widget.LinearLayoutManager
 import autodagger.AutoInjector
 import autodagger.AutoInjector
-import com.bluelinelabs.conductor.RouterTransaction
-import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler
 import com.nextcloud.talk.R
 import com.nextcloud.talk.R
+import com.nextcloud.talk.activities.BaseActivity
 import com.nextcloud.talk.adapters.items.AdvancedUserItem
 import com.nextcloud.talk.adapters.items.AdvancedUserItem
 import com.nextcloud.talk.application.NextcloudTalkApplication
 import com.nextcloud.talk.application.NextcloudTalkApplication
-import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication
-import com.nextcloud.talk.controllers.base.BaseController
-import com.nextcloud.talk.controllers.util.viewBinding
 import com.nextcloud.talk.data.user.model.User
 import com.nextcloud.talk.data.user.model.User
-import com.nextcloud.talk.databinding.ControllerGenericRvBinding
+import com.nextcloud.talk.databinding.ActivitySwitchAccountBinding
 import com.nextcloud.talk.models.ImportAccount
 import com.nextcloud.talk.models.ImportAccount
 import com.nextcloud.talk.models.json.participants.Participant
 import com.nextcloud.talk.models.json.participants.Participant
 import com.nextcloud.talk.users.UserManager
 import com.nextcloud.talk.users.UserManager
@@ -56,14 +56,11 @@ import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
 import org.osmdroid.config.Configuration
 import org.osmdroid.config.Configuration
 import java.net.CookieManager
 import java.net.CookieManager
 import javax.inject.Inject
 import javax.inject.Inject
+import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication
 
 
 @AutoInjector(NextcloudTalkApplication::class)
 @AutoInjector(NextcloudTalkApplication::class)
-class SwitchAccountController(args: Bundle? = null) :
-    BaseController(
-        R.layout.controller_generic_rv,
-        args
-    ) {
-    private val binding: ControllerGenericRvBinding? by viewBinding(ControllerGenericRvBinding::bind)
+class SwitchAccountActivity : BaseActivity() {
+    private lateinit var binding: ActivitySwitchAccountBinding
 
 
     @Inject
     @Inject
     lateinit var userManager: UserManager
     lateinit var userManager: UserManager
@@ -89,41 +86,52 @@ class SwitchAccountController(args: Bundle? = null) :
 
 
             if (userManager.setUserAsActive(user).blockingGet()) {
             if (userManager.setUserAsActive(user).blockingGet()) {
                 cookieManager.cookieStore.removeAll()
                 cookieManager.cookieStore.removeAll()
-                if (activity != null) {
-                    activity!!.runOnUiThread { router.popCurrentController() }
-                }
+                finish()
             }
             }
         }
         }
         true
         true
     }
     }
 
 
-    init {
-        setHasOptionsMenu(true)
+    @SuppressLint("SourceLockedOrientationActivity")
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
         sharedApplication!!.componentApplication.inject(this)
         sharedApplication!!.componentApplication.inject(this)
+        binding = ActivitySwitchAccountBinding.inflate(layoutInflater)
+        requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
+        setContentView(binding.root)
+        setupActionBar()
+        setupPrimaryColors()
+
         Configuration.getInstance().load(context, PreferenceManager.getDefaultSharedPreferences(context))
         Configuration.getInstance().load(context, PreferenceManager.getDefaultSharedPreferences(context))
-        if (args?.containsKey(KEY_IS_ACCOUNT_IMPORT) == true) {
-            isAccountImport = true
-        }
+
+        handleIntent()
     }
     }
 
 
-    override fun onOptionsItemSelected(item: MenuItem): Boolean {
-        return when (item.itemId) {
-            android.R.id.home -> {
-                router.popCurrentController()
-                true
+    private fun handleIntent() {
+        intent.extras?.let {
+            if (it.containsKey(KEY_IS_ACCOUNT_IMPORT)) {
+                isAccountImport = true
             }
             }
-            else -> super.onOptionsItemSelected(item)
         }
         }
     }
     }
 
 
-    override fun onViewBound(view: View) {
-        super.onViewBound(view)
-        binding?.swipeRefreshLayout?.isEnabled = false
+    private fun setupActionBar() {
+        setSupportActionBar(binding.toolbar)
+        binding.toolbar.setNavigationOnClickListener {
+            onBackPressedDispatcher.onBackPressed()
+        }
+        supportActionBar?.setDisplayHomeAsUpEnabled(true)
+        supportActionBar?.setDisplayShowHomeEnabled(true)
+        supportActionBar?.setIcon(ColorDrawable(resources!!.getColor(R.color.transparent, null)))
+        supportActionBar?.title = resources!!.getString(R.string.nc_select_an_account)
+    }
 
 
-        actionBar?.show()
+    @Suppress("Detekt.NestedBlockDepth")
+    override fun onResume() {
+        super.onResume()
 
 
         if (adapter == null) {
         if (adapter == null) {
-            adapter = FlexibleAdapter(userItems, activity, false)
+            adapter = FlexibleAdapter(userItems, this, false)
             var participant: Participant
             var participant: Participant
 
 
             if (!isAccountImport) {
             if (!isAccountImport) {
@@ -166,11 +174,10 @@ class SwitchAccountController(args: Bundle? = null) :
     }
     }
 
 
     private fun prepareViews() {
     private fun prepareViews() {
-        val layoutManager: LinearLayoutManager = SmoothScrollLinearLayoutManager(activity)
-        binding?.recyclerView?.layoutManager = layoutManager
-        binding?.recyclerView?.setHasFixedSize(true)
-        binding?.recyclerView?.adapter = adapter
-        binding?.swipeRefreshLayout?.isEnabled = false
+        val layoutManager: LinearLayoutManager = SmoothScrollLinearLayoutManager(this)
+        binding.recyclerView.layoutManager = layoutManager
+        binding.recyclerView.setHasFixedSize(true)
+        binding.recyclerView.adapter = adapter
     }
     }
 
 
     private fun reauthorizeFromImport(account: Account?) {
     private fun reauthorizeFromImport(account: Account?) {
@@ -180,14 +187,9 @@ class SwitchAccountController(args: Bundle? = null) :
         bundle.putString(KEY_USERNAME, importAccount.getUsername())
         bundle.putString(KEY_USERNAME, importAccount.getUsername())
         bundle.putString(KEY_TOKEN, importAccount.getToken())
         bundle.putString(KEY_TOKEN, importAccount.getToken())
         bundle.putBoolean(KEY_IS_ACCOUNT_IMPORT, true)
         bundle.putBoolean(KEY_IS_ACCOUNT_IMPORT, true)
-        router.pushController(
-            RouterTransaction.with(AccountVerificationController(bundle))
-                .pushChangeHandler(HorizontalChangeHandler())
-                .popChangeHandler(HorizontalChangeHandler())
-        )
-    }
 
 
-    override val title: String
-        get() =
-            resources!!.getString(R.string.nc_select_an_account)
+        val intent = Intent(context, AccountVerificationActivity::class.java)
+        intent.putExtras(bundle)
+        startActivity(intent)
+    }
 }
 }

+ 142 - 151
app/src/main/java/com/nextcloud/talk/controllers/WebViewLoginController.kt → app/src/main/java/com/nextcloud/talk/account/WebViewLoginActivity.kt

@@ -3,6 +3,8 @@
  *
  *
  * @author Mario Danic
  * @author Mario Danic
  * @author Andy Scherzinger
  * @author Andy Scherzinger
+ * @author Marcel Hibbe
+ * Copyright (C) 2023 Marcel Hibbe <dev@mhibbe.de>
  * Copyright (C) 2022 Andy Scherzinger <info@andy-scherzinger.de>
  * Copyright (C) 2022 Andy Scherzinger <info@andy-scherzinger.de>
  * Copyright (C) 2017 Mario Danic (mario@lovelyhq.com)
  * Copyright (C) 2017 Mario Danic (mario@lovelyhq.com)
  *
  *
@@ -19,9 +21,10 @@
  * You should have received a copy of the GNU General Public License
  * You should have received a copy of the GNU General Public License
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
  */
-package com.nextcloud.talk.controllers
+package com.nextcloud.talk.account
 
 
 import android.annotation.SuppressLint
 import android.annotation.SuppressLint
+import android.content.Intent
 import android.content.pm.ActivityInfo
 import android.content.pm.ActivityInfo
 import android.graphics.Bitmap
 import android.graphics.Bitmap
 import android.net.http.SslError
 import android.net.http.SslError
@@ -40,34 +43,30 @@ import android.webkit.WebResourceResponse
 import android.webkit.WebSettings
 import android.webkit.WebSettings
 import android.webkit.WebView
 import android.webkit.WebView
 import android.webkit.WebViewClient
 import android.webkit.WebViewClient
-import androidx.appcompat.app.AppCompatActivity
-import androidx.core.content.res.ResourcesCompat
-import androidx.work.Data
+import androidx.activity.OnBackPressedCallback
 import androidx.work.OneTimeWorkRequest
 import androidx.work.OneTimeWorkRequest
+import androidx.work.WorkInfo
 import androidx.work.WorkManager
 import androidx.work.WorkManager
 import autodagger.AutoInjector
 import autodagger.AutoInjector
-import com.bluelinelabs.conductor.RouterTransaction
-import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler
+import com.google.android.material.snackbar.Snackbar
 import com.nextcloud.talk.R
 import com.nextcloud.talk.R
+import com.nextcloud.talk.activities.BaseActivity
+import com.nextcloud.talk.activities.MainActivity
 import com.nextcloud.talk.application.NextcloudTalkApplication
 import com.nextcloud.talk.application.NextcloudTalkApplication
 import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication
 import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication
-import com.nextcloud.talk.controllers.base.BaseController
-import com.nextcloud.talk.controllers.util.viewBinding
-import com.nextcloud.talk.databinding.ControllerWebViewLoginBinding
+import com.nextcloud.talk.databinding.ActivityWebViewLoginBinding
 import com.nextcloud.talk.events.CertificateEvent
 import com.nextcloud.talk.events.CertificateEvent
-import com.nextcloud.talk.jobs.PushRegistrationWorker
+import com.nextcloud.talk.jobs.AccountRemovalWorker
 import com.nextcloud.talk.models.LoginData
 import com.nextcloud.talk.models.LoginData
 import com.nextcloud.talk.users.UserManager
 import com.nextcloud.talk.users.UserManager
-import com.nextcloud.talk.utils.DisplayUtils
+import com.nextcloud.talk.utils.bundle.BundleKeys
 import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_BASE_URL
 import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_BASE_URL
 import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ORIGINAL_PROTOCOL
 import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ORIGINAL_PROTOCOL
 import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_TOKEN
 import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_TOKEN
 import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_USERNAME
 import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_USERNAME
-import com.nextcloud.talk.utils.singletons.ApplicationWideMessageHolder
 import com.nextcloud.talk.utils.ssl.TrustManager
 import com.nextcloud.talk.utils.ssl.TrustManager
 import de.cotech.hw.fido.WebViewFidoBridge
 import de.cotech.hw.fido.WebViewFidoBridge
 import io.reactivex.disposables.Disposable
 import io.reactivex.disposables.Disposable
-import org.greenrobot.eventbus.EventBus
 import java.lang.reflect.Field
 import java.lang.reflect.Field
 import java.net.CookieManager
 import java.net.CookieManager
 import java.net.URLDecoder
 import java.net.URLDecoder
@@ -78,11 +77,9 @@ import java.util.Locale
 import javax.inject.Inject
 import javax.inject.Inject
 
 
 @AutoInjector(NextcloudTalkApplication::class)
 @AutoInjector(NextcloudTalkApplication::class)
-class WebViewLoginController(args: Bundle? = null) : BaseController(
-    R.layout.controller_web_view_login,
-    args
-) {
-    private val binding: ControllerWebViewLoginBinding? by viewBinding(ControllerWebViewLoginBinding::bind)
+class WebViewLoginActivity : BaseActivity() {
+
+    private lateinit var binding: ActivityWebViewLoginBinding
 
 
     @Inject
     @Inject
     lateinit var userManager: UserManager
     lateinit var userManager: UserManager
@@ -90,34 +87,26 @@ class WebViewLoginController(args: Bundle? = null) : BaseController(
     @Inject
     @Inject
     lateinit var trustManager: TrustManager
     lateinit var trustManager: TrustManager
 
 
-    @Inject
-    lateinit var eventBus: EventBus
-
     @Inject
     @Inject
     lateinit var cookieManager: CookieManager
     lateinit var cookieManager: CookieManager
 
 
     private var assembledPrefix: String? = null
     private var assembledPrefix: String? = null
     private var userQueryDisposable: Disposable? = null
     private var userQueryDisposable: Disposable? = null
     private var baseUrl: String? = null
     private var baseUrl: String? = null
-    private var isPasswordUpdate = false
+    private var reauthorizeAccount = false
     private var username: String? = null
     private var username: String? = null
     private var password: String? = null
     private var password: String? = null
     private var loginStep = 0
     private var loginStep = 0
     private var automatedLoginAttempted = false
     private var automatedLoginAttempted = false
     private var webViewFidoBridge: WebViewFidoBridge? = null
     private var webViewFidoBridge: WebViewFidoBridge? = null
 
 
-    constructor(baseUrl: String?, isPasswordUpdate: Boolean) : this() {
-        this.baseUrl = baseUrl
-        this.isPasswordUpdate = isPasswordUpdate
-    }
-
-    constructor(baseUrl: String?, isPasswordUpdate: Boolean, username: String?, password: String?) : this() {
-        this.baseUrl = baseUrl
-        this.isPasswordUpdate = isPasswordUpdate
-        this.username = username
-        this.password = password
+    private val onBackPressedCallback = object : OnBackPressedCallback(true) {
+        override fun handleOnBackPressed() {
+            val intent = Intent(context, MainActivity::class.java)
+            intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
+            startActivity(intent)
+        }
     }
     }
-
     private val webLoginUserAgent: String
     private val webLoginUserAgent: String
         get() = (
         get() = (
             Build.MANUFACTURER.substring(0, 1).toUpperCase(Locale.getDefault()) +
             Build.MANUFACTURER.substring(0, 1).toUpperCase(Locale.getDefault()) +
@@ -129,33 +118,57 @@ class WebViewLoginController(args: Bundle? = null) : BaseController(
                 ")"
                 ")"
             )
             )
 
 
-    @SuppressLint("SetJavaScriptEnabled")
-    override fun onViewBound(view: View) {
-        super.onViewBound(view)
-        activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
-
+    @SuppressLint("SourceLockedOrientationActivity")
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        sharedApplication!!.componentApplication.inject(this)
+        binding = ActivityWebViewLoginBinding.inflate(layoutInflater)
+        requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
+        setContentView(binding.root)
         actionBar?.hide()
         actionBar?.hide()
+        setupPrimaryColors()
+
+        onBackPressedDispatcher.addCallback(this, onBackPressedCallback)
+        handleIntent()
+        setupWebView()
+    }
+
+    private fun handleIntent() {
+        val extras = intent.extras!!
+        baseUrl = extras.getString(KEY_BASE_URL)
+        username = extras.getString(KEY_USERNAME)
 
 
+        if (extras.containsKey(BundleKeys.KEY_REAUTHORIZE_ACCOUNT)) {
+            reauthorizeAccount = extras.getBoolean(BundleKeys.KEY_REAUTHORIZE_ACCOUNT)
+        }
+
+        if (extras.containsKey(BundleKeys.KEY_PASSWORD)) {
+            password = extras.getString(BundleKeys.KEY_PASSWORD)
+        }
+    }
+
+    @SuppressLint("SetJavaScriptEnabled")
+    private fun setupWebView() {
         assembledPrefix = resources!!.getString(R.string.nc_talk_login_scheme) + PROTOCOL_SUFFIX + "login/"
         assembledPrefix = resources!!.getString(R.string.nc_talk_login_scheme) + PROTOCOL_SUFFIX + "login/"
-        binding?.webview?.settings?.allowFileAccess = false
-        binding?.webview?.settings?.allowFileAccessFromFileURLs = false
-        binding?.webview?.settings?.javaScriptEnabled = true
-        binding?.webview?.settings?.javaScriptCanOpenWindowsAutomatically = false
-        binding?.webview?.settings?.domStorageEnabled = true
-        binding?.webview?.settings?.setUserAgentString(webLoginUserAgent)
-        binding?.webview?.settings?.saveFormData = false
-        binding?.webview?.settings?.savePassword = false
-        binding?.webview?.settings?.setRenderPriority(WebSettings.RenderPriority.HIGH)
-        binding?.webview?.clearCache(true)
-        binding?.webview?.clearFormData()
-        binding?.webview?.clearHistory()
+        binding.webview.settings.allowFileAccess = false
+        binding.webview.settings.allowFileAccessFromFileURLs = false
+        binding.webview.settings.javaScriptEnabled = true
+        binding.webview.settings.javaScriptCanOpenWindowsAutomatically = false
+        binding.webview.settings.domStorageEnabled = true
+        binding.webview.settings.userAgentString = webLoginUserAgent
+        binding.webview.settings.saveFormData = false
+        binding.webview.settings.savePassword = false
+        binding.webview.settings.setRenderPriority(WebSettings.RenderPriority.HIGH)
+        binding.webview.clearCache(true)
+        binding.webview.clearFormData()
+        binding.webview.clearHistory()
         WebView.clearClientCertPreferences(null)
         WebView.clearClientCertPreferences(null)
-        webViewFidoBridge = WebViewFidoBridge.createInstanceForWebView(activity as AppCompatActivity?, binding?.webview)
-        CookieSyncManager.createInstance(activity)
+        webViewFidoBridge = WebViewFidoBridge.createInstanceForWebView(this, binding.webview)
+        CookieSyncManager.createInstance(this)
         android.webkit.CookieManager.getInstance().removeAllCookies(null)
         android.webkit.CookieManager.getInstance().removeAllCookies(null)
         val headers: MutableMap<String, String> = HashMap()
         val headers: MutableMap<String, String> = HashMap()
-        headers.put("OCS-APIRequest", "true")
-        binding?.webview?.webViewClient = object : WebViewClient() {
+        headers["OCS-APIRequest"] = "true"
+        binding.webview.webViewClient = object : WebViewClient() {
             private var basePageLoaded = false
             private var basePageLoaded = false
             override fun shouldInterceptRequest(view: WebView, request: WebResourceRequest): WebResourceResponse? {
             override fun shouldInterceptRequest(view: WebView, request: WebResourceRequest): WebResourceResponse? {
                 webViewFidoBridge?.delegateShouldInterceptRequest(view, request)
                 webViewFidoBridge?.delegateShouldInterceptRequest(view, request)
@@ -180,24 +193,24 @@ class WebViewLoginController(args: Bundle? = null) : BaseController(
             override fun onPageFinished(view: WebView, url: String) {
             override fun onPageFinished(view: WebView, url: String) {
                 loginStep++
                 loginStep++
                 if (!basePageLoaded) {
                 if (!basePageLoaded) {
-                    binding?.progressBar?.visibility = View.GONE
-                    binding?.webview?.visibility = View.VISIBLE
+                    binding.progressBar.visibility = View.GONE
+                    binding.webview.visibility = View.VISIBLE
 
 
                     basePageLoaded = true
                     basePageLoaded = true
                 }
                 }
                 if (!TextUtils.isEmpty(username)) {
                 if (!TextUtils.isEmpty(username)) {
                     if (loginStep == 1) {
                     if (loginStep == 1) {
-                        binding?.webview?.loadUrl(
+                        binding.webview.loadUrl(
                             "javascript: {document.getElementsByClassName('login')[0].click(); };"
                             "javascript: {document.getElementsByClassName('login')[0].click(); };"
                         )
                         )
                     } else if (!automatedLoginAttempted) {
                     } else if (!automatedLoginAttempted) {
                         automatedLoginAttempted = true
                         automatedLoginAttempted = true
                         if (TextUtils.isEmpty(password)) {
                         if (TextUtils.isEmpty(password)) {
-                            binding?.webview?.loadUrl(
+                            binding.webview.loadUrl(
                                 "javascript:var justStore = document.getElementById('user').value = '$username';"
                                 "javascript:var justStore = document.getElementById('user').value = '$username';"
                             )
                             )
                         } else {
                         } else {
-                            binding?.webview?.loadUrl(
+                            binding.webview.loadUrl(
                                 "javascript: {" +
                                 "javascript: {" +
                                     "document.getElementById('user').value = '" + username + "';" +
                                     "document.getElementById('user').value = '" + username + "';" +
                                     "document.getElementById('password').value = '" + password + "';" +
                                     "document.getElementById('password').value = '" + password + "';" +
@@ -213,8 +226,8 @@ class WebViewLoginController(args: Bundle? = null) : BaseController(
             override fun onReceivedClientCertRequest(view: WebView, request: ClientCertRequest) {
             override fun onReceivedClientCertRequest(view: WebView, request: ClientCertRequest) {
                 val user = userManager.currentUser.blockingGet()
                 val user = userManager.currentUser.blockingGet()
                 var alias: String? = null
                 var alias: String? = null
-                if (!isPasswordUpdate) {
-                    alias = appPreferences!!.temporaryClientCertAlias
+                if (!reauthorizeAccount) {
+                    alias = appPreferences.temporaryClientCertAlias
                 }
                 }
                 if (TextUtils.isEmpty(alias) && user != null) {
                 if (TextUtils.isEmpty(alias) && user != null) {
                     alias = user.clientCertificate
                     alias = user.clientCertificate
@@ -223,9 +236,9 @@ class WebViewLoginController(args: Bundle? = null) : BaseController(
                     val finalAlias = alias
                     val finalAlias = alias
                     Thread {
                     Thread {
                         try {
                         try {
-                            val privateKey = KeyChain.getPrivateKey(activity!!, finalAlias!!)
+                            val privateKey = KeyChain.getPrivateKey(applicationContext, finalAlias!!)
                             val certificates = KeyChain.getCertificateChain(
                             val certificates = KeyChain.getCertificateChain(
-                                activity!!,
+                                applicationContext,
                                 finalAlias
                                 finalAlias
                             )
                             )
                             if (privateKey != null && certificates != null) {
                             if (privateKey != null && certificates != null) {
@@ -241,16 +254,16 @@ class WebViewLoginController(args: Bundle? = null) : BaseController(
                     }.start()
                     }.start()
                 } else {
                 } else {
                     KeyChain.choosePrivateKeyAlias(
                     KeyChain.choosePrivateKeyAlias(
-                        activity!!,
+                        this@WebViewLoginActivity,
                         { chosenAlias: String? ->
                         { chosenAlias: String? ->
                             if (chosenAlias != null) {
                             if (chosenAlias != null) {
                                 appPreferences!!.temporaryClientCertAlias = chosenAlias
                                 appPreferences!!.temporaryClientCertAlias = chosenAlias
                                 Thread {
                                 Thread {
                                     var privateKey: PrivateKey? = null
                                     var privateKey: PrivateKey? = null
                                     try {
                                     try {
-                                        privateKey = KeyChain.getPrivateKey(activity!!, chosenAlias)
+                                        privateKey = KeyChain.getPrivateKey(applicationContext, chosenAlias)
                                         val certificates = KeyChain.getCertificateChain(
                                         val certificates = KeyChain.getCertificateChain(
-                                            activity!!,
+                                            applicationContext,
                                             chosenAlias
                                             chosenAlias
                                         )
                                         )
                                         if (privateKey != null && certificates != null) {
                                         if (privateKey != null && certificates != null) {
@@ -304,7 +317,7 @@ class WebViewLoginController(args: Bundle? = null) : BaseController(
                 super.onReceivedError(view, errorCode, description, failingUrl)
                 super.onReceivedError(view, errorCode, description, failingUrl)
             }
             }
         }
         }
-        binding?.webview?.loadUrl("$baseUrl/index.php/login/flow", headers)
+        binding.webview.loadUrl("$baseUrl/index.php/login/flow", headers)
     }
     }
 
 
     private fun dispose() {
     private fun dispose() {
@@ -318,80 +331,77 @@ class WebViewLoginController(args: Bundle? = null) : BaseController(
         val loginData = parseLoginData(assembledPrefix, dataString)
         val loginData = parseLoginData(assembledPrefix, dataString)
         if (loginData != null) {
         if (loginData != null) {
             dispose()
             dispose()
-            val currentUser = userManager.currentUser.blockingGet()
-            var messageType: ApplicationWideMessageHolder.MessageType? = null
-            if (!isPasswordUpdate &&
-                userManager.checkIfUserExists(loginData.username!!, baseUrl!!).blockingGet()
-            ) {
-                messageType = ApplicationWideMessageHolder.MessageType.ACCOUNT_UPDATED_NOT_ADDED
-            }
+            cookieManager.cookieStore.removeAll()
+
             if (userManager.checkIfUserIsScheduledForDeletion(loginData.username!!, baseUrl!!).blockingGet()) {
             if (userManager.checkIfUserIsScheduledForDeletion(loginData.username!!, baseUrl!!).blockingGet()) {
-                ApplicationWideMessageHolder.getInstance().messageType =
-                    ApplicationWideMessageHolder.MessageType.ACCOUNT_SCHEDULED_FOR_DELETION
-                if (!isPasswordUpdate) {
-                    router.popToRoot()
+                Log.e(TAG, "Tried to add already existing user who is scheduled for deletion.")
+                Snackbar.make(binding.root, R.string.nc_common_error_sorry, Snackbar.LENGTH_LONG).show()
+                // however the user is not yet deleted, just start AccountRemovalWorker again to make sure to delete it.
+                startAccountRemovalWorkerAndRestartApp()
+            } else if (userManager.checkIfUserExists(loginData.username!!, baseUrl!!).blockingGet()) {
+                if (reauthorizeAccount) {
+                    updateUserAndRestartApp(loginData)
                 } else {
                 } else {
-                    router.popCurrentController()
-                }
-            }
-            val finalMessageType = messageType
-            cookieManager.cookieStore.removeAll()
-            if (!isPasswordUpdate && finalMessageType == null) {
-                val bundle = Bundle()
-                bundle.putString(KEY_USERNAME, loginData.username)
-                bundle.putString(KEY_TOKEN, loginData.token)
-                bundle.putString(KEY_BASE_URL, loginData.serverUrl)
-                var protocol = ""
-                if (baseUrl!!.startsWith("http://")) {
-                    protocol = "http://"
-                } else if (baseUrl!!.startsWith("https://")) {
-                    protocol = "https://"
-                }
-                if (!TextUtils.isEmpty(protocol)) {
-                    bundle.putString(KEY_ORIGINAL_PROTOCOL, protocol)
+                    Log.w(TAG, "It was tried to add an account that account already exists. Skipped user creation.")
+                    restartApp()
                 }
                 }
-                router.pushController(
-                    RouterTransaction.with(AccountVerificationController(bundle))
-                        .pushChangeHandler(HorizontalChangeHandler())
-                        .popChangeHandler(HorizontalChangeHandler())
-                )
             } else {
             } else {
-                if (isPasswordUpdate) {
-                    if (currentUser != null) {
-                        currentUser.clientCertificate = appPreferences!!.temporaryClientCertAlias
-                        currentUser.token = loginData.token
-                        val rowsUpdated = userManager.updateOrCreateUser(currentUser).blockingGet()
-                        Log.d(TAG, "User rows updated: $rowsUpdated")
-
-                        if (finalMessageType != null) {
-                            ApplicationWideMessageHolder.getInstance().messageType = finalMessageType
-                        }
+                startAccountVerification(loginData)
+            }
+        }
+    }
 
 
-                        val data = Data.Builder().putString(
-                            PushRegistrationWorker.ORIGIN,
-                            "WebViewLoginController#parseAndLoginFromWebView"
-                        ).build()
+    private fun startAccountVerification(loginData: LoginData) {
+        val bundle = Bundle()
+        bundle.putString(KEY_USERNAME, loginData.username)
+        bundle.putString(KEY_TOKEN, loginData.token)
+        bundle.putString(KEY_BASE_URL, loginData.serverUrl)
+        var protocol = ""
+        if (baseUrl!!.startsWith("http://")) {
+            protocol = "http://"
+        } else if (baseUrl!!.startsWith("https://")) {
+            protocol = "https://"
+        }
+        if (!TextUtils.isEmpty(protocol)) {
+            bundle.putString(KEY_ORIGINAL_PROTOCOL, protocol)
+        }
+        val intent = Intent(context, AccountVerificationActivity::class.java)
+        intent.putExtras(bundle)
+        startActivity(intent)
+    }
 
 
-                        val pushRegistrationWork = OneTimeWorkRequest.Builder(
-                            PushRegistrationWorker::class.java
-                        )
-                            .setInputData(data)
-                            .build()
+    private fun restartApp() {
+        val intent = Intent(context, MainActivity::class.java)
+        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
+        startActivity(intent)
+    }
 
 
-                        WorkManager.getInstance().enqueue(pushRegistrationWork)
-                        router.popCurrentController()
-                    }
-                } else {
-                    if (finalMessageType != null) {
-                        // FIXME when the user registers a new account that was setup before (aka
-                        //  ApplicationWideMessageHolder.MessageType.ACCOUNT_UPDATED_NOT_ADDED)
-                        //  The token is not updated in the database and therefore the account not visible/usable
-                        ApplicationWideMessageHolder.getInstance().messageType = finalMessageType
+    private fun updateUserAndRestartApp(loginData: LoginData) {
+        val currentUser = userManager.currentUser.blockingGet()
+        if (currentUser != null) {
+            currentUser.clientCertificate = appPreferences.temporaryClientCertAlias
+            currentUser.token = loginData.token
+            val rowsUpdated = userManager.updateOrCreateUser(currentUser).blockingGet()
+            Log.d(TAG, "User rows updated: $rowsUpdated")
+            restartApp()
+        }
+    }
+
+    private fun startAccountRemovalWorkerAndRestartApp() {
+        val accountRemovalWork = OneTimeWorkRequest.Builder(AccountRemovalWorker::class.java).build()
+        WorkManager.getInstance(applicationContext).enqueue(accountRemovalWork)
+
+        WorkManager.getInstance(context).getWorkInfoByIdLiveData(accountRemovalWork.id)
+            .observeForever { workInfo: WorkInfo ->
+
+                when (workInfo.state) {
+                    WorkInfo.State.SUCCEEDED, WorkInfo.State.FAILED, WorkInfo.State.CANCELLED -> {
+                        restartApp()
                     }
                     }
-                    router.popToRoot()
+
+                    else -> {}
                 }
                 }
             }
             }
-        }
     }
     }
 
 
     private fun parseLoginData(prefix: String?, dataString: String): LoginData? {
     private fun parseLoginData(prefix: String?, dataString: String): LoginData? {
@@ -432,30 +442,11 @@ class WebViewLoginController(args: Bundle? = null) : BaseController(
         }
         }
     }
     }
 
 
-    override fun onAttach(view: View) {
-        super.onAttach(view)
-        if (activity != null && resources != null) {
-            DisplayUtils.applyColorToStatusBar(
-                activity,
-                ResourcesCompat.getColor(resources!!, R.color.colorPrimary, null)
-            )
-            DisplayUtils.applyColorToNavigationBar(
-                activity!!.window,
-                ResourcesCompat.getColor(resources!!, R.color.colorPrimary, null)
-            )
-        }
-    }
-
     public override fun onDestroy() {
     public override fun onDestroy() {
         super.onDestroy()
         super.onDestroy()
         dispose()
         dispose()
     }
     }
 
 
-    override fun onDestroyView(view: View) {
-        super.onDestroyView(view)
-        activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR
-    }
-
     init {
     init {
         sharedApplication!!.componentApplication.inject(this)
         sharedApplication!!.componentApplication.inject(this)
     }
     }
@@ -464,7 +455,7 @@ class WebViewLoginController(args: Bundle? = null) : BaseController(
         get() = AppBarLayoutType.EMPTY
         get() = AppBarLayoutType.EMPTY
 
 
     companion object {
     companion object {
-        const val TAG = "WebViewLoginController"
+        private val TAG = WebViewLoginActivity::class.java.simpleName
         private const val PROTOCOL_SUFFIX = "://"
         private const val PROTOCOL_SUFFIX = "://"
         private const val LOGIN_URL_DATA_KEY_VALUE_SEPARATOR = ":"
         private const val LOGIN_URL_DATA_KEY_VALUE_SEPARATOR = ":"
         private const val PARAMETER_COUNT = 3
         private const val PARAMETER_COUNT = 3

+ 1 - 1
app/src/main/java/com/nextcloud/talk/controllers/base/providers/ActionBarProvider.java → app/src/main/java/com/nextcloud/talk/activities/ActionBarProvider.java

@@ -16,7 +16,7 @@
  * See the License for the specific language governing permissions and
  * See the License for the specific language governing permissions and
  * limitations under the License.
  * limitations under the License.
  */
  */
-package com.nextcloud.talk.controllers.base.providers;
+package com.nextcloud.talk.activities;
 
 
 import androidx.appcompat.app.ActionBar;
 import androidx.appcompat.app.ActionBar;
 
 

+ 65 - 7
app/src/main/java/com/nextcloud/talk/activities/BaseActivity.kt

@@ -24,17 +24,26 @@ package com.nextcloud.talk.activities
 
 
 import android.annotation.SuppressLint
 import android.annotation.SuppressLint
 import android.content.Context
 import android.content.Context
+import android.os.Build
 import android.os.Bundle
 import android.os.Bundle
 import android.util.Log
 import android.util.Log
 import android.view.View
 import android.view.View
+import android.view.ViewGroup
 import android.view.WindowManager
 import android.view.WindowManager
+import android.view.inputmethod.EditorInfo
 import android.webkit.SslErrorHandler
 import android.webkit.SslErrorHandler
+import android.widget.EditText
+import androidx.annotation.RequiresApi
 import androidx.appcompat.app.AlertDialog
 import androidx.appcompat.app.AlertDialog
 import androidx.appcompat.app.AppCompatActivity
 import androidx.appcompat.app.AppCompatActivity
 import androidx.core.content.res.ResourcesCompat
 import androidx.core.content.res.ResourcesCompat
 import autodagger.AutoInjector
 import autodagger.AutoInjector
 import com.google.android.material.dialog.MaterialAlertDialogBuilder
 import com.google.android.material.dialog.MaterialAlertDialogBuilder
 import com.nextcloud.talk.R
 import com.nextcloud.talk.R
+import com.nextcloud.talk.account.AccountVerificationActivity
+import com.nextcloud.talk.account.ServerSelectionActivity
+import com.nextcloud.talk.account.SwitchAccountActivity
+import com.nextcloud.talk.account.WebViewLoginActivity
 import com.nextcloud.talk.application.NextcloudTalkApplication
 import com.nextcloud.talk.application.NextcloudTalkApplication
 import com.nextcloud.talk.events.CertificateEvent
 import com.nextcloud.talk.events.CertificateEvent
 import com.nextcloud.talk.ui.theme.ViewThemeUtils
 import com.nextcloud.talk.ui.theme.ViewThemeUtils
@@ -77,6 +86,8 @@ open class BaseActivity : AppCompatActivity() {
     override fun onCreate(savedInstanceState: Bundle?) {
     override fun onCreate(savedInstanceState: Bundle?) {
         NextcloudTalkApplication.sharedApplication!!.componentApplication.inject(this)
         NextcloudTalkApplication.sharedApplication!!.componentApplication.inject(this)
         super.onCreate(savedInstanceState)
         super.onCreate(savedInstanceState)
+
+        cleanTempCertPreference()
     }
     }
 
 
     public override fun onStart() {
     public override fun onStart() {
@@ -87,6 +98,11 @@ open class BaseActivity : AppCompatActivity() {
     public override fun onResume() {
     public override fun onResume() {
         super.onResume()
         super.onResume()
 
 
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && appPreferences.isKeyboardIncognito) {
+            val viewGroup = (findViewById<View>(android.R.id.content) as ViewGroup).getChildAt(0) as ViewGroup
+            disableKeyboardPersonalisedLearning(viewGroup)
+        }
+
         if (appPreferences.isScreenSecured) {
         if (appPreferences.isScreenSecured) {
             window.addFlags(WindowManager.LayoutParams.FLAG_SECURE)
             window.addFlags(WindowManager.LayoutParams.FLAG_SECURE)
         } else {
         } else {
@@ -104,6 +120,19 @@ open class BaseActivity : AppCompatActivity() {
         colorizeNavigationBar()
         colorizeNavigationBar()
     }
     }
 
 
+    fun setupPrimaryColors() {
+        if (resources != null) {
+            DisplayUtils.applyColorToStatusBar(
+                this,
+                ResourcesCompat.getColor(resources!!, R.color.colorPrimary, null)
+            )
+            DisplayUtils.applyColorToNavigationBar(
+                window,
+                ResourcesCompat.getColor(resources!!, R.color.colorPrimary, null)
+            )
+        }
+    }
+
     open fun colorizeStatusBar() {
     open fun colorizeStatusBar() {
         if (resources != null) {
         if (resources != null) {
             if (appBarLayoutType == AppBarLayoutType.SEARCH_BAR) {
             if (appBarLayoutType == AppBarLayoutType.SEARCH_BAR) {
@@ -123,7 +152,23 @@ open class BaseActivity : AppCompatActivity() {
         }
         }
     }
     }
 
 
-    fun showCertificateDialog(
+    @RequiresApi(api = Build.VERSION_CODES.O)
+    private fun disableKeyboardPersonalisedLearning(viewGroup: ViewGroup) {
+        var view: View?
+        var editText: EditText
+        for (i in 0 until viewGroup.childCount) {
+            view = viewGroup.getChildAt(i)
+            if (view is EditText) {
+                editText = view
+                editText.imeOptions = editText.imeOptions or EditorInfo.IME_FLAG_NO_PERSONALIZED_LEARNING
+            } else if (view is ViewGroup) {
+                disableKeyboardPersonalisedLearning(view)
+            }
+        }
+    }
+
+    @Suppress("Detekt.NestedBlockDepth")
+    private fun showCertificateDialog(
         cert: X509Certificate,
         cert: X509Certificate,
         trustManager: TrustManager,
         trustManager: TrustManager,
         sslErrorHandler: SslErrorHandler?
         sslErrorHandler: SslErrorHandler?
@@ -160,15 +205,17 @@ open class BaseActivity : AppCompatActivity() {
                 validUntil
                 validUntil
             )
             )
 
 
-            val dialogBuilder = MaterialAlertDialogBuilder(this)
-                .setIcon(viewThemeUtils.dialog.colorMaterialAlertDialogIcon(context, R.drawable.ic_security_white_24dp))
-                .setTitle(R.string.nc_certificate_dialog_title)
+            val dialogBuilder = MaterialAlertDialogBuilder(this).setIcon(
+                viewThemeUtils.dialog.colorMaterialAlertDialogIcon(
+                    context,
+                    R.drawable.ic_security_white_24dp
+                )
+            ).setTitle(R.string.nc_certificate_dialog_title)
                 .setMessage(dialogText)
                 .setMessage(dialogText)
                 .setPositiveButton(R.string.nc_yes) { _, _ ->
                 .setPositiveButton(R.string.nc_yes) { _, _ ->
                     trustManager.addCertInTrustStore(cert)
                     trustManager.addCertInTrustStore(cert)
                     sslErrorHandler?.proceed()
                     sslErrorHandler?.proceed()
-                }
-                .setNegativeButton(R.string.nc_no) { _, _ ->
+                }.setNegativeButton(R.string.nc_no) { _, _ ->
                     sslErrorHandler?.cancel()
                     sslErrorHandler?.cancel()
                 }
                 }
 
 
@@ -185,12 +232,23 @@ open class BaseActivity : AppCompatActivity() {
         }
         }
     }
     }
 
 
+    private fun cleanTempCertPreference() {
+        val temporaryClassNames: MutableList<String> = ArrayList()
+        temporaryClassNames.add(ServerSelectionActivity::class.java.name)
+        temporaryClassNames.add(AccountVerificationActivity::class.java.name)
+        temporaryClassNames.add(WebViewLoginActivity::class.java.name)
+        temporaryClassNames.add(SwitchAccountActivity::class.java.name)
+        if (!temporaryClassNames.contains(javaClass.name)) {
+            appPreferences.removeTemporaryClientCertAlias()
+        }
+    }
+
     @Subscribe(threadMode = ThreadMode.MAIN)
     @Subscribe(threadMode = ThreadMode.MAIN)
     fun onMessageEvent(event: CertificateEvent) {
     fun onMessageEvent(event: CertificateEvent) {
         showCertificateDialog(event.x509Certificate, event.magicTrustManager, event.sslErrorHandler)
         showCertificateDialog(event.x509Certificate, event.magicTrustManager, event.sslErrorHandler)
     }
     }
 
 
     companion object {
     companion object {
-        private val TAG = "BaseActivity"
+        private val TAG = BaseActivity::class.java.simpleName
     }
     }
 }
 }

+ 1 - 1
app/src/main/java/com/nextcloud/talk/activities/CallActivity.kt

@@ -3096,7 +3096,7 @@ class CallActivity : CallBaseActivity() {
     }
     }
 
 
     override fun suppressFitsSystemWindows() {
     override fun suppressFitsSystemWindows() {
-        binding!!.controllerCallLayout.fitsSystemWindows = false
+        binding!!.callLayout.fitsSystemWindows = false
     }
     }
 
 
     override fun onConfigurationChanged(newConfig: Configuration) {
     override fun onConfigurationChanged(newConfig: Configuration) {

+ 18 - 66
app/src/main/java/com/nextcloud/talk/activities/MainActivity.kt

@@ -37,21 +37,14 @@ import androidx.lifecycle.DefaultLifecycleObserver
 import androidx.lifecycle.LifecycleOwner
 import androidx.lifecycle.LifecycleOwner
 import androidx.lifecycle.ProcessLifecycleOwner
 import androidx.lifecycle.ProcessLifecycleOwner
 import autodagger.AutoInjector
 import autodagger.AutoInjector
-import com.bluelinelabs.conductor.Conductor
-import com.bluelinelabs.conductor.Router
-import com.bluelinelabs.conductor.RouterTransaction
-import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler
-import com.bluelinelabs.conductor.changehandler.VerticalChangeHandler
 import com.google.android.material.snackbar.Snackbar
 import com.google.android.material.snackbar.Snackbar
-import com.nextcloud.talk.BuildConfig
 import com.nextcloud.talk.R
 import com.nextcloud.talk.R
+import com.nextcloud.talk.account.ServerSelectionActivity
+import com.nextcloud.talk.account.WebViewLoginActivity
 import com.nextcloud.talk.api.NcApi
 import com.nextcloud.talk.api.NcApi
 import com.nextcloud.talk.application.NextcloudTalkApplication
 import com.nextcloud.talk.application.NextcloudTalkApplication
 import com.nextcloud.talk.callnotification.CallNotificationActivity
 import com.nextcloud.talk.callnotification.CallNotificationActivity
 import com.nextcloud.talk.chat.ChatActivity
 import com.nextcloud.talk.chat.ChatActivity
-import com.nextcloud.talk.controllers.ServerSelectionController
-import com.nextcloud.talk.controllers.WebViewLoginController
-import com.nextcloud.talk.controllers.base.providers.ActionBarProvider
 import com.nextcloud.talk.conversationlist.ConversationsListActivity
 import com.nextcloud.talk.conversationlist.ConversationsListActivity
 import com.nextcloud.talk.data.user.model.User
 import com.nextcloud.talk.data.user.model.User
 import com.nextcloud.talk.databinding.ActivityMainBinding
 import com.nextcloud.talk.databinding.ActivityMainBinding
@@ -61,7 +54,6 @@ import com.nextcloud.talk.users.UserManager
 import com.nextcloud.talk.utils.ApiUtils
 import com.nextcloud.talk.utils.ApiUtils
 import com.nextcloud.talk.utils.SecurityUtils
 import com.nextcloud.talk.utils.SecurityUtils
 import com.nextcloud.talk.utils.bundle.BundleKeys
 import com.nextcloud.talk.utils.bundle.BundleKeys
-import com.nextcloud.talk.utils.bundle.BundleKeys.ADD_ACCOUNT
 import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_TOKEN
 import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_TOKEN
 import io.reactivex.Observer
 import io.reactivex.Observer
 import io.reactivex.SingleObserver
 import io.reactivex.SingleObserver
@@ -80,13 +72,9 @@ class MainActivity : BaseActivity(), ActionBarProvider {
     @Inject
     @Inject
     lateinit var userManager: UserManager
     lateinit var userManager: UserManager
 
 
-    private var router: Router? = null
-
     private val onBackPressedCallback = object : OnBackPressedCallback(true) {
     private val onBackPressedCallback = object : OnBackPressedCallback(true) {
         override fun handleOnBackPressed() {
         override fun handleOnBackPressed() {
-            if (!router!!.handleBack()) {
-                finish()
-            }
+            finish()
         }
         }
     }
     }
 
 
@@ -111,8 +99,6 @@ class MainActivity : BaseActivity(), ActionBarProvider {
 
 
         setSupportActionBar(binding.toolbar)
         setSupportActionBar(binding.toolbar)
 
 
-        router = Conductor.attachRouter(this, binding.controllerContainer, savedInstanceState)
-
         handleIntent(intent)
         handleIntent(intent)
 
 
         onBackPressedDispatcher.addCallback(this, onBackPressedCallback)
         onBackPressedDispatcher.addCallback(this, onBackPressedCallback)
@@ -128,28 +114,24 @@ class MainActivity : BaseActivity(), ActionBarProvider {
         }
         }
     }
     }
 
 
-    private fun launchLoginScreen() {
-        if (!TextUtils.isEmpty(resources.getString(R.string.weblogin_url))) {
-            router!!.pushController(
-                RouterTransaction.with(
-                    WebViewLoginController(resources.getString(R.string.weblogin_url), false)
-                )
-                    .pushChangeHandler(HorizontalChangeHandler())
-                    .popChangeHandler(HorizontalChangeHandler())
-            )
+    private fun launchServerSelection() {
+        if (isBrandingUrlSet()) {
+            val intent = Intent(context, WebViewLoginActivity::class.java)
+            val bundle = Bundle()
+            bundle.putString(BundleKeys.KEY_BASE_URL, resources.getString(R.string.weblogin_url))
+            intent.putExtras(bundle)
+            startActivity(intent)
         } else {
         } else {
-            router!!.setRoot(
-                RouterTransaction.with(ServerSelectionController())
-                    .pushChangeHandler(HorizontalChangeHandler())
-                    .popChangeHandler(HorizontalChangeHandler())
-            )
+            val intent = Intent(context, ServerSelectionActivity::class.java)
+            startActivity(intent)
         }
         }
     }
     }
 
 
+    private fun isBrandingUrlSet() = !TextUtils.isEmpty(resources.getString(R.string.weblogin_url))
+
     override fun onStart() {
     override fun onStart() {
         Log.d(TAG, "onStart: Activity: " + System.identityHashCode(this).toString())
         Log.d(TAG, "onStart: Activity: " + System.identityHashCode(this).toString())
         super.onStart()
         super.onStart()
-        logRouterBackStack(router!!)
     }
     }
 
 
     override fun onResume() {
     override fun onResume() {
@@ -178,14 +160,6 @@ class MainActivity : BaseActivity(), ActionBarProvider {
         startActivity(intent)
         startActivity(intent)
     }
     }
 
 
-    fun addAccount() {
-        router!!.pushController(
-            RouterTransaction.with(ServerSelectionController())
-                .pushChangeHandler(VerticalChangeHandler())
-                .popChangeHandler(VerticalChangeHandler())
-        )
-    }
-
     private fun handleActionFromContact(intent: Intent) {
     private fun handleActionFromContact(intent: Intent) {
         if (intent.action == Intent.ACTION_VIEW && intent.data != null) {
         if (intent.action == Intent.ACTION_VIEW && intent.data != null) {
             val cursor = contentResolver.query(intent.data!!, null, null, null, null)
             val cursor = contentResolver.query(intent.data!!, null, null, null, null)
@@ -209,7 +183,7 @@ class MainActivity : BaseActivity(), ActionBarProvider {
                         startConversation(user)
                         startConversation(user)
                     } else {
                     } else {
                         Snackbar.make(
                         Snackbar.make(
-                            binding.controllerContainer,
+                            binding.root,
                             R.string.nc_phone_book_integration_account_not_found,
                             R.string.nc_phone_book_integration_account_not_found,
                             Snackbar.LENGTH_LONG
                             Snackbar.LENGTH_LONG
                         ).show()
                         ).show()
@@ -283,28 +257,18 @@ class MainActivity : BaseActivity(), ActionBarProvider {
         }
         }
 
 
         if (user != null && userManager.setUserAsActive(user).blockingGet()) {
         if (user != null && userManager.setUserAsActive(user).blockingGet()) {
-            // this should be avoided (it's still from conductor architecture). activities should be opened directly.
             if (intent.hasExtra(BundleKeys.KEY_FROM_NOTIFICATION_START_CALL)) {
             if (intent.hasExtra(BundleKeys.KEY_FROM_NOTIFICATION_START_CALL)) {
                 if (intent.getBooleanExtra(BundleKeys.KEY_FROM_NOTIFICATION_START_CALL, false)) {
                 if (intent.getBooleanExtra(BundleKeys.KEY_FROM_NOTIFICATION_START_CALL, false)) {
-                    if (!router!!.hasRootController()) {
-                        openConversationList()
-                    }
                     val callNotificationIntent = Intent(this, CallNotificationActivity::class.java)
                     val callNotificationIntent = Intent(this, CallNotificationActivity::class.java)
                     intent.extras?.let { callNotificationIntent.putExtras(it) }
                     intent.extras?.let { callNotificationIntent.putExtras(it) }
                     startActivity(callNotificationIntent)
                     startActivity(callNotificationIntent)
                 } else {
                 } else {
-                    logRouterBackStack(router!!)
-
                     val chatIntent = Intent(context, ChatActivity::class.java)
                     val chatIntent = Intent(context, ChatActivity::class.java)
                     chatIntent.putExtras(intent.extras!!)
                     chatIntent.putExtras(intent.extras!!)
                     startActivity(chatIntent)
                     startActivity(chatIntent)
-
-                    logRouterBackStack(router!!)
                 }
                 }
             }
             }
-        } else if (intent.hasExtra(ADD_ACCOUNT) && intent.getBooleanExtra(ADD_ACCOUNT, false)) {
-            addAccount()
-        } else if (!router!!.hasRootController()) {
+        } else {
             if (!appPreferences.isDbRoomMigrated) {
             if (!appPreferences.isDbRoomMigrated) {
                 appPreferences.isDbRoomMigrated = true
                 appPreferences.isDbRoomMigrated = true
             }
             }
@@ -321,7 +285,7 @@ class MainActivity : BaseActivity(), ActionBarProvider {
                         }
                         }
                     } else {
                     } else {
                         runOnUiThread {
                         runOnUiThread {
-                            launchLoginScreen()
+                            launchServerSelection()
                         }
                         }
                     }
                     }
                 }
                 }
@@ -333,19 +297,7 @@ class MainActivity : BaseActivity(), ActionBarProvider {
         }
         }
     }
     }
 
 
-    private fun logRouterBackStack(router: Router) {
-        if (BuildConfig.DEBUG) {
-            val backstack = router.backstack
-            var routerTransaction: RouterTransaction?
-            Log.d(TAG, "   backstack size: " + router.backstackSize)
-            for (i in 0 until router.backstackSize) {
-                routerTransaction = backstack[i]
-                Log.d(TAG, "     controller: " + routerTransaction.controller)
-            }
-        }
-    }
-
     companion object {
     companion object {
-        private const val TAG = "MainActivity"
+        private val TAG = MainActivity::class.java.simpleName
     }
     }
 }
 }

+ 1 - 1
app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingPollMessageViewHolder.kt

@@ -231,6 +231,6 @@ class IncomingPollMessageViewHolder(incomingView: View, payload: Any) :
     }
     }
 
 
     companion object {
     companion object {
-        private val TAG = NextcloudTalkApplication::class.java.simpleName
+        private val TAG = IncomingPollMessageViewHolder::class.java.simpleName
     }
     }
 }
 }

+ 1 - 1
app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingPollMessageViewHolder.kt

@@ -209,6 +209,6 @@ class OutcomingPollMessageViewHolder(outcomingView: View, payload: Any) :
     }
     }
 
 
     companion object {
     companion object {
-        private val TAG = NextcloudTalkApplication::class.java.simpleName
+        private val TAG = OutcomingPollMessageViewHolder::class.java.simpleName
     }
     }
 }
 }

+ 1 - 1
app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/items/BasicListItemWithImage.kt → app/src/main/java/com/nextcloud/talk/bottomsheet/items/BasicListItemWithImage.kt

@@ -18,7 +18,7 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
  */
 
 
-package com.nextcloud.talk.controllers.bottomsheet.items
+package com.nextcloud.talk.bottomsheet.items
 
 
 import android.widget.ImageView
 import android.widget.ImageView
 import androidx.annotation.DrawableRes
 import androidx.annotation.DrawableRes

+ 1 - 1
app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/items/MagicBottomSheets.kt → app/src/main/java/com/nextcloud/talk/bottomsheet/items/BottomSheets.kt

@@ -18,7 +18,7 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
  */
 
 
-package com.nextcloud.talk.controllers.bottomsheet.items
+package com.nextcloud.talk.bottomsheet.items
 
 
 import androidx.annotation.CheckResult
 import androidx.annotation.CheckResult
 import androidx.recyclerview.widget.LinearLayoutManager
 import androidx.recyclerview.widget.LinearLayoutManager

+ 1 - 1
app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/items/ListIconDialogAdapter.kt → app/src/main/java/com/nextcloud/talk/bottomsheet/items/ListIconDialogAdapter.kt

@@ -18,7 +18,7 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
  */
 
 
-package com.nextcloud.talk.controllers.bottomsheet.items
+package com.nextcloud.talk.bottomsheet.items
 
 
 import android.view.View
 import android.view.View
 import android.view.ViewGroup
 import android.view.ViewGroup

+ 1 - 1
app/src/main/java/com/nextcloud/talk/callnotification/CallNotificationActivity.kt

@@ -317,7 +317,7 @@ class CallNotificationActivity : CallBaseActivity() {
     }
     }
 
 
     override fun suppressFitsSystemWindows() {
     override fun suppressFitsSystemWindows() {
-        binding!!.controllerCallNotificationLayout.fitsSystemWindows = false
+        binding!!.callNotificationLayout.fitsSystemWindows = false
     }
     }
 
 
     companion object {
     companion object {

+ 3 - 3
app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt

@@ -1605,7 +1605,7 @@ class ChatActivity :
             participantPermissions.hasChatPermission() &&
             participantPermissions.hasChatPermission() &&
             !isReadOnlyConversation()
             !isReadOnlyConversation()
         ) {
         ) {
-            val messageSwipeController = MessageSwipeCallback(
+            val messageSwipeCallback = MessageSwipeCallback(
                 this,
                 this,
                 object : MessageSwipeActions {
                 object : MessageSwipeActions {
                     override fun showReplyUI(position: Int) {
                     override fun showReplyUI(position: Int) {
@@ -1617,7 +1617,7 @@ class ChatActivity :
                 }
                 }
             )
             )
 
 
-            val itemTouchHelper = ItemTouchHelper(messageSwipeController)
+            val itemTouchHelper = ItemTouchHelper(messageSwipeCallback)
             itemTouchHelper.attachToRecyclerView(binding.messagesListView)
             itemTouchHelper.attachToRecyclerView(binding.messagesListView)
         }
         }
     }
     }
@@ -2561,7 +2561,7 @@ class ChatActivity :
         super.onRequestPermissionsResult(requestCode, permissions, grantResults)
         super.onRequestPermissionsResult(requestCode, permissions, grantResults)
         if (requestCode == UploadAndShareFilesWorker.REQUEST_PERMISSION) {
         if (requestCode == UploadAndShareFilesWorker.REQUEST_PERMISSION) {
             if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
             if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
-                Log.d(ConversationsListActivity.TAG, "upload starting after permissions were granted")
+                Log.d(TAG, "upload starting after permissions were granted")
                 if (filesToUpload.isNotEmpty()) {
                 if (filesToUpload.isNotEmpty()) {
                     uploadFiles(filesToUpload)
                     uploadFiles(filesToUpload)
                 }
                 }

+ 4 - 13
app/src/main/java/com/nextcloud/talk/contacts/ContactsActivity.kt

@@ -488,17 +488,13 @@ class ContactsActivity :
                     } else {
                     } else {
                         adapter?.filterItems()
                         adapter?.filterItems()
                     }
                     }
-
-                    binding.controllerGenericRv.swipeRefreshLayout.isRefreshing = false
                 }
                 }
 
 
                 override fun onError(e: Throwable) {
                 override fun onError(e: Throwable) {
-                    binding.controllerGenericRv.swipeRefreshLayout.isRefreshing = false
                     dispose(contactsQueryDisposable)
                     dispose(contactsQueryDisposable)
                 }
                 }
 
 
                 override fun onComplete() {
                 override fun onComplete() {
-                    binding.controllerGenericRv.swipeRefreshLayout.isRefreshing = false
                     dispose(contactsQueryDisposable)
                     dispose(contactsQueryDisposable)
                     alreadyFetching = false
                     alreadyFetching = false
                     disengageProgressBar()
                     disengageProgressBar()
@@ -656,12 +652,9 @@ class ContactsActivity :
 
 
     private fun prepareViews() {
     private fun prepareViews() {
         layoutManager = SmoothScrollLinearLayoutManager(this)
         layoutManager = SmoothScrollLinearLayoutManager(this)
-        binding.controllerGenericRv.recyclerView.layoutManager = layoutManager
-        binding.controllerGenericRv.recyclerView.setHasFixedSize(true)
-        binding.controllerGenericRv.recyclerView.adapter = adapter
-        binding.controllerGenericRv.swipeRefreshLayout.setOnRefreshListener { fetchData() }
-
-        binding.controllerGenericRv.let { viewThemeUtils.androidx.themeSwipeRefreshLayout(it.swipeRefreshLayout) }
+        binding.contactsRv.layoutManager = layoutManager
+        binding.contactsRv.setHasFixedSize(true)
+        binding.contactsRv.adapter = adapter
 
 
         binding.listOpenConversationsImage.background?.setColorFilter(
         binding.listOpenConversationsImage.background?.setColorFilter(
             ResourcesCompat.getColor(resources!!, R.color.colorBackgroundDarker, null),
             ResourcesCompat.getColor(resources!!, R.color.colorBackgroundDarker, null),
@@ -677,7 +670,7 @@ class ContactsActivity :
     private fun disengageProgressBar() {
     private fun disengageProgressBar() {
         if (!alreadyFetching) {
         if (!alreadyFetching) {
             binding.loadingContent.visibility = View.GONE
             binding.loadingContent.visibility = View.GONE
-            binding.controllerGenericRv.root.visibility = View.VISIBLE
+            binding.root.visibility = View.VISIBLE
             if (isNewConversationView) {
             if (isNewConversationView) {
                 binding.callHeaderLayout.visibility = View.VISIBLE
                 binding.callHeaderLayout.visibility = View.VISIBLE
             }
             }
@@ -713,8 +706,6 @@ class ContactsActivity :
             adapter?.updateDataSet(contactItems as List<Nothing>?)
             adapter?.updateDataSet(contactItems as List<Nothing>?)
         }
         }
 
 
-        binding.controllerGenericRv?.swipeRefreshLayout?.isEnabled = !adapter!!.hasFilter()
-
         return true
         return true
     }
     }
 
 

+ 0 - 256
app/src/main/java/com/nextcloud/talk/controllers/RingtoneSelectionController.kt

@@ -1,256 +0,0 @@
-/*
- * Nextcloud Talk application
- *
- * @author Mario Danic
- * @author Andy Scherzinger
- * Copyright (C) 2022 Andy Scherzinger <info@andy-scherzinger.de>
- * Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
- *
- * 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 <http://www.gnu.org/licenses/>.
- */
-package com.nextcloud.talk.controllers
-
-import android.annotation.SuppressLint
-import android.media.MediaPlayer
-import android.media.RingtoneManager
-import android.net.Uri
-import android.os.Bundle
-import android.os.Handler
-import android.text.TextUtils
-import android.util.Log
-import android.view.MenuItem
-import android.view.View
-import androidx.recyclerview.widget.RecyclerView
-import autodagger.AutoInjector
-import com.bluelinelabs.logansquare.LoganSquare
-import com.nextcloud.talk.R
-import com.nextcloud.talk.adapters.items.NotificationSoundItem
-import com.nextcloud.talk.application.NextcloudTalkApplication
-import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication
-import com.nextcloud.talk.controllers.base.BaseController
-import com.nextcloud.talk.controllers.util.viewBinding
-import com.nextcloud.talk.databinding.ControllerGenericRvBinding
-import com.nextcloud.talk.models.RingtoneSettings
-import com.nextcloud.talk.utils.NotificationUtils
-import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ARE_CALL_SOUNDS
-import eu.davidea.flexibleadapter.FlexibleAdapter
-import eu.davidea.flexibleadapter.SelectableAdapter
-import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager
-import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
-import java.io.IOException
-
-@AutoInjector(NextcloudTalkApplication::class)
-class RingtoneSelectionController(args: Bundle) :
-    BaseController(
-        R.layout.controller_generic_rv,
-        args
-    ),
-    FlexibleAdapter.OnItemClickListener {
-    private val binding: ControllerGenericRvBinding? by viewBinding(ControllerGenericRvBinding::bind)
-
-    private var adapter: FlexibleAdapter<*>? = null
-    private var adapterDataObserver: RecyclerView.AdapterDataObserver? = null
-    private val abstractFlexibleItemList: MutableList<AbstractFlexibleItem<*>> = ArrayList()
-    private val callNotificationSounds: Boolean
-    private var mediaPlayer: MediaPlayer? = null
-    private var cancelMediaPlayerHandler: Handler? = null
-
-    override fun onViewBound(view: View) {
-        super.onViewBound(view)
-        if (adapter == null) {
-            adapter = FlexibleAdapter(abstractFlexibleItemList, activity, false)
-            adapter!!.setNotifyChangeOfUnfilteredItems(true).mode = SelectableAdapter.Mode.SINGLE
-            adapter!!.addListener(this)
-            cancelMediaPlayerHandler = Handler()
-        }
-        adapter!!.addListener(this)
-        prepareViews()
-        fetchNotificationSounds()
-    }
-
-    override fun onOptionsItemSelected(item: MenuItem): Boolean {
-        return if (item.itemId == android.R.id.home) {
-            router.popCurrentController()
-        } else {
-            super.onOptionsItemSelected(item)
-        }
-    }
-
-    private fun prepareViews() {
-        val layoutManager: RecyclerView.LayoutManager = SmoothScrollLinearLayoutManager(activity)
-        binding?.recyclerView?.layoutManager = layoutManager
-        binding?.recyclerView?.setHasFixedSize(true)
-        binding?.recyclerView?.adapter = adapter
-        adapterDataObserver = object : RecyclerView.AdapterDataObserver() {
-            override fun onChanged() {
-                super.onChanged()
-                findSelectedSound()
-            }
-        }
-        adapter!!.registerAdapterDataObserver(adapterDataObserver!!)
-        binding?.swipeRefreshLayout?.isEnabled = false
-    }
-
-    @SuppressLint("LongLogTag")
-    private fun findSelectedSound() {
-        var foundDefault = false
-        var preferencesString: String? = null
-        val callsEnabledButNoRingtone = callNotificationSounds &&
-            TextUtils.isEmpty(appPreferences.callRingtoneUri.also { preferencesString = it })
-        val noCallsAndNoMessageTone = !callNotificationSounds &&
-            TextUtils.isEmpty(appPreferences.messageRingtoneUri.also { preferencesString = it })
-        if (callsEnabledButNoRingtone || noCallsAndNoMessageTone) {
-            adapter!!.toggleSelection(1)
-            foundDefault = true
-        }
-        if (!TextUtils.isEmpty(preferencesString) && !foundDefault) {
-            try {
-                val ringtoneSettings: RingtoneSettings =
-                    LoganSquare.parse<RingtoneSettings>(preferencesString, RingtoneSettings::class.java)
-                if (ringtoneSettings.ringtoneUri == null) {
-                    adapter!!.toggleSelection(0)
-                } else if (ringtoneSettings.ringtoneUri!!.toString() == ringtoneString) {
-                    adapter!!.toggleSelection(1)
-                } else {
-                    var notificationSoundItem: NotificationSoundItem?
-                    for (i in 2 until adapter!!.itemCount) {
-                        notificationSoundItem = adapter!!.getItem(i) as NotificationSoundItem?
-                        if (
-                            notificationSoundItem!!.notificationSoundUri == ringtoneSettings.ringtoneUri!!.toString()
-                        ) {
-                            adapter!!.toggleSelection(i)
-                            break
-                        }
-                    }
-                }
-            } catch (e: IOException) {
-                Log.e(TAG, "Failed to parse ringtone settings")
-            }
-        }
-        adapter!!.unregisterAdapterDataObserver(adapterDataObserver!!)
-        adapterDataObserver = null
-    }
-
-    private val ringtoneString: String
-        get() = if (callNotificationSounds) {
-            NotificationUtils.DEFAULT_CALL_RINGTONE_URI
-        } else {
-            NotificationUtils.DEFAULT_MESSAGE_RINGTONE_URI
-        }
-
-    private fun fetchNotificationSounds() {
-        abstractFlexibleItemList.add(
-            NotificationSoundItem(
-                resources!!.getString(R.string.nc_settings_no_ringtone),
-                null
-            )
-        )
-        abstractFlexibleItemList.add(
-            NotificationSoundItem(
-                resources!!.getString(R.string.nc_settings_default_ringtone),
-                ringtoneString
-            )
-        )
-        if (activity != null) {
-            val manager = RingtoneManager(activity)
-            if (callNotificationSounds) {
-                manager.setType(RingtoneManager.TYPE_RINGTONE)
-            } else {
-                manager.setType(RingtoneManager.TYPE_NOTIFICATION)
-            }
-            val cursor = manager.cursor
-            var notificationSoundItem: NotificationSoundItem
-            while (cursor.moveToNext()) {
-                val notificationTitle = cursor.getString(RingtoneManager.TITLE_COLUMN_INDEX)
-                val notificationUri = cursor.getString(RingtoneManager.URI_COLUMN_INDEX)
-                val completeNotificationUri = notificationUri + "/" + cursor.getString(RingtoneManager.ID_COLUMN_INDEX)
-                notificationSoundItem = NotificationSoundItem(notificationTitle, completeNotificationUri)
-                abstractFlexibleItemList.add(notificationSoundItem)
-            }
-        }
-        adapter!!.updateDataSet(abstractFlexibleItemList as List<Nothing>?, false)
-    }
-
-    override fun onItemClick(view: View, position: Int): Boolean {
-        val notificationSoundItem = adapter!!.getItem(position) as NotificationSoundItem?
-        var ringtoneUri: Uri? = null
-        if (!TextUtils.isEmpty(notificationSoundItem!!.notificationSoundUri)) {
-            ringtoneUri = Uri.parse(notificationSoundItem.notificationSoundUri)
-            endMediaPlayer()
-            mediaPlayer = MediaPlayer.create(activity, ringtoneUri)
-            cancelMediaPlayerHandler = Handler()
-            cancelMediaPlayerHandler!!.postDelayed(
-                { endMediaPlayer() },
-                (mediaPlayer!!.duration + DURATION_EXTENSION).toLong()
-            )
-            mediaPlayer!!.start()
-        }
-        if (adapter!!.selectedPositions.size == 0 || adapter!!.selectedPositions[0] != position) {
-            val ringtoneSettings = RingtoneSettings()
-            ringtoneSettings.ringtoneName = notificationSoundItem.notificationSoundName
-            ringtoneSettings.ringtoneUri = ringtoneUri
-            if (callNotificationSounds) {
-                try {
-                    appPreferences!!.callRingtoneUri = LoganSquare.serialize(ringtoneSettings)
-                    adapter!!.toggleSelection(position)
-                    adapter!!.notifyDataSetChanged()
-                } catch (e: IOException) {
-                    Log.e(TAG, "Failed to store selected ringtone for calls")
-                }
-            } else {
-                try {
-                    appPreferences!!.messageRingtoneUri = LoganSquare.serialize(ringtoneSettings)
-                    adapter!!.toggleSelection(position)
-                    adapter!!.notifyDataSetChanged()
-                } catch (e: IOException) {
-                    Log.e(TAG, "Failed to store selected ringtone for calls")
-                }
-            }
-        }
-        return true
-    }
-
-    private fun endMediaPlayer() {
-        if (cancelMediaPlayerHandler != null) {
-            cancelMediaPlayerHandler!!.removeCallbacksAndMessages(null)
-        }
-        if (mediaPlayer != null) {
-            if (mediaPlayer!!.isPlaying) {
-                mediaPlayer!!.stop()
-            }
-            mediaPlayer!!.release()
-            mediaPlayer = null
-        }
-    }
-
-    public override fun onDestroy() {
-        endMediaPlayer()
-        super.onDestroy()
-    }
-
-    companion object {
-        private const val TAG = "RingtoneSelection"
-        private const val DURATION_EXTENSION = 25
-    }
-
-    init {
-        setHasOptionsMenu(true)
-        sharedApplication!!.componentApplication.inject(this)
-        callNotificationSounds = args.getBoolean(KEY_ARE_CALL_SOUNDS, false)
-    }
-
-    override val title: String
-        get() =
-            resources!!.getString(R.string.nc_settings_notification_sounds)
-}

+ 0 - 309
app/src/main/java/com/nextcloud/talk/controllers/base/BaseController.kt

@@ -1,309 +0,0 @@
-/*
- * Nextcloud Talk application
- *
- * @author Andy Scherzinger
- * @author BlueLine Labs, Inc.
- * @author Mario Danic
- * Copyright (C) 2021 Andy Scherzinger (info@andy-scherzinger.de)
- * Copyright (C) 2021 BlueLine Labs, Inc.
- * Copyright (C) 2020 Mario Danic (mario@lovelyhq.com)
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.nextcloud.talk.controllers.base
-
-import android.content.Context
-import android.os.Build
-import android.os.Bundle
-import android.util.Log
-import android.view.LayoutInflater
-import android.view.MenuItem
-import android.view.View
-import android.view.ViewGroup
-import android.view.inputmethod.EditorInfo
-import android.view.inputmethod.InputMethodManager
-import android.widget.EditText
-import androidx.annotation.LayoutRes
-import androidx.annotation.RequiresApi
-import androidx.appcompat.app.ActionBar
-import autodagger.AutoInjector
-import com.bluelinelabs.conductor.Controller
-import com.bluelinelabs.conductor.ControllerChangeHandler
-import com.bluelinelabs.conductor.ControllerChangeType
-import com.nextcloud.talk.R
-import com.nextcloud.talk.activities.MainActivity
-import com.nextcloud.talk.application.NextcloudTalkApplication
-import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication
-import com.nextcloud.talk.controllers.AccountVerificationController
-import com.nextcloud.talk.controllers.ServerSelectionController
-import com.nextcloud.talk.controllers.SwitchAccountController
-import com.nextcloud.talk.controllers.WebViewLoginController
-import com.nextcloud.talk.controllers.base.providers.ActionBarProvider
-import com.nextcloud.talk.ui.theme.ViewThemeUtils
-import com.nextcloud.talk.utils.preferences.AppPreferences
-import javax.inject.Inject
-import kotlin.jvm.internal.Intrinsics
-
-// TODO: check what needs to be migrated from this class to BaseActivity etc when conductor is removed
-@AutoInjector(NextcloudTalkApplication::class)
-abstract class BaseController(@LayoutRes var layoutRes: Int, args: Bundle? = null) : Controller(args) {
-    enum class AppBarLayoutType {
-        TOOLBAR, SEARCH_BAR, EMPTY
-    }
-
-    @Inject
-    lateinit var appPreferences: AppPreferences
-
-    @Inject
-    lateinit var context: Context
-
-    @Inject
-    lateinit var viewThemeUtils: ViewThemeUtils
-
-    protected open val title: String?
-        get() = null
-
-    @Suppress("Detekt.TooGenericExceptionCaught")
-    protected val actionBar: ActionBar?
-        get() {
-            var actionBarProvider: ActionBarProvider? = null
-            if (this.activity is ActionBarProvider) {
-                try {
-                    actionBarProvider = this.activity as ActionBarProvider?
-                } catch (e: Exception) {
-                    Log.d(TAG, "Failed to fetch the action bar provider", e)
-                }
-            }
-            return actionBarProvider?.supportActionBar
-        }
-
-    init {
-        @Suppress("LeakingThis")
-        sharedApplication!!.componentApplication.inject(this)
-        addLifecycleListener(object : LifecycleListener() {
-            override fun postCreateView(controller: Controller, view: View) {
-                onViewBound(view)
-                actionBar?.let { setTitle() }
-            }
-        })
-        cleanTempCertPreference()
-    }
-
-    fun isAlive(): Boolean {
-        return !isDestroyed && !isBeingDestroyed
-    }
-
-    override fun onCreateView(
-        inflater: LayoutInflater,
-        container: ViewGroup,
-        savedViewState: Bundle?
-    ): View {
-        return inflater.inflate(layoutRes, container, false)
-    }
-
-    protected open fun onViewBound(view: View) {
-        var activity: MainActivity? = null
-
-        // if (getActivity() != null && getActivity() is MainActivity) {
-        //     activity = getActivity() as MainActivity?
-        //     viewThemeUtils.material.themeCardView(activity!!.binding.searchToolbar)
-        //     viewThemeUtils.material.themeToolbar(activity.binding.toolbar)
-        //     viewThemeUtils.material.themeSearchBarText(activity.binding.searchText)
-        // }
-
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && appPreferences.isKeyboardIncognito) {
-            disableKeyboardPersonalisedLearning((view as ViewGroup))
-            if (activity != null) {
-                disableKeyboardPersonalisedLearning(activity.binding.appBar)
-            }
-        }
-    }
-
-    override fun onAttach(view: View) {
-        // showSearchOrToolbar()
-        setTitle()
-        if (actionBar != null) {
-            actionBar!!.setDisplayHomeAsUpEnabled(parentController != null || router.backstackSize >= 1)
-        }
-        super.onAttach(view)
-    }
-
-    // open fun showSearchOrToolbar() {
-    //     if (isValidActivity(activity)) {
-    //         val showSearchBar = appBarLayoutType == AppBarLayoutType.SEARCH_BAR
-    //         val activity = activity as MainActivity
-    //
-    //         if (appBarLayoutType == AppBarLayoutType.EMPTY) {
-    //             hideBars(activity.binding)
-    //         } else {
-    //             if (showSearchBar) {
-    //                 showSearchBar(activity.binding)
-    //             } else {
-    //                 showToolbar(activity.binding)
-    //             }
-    //             colorizeStatusBar(showSearchBar, activity, resources)
-    //         }
-    //
-    //         colorizeNavigationBar(activity, resources)
-    //     }
-    // }
-    //
-    // private fun isValidActivity(activity: Activity?): Boolean {
-    //     return activity != null && activity is MainActivity
-    // }
-    //
-    // private fun showSearchBar(binding: ActivityMainBinding) {
-    //     val layoutParams = binding.searchToolbar.layoutParams as AppBarLayout.LayoutParams
-    //     binding.searchToolbar.visibility = View.VISIBLE
-    //     binding.searchText.hint = searchHint
-    //     binding.toolbar.visibility = View.GONE
-    //     // layoutParams.setScrollFlags(AppBarLayout.LayoutParams.SCROLL_FLAG_SCROLL | AppBarLayout
-    //     // .LayoutParams.SCROLL_FLAG_SNAP | AppBarLayout.LayoutParams.SCROLL_FLAG_ENTER_ALWAYS);
-    //     layoutParams.scrollFlags = 0
-    //     binding.appBar.stateListAnimator = AnimatorInflater.loadStateListAnimator(
-    //         binding.appBar.context,
-    //         R.animator.appbar_elevation_off
-    //     )
-    //     binding.searchToolbar.layoutParams = layoutParams
-    // }
-    //
-    // private fun showToolbar(binding: ActivityMainBinding) {
-    //     val layoutParams = binding.searchToolbar.layoutParams as AppBarLayout.LayoutParams
-    //     binding.searchToolbar.visibility = View.GONE
-    //     binding.toolbar.visibility = View.VISIBLE
-    //     viewThemeUtils.material.colorToolbarOverflowIcon(binding.toolbar)
-    //     layoutParams.scrollFlags = 0
-    //     binding.appBar.stateListAnimator = AnimatorInflater.loadStateListAnimator(
-    //         binding.appBar.context,
-    //         R.animator.appbar_elevation_on
-    //     )
-    //     binding.searchToolbar.layoutParams = layoutParams
-    // }
-    //
-    // private fun hideBars(binding: ActivityMainBinding) {
-    //     binding.toolbar.visibility = View.GONE
-    //     binding.searchToolbar.visibility = View.GONE
-    // }
-    //
-    // fun hideSearchBar() {
-    //     val activity = activity as MainActivity?
-    //     val layoutParams = activity!!.binding.searchToolbar.layoutParams as AppBarLayout.LayoutParams
-    //     activity.binding.searchToolbar.visibility = View.GONE
-    //     activity.binding.toolbar.visibility = View.VISIBLE
-    //     layoutParams.scrollFlags = 0
-    //     activity.binding.appBar.stateListAnimator = AnimatorInflater.loadStateListAnimator(
-    //         activity.binding.appBar.context,
-    //         R.animator.appbar_elevation_on
-    //     )
-    // }
-    //
-    // private fun colorizeStatusBar(showSearchBar: Boolean, activity: Activity?, resources: Resources?) {
-    //     if (activity != null && resources != null) {
-    //         if (showSearchBar) {
-    //             view?.let { viewThemeUtils.platform.resetStatusBar(activity) }
-    //         } else {
-    //             view?.let { viewThemeUtils.platform.themeStatusBar(activity, it) }
-    //         }
-    //     }
-    // }
-    //
-    // private fun colorizeNavigationBar(activity: Activity?, resources: Resources?) {
-    //     if (activity != null && resources != null) {
-    //         DisplayUtils.applyColorToNavigationBar(
-    //             activity.window,
-    //             ResourcesCompat.getColor(resources, R.color.bg_default, null)
-    //         )
-    //     }
-    // }
-
-    override fun onDetach(view: View) {
-        super.onDetach(view)
-        val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
-        imm.hideSoftInputFromWindow(view.windowToken, 0)
-    }
-
-    protected fun setTitle() {
-        if (isTitleSetable()) {
-            run {
-                calculateValidParentController()
-            }
-            actionBar!!.title = title
-        }
-    }
-
-    private fun calculateValidParentController() {
-        var parentController = parentController
-        while (parentController != null) {
-            parentController = parentController.parentController
-        }
-    }
-
-    private fun isTitleSetable(): Boolean {
-        return title != null && actionBar != null
-    }
-
-    override fun onOptionsItemSelected(item: MenuItem): Boolean {
-        if (item.itemId == android.R.id.home) {
-            router.popCurrentController()
-            return true
-        }
-        return super.onOptionsItemSelected(item)
-    }
-
-    override fun onChangeStarted(changeHandler: ControllerChangeHandler, changeType: ControllerChangeType) {
-        super.onChangeStarted(changeHandler, changeType)
-        if (changeType.isEnter && actionBar != null) {
-            configureMenu(actionBar!!)
-        }
-    }
-
-    fun configureMenu(toolbar: ActionBar) {
-        Intrinsics.checkNotNullParameter(toolbar, "toolbar")
-    }
-
-    // TODO: check if this must be migrated when using activities instead of conductor
-    private fun cleanTempCertPreference() {
-        val temporaryClassNames: MutableList<String> = ArrayList()
-        temporaryClassNames.add(ServerSelectionController::class.java.name)
-        temporaryClassNames.add(AccountVerificationController::class.java.name)
-        temporaryClassNames.add(WebViewLoginController::class.java.name)
-        temporaryClassNames.add(SwitchAccountController::class.java.name)
-        if (!temporaryClassNames.contains(javaClass.name)) {
-            appPreferences.removeTemporaryClientCertAlias()
-        }
-    }
-
-    @RequiresApi(api = Build.VERSION_CODES.O)
-    private fun disableKeyboardPersonalisedLearning(viewGroup: ViewGroup) {
-        var view: View?
-        var editText: EditText
-        for (i in 0 until viewGroup.childCount) {
-            view = viewGroup.getChildAt(i)
-            if (view is EditText) {
-                editText = view
-                editText.imeOptions = editText.imeOptions or EditorInfo.IME_FLAG_NO_PERSONALIZED_LEARNING
-            } else if (view is ViewGroup) {
-                disableKeyboardPersonalisedLearning(view)
-            }
-        }
-    }
-
-    open val appBarLayoutType: AppBarLayoutType
-        get() = AppBarLayoutType.TOOLBAR
-    val searchHint: String
-        get() = context.getString(R.string.appbar_search_in, context.getString(R.string.nc_app_product_name))
-
-    companion object {
-        private val TAG = BaseController::class.java.simpleName
-    }
-}

+ 0 - 52
app/src/main/java/com/nextcloud/talk/controllers/util/ControllerViewBindingDelegate.kt

@@ -1,52 +0,0 @@
-/*
- * Nextcloud Talk application
- *
- * @author BlueLine Labs, Inc.
- * Copyright (C) 2016 BlueLine Labs, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.nextcloud.talk.controllers.util
-
-import android.view.View
-import androidx.lifecycle.LifecycleObserver
-import androidx.viewbinding.ViewBinding
-import com.bluelinelabs.conductor.Controller
-import kotlin.properties.ReadOnlyProperty
-import kotlin.reflect.KProperty
-
-fun <T : ViewBinding> Controller.viewBinding(bindingFactory: (View) -> T) =
-    ControllerViewBindingDelegate(this, bindingFactory)
-
-class ControllerViewBindingDelegate<T : ViewBinding>(
-    controller: Controller,
-    private val viewBinder: (View) -> T
-) : ReadOnlyProperty<Controller, T?>, LifecycleObserver {
-
-    private var binding: T? = null
-
-    init {
-        controller.addLifecycleListener(object : Controller.LifecycleListener() {
-            override fun postDestroyView(controller: Controller) {
-                binding = null
-            }
-        })
-    }
-
-    override fun getValue(thisRef: Controller, property: KProperty<*>): T? {
-        if (binding == null) {
-            binding = thisRef.view?.let { viewBinder(it) }
-        }
-        return binding
-    }
-}

+ 2 - 2
app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt

@@ -58,8 +58,8 @@ import com.nextcloud.talk.adapters.items.ParticipantItem
 import com.nextcloud.talk.api.NcApi
 import com.nextcloud.talk.api.NcApi
 import com.nextcloud.talk.application.NextcloudTalkApplication
 import com.nextcloud.talk.application.NextcloudTalkApplication
 import com.nextcloud.talk.contacts.ContactsActivity
 import com.nextcloud.talk.contacts.ContactsActivity
-import com.nextcloud.talk.controllers.bottomsheet.items.BasicListItemWithImage
-import com.nextcloud.talk.controllers.bottomsheet.items.listItemsWithImage
+import com.nextcloud.talk.bottomsheet.items.BasicListItemWithImage
+import com.nextcloud.talk.bottomsheet.items.listItemsWithImage
 import com.nextcloud.talk.conversationinfoedit.ConversationInfoEditActivity
 import com.nextcloud.talk.conversationinfoedit.ConversationInfoEditActivity
 import com.nextcloud.talk.data.user.model.User
 import com.nextcloud.talk.data.user.model.User
 import com.nextcloud.talk.databinding.ActivityConversationInfoBinding
 import com.nextcloud.talk.databinding.ActivityConversationInfoBinding

+ 120 - 73
app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt

@@ -50,6 +50,7 @@ import android.view.MotionEvent
 import android.view.View
 import android.view.View
 import android.view.inputmethod.EditorInfo
 import android.view.inputmethod.EditorInfo
 import android.view.inputmethod.InputMethodManager
 import android.view.inputmethod.InputMethodManager
+import android.widget.Toast
 import androidx.activity.OnBackPressedCallback
 import androidx.activity.OnBackPressedCallback
 import androidx.appcompat.app.AlertDialog
 import androidx.appcompat.app.AlertDialog
 import androidx.appcompat.widget.SearchView
 import androidx.appcompat.widget.SearchView
@@ -71,8 +72,11 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder
 import com.google.android.material.snackbar.Snackbar
 import com.google.android.material.snackbar.Snackbar
 import com.nextcloud.android.common.ui.theme.utils.ColorRole
 import com.nextcloud.android.common.ui.theme.utils.ColorRole
 import com.nextcloud.talk.R
 import com.nextcloud.talk.R
+import com.nextcloud.talk.account.ServerSelectionActivity
+import com.nextcloud.talk.account.WebViewLoginActivity
 import com.nextcloud.talk.activities.BaseActivity
 import com.nextcloud.talk.activities.BaseActivity
 import com.nextcloud.talk.activities.CallActivity
 import com.nextcloud.talk.activities.CallActivity
+import com.nextcloud.talk.activities.MainActivity
 import com.nextcloud.talk.adapters.items.ConversationItem
 import com.nextcloud.talk.adapters.items.ConversationItem
 import com.nextcloud.talk.adapters.items.GenericTextHeaderItem
 import com.nextcloud.talk.adapters.items.GenericTextHeaderItem
 import com.nextcloud.talk.adapters.items.LoadMoreResultsItem
 import com.nextcloud.talk.adapters.items.LoadMoreResultsItem
@@ -84,7 +88,7 @@ import com.nextcloud.talk.arbitrarystorage.ArbitraryStorageManager
 import com.nextcloud.talk.chat.ChatActivity
 import com.nextcloud.talk.chat.ChatActivity
 import com.nextcloud.talk.contacts.ContactsActivity
 import com.nextcloud.talk.contacts.ContactsActivity
 import com.nextcloud.talk.data.user.model.User
 import com.nextcloud.talk.data.user.model.User
-import com.nextcloud.talk.databinding.ControllerConversationsRvBinding
+import com.nextcloud.talk.databinding.ActivityConversationsBinding
 import com.nextcloud.talk.events.ConversationsListFetchDataEvent
 import com.nextcloud.talk.events.ConversationsListFetchDataEvent
 import com.nextcloud.talk.events.EventStatus
 import com.nextcloud.talk.events.EventStatus
 import com.nextcloud.talk.jobs.AccountRemovalWorker
 import com.nextcloud.talk.jobs.AccountRemovalWorker
@@ -109,6 +113,7 @@ import com.nextcloud.talk.utils.Mimetype
 import com.nextcloud.talk.utils.ParticipantPermissions
 import com.nextcloud.talk.utils.ParticipantPermissions
 import com.nextcloud.talk.utils.UserIdUtils
 import com.nextcloud.talk.utils.UserIdUtils
 import com.nextcloud.talk.utils.bundle.BundleKeys
 import com.nextcloud.talk.utils.bundle.BundleKeys
+import com.nextcloud.talk.utils.bundle.BundleKeys.ADD_ADDITIONAL_ACCOUNT
 import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_FORWARD_HIDE_SOURCE_ROOM
 import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_FORWARD_HIDE_SOURCE_ROOM
 import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_FORWARD_MSG_FLAG
 import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_FORWARD_MSG_FLAG
 import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_FORWARD_MSG_TEXT
 import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_FORWARD_MSG_TEXT
@@ -146,7 +151,7 @@ class ConversationsListActivity :
     FlexibleAdapter.OnItemClickListener,
     FlexibleAdapter.OnItemClickListener,
     FlexibleAdapter.OnItemLongClickListener {
     FlexibleAdapter.OnItemLongClickListener {
 
 
-    private lateinit var binding: ControllerConversationsRvBinding
+    private lateinit var binding: ActivityConversationsBinding
 
 
     @Inject
     @Inject
     lateinit var userManager: UserManager
     lateinit var userManager: UserManager
@@ -202,7 +207,6 @@ class ConversationsListActivity :
 
 
     private val onBackPressedCallback = object : OnBackPressedCallback(true) {
     private val onBackPressedCallback = object : OnBackPressedCallback(true) {
         override fun handleOnBackPressed() {
         override fun handleOnBackPressed() {
-            // TODO: replace this when conductor is removed. For now it avoids to load the MainActiviy which has no UI.
             finishAffinity()
             finishAffinity()
         }
         }
     }
     }
@@ -211,7 +215,7 @@ class ConversationsListActivity :
         super.onCreate(savedInstanceState)
         super.onCreate(savedInstanceState)
         NextcloudTalkApplication.sharedApplication!!.componentApplication.inject(this)
         NextcloudTalkApplication.sharedApplication!!.componentApplication.inject(this)
 
 
-        binding = ControllerConversationsRvBinding.inflate(layoutInflater)
+        binding = ActivityConversationsBinding.inflate(layoutInflater)
         setupActionBar()
         setupActionBar()
         setContentView(binding.root)
         setContentView(binding.root)
         setupSystemColors()
         setupSystemColors()
@@ -740,11 +744,20 @@ class ConversationsListActivity :
                 }
                 }
             }
             }
 
 
+            if (resources!!.getBoolean(R.bool.multiaccount_support)) {
+                dialogBuilder.setNeutralButton(R.string.nc_account_chooser_add_account) { _, _ ->
+                    val intent = Intent(this, ServerSelectionActivity::class.java)
+                    intent.putExtra(ADD_ADDITIONAL_ACCOUNT, true)
+                    startActivity(intent)
+                }
+            }
+
             viewThemeUtils.dialog.colorMaterialAlertDialogBackground(it.context, dialogBuilder)
             viewThemeUtils.dialog.colorMaterialAlertDialogBackground(it.context, dialogBuilder)
             val dialog = dialogBuilder.show()
             val dialog = dialogBuilder.show()
             viewThemeUtils.platform.colorTextButtons(
             viewThemeUtils.platform.colorTextButtons(
                 dialog.getButton(AlertDialog.BUTTON_POSITIVE),
                 dialog.getButton(AlertDialog.BUTTON_POSITIVE),
-                dialog.getButton(AlertDialog.BUTTON_NEGATIVE)
+                dialog.getButton(AlertDialog.BUTTON_NEGATIVE),
+                dialog.getButton(AlertDialog.BUTTON_NEUTRAL)
             )
             )
         }
         }
     }
     }
@@ -819,10 +832,10 @@ class ConversationsListActivity :
     @SuppressLint("ClickableViewAccessibility")
     @SuppressLint("ClickableViewAccessibility")
     private fun prepareViews() {
     private fun prepareViews() {
         layoutManager = SmoothScrollLinearLayoutManager(this)
         layoutManager = SmoothScrollLinearLayoutManager(this)
-        binding?.recyclerView?.layoutManager = layoutManager
-        binding?.recyclerView?.setHasFixedSize(true)
-        binding?.recyclerView?.adapter = adapter
-        binding?.recyclerView?.addOnScrollListener(object : RecyclerView.OnScrollListener() {
+        binding.recyclerView.layoutManager = layoutManager
+        binding.recyclerView.setHasFixedSize(true)
+        binding.recyclerView.adapter = adapter
+        binding.recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
             override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
             override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
                 super.onScrollStateChanged(recyclerView, newState)
                 super.onScrollStateChanged(recyclerView, newState)
                 if (newState == RecyclerView.SCROLL_STATE_IDLE) {
                 if (newState == RecyclerView.SCROLL_STATE_IDLE) {
@@ -1131,7 +1144,7 @@ class ConversationsListActivity :
                     selectedConversation!!.displayName
                     selectedConversation!!.displayName
                 )
                 )
             }
             }
-            binding?.floatingActionButton?.let {
+            binding.floatingActionButton.let {
                 val dialogBuilder = MaterialAlertDialogBuilder(it.context)
                 val dialogBuilder = MaterialAlertDialogBuilder(it.context)
                     .setIcon(viewThemeUtils.dialog.colorMaterialAlertDialogIcon(context, R.drawable.upload))
                     .setIcon(viewThemeUtils.dialog.colorMaterialAlertDialogIcon(context, R.drawable.upload))
                     .setTitle(confirmationQuestion)
                     .setTitle(confirmationQuestion)
@@ -1358,30 +1371,17 @@ class ConversationsListActivity :
                 .setTitle(R.string.nc_dialog_invalid_password)
                 .setTitle(R.string.nc_dialog_invalid_password)
                 .setMessage(R.string.nc_dialog_reauth_or_delete)
                 .setMessage(R.string.nc_dialog_reauth_or_delete)
                 .setCancelable(false)
                 .setCancelable(false)
-                .setPositiveButton(R.string.nc_delete) { _, _ ->
-                    val otherUserExists = userManager
-                        .scheduleUserForDeletionWithId(currentUser!!.id!!)
-                        .blockingGet()
-                    val accountRemovalWork = OneTimeWorkRequest.Builder(AccountRemovalWorker::class.java).build()
-                    WorkManager.getInstance().enqueue(accountRemovalWork)
-                    if (otherUserExists) {
-                        finish()
-                        startActivity(intent)
-                    } else if (!otherUserExists) {
-                        Log.d(TAG, "No other users found. AccountRemovalWorker will restart the app.")
-                    }
+                .setPositiveButton(R.string.nc_settings_remove_account) { _, _ ->
+                    deleteUserAndRestartApp()
+                }
+                .setNegativeButton(R.string.nc_settings_reauthorize) { _, _ ->
+                    val intent = Intent(context, WebViewLoginActivity::class.java)
+                    val bundle = Bundle()
+                    bundle.putString(BundleKeys.KEY_BASE_URL, currentUser!!.baseUrl)
+                    bundle.putBoolean(BundleKeys.KEY_REAUTHORIZE_ACCOUNT, true)
+                    intent.putExtras(bundle)
+                    startActivity(intent)
                 }
                 }
-
-            // TODO: show negative button again when conductor is removed
-            // .setNegativeButton(R.string.nc_settings_reauthorize) { _, _ ->
-            //     // router.pushController(
-            //     //     RouterTransaction.with(
-            //     //         WebViewLoginController(currentUser!!.baseUrl, true)
-            //     //     )
-            //     //         .pushChangeHandler(VerticalChangeHandler())
-            //     //         .popChangeHandler(VerticalChangeHandler())
-            //     // )
-            // }
 
 
             viewThemeUtils.dialog.colorMaterialAlertDialogBackground(it.context, dialogBuilder)
             viewThemeUtils.dialog.colorMaterialAlertDialogBackground(it.context, dialogBuilder)
             val dialog = dialogBuilder.show()
             val dialog = dialogBuilder.show()
@@ -1392,6 +1392,50 @@ class ConversationsListActivity :
         }
         }
     }
     }
 
 
+    @SuppressLint("CheckResult")
+    private fun deleteUserAndRestartApp() {
+        userManager.scheduleUserForDeletionWithId(currentUser!!.id!!).blockingGet()
+        val accountRemovalWork = OneTimeWorkRequest.Builder(AccountRemovalWorker::class.java).build()
+        WorkManager.getInstance(applicationContext).enqueue(accountRemovalWork)
+
+        WorkManager.getInstance(context).getWorkInfoByIdLiveData(accountRemovalWork.id)
+            .observeForever { workInfo: WorkInfo ->
+
+                when (workInfo.state) {
+                    WorkInfo.State.SUCCEEDED -> {
+                        val text = String.format(
+                            context.resources.getString(R.string.nc_deleted_user),
+                            currentUser!!.displayName
+                        )
+                        Toast.makeText(
+                            context,
+                            text,
+                            Toast.LENGTH_LONG
+                        ).show()
+                        restartApp()
+                    }
+
+                    WorkInfo.State.FAILED, WorkInfo.State.CANCELLED -> {
+                        Toast.makeText(
+                            context,
+                            context.resources.getString(R.string.nc_common_error_sorry),
+                            Toast.LENGTH_LONG
+                        ).show()
+                        Log.e(TAG, "something went wrong when deleting user with id " + currentUser!!.userId)
+                        restartApp()
+                    }
+
+                    else -> {}
+                }
+            }
+    }
+
+    private fun restartApp() {
+        val intent = Intent(context, MainActivity::class.java)
+        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
+        startActivity(intent)
+    }
+
     private fun showOutdatedClientDialog() {
     private fun showOutdatedClientDialog() {
         binding.floatingActionButton.let {
         binding.floatingActionButton.let {
             val dialogBuilder = MaterialAlertDialogBuilder(it.context)
             val dialogBuilder = MaterialAlertDialogBuilder(it.context)
@@ -1423,11 +1467,20 @@ class ConversationsListActivity :
                 }
                 }
             }
             }
 
 
+            if (resources!!.getBoolean(R.bool.multiaccount_support)) {
+                dialogBuilder.setNeutralButton(R.string.nc_account_chooser_add_account) { _, _ ->
+                    val intent = Intent(this, ServerSelectionActivity::class.java)
+                    intent.putExtra(ADD_ADDITIONAL_ACCOUNT, true)
+                    startActivity(intent)
+                }
+            }
+
             viewThemeUtils.dialog.colorMaterialAlertDialogBackground(it.context, dialogBuilder)
             viewThemeUtils.dialog.colorMaterialAlertDialogBackground(it.context, dialogBuilder)
             val dialog = dialogBuilder.show()
             val dialog = dialogBuilder.show()
             viewThemeUtils.platform.colorTextButtons(
             viewThemeUtils.platform.colorTextButtons(
                 dialog.getButton(AlertDialog.BUTTON_POSITIVE),
                 dialog.getButton(AlertDialog.BUTTON_POSITIVE),
-                dialog.getButton(AlertDialog.BUTTON_NEGATIVE)
+                dialog.getButton(AlertDialog.BUTTON_NEGATIVE),
+                dialog.getButton(AlertDialog.BUTTON_NEUTRAL)
             )
             )
         }
         }
     }
     }
@@ -1445,23 +1498,31 @@ class ConversationsListActivity :
                     .setTitle(R.string.nc_dialog_maintenance_mode)
                     .setTitle(R.string.nc_dialog_maintenance_mode)
                     .setMessage(R.string.nc_dialog_maintenance_mode_description)
                     .setMessage(R.string.nc_dialog_maintenance_mode_description)
                     .setCancelable(false)
                     .setCancelable(false)
+                    .setNegativeButton(R.string.nc_settings_remove_account) { _, _ ->
+                        deleteUserAndRestartApp()
+                    }
 
 
                 if (resources!!.getBoolean(R.bool.multiaccount_support) && userManager.users.blockingGet().size > 1) {
                 if (resources!!.getBoolean(R.bool.multiaccount_support) && userManager.users.blockingGet().size > 1) {
                     dialogBuilder.setPositiveButton(R.string.nc_switch_account) { _, _ ->
                     dialogBuilder.setPositiveButton(R.string.nc_switch_account) { _, _ ->
                         val newFragment: DialogFragment = ChooseAccountDialogFragment.newInstance()
                         val newFragment: DialogFragment = ChooseAccountDialogFragment.newInstance()
                         newFragment.show(supportFragmentManager, ChooseAccountDialogFragment.TAG)
                         newFragment.show(supportFragmentManager, ChooseAccountDialogFragment.TAG)
                     }
                     }
-                } else {
-                    dialogBuilder.setPositiveButton(R.string.nc_close_app) { _, _ ->
-                        finishAffinity()
-                        finish()
+                }
+
+                if (resources!!.getBoolean(R.bool.multiaccount_support)) {
+                    dialogBuilder.setNeutralButton(R.string.nc_account_chooser_add_account) { _, _ ->
+                        val intent = Intent(this, ServerSelectionActivity::class.java)
+                        intent.putExtra(ADD_ADDITIONAL_ACCOUNT, true)
+                        startActivity(intent)
                     }
                     }
                 }
                 }
 
 
                 viewThemeUtils.dialog.colorMaterialAlertDialogBackground(it.context, dialogBuilder)
                 viewThemeUtils.dialog.colorMaterialAlertDialogBackground(it.context, dialogBuilder)
                 val dialog = dialogBuilder.show()
                 val dialog = dialogBuilder.show()
                 viewThemeUtils.platform.colorTextButtons(
                 viewThemeUtils.platform.colorTextButtons(
-                    dialog.getButton(AlertDialog.BUTTON_POSITIVE)
+                    dialog.getButton(AlertDialog.BUTTON_POSITIVE),
+                    dialog.getButton(AlertDialog.BUTTON_NEGATIVE),
+                    dialog.getButton(AlertDialog.BUTTON_NEUTRAL)
                 )
                 )
             }
             }
         } else {
         } else {
@@ -1470,55 +1531,41 @@ class ConversationsListActivity :
     }
     }
 
 
     private fun showServerEOLDialog() {
     private fun showServerEOLDialog() {
-        binding?.floatingActionButton?.let {
+        binding.floatingActionButton.let {
             val dialogBuilder = MaterialAlertDialogBuilder(it.context)
             val dialogBuilder = MaterialAlertDialogBuilder(it.context)
                 .setIcon(viewThemeUtils.dialog.colorMaterialAlertDialogIcon(context, R.drawable.ic_warning_white))
                 .setIcon(viewThemeUtils.dialog.colorMaterialAlertDialogIcon(context, R.drawable.ic_warning_white))
                 .setTitle(R.string.nc_settings_server_eol_title)
                 .setTitle(R.string.nc_settings_server_eol_title)
                 .setMessage(R.string.nc_settings_server_eol)
                 .setMessage(R.string.nc_settings_server_eol)
                 .setCancelable(false)
                 .setCancelable(false)
                 .setPositiveButton(R.string.nc_settings_remove_account) { _, _ ->
                 .setPositiveButton(R.string.nc_settings_remove_account) { _, _ ->
-                    val otherUserExists = userManager
-                        .scheduleUserForDeletionWithId(currentUser!!.id!!)
-                        .blockingGet()
-                    val accountRemovalWork = OneTimeWorkRequest.Builder(AccountRemovalWorker::class.java).build()
-                    WorkManager.getInstance().enqueue(accountRemovalWork)
-                    if (otherUserExists) {
-                        finish()
-                        startActivity(intent)
-                    } else if (!otherUserExists) {
-                        restartApp(this)
-                    }
+                    deleteUserAndRestartApp()
                 }
                 }
-                .setNegativeButton(R.string.nc_cancel) { _, _ ->
-                    if (userManager.users.blockingGet().isNotEmpty()) {
-                        // TODO show SwitchAccount screen again when conductor is removed instead to close app
-                        // router.pushController(RouterTransaction.with(SwitchAccountController()))
-                        finishAffinity()
-                        finish()
-                    } else {
-                        finishAffinity()
-                        finish()
-                    }
+
+            if (resources!!.getBoolean(R.bool.multiaccount_support) && userManager.users.blockingGet().size > 1) {
+                dialogBuilder.setNegativeButton(R.string.nc_switch_account) { _, _ ->
+                    val newFragment: DialogFragment = ChooseAccountDialogFragment.newInstance()
+                    newFragment.show(supportFragmentManager, ChooseAccountDialogFragment.TAG)
                 }
                 }
+            }
+
+            if (resources!!.getBoolean(R.bool.multiaccount_support)) {
+                dialogBuilder.setNeutralButton(R.string.nc_account_chooser_add_account) { _, _ ->
+                    val intent = Intent(this, ServerSelectionActivity::class.java)
+                    intent.putExtra(ADD_ADDITIONAL_ACCOUNT, true)
+                    startActivity(intent)
+                }
+            }
 
 
             viewThemeUtils.dialog.colorMaterialAlertDialogBackground(it.context, dialogBuilder)
             viewThemeUtils.dialog.colorMaterialAlertDialogBackground(it.context, dialogBuilder)
             val dialog = dialogBuilder.show()
             val dialog = dialogBuilder.show()
             viewThemeUtils.platform.colorTextButtons(
             viewThemeUtils.platform.colorTextButtons(
                 dialog.getButton(AlertDialog.BUTTON_POSITIVE),
                 dialog.getButton(AlertDialog.BUTTON_POSITIVE),
-                dialog.getButton(AlertDialog.BUTTON_NEGATIVE)
+                dialog.getButton(AlertDialog.BUTTON_NEGATIVE),
+                dialog.getButton(AlertDialog.BUTTON_NEUTRAL)
             )
             )
         }
         }
     }
     }
 
 
-    fun restartApp(context: Context) {
-        val packageManager = context.packageManager
-        val intent = packageManager.getLaunchIntentForPackage(context.packageName)
-        val componentName = intent!!.component
-        val mainIntent = Intent.makeRestartActivityTask(componentName)
-        context.startActivity(mainIntent)
-        Runtime.getRuntime().exit(0)
-    }
-
     private fun deleteConversation(conversation: Conversation) {
     private fun deleteConversation(conversation: Conversation) {
         val data = Data.Builder()
         val data = Data.Builder()
         data.putLong(
         data.putLong(
@@ -1613,10 +1660,10 @@ class ConversationsListActivity :
     }
     }
 
 
     companion object {
     companion object {
-        const val TAG = "ConvListController"
+        private val TAG = ConversationsListActivity::class.java.simpleName
         const val UNREAD_BUBBLE_DELAY = 2500
         const val UNREAD_BUBBLE_DELAY = 2500
         const val BOTTOM_SHEET_DELAY: Long = 2500
         const val BOTTOM_SHEET_DELAY: Long = 2500
-        private const val KEY_SEARCH_QUERY = "ContactsController.searchQuery"
+        private const val KEY_SEARCH_QUERY = "ConversationsListActivity.searchQuery"
         const val SEARCH_DEBOUNCE_INTERVAL_MS = 300
         const val SEARCH_DEBOUNCE_INTERVAL_MS = 300
         const val SEARCH_MIN_CHARS = 2
         const val SEARCH_MIN_CHARS = 2
         const val HTTP_UNAUTHORIZED = 401
         const val HTTP_UNAUTHORIZED = 401

+ 0 - 15
app/src/main/java/com/nextcloud/talk/jobs/AccountRemovalWorker.java

@@ -23,10 +23,7 @@
 package com.nextcloud.talk.jobs;
 package com.nextcloud.talk.jobs;
 
 
 import android.app.NotificationManager;
 import android.app.NotificationManager;
-import android.content.ComponentName;
 import android.content.Context;
 import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
 import android.os.Build;
 import android.os.Build;
 import android.util.Log;
 import android.util.Log;
 
 
@@ -212,17 +209,5 @@ public class AccountRemovalWorker extends Worker {
                 Log.e(TAG, "error while trying to delete user", e);
                 Log.e(TAG, "error while trying to delete user", e);
             }
             }
         }
         }
-        if (userManager.getUsers().blockingGet().isEmpty()) {
-            restartApp(getApplicationContext());
-        }
-    }
-
-    public static void restartApp(Context context) {
-        PackageManager packageManager = context.getPackageManager();
-        Intent intent = packageManager.getLaunchIntentForPackage(context.getPackageName());
-        ComponentName componentName = intent.getComponent();
-        Intent mainIntent = Intent.makeRestartActivityTask(componentName);
-        context.startActivity(mainIntent);
-        Runtime.getRuntime().exit(0);
     }
     }
 }
 }

+ 1 - 1
app/src/main/java/com/nextcloud/talk/location/GeocodingActivity.kt

@@ -121,7 +121,7 @@ class GeocodingActivity :
         if (viewModel.getQuery().isNotEmpty() && adapter.itemCount == 0) {
         if (viewModel.getQuery().isNotEmpty() && adapter.itemCount == 0) {
             viewModel.searchLocation()
             viewModel.searchLocation()
         } else {
         } else {
-            Log.e(TAG, "search string that was passed to GeocodingController was null or empty")
+            Log.e(TAG, "search string that was passed to GeocodingActivity was null or empty")
         }
         }
         adapter.setOnItemClickListener(object : GeocodingAdapter.OnItemClickListener {
         adapter.setOnItemClickListener(object : GeocodingAdapter.OnItemClickListener {
             override fun onItemClick(position: Int) {
             override fun onItemClick(position: Int) {

+ 9 - 9
app/src/main/java/com/nextcloud/talk/profile/ProfileActivity.kt

@@ -608,7 +608,7 @@ class ProfileActivity : BaseActivity() {
     class UserInfoAdapter(
     class UserInfoAdapter(
         displayList: List<UserInfoDetailsItem>?,
         displayList: List<UserInfoDetailsItem>?,
         private val viewThemeUtils: ViewThemeUtils,
         private val viewThemeUtils: ViewThemeUtils,
-        private val controller: ProfileActivity
+        private val profileActivity: ProfileActivity
     ) : RecyclerView.Adapter<UserInfoAdapter.ViewHolder>() {
     ) : RecyclerView.Adapter<UserInfoAdapter.ViewHolder>() {
         var displayList: List<UserInfoDetailsItem>?
         var displayList: List<UserInfoDetailsItem>?
         var filteredDisplayList: MutableList<UserInfoDetailsItem> = LinkedList()
         var filteredDisplayList: MutableList<UserInfoDetailsItem> = LinkedList()
@@ -643,7 +643,7 @@ class ProfileActivity : BaseActivity() {
         }
         }
 
 
         override fun onBindViewHolder(holder: ViewHolder, position: Int) {
         override fun onBindViewHolder(holder: ViewHolder, position: Int) {
-            val item: UserInfoDetailsItem = if (controller.edit) {
+            val item: UserInfoDetailsItem = if (profileActivity.edit) {
                 displayList!![position]
                 displayList!![position]
             } else {
             } else {
                 filteredDisplayList[position]
                 filteredDisplayList[position]
@@ -656,11 +656,11 @@ class ProfileActivity : BaseActivity() {
 
 
             holder.binding.icon.contentDescription = item.hint
             holder.binding.icon.contentDescription = item.hint
             viewThemeUtils.platform.colorImageView(holder.binding.icon, ColorRole.PRIMARY)
             viewThemeUtils.platform.colorImageView(holder.binding.icon, ColorRole.PRIMARY)
-            if (!TextUtils.isEmpty(item.text) || controller.edit) {
+            if (!TextUtils.isEmpty(item.text) || profileActivity.edit) {
                 holder.binding.userInfoDetailContainer.visibility = View.VISIBLE
                 holder.binding.userInfoDetailContainer.visibility = View.VISIBLE
-                controller.viewThemeUtils.material.colorTextInputLayout(holder.binding.userInfoInputLayout)
-                if (controller.edit &&
-                    controller.editableFields.contains(item.field.toString().lowercase())
+                profileActivity.viewThemeUtils.material.colorTextInputLayout(holder.binding.userInfoInputLayout)
+                if (profileActivity.edit &&
+                    profileActivity.editableFields.contains(item.field.toString().lowercase())
                 ) {
                 ) {
                     holder.binding.userInfoEditTextEdit.isEnabled = true
                     holder.binding.userInfoEditTextEdit.isEnabled = true
                     holder.binding.userInfoEditTextEdit.isFocusableInTouchMode = true
                     holder.binding.userInfoEditTextEdit.isFocusableInTouchMode = true
@@ -700,7 +700,7 @@ class ProfileActivity : BaseActivity() {
                 }
                 }
 
 
                 override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
                 override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
-                    if (controller.edit) {
+                    if (profileActivity.edit) {
                         displayList!![holder.adapterPosition].text = holder.binding.userInfoEditTextEdit.text.toString()
                         displayList!![holder.adapterPosition].text = holder.binding.userInfoEditTextEdit.text.toString()
                     } else {
                     } else {
                         filteredDisplayList[holder.adapterPosition].text =
                         filteredDisplayList[holder.adapterPosition].text =
@@ -739,7 +739,7 @@ class ProfileActivity : BaseActivity() {
         }
         }
 
 
         override fun getItemCount(): Int {
         override fun getItemCount(): Int {
-            return if (controller.edit) {
+            return if (profileActivity.edit) {
                 displayList!!.size
                 displayList!!.size
             } else {
             } else {
                 filteredDisplayList.size
                 filteredDisplayList.size
@@ -762,7 +762,7 @@ class ProfileActivity : BaseActivity() {
     }
     }
 
 
     companion object {
     companion object {
-        private const val TAG: String = "ProfileController"
+        private val TAG = ProfileActivity::class.java.simpleName
         private const val DEFAULT_CACHE_SIZE: Int = 20
         private const val DEFAULT_CACHE_SIZE: Int = 20
         private const val DEFAULT_RETRIES: Long = 3
         private const val DEFAULT_RETRIES: Long = 3
         private const val HIGH_EMPHASIS_ALPHA: Float = 0.87f
         private const val HIGH_EMPHASIS_ALPHA: Float = 0.87f

+ 0 - 2
app/src/main/java/com/nextcloud/talk/receivers/ShareRecordingToChatReceiver.kt

@@ -91,8 +91,6 @@ class ShareRecordingToChatReceiver : BroadcastReceiver() {
                     // However, as we are in a broadcast receiver, this needs a TaskStackBuilder
                     // However, as we are in a broadcast receiver, this needs a TaskStackBuilder
                     // combined with addNextIntentWithParentStack. For further reading, see
                     // combined with addNextIntentWithParentStack. For further reading, see
                     // https://developer.android.com/develop/ui/views/notifications/navigation#DirectEntry
                     // https://developer.android.com/develop/ui/views/notifications/navigation#DirectEntry
-                    // As we are using the conductor framework it might be hard the combine this or to keep an overview.
-                    // For this reason there is only a Snackbar for now until we got rid of conductor.
 
 
                     Snackbar.make(
                     Snackbar.make(
                         View(context),
                         View(context),

+ 42 - 9
app/src/main/java/com/nextcloud/talk/settings/SettingsActivity.kt

@@ -27,6 +27,7 @@ package com.nextcloud.talk.settings
 
 
 import android.animation.Animator
 import android.animation.Animator
 import android.animation.AnimatorListenerAdapter
 import android.animation.AnimatorListenerAdapter
+import android.annotation.SuppressLint
 import android.app.KeyguardManager
 import android.app.KeyguardManager
 import android.content.Context
 import android.content.Context
 import android.content.DialogInterface
 import android.content.DialogInterface
@@ -51,6 +52,7 @@ import android.view.View
 import android.view.WindowManager
 import android.view.WindowManager
 import android.widget.EditText
 import android.widget.EditText
 import android.widget.LinearLayout
 import android.widget.LinearLayout
+import android.widget.Toast
 import androidx.appcompat.app.AlertDialog
 import androidx.appcompat.app.AlertDialog
 import androidx.appcompat.view.ContextThemeWrapper
 import androidx.appcompat.view.ContextThemeWrapper
 import androidx.core.content.ContextCompat
 import androidx.core.content.ContextCompat
@@ -66,6 +68,7 @@ import com.nextcloud.android.common.ui.theme.utils.ColorRole
 import com.nextcloud.talk.BuildConfig
 import com.nextcloud.talk.BuildConfig
 import com.nextcloud.talk.R
 import com.nextcloud.talk.R
 import com.nextcloud.talk.activities.BaseActivity
 import com.nextcloud.talk.activities.BaseActivity
+import com.nextcloud.talk.activities.MainActivity
 import com.nextcloud.talk.api.NcApi
 import com.nextcloud.talk.api.NcApi
 import com.nextcloud.talk.application.NextcloudTalkApplication
 import com.nextcloud.talk.application.NextcloudTalkApplication
 import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.setAppTheme
 import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.setAppTheme
@@ -465,17 +468,47 @@ class SettingsActivity : BaseActivity() {
         }
         }
     }
     }
 
 
+    @SuppressLint("CheckResult")
     private fun removeCurrentAccount() {
     private fun removeCurrentAccount() {
-        val otherUserExists = userManager.scheduleUserForDeletionWithId(currentUser!!.id!!).blockingGet()
+        userManager.scheduleUserForDeletionWithId(currentUser!!.id!!).blockingGet()
         val accountRemovalWork = OneTimeWorkRequest.Builder(AccountRemovalWorker::class.java).build()
         val accountRemovalWork = OneTimeWorkRequest.Builder(AccountRemovalWorker::class.java).build()
         WorkManager.getInstance(applicationContext).enqueue(accountRemovalWork)
         WorkManager.getInstance(applicationContext).enqueue(accountRemovalWork)
-        if (otherUserExists) {
-            // TODO: find better solution once Conductor is removed
-            finish()
-            startActivity(intent)
-        } else if (!otherUserExists) {
-            Log.d(TAG, "No other users found. AccountRemovalWorker will restart the app.")
-        }
+
+        WorkManager.getInstance(context).getWorkInfoByIdLiveData(accountRemovalWork.id)
+            .observeForever { workInfo: WorkInfo ->
+
+                when (workInfo.state) {
+                    WorkInfo.State.SUCCEEDED -> {
+                        val text = String.format(
+                            context.resources.getString(R.string.nc_deleted_user),
+                            currentUser!!.displayName
+                        )
+                        Toast.makeText(
+                            context,
+                            text,
+                            Toast.LENGTH_LONG
+                        ).show()
+                        restartApp()
+                    }
+                    WorkInfo.State.FAILED, WorkInfo.State.CANCELLED -> {
+                        Toast.makeText(
+                            context,
+                            context.resources.getString(R.string.nc_common_error_sorry),
+                            Toast.LENGTH_LONG
+                        ).show()
+                        Log.e(TAG, "something went wrong when deleting user with id " + currentUser!!.userId)
+                        restartApp()
+                    }
+
+                    else -> {}
+                }
+            }
+    }
+
+    private fun restartApp() {
+        val intent = Intent(context, MainActivity::class.java)
+        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
+        startActivity(intent)
     }
     }
 
 
     private fun getRingtoneName(context: Context, ringtoneUri: Uri?): String {
     private fun getRingtoneName(context: Context, ringtoneUri: Uri?): String {
@@ -1205,7 +1238,7 @@ class SettingsActivity : BaseActivity() {
     }
     }
 
 
     companion object {
     companion object {
-        private const val TAG = "SettingsController"
+        private val TAG = SettingsActivity::class.java.simpleName
         private const val DURATION: Long = 2500
         private const val DURATION: Long = 2500
         private const val START_DELAY: Long = 5000
         private const val START_DELAY: Long = 5000
         private const val DISABLED_ALPHA: Float = 0.38f
         private const val DISABLED_ALPHA: Float = 0.38f

+ 2 - 2
app/src/main/java/com/nextcloud/talk/ui/bottom/sheet/ProfileBottomSheet.kt

@@ -31,8 +31,8 @@ import com.afollestad.materialdialogs.bottomsheets.BottomSheet
 import com.nextcloud.talk.R
 import com.nextcloud.talk.R
 import com.nextcloud.talk.api.NcApi
 import com.nextcloud.talk.api.NcApi
 import com.nextcloud.talk.chat.ChatActivity
 import com.nextcloud.talk.chat.ChatActivity
-import com.nextcloud.talk.controllers.bottomsheet.items.BasicListItemWithImage
-import com.nextcloud.talk.controllers.bottomsheet.items.listItemsWithImage
+import com.nextcloud.talk.bottomsheet.items.BasicListItemWithImage
+import com.nextcloud.talk.bottomsheet.items.listItemsWithImage
 import com.nextcloud.talk.data.user.model.User
 import com.nextcloud.talk.data.user.model.User
 import com.nextcloud.talk.models.json.conversations.RoomOverall
 import com.nextcloud.talk.models.json.conversations.RoomOverall
 import com.nextcloud.talk.models.json.hovercard.HoverCardAction
 import com.nextcloud.talk.models.json.hovercard.HoverCardAction

+ 4 - 6
app/src/main/java/com/nextcloud/talk/ui/dialog/ChooseAccountDialogFragment.java

@@ -35,7 +35,7 @@ import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewGroup;
 
 
 import com.google.android.material.dialog.MaterialAlertDialogBuilder;
 import com.google.android.material.dialog.MaterialAlertDialogBuilder;
-import com.nextcloud.talk.activities.MainActivity;
+import com.nextcloud.talk.account.ServerSelectionActivity;
 import com.nextcloud.talk.adapters.items.AdvancedUserItem;
 import com.nextcloud.talk.adapters.items.AdvancedUserItem;
 import com.nextcloud.talk.api.NcApi;
 import com.nextcloud.talk.api.NcApi;
 import com.nextcloud.talk.application.NextcloudTalkApplication;
 import com.nextcloud.talk.application.NextcloudTalkApplication;
@@ -71,7 +71,7 @@ import io.reactivex.android.schedulers.AndroidSchedulers;
 import io.reactivex.disposables.Disposable;
 import io.reactivex.disposables.Disposable;
 import io.reactivex.schedulers.Schedulers;
 import io.reactivex.schedulers.Schedulers;
 
 
-import static com.nextcloud.talk.utils.bundle.BundleKeys.ADD_ACCOUNT;
+import static com.nextcloud.talk.utils.bundle.BundleKeys.ADD_ADDITIONAL_ACCOUNT;
 
 
 @AutoInjector(NextcloudTalkApplication.class)
 @AutoInjector(NextcloudTalkApplication.class)
 public class ChooseAccountDialogFragment extends DialogFragment {
 public class ChooseAccountDialogFragment extends DialogFragment {
@@ -185,11 +185,9 @@ public class ChooseAccountDialogFragment extends DialogFragment {
         // Creating listeners for quick-actions
         // Creating listeners for quick-actions
         binding.currentAccount.getRoot().setOnClickListener(v -> dismiss());
         binding.currentAccount.getRoot().setOnClickListener(v -> dismiss());
 
 
-
         binding.addAccount.setOnClickListener(v -> {
         binding.addAccount.setOnClickListener(v -> {
-            // TODO: change this when conductor is removed
-            Intent intent = new Intent(getContext(), MainActivity.class);
-            intent.putExtra(ADD_ACCOUNT, true);
+            Intent intent = new Intent(getContext(), ServerSelectionActivity.class);
+            intent.putExtra(ADD_ADDITIONAL_ACCOUNT, true);
             startActivity(intent);
             startActivity(intent);
             dismiss();
             dismiss();
         });
         });

+ 3 - 1
app/src/main/java/com/nextcloud/talk/utils/bundle/BundleKeys.kt

@@ -84,6 +84,8 @@ object BundleKeys {
     const val KEY_DISMISS_RECORDING_URL = "KEY_DISMISS_RECORDING_URL"
     const val KEY_DISMISS_RECORDING_URL = "KEY_DISMISS_RECORDING_URL"
     const val KEY_SHARE_RECORDING_TO_CHAT_URL = "KEY_SHARE_RECORDING_TO_CHAT_URL"
     const val KEY_SHARE_RECORDING_TO_CHAT_URL = "KEY_SHARE_RECORDING_TO_CHAT_URL"
     const val KEY_GEOCODING_RESULT = "KEY_GEOCODING_RESULT"
     const val KEY_GEOCODING_RESULT = "KEY_GEOCODING_RESULT"
-    const val ADD_ACCOUNT = "ADD_ACCOUNT" // temp workaround until conductor is removed
+    const val ADD_ADDITIONAL_ACCOUNT = "ADD_ADDITIONAL_ACCOUNT"
     const val SAVED_TRANSLATED_MESSAGE = "SAVED_TRANSLATED_MESSAGE"
     const val SAVED_TRANSLATED_MESSAGE = "SAVED_TRANSLATED_MESSAGE"
+    const val KEY_REAUTHORIZE_ACCOUNT = "KEY_REAUTHORIZE_ACCOUNT"
+    const val KEY_PASSWORD = "KEY_PASSWORD"
 }
 }

+ 1 - 1
app/src/main/java/com/nextcloud/talk/utils/singletons/ApplicationWideMessageHolder.java

@@ -39,7 +39,7 @@ public class ApplicationWideMessageHolder {
     }
     }
 
 
     public enum MessageType {
     public enum MessageType {
-        WRONG_ACCOUNT, ACCOUNT_UPDATED_NOT_ADDED, ACCOUNT_SCHEDULED_FOR_DELETION, SERVER_WITHOUT_TALK,
+        WRONG_ACCOUNT, ACCOUNT_UPDATED_NOT_ADDED, SERVER_WITHOUT_TALK,
         FAILED_TO_IMPORT_ACCOUNT, ACCOUNT_WAS_IMPORTED, CALL_PASSWORD_WRONG
         FAILED_TO_IMPORT_ACCOUNT, ACCOUNT_WAS_IMPORTED, CALL_PASSWORD_WRONG
     }
     }
 
 

+ 0 - 0
app/src/main/res/layout/controller_account_verification.xml → app/src/main/res/layout/activity_account_verification.xml


+ 1 - 1
app/src/main/res/layout/activity_chat.xml

@@ -234,7 +234,7 @@
                 android:id="@+id/separator_1"
                 android:id="@+id/separator_1"
                 android:layout_width="match_parent"
                 android:layout_width="match_parent"
                 android:layout_height="1dp"
                 android:layout_height="1dp"
-                android:background="@color/controller_chat_separator" />
+                android:background="@color/chat_separator" />
 
 
             <TextView
             <TextView
                 android:id="@+id/typing_indicator"
                 android:id="@+id/typing_indicator"

+ 11 - 3
app/src/main/res/layout/activity_contacts.xml

@@ -178,7 +178,15 @@
             android:textAppearance="@style/ListItem" />
             android:textAppearance="@style/ListItem" />
     </RelativeLayout>
     </RelativeLayout>
 
 
-    <include
-        android:id="@+id/controller_generic_rv"
-        layout="@layout/controller_generic_rv" />
+    <RelativeLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical">
+
+        <androidx.recyclerview.widget.RecyclerView
+            android:id="@+id/contacts_rv"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            app:layout_anchorGravity="center" />
+    </RelativeLayout>
 </LinearLayout>
 </LinearLayout>

+ 0 - 0
app/src/main/res/layout/controller_conversations_rv.xml → app/src/main/res/layout/activity_conversations.xml


+ 0 - 9
app/src/main/res/layout/activity_main.xml

@@ -40,8 +40,6 @@
         android:windowContentOverlay="@null"
         android:windowContentOverlay="@null"
         app:elevation="0dp">
         app:elevation="0dp">
 
 
-
-
         <com.google.android.material.appbar.MaterialToolbar
         <com.google.android.material.appbar.MaterialToolbar
             android:id="@+id/toolbar"
             android:id="@+id/toolbar"
             android:layout_width="match_parent"
             android:layout_width="match_parent"
@@ -58,11 +56,4 @@
 
 
     </com.google.android.material.appbar.AppBarLayout>
     </com.google.android.material.appbar.AppBarLayout>
 
 
-    <com.bluelinelabs.conductor.ChangeHandlerFrameLayout
-        android:id="@+id/controller_container"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:background="@color/bg_default"
-        app:layout_behavior="@string/appbar_scrolling_view_behavior" />
-
 </androidx.coordinatorlayout.widget.CoordinatorLayout>
 </androidx.coordinatorlayout.widget.CoordinatorLayout>

+ 0 - 0
app/src/main/res/layout/controller_server_selection.xml → app/src/main/res/layout/activity_server_selection.xml


+ 20 - 11
app/src/main/res/layout/controller_generic_rv.xml → app/src/main/res/layout/activity_switch_account.xml

@@ -18,25 +18,34 @@
   ~ along with this program.  If not, see <http://www.gnu.org/licenses/>.
   ~ along with this program.  If not, see <http://www.gnu.org/licenses/>.
   -->
   -->
 
 
-<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     xmlns:tools="http://schemas.android.com/tools"
     xmlns:tools="http://schemas.android.com/tools"
-    android:id="@+id/generic_rv_layout"
     android:layout_width="match_parent"
     android:layout_width="match_parent"
-    android:layout_height="match_parent">
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+    android:animateLayoutChanges="true">
 
 
-    <androidx.swiperefreshlayout.widget.SwipeRefreshLayout
-        android:id="@+id/swipe_refresh_layout"
+    <com.google.android.material.appbar.AppBarLayout
+        android:id="@+id/appBar"
         android:layout_width="match_parent"
         android:layout_width="match_parent"
-        android:layout_height="match_parent">
+        android:layout_height="wrap_content">
 
 
-        <FrameLayout
+        <com.google.android.material.appbar.MaterialToolbar
+            android:id="@+id/toolbar"
             android:layout_width="match_parent"
             android:layout_width="match_parent"
-            android:layout_height="match_parent">
+            android:layout_height="?attr/actionBarSize"
+            android:background="@color/appbar"
+            android:theme="?attr/actionBarPopupTheme"
+            app:layout_scrollFlags="enterAlwaysCollapsed|noScroll"
+            app:navigationIconTint="@color/fontAppbar"
+            app:popupTheme="@style/appActionBarPopupMenu"
+            app:titleTextColor="@color/fontAppbar"
+            tools:title="@string/nc_select_an_account">
 
 
-        </FrameLayout>
+        </com.google.android.material.appbar.MaterialToolbar>
 
 
-    </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
+    </com.google.android.material.appbar.AppBarLayout>
 
 
     <androidx.recyclerview.widget.RecyclerView
     <androidx.recyclerview.widget.RecyclerView
         android:id="@+id/recycler_view"
         android:id="@+id/recycler_view"
@@ -44,4 +53,4 @@
         android:layout_height="match_parent"
         android:layout_height="match_parent"
         app:layout_anchor="@+id/swipe_refresh_layout"
         app:layout_anchor="@+id/swipe_refresh_layout"
         app:layout_anchorGravity="center" />
         app:layout_anchorGravity="center" />
-</androidx.coordinatorlayout.widget.CoordinatorLayout>
+</LinearLayout>

+ 0 - 0
app/src/main/res/layout/controller_web_view_login.xml → app/src/main/res/layout/activity_web_view_login.xml


+ 2 - 2
app/src/main/res/layout/call_activity.xml

@@ -28,7 +28,7 @@
 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     xmlns:tools="http://schemas.android.com/tools"
     xmlns:tools="http://schemas.android.com/tools"
-    android:id="@+id/controllerCallLayout"
+    android:id="@+id/callLayout"
     android:layout_width="match_parent"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:layout_height="match_parent"
     android:fitsSystemWindows="true"
     android:fitsSystemWindows="true"
@@ -128,7 +128,7 @@
                     android:layout_width="match_parent"
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
                     android:layout_height="wrap_content"
                     android:textAlignment="center"
                     android:textAlignment="center"
-                    android:textColor="@color/controller_call_incomingCallTextView"
+                    android:textColor="@color/call_incomingCallTextView"
                     android:textSize="16sp"
                     android:textSize="16sp"
                     app:layout_constraintEnd_toEndOf="parent"
                     app:layout_constraintEnd_toEndOf="parent"
                     app:layout_constraintStart_toStartOf="parent"
                     app:layout_constraintStart_toStartOf="parent"

+ 3 - 3
app/src/main/res/layout/call_notification_activity.xml

@@ -24,7 +24,7 @@
 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     xmlns:tools="http://schemas.android.com/tools"
     xmlns:tools="http://schemas.android.com/tools"
-    android:id="@+id/controllerCallNotificationLayout"
+    android:id="@+id/callNotificationLayout"
     android:layout_width="match_parent"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:layout_height="match_parent"
     android:background="@color/grey950">
     android:background="@color/grey950">
@@ -83,7 +83,7 @@
             android:layout_marginTop="16dp"
             android:layout_marginTop="16dp"
             android:text="@string/nc_call_unknown"
             android:text="@string/nc_call_unknown"
             android:textAlignment="center"
             android:textAlignment="center"
-            android:textColor="@color/controller_call_incomingCallTextView"
+            android:textColor="@color/call_incomingCallTextView"
             android:textSize="16sp"
             android:textSize="16sp"
             app:layout_constraintEnd_toEndOf="parent"
             app:layout_constraintEnd_toEndOf="parent"
             app:layout_constraintStart_toStartOf="parent"
             app:layout_constraintStart_toStartOf="parent"
@@ -109,7 +109,7 @@
             android:layout_below="@+id/conversationNameTextView"
             android:layout_below="@+id/conversationNameTextView"
             android:text="@string/nc_call_incoming"
             android:text="@string/nc_call_incoming"
             android:textAlignment="center"
             android:textAlignment="center"
-            android:textColor="@color/controller_call_incomingCallTextView"
+            android:textColor="@color/call_incomingCallTextView"
             android:textSize="16sp" />
             android:textSize="16sp" />
 
 
     </RelativeLayout>
     </RelativeLayout>

+ 1 - 1
app/src/main/res/values-night/colors.xml

@@ -53,7 +53,7 @@
     <color name="conversation_unread_bubble">#373737</color>
     <color name="conversation_unread_bubble">#373737</color>
     <color name="conversation_unread_bubble_text">#D8D8D8</color>
     <color name="conversation_unread_bubble_text">#D8D8D8</color>
 
 
-    <color name="controller_chat_separator">#484848</color>
+    <color name="chat_separator">#484848</color>
 
 
     <color name="colorBackgroundDarker">#2C2C2C</color>
     <color name="colorBackgroundDarker">#2C2C2C</color>
 
 

+ 2 - 2
app/src/main/res/values/colors.xml

@@ -61,10 +61,10 @@
     <color name="nc_darkRed">#D32F2F</color>
     <color name="nc_darkRed">#D32F2F</color>
     <color name="nc_darkYellow">#FF9800</color>
     <color name="nc_darkYellow">#FF9800</color>
     <color name="nc_darkGreen">#006400</color>
     <color name="nc_darkGreen">#006400</color>
-    <color name="controller_chat_separator">#E8E8E8</color>
+    <color name="chat_separator">#E8E8E8</color>
     <color name="grey_600">#757575</color>
     <color name="grey_600">#757575</color>
     <color name="nc_grey">#D5D5D5</color>
     <color name="nc_grey">#D5D5D5</color>
-    <color name="controller_call_incomingCallTextView">#E9FFFFFF</color>
+    <color name="call_incomingCallTextView">#E9FFFFFF</color>
     <color name="grey950">#111111</color>
     <color name="grey950">#111111</color>
     <color name="textColorMaxContrast">#767676</color>
     <color name="textColorMaxContrast">#767676</color>
     <color name="colorBackgroundDarker">#DBDBDB</color>
     <color name="colorBackgroundDarker">#DBDBDB</color>

+ 1 - 1
app/src/main/res/values/setup.xml

@@ -35,7 +35,7 @@
 
 
     <!-- Branding -->
     <!-- Branding -->
     <bool name="hide_provider">false</bool>
     <bool name="hide_provider">false</bool>
-    <bool name="hide_auth_cert">false</bool>
+    <bool name="hide_auth_cert">true</bool>
     <bool name="multiaccount_support">true</bool>
     <bool name="multiaccount_support">true</bool>
     <string name="weblogin_url" translatable="false"></string>
     <string name="weblogin_url" translatable="false"></string>
 
 

+ 1 - 0
app/src/main/res/values/strings.xml

@@ -574,6 +574,7 @@ How to translate with transifex:
     <string name="filename_progress">%1$s (%2$d)</string>
     <string name="filename_progress">%1$s (%2$d)</string>
     <string name="nc_dialog_invalid_password">Invalid password</string>
     <string name="nc_dialog_invalid_password">Invalid password</string>
     <string name="nc_dialog_reauth_or_delete">Do you want to reauthorize or delete this account?</string>
     <string name="nc_dialog_reauth_or_delete">Do you want to reauthorize or delete this account?</string>
+    <string name="nc_deleted_user">User %1$s was removed</string>
 
 
     <string name="nc_dialog_outdated_client">App is outdated</string>
     <string name="nc_dialog_outdated_client">App is outdated</string>
     <string name="nc_dialog_outdated_client_description">The app is too old and no longer supported by this server. Please update.</string>
     <string name="nc_dialog_outdated_client_description">The app is too old and no longer supported by this server. Please update.</string>

+ 1 - 1
app/src/test/java/com/nextcloud/talk/utils/BundleKeysTest.kt

@@ -97,7 +97,7 @@ class BundleKeysTest {
         assertEquals("KEY_DISMISS_RECORDING_URL", BundleKeys.KEY_DISMISS_RECORDING_URL)
         assertEquals("KEY_DISMISS_RECORDING_URL", BundleKeys.KEY_DISMISS_RECORDING_URL)
         assertEquals("KEY_SHARE_RECORDING_TO_CHAT_URL", BundleKeys.KEY_SHARE_RECORDING_TO_CHAT_URL)
         assertEquals("KEY_SHARE_RECORDING_TO_CHAT_URL", BundleKeys.KEY_SHARE_RECORDING_TO_CHAT_URL)
         assertEquals("KEY_GEOCODING_RESULT", BundleKeys.KEY_GEOCODING_RESULT)
         assertEquals("KEY_GEOCODING_RESULT", BundleKeys.KEY_GEOCODING_RESULT)
-        assertEquals("ADD_ACCOUNT", BundleKeys.ADD_ACCOUNT)
+        assertEquals("ADD_ADDITIONAL_ACCOUNT", BundleKeys.ADD_ADDITIONAL_ACCOUNT)
         assertEquals("SAVED_TRANSLATED_MESSAGE", BundleKeys.SAVED_TRANSLATED_MESSAGE)
         assertEquals("SAVED_TRANSLATED_MESSAGE", BundleKeys.SAVED_TRANSLATED_MESSAGE)
     }
     }
 }
 }