mirror of
https://github.com/nextcloud/talk-android.git
synced 2024-11-21 20:45:29 +03:00
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>
This commit is contained in:
parent
074fc301d6
commit
591d6dc3e8
49 changed files with 840 additions and 1410 deletions
|
@ -289,7 +289,6 @@ We are using [Dagger 2](https://dagger.dev/) to inject dependencies into major A
|
|||
|
||||
* `Activity`
|
||||
* `Fragment`
|
||||
* `Controller`
|
||||
* `Service`
|
||||
* `BroadcastReceiver`
|
||||
* `ContentProvider`
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* @author Tim Krüger
|
||||
* Copyright (C) 2021 Andy Scherzinger <info@andy-scherzinger.de>
|
||||
* 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>
|
||||
*
|
||||
* 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:rxjava:2.2.21"
|
||||
|
||||
implementation 'com.bluelinelabs:conductor:3.2.0'
|
||||
|
||||
implementation "com.squareup.okhttp3:okhttp:${okhttpVersion}"
|
||||
implementation "com.squareup.okhttp3:okhttp-urlconnection:${okhttpVersion}"
|
||||
implementation "com.squareup.okhttp3:logging-interceptor:${okhttpVersion}"
|
||||
|
|
|
@ -32,6 +32,5 @@
|
|||
|
||||
<issue id="ObsoleteLintCustomCheck" severity="warning">
|
||||
<ignore path="**/jetified-annotation-experimental-1.**/**/lint.jar" />
|
||||
<ignore path="**/jetified-conductor-2.**/**/lint.jar" />
|
||||
</issue>
|
||||
</lint>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
~ @author Mario Danic
|
||||
~ @author Marcel Hibbe
|
||||
~ 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
|
||||
~ it under the terms of the GNU General Public License as published by
|
||||
|
@ -131,6 +131,44 @@
|
|||
</intent-filter>
|
||||
</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
|
||||
android:name=".activities.CallActivity"
|
||||
android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"
|
||||
|
@ -215,32 +253,10 @@
|
|||
android:name=".contacts.ContactsActivity"
|
||||
android:theme="@style/AppTheme" />
|
||||
|
||||
<activity
|
||||
android:name=".chat.ChatActivity"
|
||||
android:theme="@style/AppTheme" />
|
||||
|
||||
<activity
|
||||
android:name=".openconversations.ListOpenConversationsActivity"
|
||||
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=".lock.LockedActivity"
|
||||
android:theme="@style/AppTheme" />
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
*
|
||||
* @author Mario Danic
|
||||
* @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) 2017 Mario Danic (mario@lovelyhq.com)
|
||||
*
|
||||
|
@ -19,7 +21,7 @@
|
|||
* 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
|
||||
package com.nextcloud.talk.account
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Intent
|
||||
|
@ -28,25 +30,24 @@ import android.os.Bundle
|
|||
import android.os.Handler
|
||||
import android.text.TextUtils
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import android.widget.Toast
|
||||
import androidx.work.Data
|
||||
import androidx.work.OneTimeWorkRequest
|
||||
import androidx.work.WorkInfo
|
||||
import androidx.work.WorkManager
|
||||
import autodagger.AutoInjector
|
||||
import com.bluelinelabs.conductor.RouterTransaction
|
||||
import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler
|
||||
import com.bluelinelabs.logansquare.LoganSquare
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import com.nextcloud.talk.R
|
||||
import com.nextcloud.talk.activities.BaseActivity
|
||||
import com.nextcloud.talk.api.NcApi
|
||||
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.conversationlist.ConversationsListActivity
|
||||
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.jobs.AccountRemovalWorker
|
||||
import com.nextcloud.talk.jobs.CapabilitiesWorker
|
||||
import com.nextcloud.talk.jobs.PushRegistrationWorker
|
||||
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_IS_ACCOUNT_IMPORT
|
||||
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_USERNAME
|
||||
import com.nextcloud.talk.utils.singletons.ApplicationWideMessageHolder
|
||||
|
@ -71,20 +73,15 @@ import io.reactivex.Observer
|
|||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.disposables.Disposable
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import org.greenrobot.eventbus.Subscribe
|
||||
import org.greenrobot.eventbus.ThreadMode
|
||||
import java.net.CookieManager
|
||||
import javax.inject.Inject
|
||||
|
||||
@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
|
||||
lateinit var ncApi: NcApi
|
||||
|
@ -95,9 +92,6 @@ class AccountVerificationController(args: Bundle? = null) : BaseController(
|
|||
@Inject
|
||||
lateinit var cookieManager: CookieManager
|
||||
|
||||
@Inject
|
||||
lateinit var eventBus: EventBus
|
||||
|
||||
private var internalAccountId: Long = -1
|
||||
private val disposables: MutableList<Disposable> = ArrayList()
|
||||
private var baseUrl: String? = null
|
||||
|
@ -106,43 +100,53 @@ class AccountVerificationController(args: Bundle? = null) : BaseController(
|
|||
private var isAccountImport = false
|
||||
private var originalProtocol: String? = null
|
||||
|
||||
override fun onAttach(view: View) {
|
||||
super.onAttach(view)
|
||||
eventBus.register(this)
|
||||
}
|
||||
|
||||
override fun onDetach(view: View) {
|
||||
super.onDetach(view)
|
||||
eventBus.unregister(this)
|
||||
}
|
||||
|
||||
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 = ActivityAccountVerificationBinding.inflate(layoutInflater)
|
||||
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
|
||||
setContentView(binding.root)
|
||||
actionBar?.hide()
|
||||
setupPrimaryColors()
|
||||
|
||||
handleIntent()
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
|
||||
if (
|
||||
isAccountImport &&
|
||||
!UriUtils.hasHttpProtocolPrefixed(baseUrl!!) ||
|
||||
isSameProtocol(baseUrl!!, originalProtocol!!)
|
||||
isNotSameProtocol(baseUrl!!, originalProtocol)
|
||||
) {
|
||||
determineBaseUrlProtocol(true)
|
||||
} 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)
|
||||
}
|
||||
|
||||
private fun checkEverything() {
|
||||
val credentials = ApiUtils.getCredentials(username, token)
|
||||
cookieManager.cookieStore.removeAll()
|
||||
findServerTalkApp(credentials)
|
||||
}
|
||||
|
||||
private fun determineBaseUrlProtocol(checkForcedHttps: Boolean) {
|
||||
cookieManager.cookieStore.removeAll()
|
||||
baseUrl = baseUrl!!.replace("http://", "").replace("https://", "")
|
||||
|
@ -166,20 +170,16 @@ class AccountVerificationController(args: Bundle? = null) : BaseController(
|
|||
"http://$baseUrl"
|
||||
}
|
||||
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 {
|
||||
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))
|
||||
.subscribeOn(Schedulers.io())
|
||||
.subscribe(object : Observer<CapabilitiesOverall> {
|
||||
|
@ -214,27 +217,24 @@ class AccountVerificationController(args: Bundle? = null) : BaseController(
|
|||
if (hasTalk) {
|
||||
fetchProfile(credentials, capabilitiesOverall)
|
||||
} else {
|
||||
if (activity != null && resources != null) {
|
||||
activity!!.runOnUiThread {
|
||||
binding?.progressText?.setText(
|
||||
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_app_product_name)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
ApplicationWideMessageHolder.getInstance().setMessageType(
|
||||
ApplicationWideMessageHolder.getInstance().messageType =
|
||||
ApplicationWideMessageHolder.MessageType.SERVER_WITHOUT_TALK
|
||||
)
|
||||
abortVerification()
|
||||
}
|
||||
}
|
||||
|
||||
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_app_product_name)
|
||||
)
|
||||
|
@ -263,7 +263,7 @@ class AccountVerificationController(args: Bundle? = null) : BaseController(
|
|||
displayName = displayName,
|
||||
pushConfigurationState = null,
|
||||
capabilities = LoganSquare.serialize(capabilities),
|
||||
certificateAlias = appPreferences!!.temporaryClientCertAlias,
|
||||
certificateAlias = appPreferences.temporaryClientCertAlias,
|
||||
externalSignalingServer = null
|
||||
)
|
||||
)
|
||||
|
@ -279,9 +279,9 @@ class AccountVerificationController(args: Bundle? = null) : BaseController(
|
|||
if (ClosedInterfaceImpl().isGooglePlayServicesAvailable) {
|
||||
registerForPush()
|
||||
} else {
|
||||
activity!!.runOnUiThread {
|
||||
binding?.progressText?.text =
|
||||
""" ${binding?.progressText?.text}
|
||||
runOnUiThread {
|
||||
binding.progressText.text =
|
||||
""" ${binding.progressText.text}
|
||||
${resources!!.getString(R.string.nc_push_disabled)}
|
||||
""".trimIndent()
|
||||
}
|
||||
|
@ -291,7 +291,7 @@ class AccountVerificationController(args: Bundle? = null) : BaseController(
|
|||
|
||||
@SuppressLint("SetTextI18n")
|
||||
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)
|
||||
abortVerification()
|
||||
}
|
||||
|
@ -328,30 +328,26 @@ class AccountVerificationController(args: Bundle? = null) : BaseController(
|
|||
capabilities.ocs!!.data!!.capabilities!!
|
||||
)
|
||||
} else {
|
||||
if (activity != null) {
|
||||
activity!!.runOnUiThread {
|
||||
binding?.progressText?.text =
|
||||
runOnUiThread {
|
||||
binding.progressText.text =
|
||||
"""
|
||||
${binding?.progressText?.text}
|
||||
${binding.progressText.text}
|
||||
${resources!!.getString(R.string.nc_display_name_not_fetched)}
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
abortVerification()
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
override fun onError(e: Throwable) {
|
||||
if (activity != null) {
|
||||
activity!!.runOnUiThread {
|
||||
binding?.progressText?.text =
|
||||
runOnUiThread {
|
||||
binding.progressText.text =
|
||||
"""
|
||||
${binding?.progressText?.text}
|
||||
${binding.progressText.text}
|
||||
${resources!!.getString(R.string.nc_display_name_not_fetched)}
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
abortVerification()
|
||||
}
|
||||
|
||||
|
@ -364,7 +360,7 @@ class AccountVerificationController(args: Bundle? = null) : BaseController(
|
|||
private fun registerForPush() {
|
||||
val data =
|
||||
Data.Builder()
|
||||
.putString(PushRegistrationWorker.ORIGIN, "AccountVerificationController#registerForPush")
|
||||
.putString(PushRegistrationWorker.ORIGIN, "AccountVerificationActivity#registerForPush")
|
||||
.build()
|
||||
val pushRegistrationWork =
|
||||
OneTimeWorkRequest.Builder(PushRegistrationWorker::class.java)
|
||||
|
@ -377,11 +373,11 @@ class AccountVerificationController(args: Bundle? = null) : BaseController(
|
|||
@Subscribe(threadMode = ThreadMode.BACKGROUND)
|
||||
fun onMessageEvent(eventStatus: EventStatus) {
|
||||
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)}
|
||||
""".trimIndent()
|
||||
}
|
||||
|
@ -389,31 +385,27 @@ class AccountVerificationController(args: Bundle? = null) : BaseController(
|
|||
fetchAndStoreCapabilities()
|
||||
} else if (eventStatus.eventType == EventStatus.EventType.CAPABILITIES_FETCH) {
|
||||
if (internalAccountId == eventStatus.userId && !eventStatus.isAllGood) {
|
||||
if (activity != null) {
|
||||
activity!!.runOnUiThread {
|
||||
binding?.progressText?.text =
|
||||
runOnUiThread {
|
||||
binding.progressText.text =
|
||||
"""
|
||||
${binding?.progressText?.text}
|
||||
${binding.progressText.text}
|
||||
${resources!!.getString(R.string.nc_capabilities_failed)}
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
abortVerification()
|
||||
} else if (internalAccountId == eventStatus.userId && eventStatus.isAllGood) {
|
||||
fetchAndStoreExternalSignalingSettings()
|
||||
}
|
||||
} else if (eventStatus.eventType == EventStatus.EventType.SIGNALING_SETTINGS) {
|
||||
if (internalAccountId == eventStatus.userId && !eventStatus.isAllGood) {
|
||||
if (activity != null) {
|
||||
activity!!.runOnUiThread {
|
||||
binding?.progressText?.text =
|
||||
runOnUiThread {
|
||||
binding.progressText.text =
|
||||
"""
|
||||
${binding?.progressText?.text}
|
||||
${binding.progressText.text}
|
||||
${resources!!.getString(R.string.nc_external_server_failed)}
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
}
|
||||
proceedWithLogin()
|
||||
}
|
||||
}
|
||||
|
@ -457,8 +449,7 @@ class AccountVerificationController(args: Bundle? = null) : BaseController(
|
|||
Log.d(TAG, "userToSetAsActive: " + userToSetAsActive.username)
|
||||
|
||||
if (userManager.setUserAsActive(userToSetAsActive).blockingGet()) {
|
||||
if (activity != null) {
|
||||
activity!!.runOnUiThread {
|
||||
runOnUiThread {
|
||||
if (userManager.users.blockingGet().size == 1) {
|
||||
val intent = Intent(context, ConversationsListActivity::class.java)
|
||||
startActivity(intent)
|
||||
|
@ -471,10 +462,9 @@ class AccountVerificationController(args: Bundle? = null) : BaseController(
|
|||
startActivity(intent)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
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() {
|
||||
dispose()
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
private fun abortVerification() {
|
||||
if (!isAccountImport) {
|
||||
if (internalAccountId != -1L) {
|
||||
val count = userManager.deleteUser(internalAccountId)
|
||||
if (count > 0) {
|
||||
activity?.runOnUiThread { Handler().postDelayed({ router.popToRoot() }, DELAY_IN_MILLIS) }
|
||||
}
|
||||
} else {
|
||||
activity?.runOnUiThread { Handler().postDelayed({ router.popToRoot() }, DELAY_IN_MILLIS) }
|
||||
}
|
||||
} else {
|
||||
ApplicationWideMessageHolder.getInstance().setMessageType(
|
||||
ApplicationWideMessageHolder.MessageType.FAILED_TO_IMPORT_ACCOUNT
|
||||
)
|
||||
activity?.runOnUiThread {
|
||||
if (isAccountImport) {
|
||||
ApplicationWideMessageHolder.getInstance().messageType = ApplicationWideMessageHolder.MessageType
|
||||
.FAILED_TO_IMPORT_ACCOUNT
|
||||
runOnUiThread {
|
||||
Handler().postDelayed({
|
||||
if (router.hasRootController()) {
|
||||
if (activity != null) {
|
||||
router.popToRoot()
|
||||
}
|
||||
} else {
|
||||
if (userManager.users.blockingGet().isNotEmpty()) {
|
||||
val intent = Intent(context, ConversationsListActivity::class.java)
|
||||
val intent = Intent(this, ServerSelectionActivity::class.java)
|
||||
startActivity(intent)
|
||||
} else {
|
||||
router.setRoot(
|
||||
RouterTransaction.with(ServerSelectionController())
|
||||
.pushChangeHandler(HorizontalChangeHandler())
|
||||
.popChangeHandler(HorizontalChangeHandler())
|
||||
)
|
||||
}
|
||||
}
|
||||
}, DELAY_IN_MILLIS)
|
||||
}
|
||||
} else {
|
||||
if (internalAccountId != -1L) {
|
||||
runOnUiThread {
|
||||
deleteUserAndStartServerSelection(internalAccountId)
|
||||
}
|
||||
} else {
|
||||
runOnUiThread {
|
||||
Handler().postDelayed({
|
||||
val intent = Intent(this, ServerSelectionActivity::class.java)
|
||||
startActivity(intent)
|
||||
}, DELAY_IN_MILLIS)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@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)
|
||||
}
|
||||
|
||||
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 {
|
||||
const val TAG = "AccountVerification"
|
||||
private val TAG = AccountVerificationActivity::class.java.simpleName
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,6 +3,8 @@
|
|||
*
|
||||
* @author Andy Scherzinger
|
||||
* @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) 2017 Mario Danic <mario@lovelyhq.com>
|
||||
*
|
||||
|
@ -19,7 +21,7 @@
|
|||
* 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
|
||||
package com.nextcloud.talk.account
|
||||
|
||||
import android.accounts.Account
|
||||
import android.annotation.SuppressLint
|
||||
|
@ -34,24 +36,21 @@ import android.view.KeyEvent
|
|||
import android.view.View
|
||||
import android.view.inputmethod.EditorInfo
|
||||
import android.widget.TextView
|
||||
import androidx.core.content.res.ResourcesCompat
|
||||
import androidx.activity.OnBackPressedCallback
|
||||
import autodagger.AutoInjector
|
||||
import com.bluelinelabs.conductor.RouterTransaction
|
||||
import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler
|
||||
import com.nextcloud.talk.R
|
||||
import com.nextcloud.talk.activities.BaseActivity
|
||||
import com.nextcloud.talk.api.NcApi
|
||||
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.generic.Status
|
||||
import com.nextcloud.talk.users.UserManager
|
||||
import com.nextcloud.talk.utils.AccountUtils
|
||||
import com.nextcloud.talk.utils.ApiUtils
|
||||
import com.nextcloud.talk.utils.DisplayUtils
|
||||
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.database.user.CapabilitiesUtilNew
|
||||
import com.nextcloud.talk.utils.singletons.ApplicationWideMessageHolder
|
||||
|
@ -61,12 +60,12 @@ import io.reactivex.disposables.Disposable
|
|||
import io.reactivex.schedulers.Schedulers
|
||||
import java.security.cert.CertificateException
|
||||
import javax.inject.Inject
|
||||
import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication
|
||||
|
||||
@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
|
||||
lateinit var ncApi: NcApi
|
||||
|
@ -76,44 +75,40 @@ class ServerSelectionController :
|
|||
|
||||
private var statusQueryDisposable: Disposable? = null
|
||||
|
||||
fun onCertClick() {
|
||||
if (activity != null) {
|
||||
KeyChain.choosePrivateKeyAlias(
|
||||
activity!!,
|
||||
{ alias: String? ->
|
||||
if (alias != null) {
|
||||
appPreferences!!.temporaryClientCertAlias = alias
|
||||
private val onBackPressedCallback = object : OnBackPressedCallback(true) {
|
||||
override fun handleOnBackPressed() {
|
||||
if (intent.hasExtra(ADD_ADDITIONAL_ACCOUNT) && intent.getBooleanExtra(ADD_ADDITIONAL_ACCOUNT, false)) {
|
||||
finish()
|
||||
} else {
|
||||
appPreferences!!.removeTemporaryClientCertAlias()
|
||||
finishAffinity()
|
||||
}
|
||||
setCertTextView()
|
||||
},
|
||||
arrayOf("RSA", "EC"),
|
||||
null,
|
||||
null,
|
||||
-1,
|
||||
null
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onViewBound(view: View) {
|
||||
super.onViewBound(view)
|
||||
@SuppressLint("SourceLockedOrientationActivity")
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
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()
|
||||
setupPrimaryColors()
|
||||
|
||||
onBackPressedDispatcher.addCallback(this, onBackPressedCallback)
|
||||
}
|
||||
|
||||
actionBar?.hide()
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
|
||||
binding?.hostUrlInputHelperText?.text = String.format(
|
||||
binding.hostUrlInputHelperText.text = String.format(
|
||||
resources!!.getString(R.string.nc_server_helper_text),
|
||||
resources!!.getString(R.string.nc_server_product_name)
|
||||
)
|
||||
binding?.serverEntryTextInputLayout?.setEndIconOnClickListener { checkServerAndProceed() }
|
||||
binding.serverEntryTextInputLayout.setEndIconOnClickListener { checkServerAndProceed() }
|
||||
|
||||
if (resources!!.getBoolean(R.bool.hide_auth_cert)) {
|
||||
binding?.certTextView?.visibility = View.GONE
|
||||
binding.certTextView.visibility = View.GONE
|
||||
}
|
||||
|
||||
val loggedInUsers = userManager.users.blockingGet()
|
||||
|
@ -124,21 +119,54 @@ class ServerSelectionController :
|
|||
} else if (isAbleToShowProviderLink() && loggedInUsers.isEmpty()) {
|
||||
showVisitProvidersInfo()
|
||||
} 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))) {
|
||||
binding?.serverEntryTextInputEditText?.setText(resources!!.getString(R.string.weblogin_url))
|
||||
binding.serverEntryTextInputEditText.setText(resources!!.getString(R.string.weblogin_url))
|
||||
checkServerAndProceed()
|
||||
}
|
||||
binding?.serverEntryTextInputEditText?.setOnEditorActionListener { _: TextView?, i: Int, _: KeyEvent? ->
|
||||
binding.serverEntryTextInputEditText.setOnEditorActionListener { _: TextView?, i: Int, _: KeyEvent? ->
|
||||
if (i == EditorInfo.IME_ACTION_DONE) {
|
||||
checkServerAndProceed()
|
||||
}
|
||||
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 {
|
||||
|
@ -152,41 +180,37 @@ class ServerSelectionController :
|
|||
)
|
||||
) {
|
||||
if (availableAccounts.size > 1) {
|
||||
binding?.importOrChooseProviderText?.text = String.format(
|
||||
binding.importOrChooseProviderText.text = String.format(
|
||||
resources!!.getString(R.string.nc_server_import_accounts),
|
||||
AccountUtils.getAppNameBasedOnPackage(resources!!.getString(R.string.nc_import_accounts_from))
|
||||
)
|
||||
} else {
|
||||
binding?.importOrChooseProviderText?.text = String.format(
|
||||
binding.importOrChooseProviderText.text = String.format(
|
||||
resources!!.getString(R.string.nc_server_import_account),
|
||||
AccountUtils.getAppNameBasedOnPackage(resources!!.getString(R.string.nc_import_accounts_from))
|
||||
)
|
||||
}
|
||||
} else {
|
||||
if (availableAccounts.size > 1) {
|
||||
binding?.importOrChooseProviderText?.text =
|
||||
binding.importOrChooseProviderText.text =
|
||||
resources!!.getString(R.string.nc_server_import_accounts_plain)
|
||||
} else {
|
||||
binding?.importOrChooseProviderText?.text =
|
||||
binding.importOrChooseProviderText.text =
|
||||
resources!!.getString(R.string.nc_server_import_account_plain)
|
||||
}
|
||||
}
|
||||
binding?.importOrChooseProviderText?.setOnClickListener {
|
||||
binding.importOrChooseProviderText.setOnClickListener {
|
||||
val bundle = Bundle()
|
||||
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() {
|
||||
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(
|
||||
Intent.ACTION_VIEW,
|
||||
Uri.parse(
|
||||
|
@ -206,11 +230,11 @@ class ServerSelectionController :
|
|||
@Suppress("Detekt.TooGenericExceptionCaught")
|
||||
private fun checkServerAndProceed() {
|
||||
dispose()
|
||||
var url: String = binding?.serverEntryTextInputEditText?.text.toString().trim { it <= ' ' }
|
||||
var url: String = binding.serverEntryTextInputEditText.text.toString().trim { it <= ' ' }
|
||||
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("/")) {
|
||||
url = url.substring(0, url.length - 1)
|
||||
|
@ -278,17 +302,17 @@ class ServerSelectionController :
|
|||
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()
|
||||
}
|
||||
}) {
|
||||
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()
|
||||
}
|
||||
|
@ -311,29 +335,25 @@ class ServerSelectionController :
|
|||
capabilities.spreedCapability?.features?.isNotEmpty() == true
|
||||
|
||||
if (hasTalk) {
|
||||
activity?.runOnUiThread {
|
||||
runOnUiThread {
|
||||
if (CapabilitiesUtilNew.isServerEOL(capabilities)) {
|
||||
if (resources != null) {
|
||||
activity!!.runOnUiThread {
|
||||
runOnUiThread {
|
||||
setErrorText(resources!!.getString(R.string.nc_settings_server_eol))
|
||||
}
|
||||
}
|
||||
} 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 {
|
||||
if (activity != null && resources != null) {
|
||||
activity!!.runOnUiThread {
|
||||
if (resources != null) {
|
||||
runOnUiThread {
|
||||
setErrorText(resources!!.getString(R.string.nc_server_unsupported))
|
||||
}
|
||||
}
|
||||
|
@ -342,8 +362,8 @@ class ServerSelectionController :
|
|||
|
||||
override fun onError(e: Throwable) {
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
@ -360,72 +380,31 @@ class ServerSelectionController :
|
|||
}
|
||||
|
||||
private fun setErrorText(text: String) {
|
||||
binding?.errorWrapper?.visibility = View.VISIBLE
|
||||
binding?.errorText?.text = text
|
||||
binding.errorWrapper.visibility = View.VISIBLE
|
||||
binding.errorText.text = text
|
||||
hideserverEntryProgressBar()
|
||||
}
|
||||
|
||||
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() {
|
||||
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")
|
||||
private fun setCertTextView() {
|
||||
if (activity != null) {
|
||||
activity!!.runOnUiThread {
|
||||
if (!TextUtils.isEmpty(appPreferences!!.temporaryClientCertAlias)) {
|
||||
binding?.certTextView?.setText(R.string.nc_change_cert_auth)
|
||||
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)
|
||||
binding.certTextView.setText(R.string.nc_configure_cert_auth)
|
||||
}
|
||||
hideserverEntryProgressBar()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroyView(view: View) {
|
||||
super.onDestroyView(view)
|
||||
if (activity != null) {
|
||||
activity!!.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR
|
||||
}
|
||||
}
|
||||
|
||||
public override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
|
@ -443,7 +422,7 @@ class ServerSelectionController :
|
|||
get() = AppBarLayoutType.EMPTY
|
||||
|
||||
companion object {
|
||||
const val TAG = "ServerSelectionController"
|
||||
private val TAG = ServerSelectionActivity::class.java.simpleName
|
||||
const val MIN_SERVER_MAJOR_VERSION = 13
|
||||
}
|
||||
}
|
|
@ -3,6 +3,8 @@
|
|||
*
|
||||
* @author Mario Danic
|
||||
* @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) 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:
|
||||
* https://github.com/nextcloud/ownCloud-Account-Importer
|
||||
*/
|
||||
package com.nextcloud.talk.controllers
|
||||
package com.nextcloud.talk.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.view.MenuItem
|
||||
import android.view.View
|
||||
import androidx.preference.PreferenceManager
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import autodagger.AutoInjector
|
||||
import com.bluelinelabs.conductor.RouterTransaction
|
||||
import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler
|
||||
import com.nextcloud.talk.R
|
||||
import com.nextcloud.talk.activities.BaseActivity
|
||||
import com.nextcloud.talk.adapters.items.AdvancedUserItem
|
||||
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.databinding.ControllerGenericRvBinding
|
||||
import com.nextcloud.talk.databinding.ActivitySwitchAccountBinding
|
||||
import com.nextcloud.talk.models.ImportAccount
|
||||
import com.nextcloud.talk.models.json.participants.Participant
|
||||
import com.nextcloud.talk.users.UserManager
|
||||
|
@ -56,14 +56,11 @@ import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
|||
import org.osmdroid.config.Configuration
|
||||
import java.net.CookieManager
|
||||
import javax.inject.Inject
|
||||
import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication
|
||||
|
||||
@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
|
||||
lateinit var userManager: UserManager
|
||||
|
@ -89,41 +86,52 @@ class SwitchAccountController(args: Bundle? = null) :
|
|||
|
||||
if (userManager.setUserAsActive(user).blockingGet()) {
|
||||
cookieManager.cookieStore.removeAll()
|
||||
if (activity != null) {
|
||||
activity!!.runOnUiThread { router.popCurrentController() }
|
||||
}
|
||||
finish()
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
init {
|
||||
setHasOptionsMenu(true)
|
||||
@SuppressLint("SourceLockedOrientationActivity")
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
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))
|
||||
if (args?.containsKey(KEY_IS_ACCOUNT_IMPORT) == true) {
|
||||
|
||||
handleIntent()
|
||||
}
|
||||
|
||||
private fun handleIntent() {
|
||||
intent.extras?.let {
|
||||
if (it.containsKey(KEY_IS_ACCOUNT_IMPORT)) {
|
||||
isAccountImport = true
|
||||
}
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
return when (item.itemId) {
|
||||
android.R.id.home -> {
|
||||
router.popCurrentController()
|
||||
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) {
|
||||
adapter = FlexibleAdapter(userItems, activity, false)
|
||||
adapter = FlexibleAdapter(userItems, this, false)
|
||||
var participant: Participant
|
||||
|
||||
if (!isAccountImport) {
|
||||
|
@ -166,11 +174,10 @@ class SwitchAccountController(args: Bundle? = null) :
|
|||
}
|
||||
|
||||
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?) {
|
||||
|
@ -180,14 +187,9 @@ class SwitchAccountController(args: Bundle? = null) :
|
|||
bundle.putString(KEY_USERNAME, importAccount.getUsername())
|
||||
bundle.putString(KEY_TOKEN, importAccount.getToken())
|
||||
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)
|
||||
}
|
||||
}
|
|
@ -3,6 +3,8 @@
|
|||
*
|
||||
* @author Mario Danic
|
||||
* @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) 2017 Mario Danic (mario@lovelyhq.com)
|
||||
*
|
||||
|
@ -19,9 +21,10 @@
|
|||
* 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
|
||||
package com.nextcloud.talk.account
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Intent
|
||||
import android.content.pm.ActivityInfo
|
||||
import android.graphics.Bitmap
|
||||
import android.net.http.SslError
|
||||
|
@ -40,34 +43,30 @@ import android.webkit.WebResourceResponse
|
|||
import android.webkit.WebSettings
|
||||
import android.webkit.WebView
|
||||
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.WorkInfo
|
||||
import androidx.work.WorkManager
|
||||
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.activities.BaseActivity
|
||||
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.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.jobs.PushRegistrationWorker
|
||||
import com.nextcloud.talk.jobs.AccountRemovalWorker
|
||||
import com.nextcloud.talk.models.LoginData
|
||||
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_ORIGINAL_PROTOCOL
|
||||
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_TOKEN
|
||||
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_USERNAME
|
||||
import com.nextcloud.talk.utils.singletons.ApplicationWideMessageHolder
|
||||
import com.nextcloud.talk.utils.ssl.TrustManager
|
||||
import de.cotech.hw.fido.WebViewFidoBridge
|
||||
import io.reactivex.disposables.Disposable
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import java.lang.reflect.Field
|
||||
import java.net.CookieManager
|
||||
import java.net.URLDecoder
|
||||
|
@ -78,11 +77,9 @@ import java.util.Locale
|
|||
import javax.inject.Inject
|
||||
|
||||
@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
|
||||
lateinit var userManager: UserManager
|
||||
|
@ -90,34 +87,26 @@ class WebViewLoginController(args: Bundle? = null) : BaseController(
|
|||
@Inject
|
||||
lateinit var trustManager: TrustManager
|
||||
|
||||
@Inject
|
||||
lateinit var eventBus: EventBus
|
||||
|
||||
@Inject
|
||||
lateinit var cookieManager: CookieManager
|
||||
|
||||
private var assembledPrefix: String? = null
|
||||
private var userQueryDisposable: Disposable? = null
|
||||
private var baseUrl: String? = null
|
||||
private var isPasswordUpdate = false
|
||||
private var reauthorizeAccount = false
|
||||
private var username: String? = null
|
||||
private var password: String? = null
|
||||
private var loginStep = 0
|
||||
private var automatedLoginAttempted = false
|
||||
private var webViewFidoBridge: WebViewFidoBridge? = null
|
||||
|
||||
constructor(baseUrl: String?, isPasswordUpdate: Boolean) : this() {
|
||||
this.baseUrl = baseUrl
|
||||
this.isPasswordUpdate = isPasswordUpdate
|
||||
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)
|
||||
}
|
||||
|
||||
constructor(baseUrl: String?, isPasswordUpdate: Boolean, username: String?, password: String?) : this() {
|
||||
this.baseUrl = baseUrl
|
||||
this.isPasswordUpdate = isPasswordUpdate
|
||||
this.username = username
|
||||
this.password = password
|
||||
}
|
||||
|
||||
private val webLoginUserAgent: String
|
||||
get() = (
|
||||
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()
|
||||
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/"
|
||||
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)
|
||||
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)
|
||||
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
|
||||
override fun shouldInterceptRequest(view: WebView, request: WebResourceRequest): WebResourceResponse? {
|
||||
webViewFidoBridge?.delegateShouldInterceptRequest(view, request)
|
||||
|
@ -180,24 +193,24 @@ class WebViewLoginController(args: Bundle? = null) : BaseController(
|
|||
override fun onPageFinished(view: WebView, url: String) {
|
||||
loginStep++
|
||||
if (!basePageLoaded) {
|
||||
binding?.progressBar?.visibility = View.GONE
|
||||
binding?.webview?.visibility = View.VISIBLE
|
||||
binding.progressBar.visibility = View.GONE
|
||||
binding.webview.visibility = View.VISIBLE
|
||||
|
||||
basePageLoaded = true
|
||||
}
|
||||
if (!TextUtils.isEmpty(username)) {
|
||||
if (loginStep == 1) {
|
||||
binding?.webview?.loadUrl(
|
||||
binding.webview.loadUrl(
|
||||
"javascript: {document.getElementsByClassName('login')[0].click(); };"
|
||||
)
|
||||
} else if (!automatedLoginAttempted) {
|
||||
automatedLoginAttempted = true
|
||||
if (TextUtils.isEmpty(password)) {
|
||||
binding?.webview?.loadUrl(
|
||||
binding.webview.loadUrl(
|
||||
"javascript:var justStore = document.getElementById('user').value = '$username';"
|
||||
)
|
||||
} else {
|
||||
binding?.webview?.loadUrl(
|
||||
binding.webview.loadUrl(
|
||||
"javascript: {" +
|
||||
"document.getElementById('user').value = '" + username + "';" +
|
||||
"document.getElementById('password').value = '" + password + "';" +
|
||||
|
@ -213,8 +226,8 @@ class WebViewLoginController(args: Bundle? = null) : BaseController(
|
|||
override fun onReceivedClientCertRequest(view: WebView, request: ClientCertRequest) {
|
||||
val user = userManager.currentUser.blockingGet()
|
||||
var alias: String? = null
|
||||
if (!isPasswordUpdate) {
|
||||
alias = appPreferences!!.temporaryClientCertAlias
|
||||
if (!reauthorizeAccount) {
|
||||
alias = appPreferences.temporaryClientCertAlias
|
||||
}
|
||||
if (TextUtils.isEmpty(alias) && user != null) {
|
||||
alias = user.clientCertificate
|
||||
|
@ -223,9 +236,9 @@ class WebViewLoginController(args: Bundle? = null) : BaseController(
|
|||
val finalAlias = alias
|
||||
Thread {
|
||||
try {
|
||||
val privateKey = KeyChain.getPrivateKey(activity!!, finalAlias!!)
|
||||
val privateKey = KeyChain.getPrivateKey(applicationContext, finalAlias!!)
|
||||
val certificates = KeyChain.getCertificateChain(
|
||||
activity!!,
|
||||
applicationContext,
|
||||
finalAlias
|
||||
)
|
||||
if (privateKey != null && certificates != null) {
|
||||
|
@ -241,16 +254,16 @@ class WebViewLoginController(args: Bundle? = null) : BaseController(
|
|||
}.start()
|
||||
} else {
|
||||
KeyChain.choosePrivateKeyAlias(
|
||||
activity!!,
|
||||
this@WebViewLoginActivity,
|
||||
{ chosenAlias: String? ->
|
||||
if (chosenAlias != null) {
|
||||
appPreferences!!.temporaryClientCertAlias = chosenAlias
|
||||
Thread {
|
||||
var privateKey: PrivateKey? = null
|
||||
try {
|
||||
privateKey = KeyChain.getPrivateKey(activity!!, chosenAlias)
|
||||
privateKey = KeyChain.getPrivateKey(applicationContext, chosenAlias)
|
||||
val certificates = KeyChain.getCertificateChain(
|
||||
activity!!,
|
||||
applicationContext,
|
||||
chosenAlias
|
||||
)
|
||||
if (privateKey != null && certificates != null) {
|
||||
|
@ -304,7 +317,7 @@ class WebViewLoginController(args: Bundle? = null) : BaseController(
|
|||
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() {
|
||||
|
@ -318,25 +331,27 @@ class WebViewLoginController(args: Bundle? = null) : BaseController(
|
|||
val loginData = parseLoginData(assembledPrefix, dataString)
|
||||
if (loginData != null) {
|
||||
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
|
||||
}
|
||||
if (userManager.checkIfUserIsScheduledForDeletion(loginData.username!!, baseUrl!!).blockingGet()) {
|
||||
ApplicationWideMessageHolder.getInstance().messageType =
|
||||
ApplicationWideMessageHolder.MessageType.ACCOUNT_SCHEDULED_FOR_DELETION
|
||||
if (!isPasswordUpdate) {
|
||||
router.popToRoot()
|
||||
} else {
|
||||
router.popCurrentController()
|
||||
}
|
||||
}
|
||||
val finalMessageType = messageType
|
||||
cookieManager.cookieStore.removeAll()
|
||||
if (!isPasswordUpdate && finalMessageType == null) {
|
||||
|
||||
if (userManager.checkIfUserIsScheduledForDeletion(loginData.username!!, baseUrl!!).blockingGet()) {
|
||||
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 {
|
||||
Log.w(TAG, "It was tried to add an account that account already exists. Skipped user creation.")
|
||||
restartApp()
|
||||
}
|
||||
} else {
|
||||
startAccountVerification(loginData)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun startAccountVerification(loginData: LoginData) {
|
||||
val bundle = Bundle()
|
||||
bundle.putString(KEY_USERNAME, loginData.username)
|
||||
bundle.putString(KEY_TOKEN, loginData.token)
|
||||
|
@ -350,46 +365,41 @@ class WebViewLoginController(args: Bundle? = null) : BaseController(
|
|||
if (!TextUtils.isEmpty(protocol)) {
|
||||
bundle.putString(KEY_ORIGINAL_PROTOCOL, protocol)
|
||||
}
|
||||
router.pushController(
|
||||
RouterTransaction.with(AccountVerificationController(bundle))
|
||||
.pushChangeHandler(HorizontalChangeHandler())
|
||||
.popChangeHandler(HorizontalChangeHandler())
|
||||
)
|
||||
} else {
|
||||
if (isPasswordUpdate) {
|
||||
val intent = Intent(context, AccountVerificationActivity::class.java)
|
||||
intent.putExtras(bundle)
|
||||
startActivity(intent)
|
||||
}
|
||||
|
||||
private fun restartApp() {
|
||||
val intent = Intent(context, MainActivity::class.java)
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
|
||||
startActivity(intent)
|
||||
}
|
||||
|
||||
private fun updateUserAndRestartApp(loginData: LoginData) {
|
||||
val currentUser = userManager.currentUser.blockingGet()
|
||||
if (currentUser != null) {
|
||||
currentUser.clientCertificate = appPreferences!!.temporaryClientCertAlias
|
||||
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
|
||||
restartApp()
|
||||
}
|
||||
}
|
||||
|
||||
val data = Data.Builder().putString(
|
||||
PushRegistrationWorker.ORIGIN,
|
||||
"WebViewLoginController#parseAndLoginFromWebView"
|
||||
).build()
|
||||
private fun startAccountRemovalWorkerAndRestartApp() {
|
||||
val accountRemovalWork = OneTimeWorkRequest.Builder(AccountRemovalWorker::class.java).build()
|
||||
WorkManager.getInstance(applicationContext).enqueue(accountRemovalWork)
|
||||
|
||||
val pushRegistrationWork = OneTimeWorkRequest.Builder(
|
||||
PushRegistrationWorker::class.java
|
||||
)
|
||||
.setInputData(data)
|
||||
.build()
|
||||
WorkManager.getInstance(context).getWorkInfoByIdLiveData(accountRemovalWork.id)
|
||||
.observeForever { workInfo: WorkInfo ->
|
||||
|
||||
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
|
||||
}
|
||||
router.popToRoot()
|
||||
when (workInfo.state) {
|
||||
WorkInfo.State.SUCCEEDED, WorkInfo.State.FAILED, WorkInfo.State.CANCELLED -> {
|
||||
restartApp()
|
||||
}
|
||||
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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() {
|
||||
super.onDestroy()
|
||||
dispose()
|
||||
}
|
||||
|
||||
override fun onDestroyView(view: View) {
|
||||
super.onDestroyView(view)
|
||||
activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR
|
||||
}
|
||||
|
||||
init {
|
||||
sharedApplication!!.componentApplication.inject(this)
|
||||
}
|
||||
|
@ -464,7 +455,7 @@ class WebViewLoginController(args: Bundle? = null) : BaseController(
|
|||
get() = AppBarLayoutType.EMPTY
|
||||
|
||||
companion object {
|
||||
const val TAG = "WebViewLoginController"
|
||||
private val TAG = WebViewLoginActivity::class.java.simpleName
|
||||
private const val PROTOCOL_SUFFIX = "://"
|
||||
private const val LOGIN_URL_DATA_KEY_VALUE_SEPARATOR = ":"
|
||||
private const val PARAMETER_COUNT = 3
|
|
@ -16,7 +16,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.nextcloud.talk.controllers.base.providers;
|
||||
package com.nextcloud.talk.activities;
|
||||
|
||||
import androidx.appcompat.app.ActionBar;
|
||||
|
|
@ -24,17 +24,26 @@ package com.nextcloud.talk.activities
|
|||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.WindowManager
|
||||
import android.view.inputmethod.EditorInfo
|
||||
import android.webkit.SslErrorHandler
|
||||
import android.widget.EditText
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.content.res.ResourcesCompat
|
||||
import autodagger.AutoInjector
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
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.events.CertificateEvent
|
||||
import com.nextcloud.talk.ui.theme.ViewThemeUtils
|
||||
|
@ -77,6 +86,8 @@ open class BaseActivity : AppCompatActivity() {
|
|||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
NextcloudTalkApplication.sharedApplication!!.componentApplication.inject(this)
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
cleanTempCertPreference()
|
||||
}
|
||||
|
||||
public override fun onStart() {
|
||||
|
@ -87,6 +98,11 @@ open class BaseActivity : AppCompatActivity() {
|
|||
public override fun 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) {
|
||||
window.addFlags(WindowManager.LayoutParams.FLAG_SECURE)
|
||||
} else {
|
||||
|
@ -104,6 +120,19 @@ open class BaseActivity : AppCompatActivity() {
|
|||
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() {
|
||||
if (resources != null) {
|
||||
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,
|
||||
trustManager: TrustManager,
|
||||
sslErrorHandler: SslErrorHandler?
|
||||
|
@ -160,15 +205,17 @@ open class BaseActivity : AppCompatActivity() {
|
|||
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)
|
||||
.setPositiveButton(R.string.nc_yes) { _, _ ->
|
||||
trustManager.addCertInTrustStore(cert)
|
||||
sslErrorHandler?.proceed()
|
||||
}
|
||||
.setNegativeButton(R.string.nc_no) { _, _ ->
|
||||
}.setNegativeButton(R.string.nc_no) { _, _ ->
|
||||
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)
|
||||
fun onMessageEvent(event: CertificateEvent) {
|
||||
showCertificateDialog(event.x509Certificate, event.magicTrustManager, event.sslErrorHandler)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val TAG = "BaseActivity"
|
||||
private val TAG = BaseActivity::class.java.simpleName
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3096,7 +3096,7 @@ class CallActivity : CallBaseActivity() {
|
|||
}
|
||||
|
||||
override fun suppressFitsSystemWindows() {
|
||||
binding!!.controllerCallLayout.fitsSystemWindows = false
|
||||
binding!!.callLayout.fitsSystemWindows = false
|
||||
}
|
||||
|
||||
override fun onConfigurationChanged(newConfig: Configuration) {
|
||||
|
|
|
@ -37,21 +37,14 @@ import androidx.lifecycle.DefaultLifecycleObserver
|
|||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.lifecycle.ProcessLifecycleOwner
|
||||
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.nextcloud.talk.BuildConfig
|
||||
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.application.NextcloudTalkApplication
|
||||
import com.nextcloud.talk.callnotification.CallNotificationActivity
|
||||
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.data.user.model.User
|
||||
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.SecurityUtils
|
||||
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 io.reactivex.Observer
|
||||
import io.reactivex.SingleObserver
|
||||
|
@ -80,15 +72,11 @@ class MainActivity : BaseActivity(), ActionBarProvider {
|
|||
@Inject
|
||||
lateinit var userManager: UserManager
|
||||
|
||||
private var router: Router? = null
|
||||
|
||||
private val onBackPressedCallback = object : OnBackPressedCallback(true) {
|
||||
override fun handleOnBackPressed() {
|
||||
if (!router!!.handleBack()) {
|
||||
finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("Detekt.TooGenericExceptionCaught")
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
|
@ -111,8 +99,6 @@ class MainActivity : BaseActivity(), ActionBarProvider {
|
|||
|
||||
setSupportActionBar(binding.toolbar)
|
||||
|
||||
router = Conductor.attachRouter(this, binding.controllerContainer, savedInstanceState)
|
||||
|
||||
handleIntent(intent)
|
||||
|
||||
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 {
|
||||
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() {
|
||||
Log.d(TAG, "onStart: Activity: " + System.identityHashCode(this).toString())
|
||||
super.onStart()
|
||||
logRouterBackStack(router!!)
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
|
@ -178,14 +160,6 @@ class MainActivity : BaseActivity(), ActionBarProvider {
|
|||
startActivity(intent)
|
||||
}
|
||||
|
||||
fun addAccount() {
|
||||
router!!.pushController(
|
||||
RouterTransaction.with(ServerSelectionController())
|
||||
.pushChangeHandler(VerticalChangeHandler())
|
||||
.popChangeHandler(VerticalChangeHandler())
|
||||
)
|
||||
}
|
||||
|
||||
private fun handleActionFromContact(intent: Intent) {
|
||||
if (intent.action == Intent.ACTION_VIEW && intent.data != null) {
|
||||
val cursor = contentResolver.query(intent.data!!, null, null, null, null)
|
||||
|
@ -209,7 +183,7 @@ class MainActivity : BaseActivity(), ActionBarProvider {
|
|||
startConversation(user)
|
||||
} else {
|
||||
Snackbar.make(
|
||||
binding.controllerContainer,
|
||||
binding.root,
|
||||
R.string.nc_phone_book_integration_account_not_found,
|
||||
Snackbar.LENGTH_LONG
|
||||
).show()
|
||||
|
@ -283,28 +257,18 @@ class MainActivity : BaseActivity(), ActionBarProvider {
|
|||
}
|
||||
|
||||
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.getBooleanExtra(BundleKeys.KEY_FROM_NOTIFICATION_START_CALL, false)) {
|
||||
if (!router!!.hasRootController()) {
|
||||
openConversationList()
|
||||
}
|
||||
val callNotificationIntent = Intent(this, CallNotificationActivity::class.java)
|
||||
intent.extras?.let { callNotificationIntent.putExtras(it) }
|
||||
startActivity(callNotificationIntent)
|
||||
} else {
|
||||
logRouterBackStack(router!!)
|
||||
|
||||
val chatIntent = Intent(context, ChatActivity::class.java)
|
||||
chatIntent.putExtras(intent.extras!!)
|
||||
startActivity(chatIntent)
|
||||
|
||||
logRouterBackStack(router!!)
|
||||
}
|
||||
}
|
||||
} else if (intent.hasExtra(ADD_ACCOUNT) && intent.getBooleanExtra(ADD_ACCOUNT, false)) {
|
||||
addAccount()
|
||||
} else if (!router!!.hasRootController()) {
|
||||
} else {
|
||||
if (!appPreferences.isDbRoomMigrated) {
|
||||
appPreferences.isDbRoomMigrated = true
|
||||
}
|
||||
|
@ -321,7 +285,7 @@ class MainActivity : BaseActivity(), ActionBarProvider {
|
|||
}
|
||||
} else {
|
||||
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 {
|
||||
private const val TAG = "MainActivity"
|
||||
private val TAG = MainActivity::class.java.simpleName
|
||||
}
|
||||
}
|
||||
|
|
|
@ -231,6 +231,6 @@ class IncomingPollMessageViewHolder(incomingView: View, payload: Any) :
|
|||
}
|
||||
|
||||
companion object {
|
||||
private val TAG = NextcloudTalkApplication::class.java.simpleName
|
||||
private val TAG = IncomingPollMessageViewHolder::class.java.simpleName
|
||||
}
|
||||
}
|
||||
|
|
|
@ -209,6 +209,6 @@ class OutcomingPollMessageViewHolder(outcomingView: View, payload: Any) :
|
|||
}
|
||||
|
||||
companion object {
|
||||
private val TAG = NextcloudTalkApplication::class.java.simpleName
|
||||
private val TAG = OutcomingPollMessageViewHolder::class.java.simpleName
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
* 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 androidx.annotation.DrawableRes
|
|
@ -18,7 +18,7 @@
|
|||
* 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.recyclerview.widget.LinearLayoutManager
|
|
@ -18,7 +18,7 @@
|
|||
* 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.ViewGroup
|
|
@ -317,7 +317,7 @@ class CallNotificationActivity : CallBaseActivity() {
|
|||
}
|
||||
|
||||
override fun suppressFitsSystemWindows() {
|
||||
binding!!.controllerCallNotificationLayout.fitsSystemWindows = false
|
||||
binding!!.callNotificationLayout.fitsSystemWindows = false
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
|
|
@ -1605,7 +1605,7 @@ class ChatActivity :
|
|||
participantPermissions.hasChatPermission() &&
|
||||
!isReadOnlyConversation()
|
||||
) {
|
||||
val messageSwipeController = MessageSwipeCallback(
|
||||
val messageSwipeCallback = MessageSwipeCallback(
|
||||
this,
|
||||
object : MessageSwipeActions {
|
||||
override fun showReplyUI(position: Int) {
|
||||
|
@ -1617,7 +1617,7 @@ class ChatActivity :
|
|||
}
|
||||
)
|
||||
|
||||
val itemTouchHelper = ItemTouchHelper(messageSwipeController)
|
||||
val itemTouchHelper = ItemTouchHelper(messageSwipeCallback)
|
||||
itemTouchHelper.attachToRecyclerView(binding.messagesListView)
|
||||
}
|
||||
}
|
||||
|
@ -2561,7 +2561,7 @@ class ChatActivity :
|
|||
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
||||
if (requestCode == UploadAndShareFilesWorker.REQUEST_PERMISSION) {
|
||||
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()) {
|
||||
uploadFiles(filesToUpload)
|
||||
}
|
||||
|
|
|
@ -488,17 +488,13 @@ class ContactsActivity :
|
|||
} else {
|
||||
adapter?.filterItems()
|
||||
}
|
||||
|
||||
binding.controllerGenericRv.swipeRefreshLayout.isRefreshing = false
|
||||
}
|
||||
|
||||
override fun onError(e: Throwable) {
|
||||
binding.controllerGenericRv.swipeRefreshLayout.isRefreshing = false
|
||||
dispose(contactsQueryDisposable)
|
||||
}
|
||||
|
||||
override fun onComplete() {
|
||||
binding.controllerGenericRv.swipeRefreshLayout.isRefreshing = false
|
||||
dispose(contactsQueryDisposable)
|
||||
alreadyFetching = false
|
||||
disengageProgressBar()
|
||||
|
@ -656,12 +652,9 @@ class ContactsActivity :
|
|||
|
||||
private fun prepareViews() {
|
||||
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(
|
||||
ResourcesCompat.getColor(resources!!, R.color.colorBackgroundDarker, null),
|
||||
|
@ -677,7 +670,7 @@ class ContactsActivity :
|
|||
private fun disengageProgressBar() {
|
||||
if (!alreadyFetching) {
|
||||
binding.loadingContent.visibility = View.GONE
|
||||
binding.controllerGenericRv.root.visibility = View.VISIBLE
|
||||
binding.root.visibility = View.VISIBLE
|
||||
if (isNewConversationView) {
|
||||
binding.callHeaderLayout.visibility = View.VISIBLE
|
||||
}
|
||||
|
@ -713,8 +706,6 @@ class ContactsActivity :
|
|||
adapter?.updateDataSet(contactItems as List<Nothing>?)
|
||||
}
|
||||
|
||||
binding.controllerGenericRv?.swipeRefreshLayout?.isEnabled = !adapter!!.hasFilter()
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -58,8 +58,8 @@ import com.nextcloud.talk.adapters.items.ParticipantItem
|
|||
import com.nextcloud.talk.api.NcApi
|
||||
import com.nextcloud.talk.application.NextcloudTalkApplication
|
||||
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.data.user.model.User
|
||||
import com.nextcloud.talk.databinding.ActivityConversationInfoBinding
|
||||
|
|
|
@ -50,6 +50,7 @@ import android.view.MotionEvent
|
|||
import android.view.View
|
||||
import android.view.inputmethod.EditorInfo
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import android.widget.Toast
|
||||
import androidx.activity.OnBackPressedCallback
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
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.nextcloud.android.common.ui.theme.utils.ColorRole
|
||||
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.CallActivity
|
||||
import com.nextcloud.talk.activities.MainActivity
|
||||
import com.nextcloud.talk.adapters.items.ConversationItem
|
||||
import com.nextcloud.talk.adapters.items.GenericTextHeaderItem
|
||||
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.contacts.ContactsActivity
|
||||
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.EventStatus
|
||||
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.UserIdUtils
|
||||
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_MSG_FLAG
|
||||
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_FORWARD_MSG_TEXT
|
||||
|
@ -146,7 +151,7 @@ class ConversationsListActivity :
|
|||
FlexibleAdapter.OnItemClickListener,
|
||||
FlexibleAdapter.OnItemLongClickListener {
|
||||
|
||||
private lateinit var binding: ControllerConversationsRvBinding
|
||||
private lateinit var binding: ActivityConversationsBinding
|
||||
|
||||
@Inject
|
||||
lateinit var userManager: UserManager
|
||||
|
@ -202,7 +207,6 @@ class ConversationsListActivity :
|
|||
|
||||
private val onBackPressedCallback = object : OnBackPressedCallback(true) {
|
||||
override fun handleOnBackPressed() {
|
||||
// TODO: replace this when conductor is removed. For now it avoids to load the MainActiviy which has no UI.
|
||||
finishAffinity()
|
||||
}
|
||||
}
|
||||
|
@ -211,7 +215,7 @@ class ConversationsListActivity :
|
|||
super.onCreate(savedInstanceState)
|
||||
NextcloudTalkApplication.sharedApplication!!.componentApplication.inject(this)
|
||||
|
||||
binding = ControllerConversationsRvBinding.inflate(layoutInflater)
|
||||
binding = ActivityConversationsBinding.inflate(layoutInflater)
|
||||
setupActionBar()
|
||||
setContentView(binding.root)
|
||||
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)
|
||||
val dialog = dialogBuilder.show()
|
||||
viewThemeUtils.platform.colorTextButtons(
|
||||
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")
|
||||
private fun prepareViews() {
|
||||
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) {
|
||||
super.onScrollStateChanged(recyclerView, newState)
|
||||
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
|
||||
|
@ -1131,7 +1144,7 @@ class ConversationsListActivity :
|
|||
selectedConversation!!.displayName
|
||||
)
|
||||
}
|
||||
binding?.floatingActionButton?.let {
|
||||
binding.floatingActionButton.let {
|
||||
val dialogBuilder = MaterialAlertDialogBuilder(it.context)
|
||||
.setIcon(viewThemeUtils.dialog.colorMaterialAlertDialogIcon(context, R.drawable.upload))
|
||||
.setTitle(confirmationQuestion)
|
||||
|
@ -1358,30 +1371,17 @@ class ConversationsListActivity :
|
|||
.setTitle(R.string.nc_dialog_invalid_password)
|
||||
.setMessage(R.string.nc_dialog_reauth_or_delete)
|
||||
.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()
|
||||
.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)
|
||||
} else if (!otherUserExists) {
|
||||
Log.d(TAG, "No other users found. AccountRemovalWorker will restart the app.")
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
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() {
|
||||
binding.floatingActionButton.let {
|
||||
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)
|
||||
val dialog = dialogBuilder.show()
|
||||
viewThemeUtils.platform.colorTextButtons(
|
||||
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)
|
||||
.setMessage(R.string.nc_dialog_maintenance_mode_description)
|
||||
.setCancelable(false)
|
||||
.setNegativeButton(R.string.nc_settings_remove_account) { _, _ ->
|
||||
deleteUserAndRestartApp()
|
||||
}
|
||||
|
||||
if (resources!!.getBoolean(R.bool.multiaccount_support) && userManager.users.blockingGet().size > 1) {
|
||||
dialogBuilder.setPositiveButton(R.string.nc_switch_account) { _, _ ->
|
||||
val newFragment: DialogFragment = ChooseAccountDialogFragment.newInstance()
|
||||
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)
|
||||
val dialog = dialogBuilder.show()
|
||||
viewThemeUtils.platform.colorTextButtons(
|
||||
dialog.getButton(AlertDialog.BUTTON_POSITIVE)
|
||||
dialog.getButton(AlertDialog.BUTTON_POSITIVE),
|
||||
dialog.getButton(AlertDialog.BUTTON_NEGATIVE),
|
||||
dialog.getButton(AlertDialog.BUTTON_NEUTRAL)
|
||||
)
|
||||
}
|
||||
} else {
|
||||
|
@ -1470,34 +1531,28 @@ class ConversationsListActivity :
|
|||
}
|
||||
|
||||
private fun showServerEOLDialog() {
|
||||
binding?.floatingActionButton?.let {
|
||||
binding.floatingActionButton.let {
|
||||
val dialogBuilder = MaterialAlertDialogBuilder(it.context)
|
||||
.setIcon(viewThemeUtils.dialog.colorMaterialAlertDialogIcon(context, R.drawable.ic_warning_white))
|
||||
.setTitle(R.string.nc_settings_server_eol_title)
|
||||
.setMessage(R.string.nc_settings_server_eol)
|
||||
.setCancelable(false)
|
||||
.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()
|
||||
deleteUserAndRestartApp()
|
||||
}
|
||||
|
||||
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)
|
||||
} else if (!otherUserExists) {
|
||||
restartApp(this)
|
||||
}
|
||||
}
|
||||
.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()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1505,20 +1560,12 @@ class ConversationsListActivity :
|
|||
val dialog = dialogBuilder.show()
|
||||
viewThemeUtils.platform.colorTextButtons(
|
||||
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) {
|
||||
val data = Data.Builder()
|
||||
data.putLong(
|
||||
|
@ -1613,10 +1660,10 @@ class ConversationsListActivity :
|
|||
}
|
||||
|
||||
companion object {
|
||||
const val TAG = "ConvListController"
|
||||
private val TAG = ConversationsListActivity::class.java.simpleName
|
||||
const val UNREAD_BUBBLE_DELAY = 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_MIN_CHARS = 2
|
||||
const val HTTP_UNAUTHORIZED = 401
|
||||
|
|
|
@ -23,10 +23,7 @@
|
|||
package com.nextcloud.talk.jobs;
|
||||
|
||||
import android.app.NotificationManager;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Build;
|
||||
import android.util.Log;
|
||||
|
||||
|
@ -212,17 +209,5 @@ public class AccountRemovalWorker extends Worker {
|
|||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -121,7 +121,7 @@ class GeocodingActivity :
|
|||
if (viewModel.getQuery().isNotEmpty() && adapter.itemCount == 0) {
|
||||
viewModel.searchLocation()
|
||||
} 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 {
|
||||
override fun onItemClick(position: Int) {
|
||||
|
|
|
@ -608,7 +608,7 @@ class ProfileActivity : BaseActivity() {
|
|||
class UserInfoAdapter(
|
||||
displayList: List<UserInfoDetailsItem>?,
|
||||
private val viewThemeUtils: ViewThemeUtils,
|
||||
private val controller: ProfileActivity
|
||||
private val profileActivity: ProfileActivity
|
||||
) : RecyclerView.Adapter<UserInfoAdapter.ViewHolder>() {
|
||||
var displayList: List<UserInfoDetailsItem>?
|
||||
var filteredDisplayList: MutableList<UserInfoDetailsItem> = LinkedList()
|
||||
|
@ -643,7 +643,7 @@ class ProfileActivity : BaseActivity() {
|
|||
}
|
||||
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
val item: UserInfoDetailsItem = if (controller.edit) {
|
||||
val item: UserInfoDetailsItem = if (profileActivity.edit) {
|
||||
displayList!![position]
|
||||
} else {
|
||||
filteredDisplayList[position]
|
||||
|
@ -656,11 +656,11 @@ class ProfileActivity : BaseActivity() {
|
|||
|
||||
holder.binding.icon.contentDescription = item.hint
|
||||
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
|
||||
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.isFocusableInTouchMode = true
|
||||
|
@ -700,7 +700,7 @@ class ProfileActivity : BaseActivity() {
|
|||
}
|
||||
|
||||
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()
|
||||
} else {
|
||||
filteredDisplayList[holder.adapterPosition].text =
|
||||
|
@ -739,7 +739,7 @@ class ProfileActivity : BaseActivity() {
|
|||
}
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return if (controller.edit) {
|
||||
return if (profileActivity.edit) {
|
||||
displayList!!.size
|
||||
} else {
|
||||
filteredDisplayList.size
|
||||
|
@ -762,7 +762,7 @@ class ProfileActivity : BaseActivity() {
|
|||
}
|
||||
|
||||
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_RETRIES: Long = 3
|
||||
private const val HIGH_EMPHASIS_ALPHA: Float = 0.87f
|
||||
|
|
|
@ -91,8 +91,6 @@ class ShareRecordingToChatReceiver : BroadcastReceiver() {
|
|||
// However, as we are in a broadcast receiver, this needs a TaskStackBuilder
|
||||
// combined with addNextIntentWithParentStack. For further reading, see
|
||||
// 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(
|
||||
View(context),
|
||||
|
|
|
@ -27,6 +27,7 @@ package com.nextcloud.talk.settings
|
|||
|
||||
import android.animation.Animator
|
||||
import android.animation.AnimatorListenerAdapter
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.KeyguardManager
|
||||
import android.content.Context
|
||||
import android.content.DialogInterface
|
||||
|
@ -51,6 +52,7 @@ import android.view.View
|
|||
import android.view.WindowManager
|
||||
import android.widget.EditText
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.view.ContextThemeWrapper
|
||||
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.R
|
||||
import com.nextcloud.talk.activities.BaseActivity
|
||||
import com.nextcloud.talk.activities.MainActivity
|
||||
import com.nextcloud.talk.api.NcApi
|
||||
import com.nextcloud.talk.application.NextcloudTalkApplication
|
||||
import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.setAppTheme
|
||||
|
@ -465,17 +468,47 @@ class SettingsActivity : BaseActivity() {
|
|||
}
|
||||
}
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
private fun removeCurrentAccount() {
|
||||
val otherUserExists = userManager.scheduleUserForDeletionWithId(currentUser!!.id!!).blockingGet()
|
||||
userManager.scheduleUserForDeletionWithId(currentUser!!.id!!).blockingGet()
|
||||
val accountRemovalWork = OneTimeWorkRequest.Builder(AccountRemovalWorker::class.java).build()
|
||||
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 {
|
||||
|
@ -1205,7 +1238,7 @@ class SettingsActivity : BaseActivity() {
|
|||
}
|
||||
|
||||
companion object {
|
||||
private const val TAG = "SettingsController"
|
||||
private val TAG = SettingsActivity::class.java.simpleName
|
||||
private const val DURATION: Long = 2500
|
||||
private const val START_DELAY: Long = 5000
|
||||
private const val DISABLED_ALPHA: Float = 0.38f
|
||||
|
|
|
@ -31,8 +31,8 @@ import com.afollestad.materialdialogs.bottomsheets.BottomSheet
|
|||
import com.nextcloud.talk.R
|
||||
import com.nextcloud.talk.api.NcApi
|
||||
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.models.json.conversations.RoomOverall
|
||||
import com.nextcloud.talk.models.json.hovercard.HoverCardAction
|
||||
|
|
|
@ -35,7 +35,7 @@ import android.view.View;
|
|||
import android.view.ViewGroup;
|
||||
|
||||
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.api.NcApi;
|
||||
import com.nextcloud.talk.application.NextcloudTalkApplication;
|
||||
|
@ -71,7 +71,7 @@ import io.reactivex.android.schedulers.AndroidSchedulers;
|
|||
import io.reactivex.disposables.Disposable;
|
||||
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)
|
||||
public class ChooseAccountDialogFragment extends DialogFragment {
|
||||
|
@ -185,11 +185,9 @@ public class ChooseAccountDialogFragment extends DialogFragment {
|
|||
// Creating listeners for quick-actions
|
||||
binding.currentAccount.getRoot().setOnClickListener(v -> dismiss());
|
||||
|
||||
|
||||
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);
|
||||
dismiss();
|
||||
});
|
||||
|
|
|
@ -84,6 +84,8 @@ object BundleKeys {
|
|||
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_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 KEY_REAUTHORIZE_ACCOUNT = "KEY_REAUTHORIZE_ACCOUNT"
|
||||
const val KEY_PASSWORD = "KEY_PASSWORD"
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ public class ApplicationWideMessageHolder {
|
|||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
|
|
|
@ -234,7 +234,7 @@
|
|||
android:id="@+id/separator_1"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:background="@color/controller_chat_separator" />
|
||||
android:background="@color/chat_separator" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/typing_indicator"
|
||||
|
|
|
@ -178,7 +178,15 @@
|
|||
android:textAppearance="@style/ListItem" />
|
||||
</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>
|
||||
|
|
|
@ -40,8 +40,6 @@
|
|||
android:windowContentOverlay="@null"
|
||||
app:elevation="0dp">
|
||||
|
||||
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
|
@ -58,11 +56,4 @@
|
|||
|
||||
</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>
|
||||
|
|
|
@ -18,25 +18,34 @@
|
|||
~ 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:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/generic_rv_layout"
|
||||
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_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_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
|
||||
android:id="@+id/recycler_view"
|
||||
|
@ -44,4 +53,4 @@
|
|||
android:layout_height="match_parent"
|
||||
app:layout_anchor="@+id/swipe_refresh_layout"
|
||||
app:layout_anchorGravity="center" />
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
</LinearLayout>
|
|
@ -28,7 +28,7 @@
|
|||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/controllerCallLayout"
|
||||
android:id="@+id/callLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fitsSystemWindows="true"
|
||||
|
@ -128,7 +128,7 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAlignment="center"
|
||||
android:textColor="@color/controller_call_incomingCallTextView"
|
||||
android:textColor="@color/call_incomingCallTextView"
|
||||
android:textSize="16sp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/controllerCallNotificationLayout"
|
||||
android:id="@+id/callNotificationLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/grey950">
|
||||
|
@ -83,7 +83,7 @@
|
|||
android:layout_marginTop="16dp"
|
||||
android:text="@string/nc_call_unknown"
|
||||
android:textAlignment="center"
|
||||
android:textColor="@color/controller_call_incomingCallTextView"
|
||||
android:textColor="@color/call_incomingCallTextView"
|
||||
android:textSize="16sp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
|
@ -109,7 +109,7 @@
|
|||
android:layout_below="@+id/conversationNameTextView"
|
||||
android:text="@string/nc_call_incoming"
|
||||
android:textAlignment="center"
|
||||
android:textColor="@color/controller_call_incomingCallTextView"
|
||||
android:textColor="@color/call_incomingCallTextView"
|
||||
android:textSize="16sp" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
|
|
@ -53,7 +53,7 @@
|
|||
<color name="conversation_unread_bubble">#373737</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>
|
||||
|
||||
|
|
|
@ -61,10 +61,10 @@
|
|||
<color name="nc_darkRed">#D32F2F</color>
|
||||
<color name="nc_darkYellow">#FF9800</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="nc_grey">#D5D5D5</color>
|
||||
<color name="controller_call_incomingCallTextView">#E9FFFFFF</color>
|
||||
<color name="call_incomingCallTextView">#E9FFFFFF</color>
|
||||
<color name="grey950">#111111</color>
|
||||
<color name="textColorMaxContrast">#767676</color>
|
||||
<color name="colorBackgroundDarker">#DBDBDB</color>
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
|
||||
<!-- Branding -->
|
||||
<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>
|
||||
<string name="weblogin_url" translatable="false"></string>
|
||||
|
||||
|
|
|
@ -574,6 +574,7 @@ How to translate with transifex:
|
|||
<string name="filename_progress">%1$s (%2$d)</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_deleted_user">User %1$s was removed</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>
|
||||
|
|
|
@ -97,7 +97,7 @@ class BundleKeysTest {
|
|||
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_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)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue