diff --git a/app/src/main/java/com/nextcloud/talk/application/NextcloudTalkApplication.kt b/app/src/main/java/com/nextcloud/talk/application/NextcloudTalkApplication.kt
index 41ef27f91..497da93e5 100644
--- a/app/src/main/java/com/nextcloud/talk/application/NextcloudTalkApplication.kt
+++ b/app/src/main/java/com/nextcloud/talk/application/NextcloudTalkApplication.kt
@@ -51,6 +51,7 @@ import com.nextcloud.talk.newarch.domain.di.module.UseCasesModule
import com.nextcloud.talk.newarch.features.account.di.module.AccountModule
import com.nextcloud.talk.newarch.features.contactsflow.di.module.ContactsFlowModule
import com.nextcloud.talk.newarch.features.conversationsList.di.module.ConversationsListModule
+import com.nextcloud.talk.newarch.features.settingsflow.di.module.SettingsModule
import com.nextcloud.talk.newarch.local.dao.UsersDao
import com.nextcloud.talk.newarch.local.models.User
import com.nextcloud.talk.newarch.local.models.other.UserStatus.*
@@ -180,7 +181,7 @@ class NextcloudTalkApplication : Application(), LifecycleObserver, Configuration
startKoin {
androidContext(this@NextcloudTalkApplication)
androidLogger()
- modules(listOf(CommunicationModule, StorageModule, NetworkModule, ConversationsListModule, ServiceModule, AccountModule, UseCasesModule, ContactsFlowModule))
+ modules(listOf(CommunicationModule, StorageModule, NetworkModule, ConversationsListModule, ServiceModule, AccountModule, UseCasesModule, ContactsFlowModule, SettingsModule))
}
}
diff --git a/app/src/main/java/com/nextcloud/talk/controllers/RingtoneSelectionController.kt b/app/src/main/java/com/nextcloud/talk/controllers/RingtoneSelectionController.kt
index f7f2b1a13..881f4efb7 100644
--- a/app/src/main/java/com/nextcloud/talk/controllers/RingtoneSelectionController.kt
+++ b/app/src/main/java/com/nextcloud/talk/controllers/RingtoneSelectionController.kt
@@ -204,7 +204,12 @@ class RingtoneSelectionController(args: Bundle) : BaseController(), FlexibleAdap
}
override fun getTitle(): String? {
- return resources!!.getString(R.string.nc_settings_notification_sounds)
+ return if (callNotificationSounds) {
+ resources?.getString(R.string.nc_settings_calls_sound)
+ } else {
+ resources?.getString(R.string.nc_settings_notifications_sound)
+
+ }
}
@SuppressLint("LongLogTag")
diff --git a/app/src/main/java/com/nextcloud/talk/controllers/SettingsController.kt b/app/src/main/java/com/nextcloud/talk/controllers/SettingsController.kt
deleted file mode 100644
index 6570c36f8..000000000
--- a/app/src/main/java/com/nextcloud/talk/controllers/SettingsController.kt
+++ /dev/null
@@ -1,852 +0,0 @@
-/*
- * Nextcloud Talk application
- *
- * @author Mario Danic
- * Copyright (C) 2017 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 .
- */
-
-package com.nextcloud.talk.controllers
-
-import android.animation.Animator
-import android.animation.AnimatorListenerAdapter
-import android.app.Activity
-import android.app.KeyguardManager
-import android.content.Context
-import android.content.Intent
-import android.net.Uri
-import android.os.Build
-import android.os.Bundle
-import android.security.KeyChain
-import android.text.TextUtils
-import android.util.Log
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import android.view.WindowManager
-import android.widget.Checkable
-import android.widget.ImageView
-import android.widget.TextView
-import androidx.core.view.ViewCompat
-import androidx.emoji.widget.EmojiTextView
-import androidx.work.OneTimeWorkRequest
-import androidx.work.WorkManager
-import butterknife.BindView
-import butterknife.OnClick
-import coil.api.load
-import coil.transform.CircleCropTransformation
-import com.bluelinelabs.conductor.RouterTransaction
-import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler
-import com.bluelinelabs.conductor.changehandler.VerticalChangeHandler
-import com.bluelinelabs.logansquare.LoganSquare
-import com.nextcloud.talk.BuildConfig
-import com.nextcloud.talk.R
-import com.nextcloud.talk.api.NcApi
-import com.nextcloud.talk.application.NextcloudTalkApplication
-import com.nextcloud.talk.controllers.base.BaseController
-import com.nextcloud.talk.jobs.AccountRemovalWorker
-import com.nextcloud.talk.models.RingtoneSettings
-import com.nextcloud.talk.models.json.userprofile.UserProfileOverall
-import com.nextcloud.talk.newarch.domain.repository.offline.UsersRepository
-import com.nextcloud.talk.newarch.features.account.serverentry.ServerEntryView
-import com.nextcloud.talk.newarch.local.models.UserNgEntity
-import com.nextcloud.talk.newarch.local.models.getCredentials
-import com.nextcloud.talk.newarch.local.models.other.UserStatus
-import com.nextcloud.talk.utils.*
-import com.nextcloud.talk.utils.bundle.BundleKeys
-import com.nextcloud.talk.utils.preferences.MagicUserInputModule
-import com.nextcloud.talk.utils.singletons.ApplicationWideMessageHolder
-import com.uber.autodispose.AutoDispose
-import com.uber.autodispose.ObservableSubscribeProxy
-import com.yarolegovich.lovelydialog.LovelySaveStateHandler
-import com.yarolegovich.lovelydialog.LovelyStandardDialog
-import com.yarolegovich.mp.*
-import io.reactivex.android.schedulers.AndroidSchedulers
-import io.reactivex.schedulers.Schedulers
-import kotlinx.coroutines.*
-import net.orange_box.storebox.listeners.OnPreferenceValueChangedListener
-import org.koin.android.ext.android.inject
-import java.io.IOException
-import java.net.URI
-import java.net.URISyntaxException
-import java.util.*
-
-class SettingsController : BaseController() {
- @JvmField
- @BindView(R.id.settings_screen)
- var settingsScreen: MaterialPreferenceScreen? = null
-
- @JvmField
- @BindView(R.id.settings_proxy_choice)
- var proxyChoice: MaterialChoicePreference? = null
-
- @JvmField
- @BindView(R.id.settings_proxy_port_edit)
- var proxyPortEditText: MaterialEditTextPreference? = null
-
- @JvmField
- @BindView(R.id.settings_licence)
- var licenceButton: MaterialStandardPreference? = null
-
- @JvmField
- @BindView(R.id.settings_privacy)
- var privacyButton: MaterialStandardPreference? = null
-
- @JvmField
- @BindView(R.id.settings_source_code)
- var sourceCodeButton: MaterialStandardPreference? = null
-
- @JvmField
- @BindView(R.id.settings_version)
- var versionInfo: MaterialStandardPreference? = null
-
- @JvmField
- @BindView(R.id.avatar_image)
- var avatarImageView: ImageView? = null
-
- @JvmField
- @BindView(R.id.display_name_text)
- var displayNameTextView: EmojiTextView? = null
-
- @JvmField
- @BindView(R.id.base_url_text)
- var baseUrlTextView: TextView? = null
-
- @JvmField
- @BindView(R.id.settings_call_sound)
- var settingsCallSound: MaterialStandardPreference? = null
-
- @JvmField
- @BindView(R.id.settings_message_sound)
- var settingsMessageSound: MaterialStandardPreference? = null
-
- @JvmField
- @BindView(R.id.settings_remove_account)
- var removeAccountButton: MaterialStandardPreference? = null
-
- @JvmField
- @BindView(R.id.settings_switch)
- var switchAccountButton: MaterialStandardPreference? = null
-
- @JvmField
- @BindView(R.id.settings_reauthorize)
- var reauthorizeButton: MaterialStandardPreference? = null
-
- @JvmField
- @BindView(R.id.settings_add_account)
- var addAccountButton: MaterialStandardPreference? = null
-
- @JvmField
- @BindView(R.id.message_view)
- var messageView: MaterialPreferenceCategory? = null
-
- @JvmField
- @BindView(R.id.settings_client_cert)
- var certificateSetup: MaterialStandardPreference? = null
-
- @JvmField
- @BindView(R.id.settings_always_vibrate)
- var shouldVibrateSwitchPreference: MaterialSwitchPreference? = null
-
- @JvmField
- @BindView(R.id.settings_incognito_keyboard)
- var incognitoKeyboardSwitchPreference: MaterialSwitchPreference? = null
-
- @JvmField
- @BindView(R.id.settings_screen_security)
- var screenSecuritySwitchPreference: MaterialSwitchPreference? = null
-
- @JvmField
- @BindView(R.id.settings_link_previews)
- var linkPreviewsSwitchPreference: MaterialSwitchPreference? = null
-
- @JvmField
- @BindView(R.id.settings_screen_lock)
- var screenLockSwitchPreference: MaterialSwitchPreference? = null
-
- @JvmField
- @BindView(R.id.settings_screen_lock_timeout)
- var screenLockTimeoutChoicePreference: MaterialChoicePreference? = null
-
- @JvmField
- @BindView(R.id.message_text)
- var messageText: TextView? = null
- val ncApi: NcApi by inject()
- val usersRepository: UsersRepository by inject()
- private var saveStateHandler: LovelySaveStateHandler? = null
- private var currentUser: UserNgEntity? = null
- private var credentials: String? = null
- lateinit var proxyTypeChangeListener: OnPreferenceValueChangedListener
- lateinit var proxyCredentialsChangeListener: OnPreferenceValueChangedListener
- lateinit var screenSecurityChangeListener: OnPreferenceValueChangedListener
- lateinit var screenLockChangeListener: OnPreferenceValueChangedListener
- lateinit var screenLockTimeoutChangeListener: OnPreferenceValueChangedListener
- lateinit var themeChangeListener: OnPreferenceValueChangedListener
-
- override fun inflateView(
- inflater: LayoutInflater,
- container: ViewGroup
- ): View {
- return inflater.inflate(R.layout.controller_settings, container, false)
- }
-
- override fun onViewBound(view: View) {
- super.onViewBound(view)
- setHasOptionsMenu(true)
-
- ViewCompat.setTransitionName(avatarImageView!!, "userAvatar.transitionTag")
-
- if (saveStateHandler == null) {
- saveStateHandler = LovelySaveStateHandler()
- }
-
- proxyTypeChangeListener = ProxyTypeChangeListener()
- proxyCredentialsChangeListener = ProxyCredentialsChangeListener()
- screenSecurityChangeListener = ScreenSecurityChangeListener()
- screenLockChangeListener = ScreenLockListener()
- screenLockTimeoutChangeListener = ScreenLockTimeoutListener()
- themeChangeListener = ThemeChangeListener()
- }
-
- private fun showLovelyDialog(
- dialogId: Int,
- savedInstanceState: Bundle?
- ) {
- when (dialogId) {
- ID_REMOVE_ACCOUNT_WARNING_DIALOG -> showRemoveAccountWarning(savedInstanceState)
- else -> {
- }
- }
- }
-
- @OnClick(R.id.settings_version)
- fun sendLogs() {
- if (resources!!.getBoolean(R.bool.nc_is_debug)) {
- LoggingUtils.sendMailWithAttachment(context)
- }
- }
-
- override fun onSaveViewState(
- view: View,
- outState: Bundle
- ) {
- saveStateHandler!!.saveInstanceState(outState)
- super.onSaveViewState(view, outState)
- }
-
- override fun onRestoreViewState(
- view: View,
- savedViewState: Bundle
- ) {
- super.onRestoreViewState(view, savedViewState)
- if (LovelySaveStateHandler.wasDialogOnScreen(savedViewState)) {
- //Dialog won't be restarted automatically, so we need to call this method.
- //Each dialog knows how to restore its viewState
- showLovelyDialog(LovelySaveStateHandler.getSavedDialogId(savedViewState), savedViewState)
- }
- }
-
- private fun showRemoveAccountWarning(savedInstanceState: Bundle?) {
- if (activity != null) {
- LovelyStandardDialog(activity, LovelyStandardDialog.ButtonLayout.HORIZONTAL)
- .setTopColorRes(R.color.nc_darkRed)
- .setIcon(
- DisplayUtils.getTintedDrawable(
- resources!!,
- R.drawable.ic_delete_black_24dp, R.color.bg_default
- )
- )
- .setPositiveButtonColor(context.resources.getColor(R.color.nc_darkRed))
- .setTitle(R.string.nc_settings_remove_account)
- .setMessage(R.string.nc_settings_remove_confirmation)
- .setPositiveButton(R.string.nc_settings_remove) { removeCurrentAccount() }
- .setNegativeButton(R.string.nc_cancel, null)
- .setInstanceStateHandler(ID_REMOVE_ACCOUNT_WARNING_DIALOG, saveStateHandler!!)
- .setSavedInstanceState(savedInstanceState)
- .show()
- }
- }
-
- private fun removeCurrentAccount() {
- GlobalScope.launch {
- val job = async {
- val user = usersRepository.getActiveUser()
- user!!.status = UserStatus.PENDING_DELETE
- usersRepository.updateUser(user)
- val accountRemovalWork = OneTimeWorkRequest.Builder(AccountRemovalWorker::class.java)
- .build()
- WorkManager.getInstance()
- .enqueue(accountRemovalWork)
- }
- job.await()
-
- if (usersRepository.setAnyUserAsActive()) {
- withContext(Dispatchers.Main) {
- onViewBound(view!!)
- onAttach(view!!)
- }
- } else {
- withContext(Dispatchers.Main) {
- router.setRoot(RouterTransaction.with(
- ServerEntryView()
- )
- .pushChangeHandler(VerticalChangeHandler())
- .popChangeHandler(VerticalChangeHandler())
- )
- }
- }
- }
- }
-
- override fun onAttach(view: View) {
- super.onAttach(view)
-
- if (actionBar != null) {
- actionBar!!.show()
- }
-
- GlobalScope.launch {
- var hasMultipleUsers = false
- val job = async {
- currentUser = usersRepository.getActiveUser()
- hasMultipleUsers = usersRepository.getUsers().isNotEmpty()
- credentials = currentUser!!.getCredentials()
- }
-
- job.await()
- withContext(Dispatchers.Main) {
- appPreferences.registerProxyTypeListener(proxyTypeChangeListener)
- appPreferences.registerProxyCredentialsListener { proxyCredentialsChangeListener }
- appPreferences.registerScreenSecurityListener { screenSecurityChangeListener }
- appPreferences.registerScreenLockListener { screenLockChangeListener }
- appPreferences.registerScreenLockTimeoutListener { screenLockTimeoutChangeListener }
- appPreferences.registerThemeChangeListener { themeChangeListener }
-
- val listWithIntFields = ArrayList()
- listWithIntFields.add("proxy_port")
-
- settingsScreen!!.setUserInputModule(MagicUserInputModule(activity, listWithIntFields))
- settingsScreen!!.setVisibilityController(
- R.id.settings_proxy_use_credentials,
- Arrays.asList(R.id.settings_proxy_username_edit, R.id.settings_proxy_password_edit),
- true
- )
-
- if (!TextUtils.isEmpty(resources!!.getString(R.string.nc_gpl3_url))) {
- licenceButton!!.addPreferenceClickListener { view1 ->
- val browserIntent =
- Intent(Intent.ACTION_VIEW, Uri.parse(resources!!.getString(R.string.nc_gpl3_url)))
- startActivity(browserIntent)
- }
- } else {
- licenceButton!!.visibility = View.GONE
- }
-
- if (!DoNotDisturbUtils.hasVibrator()) {
- shouldVibrateSwitchPreference!!.visibility = View.GONE
- }
-
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
- incognitoKeyboardSwitchPreference!!.visibility = View.GONE
- }
-
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
- screenLockSwitchPreference!!.visibility = View.GONE
- screenLockTimeoutChoicePreference!!.visibility = View.GONE
- } else {
- screenLockSwitchPreference!!.setSummary(
- String.format(
- Locale.getDefault(),
- resources!!.getString(R.string.nc_settings_screen_lock_desc),
- resources!!.getString(R.string.nc_app_name)
- )
- )
- }
-
- if (!TextUtils.isEmpty(resources!!.getString(R.string.nc_privacy_url))) {
- privacyButton!!.addPreferenceClickListener { view12 ->
- val browserIntent =
- Intent(Intent.ACTION_VIEW, Uri.parse(resources!!.getString(R.string.nc_privacy_url)))
- startActivity(browserIntent)
- }
- } else {
- privacyButton!!.visibility = View.GONE
- }
-
- if (!TextUtils.isEmpty(resources!!.getString(R.string.nc_source_code_url))) {
- sourceCodeButton!!.addPreferenceClickListener { view13 ->
- val browserIntent =
- Intent(Intent.ACTION_VIEW, Uri.parse(resources!!.getString(R.string.nc_source_code_url)))
- startActivity(browserIntent)
- }
- } else {
- sourceCodeButton!!.visibility = View.GONE
- }
-
- versionInfo!!.setSummary("v" + BuildConfig.VERSION_NAME)
-
- settingsCallSound!!.setOnClickListener { v ->
- val bundle = Bundle()
- bundle.putBoolean(BundleKeys.KEY_ARE_CALL_SOUNDS, true)
- router.pushController(
- RouterTransaction.with(RingtoneSelectionController(bundle))
- .pushChangeHandler(HorizontalChangeHandler())
- .popChangeHandler(HorizontalChangeHandler())
- )
- }
-
- settingsMessageSound!!.setOnClickListener { v ->
- val bundle = Bundle()
- bundle.putBoolean(BundleKeys.KEY_ARE_CALL_SOUNDS, false)
- router.pushController(
- RouterTransaction.with(RingtoneSelectionController(bundle))
- .pushChangeHandler(HorizontalChangeHandler())
- .popChangeHandler(HorizontalChangeHandler())
- )
- }
-
- addAccountButton!!.addPreferenceClickListener { view15 ->
- router.pushController(
- RouterTransaction.with(ServerEntryView()).pushChangeHandler(
- VerticalChangeHandler()
- )
- .popChangeHandler(VerticalChangeHandler())
- )
- }
-
- switchAccountButton!!.addPreferenceClickListener { view16 ->
- router.pushController(
- RouterTransaction.with(SwitchAccountController()).pushChangeHandler(
- VerticalChangeHandler()
- )
- .popChangeHandler(VerticalChangeHandler())
- )
- }
-
- var host: String? = null
- var port = -1
-
- val uri: URI
- try {
- uri = URI(currentUser!!.baseUrl)
- host = uri.host
- port = uri.port
- } catch (e: URISyntaxException) {
- Log.e(TAG, "Failed to create uri")
- }
-
- val finalHost = host
- val finalPort = port
- certificateSetup!!.addPreferenceClickListener { v ->
- KeyChain.choosePrivateKeyAlias(
- Objects.requireNonNull(activity), { alias ->
- activity!!.runOnUiThread {
- if (alias != null) {
- certificateSetup!!.setTitle(R.string.nc_client_cert_change)
- } else {
- certificateSetup!!.setTitle(R.string.nc_client_cert_setup)
- }
- }
-
- var realAlias = alias
- if (realAlias == null) {
- realAlias = ""
- }
-
- currentUser = usersRepository.getUserWithId(currentUser!!.id)
- currentUser!!.clientCertificate = realAlias
- GlobalScope.launch {
- usersRepository.updateUser(currentUser!!)
- }
- }, arrayOf("RSA", "EC"), null, finalHost, finalPort,
- currentUser!!.clientCertificate
- )
- }
-
- if (!TextUtils.isEmpty(currentUser!!.clientCertificate)) {
- certificateSetup!!.setTitle(R.string.nc_client_cert_change)
- } else {
- certificateSetup!!.setTitle(R.string.nc_client_cert_setup)
- }
-
- if (shouldVibrateSwitchPreference!!.visibility == View.VISIBLE) {
- (shouldVibrateSwitchPreference!!.findViewById(
- R.id.mp_checkable
- ) as Checkable).isChecked = appPreferences.shouldVibrateSetting
- }
-
- (screenSecuritySwitchPreference!!.findViewById(
- R.id.mp_checkable
- ) as Checkable).isChecked = appPreferences.isScreenSecured
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
- (incognitoKeyboardSwitchPreference!!.findViewById(
- R.id.mp_checkable
- ) as Checkable).isChecked =
- appPreferences.isKeyboardIncognito
- }
-
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- (incognitoKeyboardSwitchPreference!!.findViewById(
- R.id.mp_checkable
- ) as Checkable).isChecked =
- appPreferences.isKeyboardIncognito
- }
-
- (linkPreviewsSwitchPreference!!.findViewById(R.id.mp_checkable) as Checkable).isChecked =
- appPreferences.areLinkPreviewsAllowed
-
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- val keyguardManager = context.getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager
-
- if (keyguardManager.isKeyguardSecure) {
- screenLockSwitchPreference!!.isEnabled = true
- screenLockTimeoutChoicePreference!!.isEnabled = true
- (screenLockSwitchPreference!!.findViewById(
- R.id.mp_checkable
- ) as Checkable).isChecked =
- appPreferences.isScreenLocked
-
- screenLockTimeoutChoicePreference!!.isEnabled = appPreferences.isScreenLocked
-
- if (appPreferences.isScreenLocked) {
- screenLockTimeoutChoicePreference!!.alpha = 1.0f
- } else {
- screenLockTimeoutChoicePreference!!.alpha = 0.38f
- }
-
- screenLockSwitchPreference!!.alpha = 1.0f
- } else {
- screenLockSwitchPreference!!.isEnabled = false
- screenLockTimeoutChoicePreference!!.isEnabled = false
- appPreferences.removeScreenLock()
- appPreferences.removeScreenLockTimeout()
- (screenLockSwitchPreference!!.findViewById(
- R.id.mp_checkable
- ) as Checkable).isChecked =
- false
- screenLockSwitchPreference!!.alpha = 0.38f
- screenLockTimeoutChoicePreference!!.alpha = 0.38f
- }
- }
-
- var ringtoneName = ""
- var ringtoneSettings: RingtoneSettings
- if (!TextUtils.isEmpty(appPreferences.callRingtoneUri)) {
- try {
- ringtoneSettings =
- LoganSquare.parse(appPreferences.callRingtoneUri, RingtoneSettings::class.java)
- ringtoneName = ringtoneSettings.ringtoneName
- } catch (e: IOException) {
- Log.e(TAG, "Failed to parse ringtone name")
- }
-
- settingsCallSound!!.setSummary(ringtoneName)
- } else {
- settingsCallSound!!.setSummary(R.string.nc_settings_default_ringtone)
- }
-
- ringtoneName = ""
-
- if (!TextUtils.isEmpty(appPreferences.messageRingtoneUri)) {
- try {
- ringtoneSettings =
- LoganSquare.parse(appPreferences.messageRingtoneUri, RingtoneSettings::class.java)
- ringtoneName = ringtoneSettings.ringtoneName
- } catch (e: IOException) {
- Log.e(TAG, "Failed to parse ringtone name")
- }
-
- settingsMessageSound!!.setSummary(ringtoneName)
- } else {
- settingsMessageSound!!.setSummary(R.string.nc_settings_default_ringtone)
- }
-
- if ("No proxy" == appPreferences.proxyType || appPreferences.proxyType == null) {
- hideProxySettings()
- } else {
- showProxySettings()
- }
-
- if (appPreferences.proxyCredentials) {
- showProxyCredentials()
- } else {
- hideProxyCredentials()
- }
-
- if (currentUser != null) {
-
- baseUrlTextView!!.text = Uri.parse(currentUser!!.baseUrl)
- .host
-
- reauthorizeButton!!.addPreferenceClickListener { view14 ->
- }
-
- if (currentUser!!.displayName != null) {
- displayNameTextView!!.text = currentUser!!.displayName
- }
-
- loadAvatarImage()
-
- ncApi.getUserProfile(
- credentials,
- ApiUtils.getUrlForUserProfile(currentUser!!.baseUrl)
- )
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .`as`>(
- AutoDispose.autoDisposable(scopeProvider)
- )
- .subscribe({ userProfileOverall ->
-
- var displayName: String? = userProfileOverall.ocs.data.displayName
-
- if (!TextUtils.isEmpty(displayName) && displayName != currentUser!!.displayName) {
- val user = usersRepository.getUserWithId(currentUser!!.id)
- user.displayName = displayName
- GlobalScope.launch {
- usersRepository.updateUser(user)
- }
- displayNameTextView!!.text = displayName
-
- }
- }, { throwable -> }, { Log.d(TAG, "") })
-
- removeAccountButton!!.addPreferenceClickListener { view1 ->
- showLovelyDialog(
- ID_REMOVE_ACCOUNT_WARNING_DIALOG, null
- )
- }
- }
-
- if (!hasMultipleUsers) {
- switchAccountButton!!.visibility = View.GONE
- }
-
- if (ApplicationWideMessageHolder.getInstance().messageType != null) {
- when (ApplicationWideMessageHolder.getInstance().messageType) {
- ApplicationWideMessageHolder.MessageType.ACCOUNT_UPDATED_NOT_ADDED -> {
- messageText!!.setTextColor(resources!!.getColor(R.color.colorPrimary))
- messageText!!.text = resources!!.getString(R.string.nc_settings_account_updated)
- messageView!!.visibility = View.VISIBLE
- }
- ApplicationWideMessageHolder.MessageType.SERVER_WITHOUT_TALK -> {
- messageText!!.setTextColor(resources!!.getColor(R.color.nc_darkRed))
- messageText!!.text = resources!!.getString(R.string.nc_settings_wrong_account)
- messageView!!.visibility = View.VISIBLE
- messageText!!.setTextColor(resources!!.getColor(R.color.colorPrimary))
- messageText!!.text = resources!!.getString(R.string.nc_server_account_imported)
- messageView!!.visibility = View.VISIBLE
- }
- ApplicationWideMessageHolder.MessageType.ACCOUNT_WAS_IMPORTED -> {
- messageText!!.setTextColor(resources!!.getColor(R.color.colorPrimary))
- messageText!!.text = resources!!.getString(R.string.nc_server_account_imported)
- messageView!!.visibility = View.VISIBLE
- }
- ApplicationWideMessageHolder.MessageType.FAILED_TO_IMPORT_ACCOUNT -> {
- messageText!!.setTextColor(resources!!.getColor(R.color.nc_darkRed))
- messageText!!.text = resources!!.getString(R.string.nc_server_failed_to_import_account)
- messageView!!.visibility = View.VISIBLE
- }
- else -> messageView!!.visibility = View.GONE
- }
- ApplicationWideMessageHolder.getInstance().messageType = null
-
- messageView!!.animate()
- .translationY(0f)
- .alpha(0.0f)
- .setDuration(2500)
- .setStartDelay(5000)
- .setListener(object : AnimatorListenerAdapter() {
- override fun onAnimationEnd(animation: Animator) {
- super.onAnimationEnd(animation)
- if (messageView != null) {
- messageView!!.visibility = View.GONE
- }
- }
- })
- } else {
- if (messageView != null) {
- messageView!!.visibility = View.GONE
- } else {
- // do nothing
- }
- }
- }
- }
-
-
- }
-
- private fun loadAvatarImage() {
- val avatarId: String
- if (!TextUtils.isEmpty(currentUser!!.userId)) {
- avatarId = currentUser!!.userId
- } else {
- avatarId = currentUser!!.username
- }
-
- avatarImageView!!.load(
- ApiUtils.getUrlForAvatarWithName(
- currentUser!!.baseUrl,
- avatarId, R.dimen.avatar_size_big
- )
- ) {
- addHeader("Authorization", currentUser!!.getCredentials())
- transformations(CircleCropTransformation())
- }
- }
-
- public override fun onDestroy() {
- appPreferences.unregisterProxyTypeListener(proxyTypeChangeListener)
- appPreferences.unregisterProxyCredentialsListener(proxyCredentialsChangeListener)
- appPreferences.unregisterScreenSecurityListener(screenSecurityChangeListener)
- appPreferences.unregisterScreenLockListener(screenLockChangeListener)
- appPreferences.unregisterScreenLockTimeoutListener(screenLockTimeoutChangeListener)
- appPreferences.unregisterThemeChangeListener(themeChangeListener)
- super.onDestroy()
- }
-
- private fun hideProxySettings() {
- appPreferences.removeProxyHost()
- appPreferences.removeProxyPort()
- appPreferences.removeProxyCredentials()
- appPreferences.removeProxyUsername()
- appPreferences.removeProxyPassword()
- settingsScreen!!.findViewById(R.id.settings_proxy_host_edit)
- .visibility = View.GONE
- settingsScreen!!.findViewById(R.id.settings_proxy_port_edit)
- .visibility = View.GONE
- settingsScreen!!.findViewById(R.id.settings_proxy_use_credentials)
- .visibility = View.GONE
- settingsScreen!!.findViewById(R.id.settings_proxy_username_edit)
- .visibility = View.GONE
- settingsScreen!!.findViewById(R.id.settings_proxy_password_edit)
- .visibility = View.GONE
- }
-
- private fun showProxySettings() {
- settingsScreen!!.findViewById(R.id.settings_proxy_host_edit)
- .visibility = View.VISIBLE
- settingsScreen!!.findViewById(R.id.settings_proxy_port_edit)
- .visibility = View.VISIBLE
- settingsScreen!!.findViewById(R.id.settings_proxy_use_credentials)
- .visibility = View.VISIBLE
- }
-
- private fun showProxyCredentials() {
- settingsScreen!!.findViewById(R.id.settings_proxy_username_edit)
- .visibility = View.VISIBLE
- settingsScreen!!.findViewById(R.id.settings_proxy_password_edit)
- .visibility = View.VISIBLE
- }
-
- private fun hideProxyCredentials() {
- appPreferences.removeProxyUsername()
- appPreferences.removeProxyPassword()
- settingsScreen!!.findViewById(R.id.settings_proxy_username_edit)
- .visibility = View.GONE
- settingsScreen!!.findViewById(R.id.settings_proxy_password_edit)
- .visibility = View.GONE
- }
-
- override fun getTitle(): String? {
- return resources!!.getString(R.string.nc_settings)
- }
-
- private inner class ScreenLockTimeoutListener : OnPreferenceValueChangedListener {
-
- override fun onChanged(newValue: String) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- SecurityUtils.createKey(appPreferences.screenLockTimeout)
- }
- }
- }
-
- private inner class ScreenLockListener : OnPreferenceValueChangedListener {
-
- override fun onChanged(newValue: Boolean?) {
- screenLockTimeoutChoicePreference!!.isEnabled = newValue!!
-
- if (newValue) {
- screenLockTimeoutChoicePreference!!.alpha = 1.0f
- } else {
- screenLockTimeoutChoicePreference!!.alpha = 0.38f
- }
- }
- }
-
- private inner class ScreenSecurityChangeListener : OnPreferenceValueChangedListener {
-
- override fun onChanged(newValue: Boolean) {
- if (newValue) {
- if (activity != null) {
- activity!!.window.addFlags(WindowManager.LayoutParams.FLAG_SECURE)
- }
- } else {
- if (activity != null) {
- activity!!.window.clearFlags(WindowManager.LayoutParams.FLAG_SECURE)
- }
- }
- }
- }
-
- private inner class ProxyCredentialsChangeListener : OnPreferenceValueChangedListener {
-
- override fun onChanged(newValue: Boolean) {
- if (newValue) {
- showProxyCredentials()
- } else {
- hideProxyCredentials()
- }
- }
- }
-
- private inner class ProxyTypeChangeListener : OnPreferenceValueChangedListener {
-
- override fun onChanged(newValue: String) {
- if ("No proxy" == newValue) {
- hideProxySettings()
- } else {
- when (newValue) {
- "HTTP" -> if (proxyPortEditText != null) {
- proxyPortEditText!!.value = "3128"
- }
- "DIRECT" -> if (proxyPortEditText != null) {
- proxyPortEditText!!.value = "8080"
- }
- "SOCKS" -> if (proxyPortEditText != null) {
- proxyPortEditText!!.value = "1080"
- }
- else -> {
- }
- }
-
- showProxySettings()
- }
- }
- }
-
- private inner class ThemeChangeListener : OnPreferenceValueChangedListener {
- override fun onChanged(newValue: String) {
- NextcloudTalkApplication.setAppTheme(newValue)
- }
- }
-
- companion object {
-
- val TAG = "SettingsController"
- private val ID_REMOVE_ACCOUNT_WARNING_DIALOG = 0
- }
-}
diff --git a/app/src/main/java/com/nextcloud/talk/controllers/SwitchAccountController.kt b/app/src/main/java/com/nextcloud/talk/controllers/SwitchAccountController.kt
deleted file mode 100644
index 2ebe16992..000000000
--- a/app/src/main/java/com/nextcloud/talk/controllers/SwitchAccountController.kt
+++ /dev/null
@@ -1,266 +0,0 @@
-/*
- * Nextcloud Talk application
- *
- * @author Mario Danic
- * Copyright (C) 2017 Mario Danic
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * Parts related to account import were either copied from or inspired by the great work done by David Luhmer at:
- * https://github.com/nextcloud/ownCloud-Account-Importer
- */
-
-package com.nextcloud.talk.controllers
-
-import android.accounts.Account
-import android.os.Bundle
-import android.view.LayoutInflater
-import android.view.MenuItem
-import android.view.View
-import android.view.ViewGroup
-import androidx.recyclerview.widget.RecyclerView
-import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
-import butterknife.BindView
-import com.nextcloud.talk.R
-import com.nextcloud.talk.adapters.items.AdvancedUserItem
-import com.nextcloud.talk.controllers.base.BaseController
-import com.nextcloud.talk.models.ImportAccount
-import com.nextcloud.talk.models.json.participants.Participant
-import com.nextcloud.talk.newarch.domain.repository.offline.UsersRepository
-import com.nextcloud.talk.newarch.local.models.UserNgEntity
-import com.nextcloud.talk.newarch.local.models.other.UserStatus
-import com.nextcloud.talk.utils.AccountUtils
-import com.nextcloud.talk.utils.bundle.BundleKeys
-import eu.davidea.flexibleadapter.FlexibleAdapter
-import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager
-import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.GlobalScope
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.withContext
-import org.koin.android.ext.android.inject
-import java.net.CookieManager
-import java.util.*
-
-class SwitchAccountController : BaseController {
- @JvmField
- @BindView(R.id.recyclerView)
- internal var recyclerView: RecyclerView? = null
-
- val cookieManager: CookieManager by inject()
- val usersRepository: UsersRepository by inject()
-
- @JvmField
- @BindView(R.id.swipe_refresh_layout)
- internal var swipeRefreshLayout: SwipeRefreshLayout? = null
- private var adapter: FlexibleAdapter>? = null
- private val userItems = ArrayList>()
-
- private var isAccountImport = false
-
- private val onImportItemClickListener = FlexibleAdapter.OnItemClickListener { view, position ->
- if (userItems.size > position) {
- val account = (userItems[position] as AdvancedUserItem).account
- reauthorizeFromImport(account)
- }
-
- true
- }
-
- private val onSwitchItemClickListener = FlexibleAdapter.OnItemClickListener { view, position ->
- if (userItems.size > position) {
- val userEntity = (userItems[position] as AdvancedUserItem).entity
- GlobalScope.launch {
- usersRepository.setUserAsActiveWithId(userEntity!!.id)
- cookieManager.cookieStore.removeAll()
- withContext(Dispatchers.Main) {
- router.popCurrentController()
- }
- }
- }
-
- true
- }
-
- constructor() {
- setHasOptionsMenu(true)
- }
-
- constructor(args: Bundle) : super() {
- setHasOptionsMenu(true)
-
- if (args.containsKey(BundleKeys.KEY_IS_ACCOUNT_IMPORT)) {
- isAccountImport = true
- }
- }
-
- override fun onOptionsItemSelected(item: MenuItem): Boolean {
- when (item.itemId) {
- android.R.id.home -> {
- router.popCurrentController()
- return true
- }
- else -> return super.onOptionsItemSelected(item)
- }
- }
-
- override fun inflateView(inflater: LayoutInflater, container: ViewGroup): View {
- return inflater.inflate(R.layout.controller_generic_rv, container, false)
- }
-
- override fun onCreateView(
- inflater: LayoutInflater,
- container: ViewGroup
- ): View {
- swipeRefreshLayout?.isEnabled = false
- actionBar?.show()
-
- adapter = FlexibleAdapter(userItems, activity, false)
- GlobalScope.launch {
- val users = usersRepository.getUsers()
- var userEntity: UserNgEntity
- var participant: Participant
-
- if (isAccountImport) {
- var account: Account
- var importAccount: ImportAccount
- for (accountObject in AccountUtils.findAccounts(users)) {
- account = accountObject
- importAccount = AccountUtils.getInformationFromAccount(account)
-
- participant = Participant()
- participant.name = importAccount.username
- participant.userId = importAccount.username
- userEntity = UserNgEntity(-1, "!", "!", importAccount.baseUrl)
- userItems.add(AdvancedUserItem(participant, userEntity, account))
- }
-
- adapter!!.addListener(onImportItemClickListener)
- withContext(Dispatchers.Main) {
- adapter!!.updateDataSet(userItems, false)
- }
-
-
- } else {
- for (userEntityObject in users) {
- userEntity = userEntityObject
- if (userEntity.status != UserStatus.ACTIVE) {
- participant = Participant()
- participant.name = userEntity.displayName
-
- val userId: String
-
- if (userEntity.userId != null) {
- userId = userEntity.userId
- } else {
- userId = userEntity.username
- }
- participant.userId = userId
- userItems.add(AdvancedUserItem(participant, userEntity, null))
- }
- }
-
- adapter!!.addListener(onSwitchItemClickListener)
- withContext(Dispatchers.Main) {
- adapter!!.updateDataSet(userItems, false)
- }
-
- }
-
- }
- return super.onCreateView(inflater, container)
- }
-
- override fun onViewBound(view: View) {
- super.onViewBound(view)
- swipeRefreshLayout!!.isEnabled = false
-
- if (actionBar != null) {
- actionBar!!.show()
- }
-
- /*
-
- if (adapter == null) {
- adapter = FlexibleAdapter(userItems, activity, false)
-
- var userEntity: UserNgEntity
- var participant: Participant
-
- if (!isAccountImport) {
- for (userEntityObject in userUtils!!.users) {
- userEntity = userEntityObject as UserEntity
- if (!userEntity.getCurrent()) {
- participant = Participant()
- participant.setName(userEntity.displayName)
-
- val userId: String
-
- if (userEntity.userId != null) {
- userId = userEntity.userId
- } else {
- userId = userEntity.username
- }
- participant.setUserId(userId)
- userItems.add(AdvancedUserItem(participant, userEntity, null))
- }
- }
-
- adapter!!.addListener(onSwitchItemClickListener)
- adapter!!.updateDataSet(userItems, false)
- } else {
- var account: Account
- var importAccount: ImportAccount
- for (accountObject in AccountUtils.findAccounts(userUtils!!.users)) {
- account = accountObject
- importAccount = AccountUtils.getInformationFromAccount(account)
-
- participant = Participant()
- participant.name = importAccount.username
- participant.userId = importAccount.username
- userEntity = UserEntity()
- userEntity.baseUrl = importAccount.getBaseUrl()
- userItems.add(AdvancedUserItem(participant, userEntity, account))
- }
-
- adapter!!.addListener(onImportItemClickListener)
- adapter!!.updateDataSet(userItems, false)
- }
- }*/
-
- prepareViews()
- }
-
- private fun prepareViews() {
- val layoutManager = SmoothScrollLinearLayoutManager(activity!!)
- recyclerView!!.layoutManager = layoutManager
- recyclerView!!.setHasFixedSize(true)
- recyclerView!!.adapter = adapter
-
- swipeRefreshLayout!!.isEnabled = false
- }
-
- private fun reauthorizeFromImport(account: Account?) {
- val importAccount = AccountUtils.getInformationFromAccount(account!!)
- val bundle = Bundle()
- bundle.putString(BundleKeys.KEY_BASE_URL, importAccount.baseUrl)
- bundle.putString(BundleKeys.KEY_USERNAME, importAccount.username)
- bundle.putString(BundleKeys.KEY_TOKEN, importAccount.token)
- bundle.putBoolean(BundleKeys.KEY_IS_ACCOUNT_IMPORT, true)
- }
-
- override fun getTitle(): String? {
- return resources!!.getString(R.string.nc_select_an_account)
- }
-}
diff --git a/app/src/main/java/com/nextcloud/talk/controllers/base/BaseController.kt b/app/src/main/java/com/nextcloud/talk/controllers/base/BaseController.kt
index 0428f89a9..26f756f1a 100644
--- a/app/src/main/java/com/nextcloud/talk/controllers/base/BaseController.kt
+++ b/app/src/main/java/com/nextcloud/talk/controllers/base/BaseController.kt
@@ -32,7 +32,6 @@ import android.view.inputmethod.EditorInfo
import android.view.inputmethod.InputMethodManager
import android.widget.EditText
import android.widget.ProgressBar
-import android.widget.Toolbar
import androidx.annotation.RequiresApi
import androidx.appcompat.app.ActionBar
import androidx.coordinatorlayout.widget.CoordinatorLayout
@@ -45,10 +44,8 @@ import com.google.android.material.appbar.MaterialToolbar
import com.google.android.material.floatingactionbutton.FloatingActionButton
import com.nextcloud.talk.R
import com.nextcloud.talk.activities.MainActivity
-import com.nextcloud.talk.controllers.SwitchAccountController
import com.nextcloud.talk.controllers.base.providers.ActionBarProvider
import com.nextcloud.talk.newarch.utils.dp
-import com.nextcloud.talk.newarch.utils.px
import com.nextcloud.talk.utils.preferences.AppPreferences
import com.uber.autodispose.lifecycle.LifecycleScopeProvider
import kotlinx.android.synthetic.main.activity_main.*
@@ -56,7 +53,6 @@ import kotlinx.android.synthetic.main.search_layout.*
import kotlinx.android.synthetic.main.search_layout.view.*
import org.greenrobot.eventbus.EventBus
import org.koin.android.ext.android.inject
-import java.util.*
abstract class BaseController : ButterKnifeController(), ComponentCallbacks {
enum class AppBarLayoutType {
@@ -213,20 +209,9 @@ abstract class BaseController : ButterKnifeController(), ComponentCallbacks {
}
- private fun cleanTempCertPreference() {
- val temporaryClassNames = ArrayList()
- temporaryClassNames.add(SwitchAccountController::class.java.name)
-
- if (!temporaryClassNames.contains(javaClass.name)) {
- appPreferences.removeTemporaryClientCertAlias()
- }
-
- }
-
override fun onViewBound(view: View) {
super.onViewBound(view)
- cleanTempCertPreference()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && appPreferences.isKeyboardIncognito) {
disableKeyboardPersonalisedLearning(view as ViewGroup)
diff --git a/app/src/main/java/com/nextcloud/talk/newarch/data/repository/offline/UsersRepositoryImpl.kt b/app/src/main/java/com/nextcloud/talk/newarch/data/repository/offline/UsersRepositoryImpl.kt
index 895d49d77..f9b004159 100644
--- a/app/src/main/java/com/nextcloud/talk/newarch/data/repository/offline/UsersRepositoryImpl.kt
+++ b/app/src/main/java/com/nextcloud/talk/newarch/data/repository/offline/UsersRepositoryImpl.kt
@@ -24,9 +24,12 @@ package com.nextcloud.talk.newarch.data.repository.offline
import androidx.lifecycle.LiveData
import androidx.lifecycle.distinctUntilChanged
+import androidx.lifecycle.map
import com.nextcloud.talk.newarch.domain.repository.offline.UsersRepository
import com.nextcloud.talk.newarch.local.dao.UsersDao
+import com.nextcloud.talk.newarch.local.models.User
import com.nextcloud.talk.newarch.local.models.UserNgEntity
+import com.nextcloud.talk.newarch.local.models.toUser
class UsersRepositoryImpl(private val usersDao: UsersDao) : UsersRepository {
override fun getActiveUserLiveData(): LiveData {
@@ -45,6 +48,14 @@ class UsersRepositoryImpl(private val usersDao: UsersDao) : UsersRepository {
return usersDao.getUserWithId(id)
}
+ override fun getUsersLiveData(): LiveData> {
+ return usersDao.getUsersLiveData().distinctUntilChanged().map { usersList ->
+ usersList.map {
+ it.toUser()
+ }
+ }
+ }
+
override suspend fun getUserWithUsernameAndServer(
username: String,
server: String
@@ -72,4 +83,8 @@ class UsersRepositoryImpl(private val usersDao: UsersDao) : UsersRepository {
return usersDao.setAnyUserAsActive()
}
+ override suspend fun markUserForDeletion(id: Long): Boolean {
+ return usersDao.markUserForDeletion(id)
+ }
+
}
diff --git a/app/src/main/java/com/nextcloud/talk/newarch/domain/repository/offline/UsersRepository.kt b/app/src/main/java/com/nextcloud/talk/newarch/domain/repository/offline/UsersRepository.kt
index 613139fd6..717d46034 100644
--- a/app/src/main/java/com/nextcloud/talk/newarch/domain/repository/offline/UsersRepository.kt
+++ b/app/src/main/java/com/nextcloud/talk/newarch/domain/repository/offline/UsersRepository.kt
@@ -23,6 +23,7 @@
package com.nextcloud.talk.newarch.domain.repository.offline
import androidx.lifecycle.LiveData
+import com.nextcloud.talk.newarch.local.models.User
import com.nextcloud.talk.newarch.local.models.UserNgEntity
interface UsersRepository {
@@ -30,10 +31,12 @@ interface UsersRepository {
fun getActiveUser(): UserNgEntity?
fun getUsers(): List
fun getUserWithId(id: Long): UserNgEntity
+ fun getUsersLiveData(): LiveData>
suspend fun getUserWithUsernameAndServer(username: String, server: String): UserNgEntity?
suspend fun updateUser(user: UserNgEntity): Int
suspend fun insertUser(user: UserNgEntity): Long
suspend fun setUserAsActiveWithId(id: Long)
suspend fun deleteUserWithId(id: Long)
suspend fun setAnyUserAsActive(): Boolean
+ suspend fun markUserForDeletion(id: Long): Boolean
}
\ No newline at end of file
diff --git a/app/src/main/java/com/nextcloud/talk/newarch/features/chat/ChatView.kt b/app/src/main/java/com/nextcloud/talk/newarch/features/chat/ChatView.kt
index bced434a5..fe88b3992 100644
--- a/app/src/main/java/com/nextcloud/talk/newarch/features/chat/ChatView.kt
+++ b/app/src/main/java/com/nextcloud/talk/newarch/features/chat/ChatView.kt
@@ -267,7 +267,7 @@ class ChatView(private val bundle: Bundle) : BaseView(), ImageLoaderInterface {
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
android.R.id.home -> {
- router.popCurrentController()
+ router.popController(this)
return true
}
R.id.conversation_video_call -> {
diff --git a/app/src/main/java/com/nextcloud/talk/newarch/features/conversationsList/ConversationsListView.kt b/app/src/main/java/com/nextcloud/talk/newarch/features/conversationsList/ConversationsListView.kt
index 60c41ac89..78c9c1038 100644
--- a/app/src/main/java/com/nextcloud/talk/newarch/features/conversationsList/ConversationsListView.kt
+++ b/app/src/main/java/com/nextcloud/talk/newarch/features/conversationsList/ConversationsListView.kt
@@ -41,13 +41,13 @@ import com.bluelinelabs.conductor.changehandler.TransitionChangeHandlerCompat
import com.bluelinelabs.conductor.changehandler.VerticalChangeHandler
import com.nextcloud.talk.R
import com.nextcloud.talk.R.drawable
-import com.nextcloud.talk.controllers.SettingsController
import com.nextcloud.talk.controllers.bottomsheet.items.BasicListItemWithImage
import com.nextcloud.talk.controllers.bottomsheet.items.listItemsWithImage
import com.nextcloud.talk.models.json.conversations.Conversation
import com.nextcloud.talk.newarch.data.presenters.AdvancedEmptyPresenter
import com.nextcloud.talk.newarch.features.contactsflow.contacts.ContactsView
import com.nextcloud.talk.newarch.features.search.DebouncingTextWatcher
+import com.nextcloud.talk.newarch.features.settingsflow.settings.SettingsView
import com.nextcloud.talk.newarch.local.models.toUser
import com.nextcloud.talk.newarch.mvvm.BaseView
import com.nextcloud.talk.utils.ConductorRemapping
@@ -115,17 +115,13 @@ class ConversationsListView : BaseView() {
activity?.settingsButton?.setOnClickListener {
val settingsTransitionName = "userAvatar.transitionTag"
router.pushController(
- RouterTransaction.with(SettingsController())
+ RouterTransaction.with(SettingsView())
.pushChangeHandler(
TransitionChangeHandlerCompat(
SharedElementTransition(arrayListOf(settingsTransitionName)), VerticalChangeHandler()
)
)
- .popChangeHandler(
- TransitionChangeHandlerCompat(
- SharedElementTransition(arrayListOf(settingsTransitionName)), VerticalChangeHandler()
- )
- )
+ .popChangeHandler(HorizontalChangeHandler())
)
}
diff --git a/app/src/main/java/com/nextcloud/talk/newarch/features/settingsflow/di/module/SettingsModule.kt b/app/src/main/java/com/nextcloud/talk/newarch/features/settingsflow/di/module/SettingsModule.kt
new file mode 100644
index 000000000..6b150c49d
--- /dev/null
+++ b/app/src/main/java/com/nextcloud/talk/newarch/features/settingsflow/di/module/SettingsModule.kt
@@ -0,0 +1,22 @@
+package com.nextcloud.talk.newarch.features.settingsflow.di.module
+
+import android.app.Application
+import com.nextcloud.talk.newarch.data.source.remote.ApiErrorHandler
+import com.nextcloud.talk.newarch.domain.repository.offline.UsersRepository
+import com.nextcloud.talk.newarch.features.settingsflow.settings.SettingsViewModelFactory
+import com.nextcloud.talk.newarch.services.GlobalService
+import com.nextcloud.talk.newarch.utils.NetworkComponents
+import org.koin.android.ext.koin.androidApplication
+import org.koin.dsl.module
+
+val SettingsModule = module {
+ factory {
+ createSettingsViewModelFactory(
+ androidApplication(), get(), get(), get(), get()
+ )
+ }
+}
+
+fun createSettingsViewModelFactory(application: Application, usersRepository: UsersRepository, networkComponents: NetworkComponents, apiErrorHandler: ApiErrorHandler, globalService: GlobalService): SettingsViewModelFactory {
+ return SettingsViewModelFactory(application, usersRepository, networkComponents, apiErrorHandler, globalService)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/nextcloud/talk/newarch/features/settingsflow/looknfeel/SettingsLookNFeelView.kt b/app/src/main/java/com/nextcloud/talk/newarch/features/settingsflow/looknfeel/SettingsLookNFeelView.kt
new file mode 100644
index 000000000..0312a8fb2
--- /dev/null
+++ b/app/src/main/java/com/nextcloud/talk/newarch/features/settingsflow/looknfeel/SettingsLookNFeelView.kt
@@ -0,0 +1,149 @@
+/*
+ *
+ * * Nextcloud Talk application
+ * *
+ * * @author Mario Danic
+ * * Copyright (C) 2017-2020 Mario Danic
+ * *
+ * * This program is free software: you can redistribute it and/or modify
+ * * it under the terms of the GNU General Public License as published by
+ * * the Free Software Foundation, either version 3 of the License, or
+ * * at your option) any later version.
+ * *
+ * * This program is distributed in the hope that it will be useful,
+ * * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * * GNU General Public License for more details.
+ * *
+ * * You should have received a copy of the GNU General Public License
+ * * along with this program. If not, see .
+ *
+ */
+package com.nextcloud.talk.newarch.features.settingsflow.looknfeel
+
+import android.os.Bundle
+import android.text.TextUtils
+import android.view.LayoutInflater
+import android.view.MenuItem
+import android.view.View
+import android.view.ViewGroup
+import androidx.core.view.isVisible
+import com.bluelinelabs.conductor.RouterTransaction
+import com.bluelinelabs.conductor.archlifecycle.ControllerLifecycleOwner
+import com.bluelinelabs.conductor.autodispose.ControllerScopeProvider
+import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler
+import com.bluelinelabs.logansquare.LoganSquare
+import com.nextcloud.talk.R
+import com.nextcloud.talk.application.NextcloudTalkApplication
+import com.nextcloud.talk.controllers.RingtoneSelectionController
+import com.nextcloud.talk.models.RingtoneSettings
+import com.nextcloud.talk.newarch.mvvm.BaseView
+import com.nextcloud.talk.utils.DoNotDisturbUtils
+import com.nextcloud.talk.utils.bundle.BundleKeys
+import com.uber.autodispose.lifecycle.LifecycleScopeProvider
+import kotlinx.android.synthetic.main.settings_looknfeel_view.view.*
+import net.orange_box.storebox.listeners.OnPreferenceValueChangedListener
+import java.io.IOException
+
+class SettingsLookNFeelView(private val bundle: Bundle? = null) : BaseView() {
+ override val scopeProvider: LifecycleScopeProvider<*> = ControllerScopeProvider.from(this)
+ override val lifecycleOwner = ControllerLifecycleOwner(this)
+ private var themeChangeListener: OnPreferenceValueChangedListener = ThemeChangeListener()
+
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup): View {
+ setHasOptionsMenu(true)
+ appPreferences.registerThemeChangeListener(themeChangeListener)
+ val view = super.onCreateView(inflater, container)
+
+ view.settings_call_sound.setOnClickListener { v ->
+ showRingtoneSelectionScreen(true)
+ }
+
+ view.settings_message_sound.setOnClickListener { v ->
+ showRingtoneSelectionScreen(false)
+ }
+
+ view.settings_always_vibrate.isVisible = DoNotDisturbUtils.hasVibrator()
+
+ return view
+ }
+
+ override fun onAttach(view: View) {
+ super.onAttach(view)
+
+ var ringtoneName = ""
+ var ringtoneSettings: RingtoneSettings
+
+ if (!TextUtils.isEmpty(appPreferences.callRingtoneUri)) {
+ try {
+ ringtoneSettings =
+ LoganSquare.parse(appPreferences.callRingtoneUri, RingtoneSettings::class.java)
+ ringtoneName = ringtoneSettings.ringtoneName
+ } catch (e: IOException) {
+ }
+
+ view.settings_call_sound.setSummary(ringtoneName)
+ } else {
+ view.settings_call_sound.setSummary(R.string.nc_settings_default_ringtone)
+ }
+
+ ringtoneName = ""
+
+ if (!TextUtils.isEmpty(appPreferences.messageRingtoneUri)) {
+ try {
+ ringtoneSettings =
+ LoganSquare.parse(appPreferences.messageRingtoneUri, RingtoneSettings::class.java)
+ ringtoneName = ringtoneSettings.ringtoneName
+ } catch (e: IOException) {
+ }
+
+ view.settings_message_sound.setSummary(ringtoneName)
+ } else {
+ view.settings_message_sound.setSummary(R.string.nc_settings_default_ringtone)
+ }
+ }
+
+ override fun onDestroyView(view: View) {
+ appPreferences.unregisterThemeChangeListener(themeChangeListener)
+ super.onDestroyView(view)
+ }
+
+ private fun showRingtoneSelectionScreen(callSounds: Boolean) {
+ val bundle = Bundle()
+ bundle.putBoolean(BundleKeys.KEY_ARE_CALL_SOUNDS, callSounds)
+ router.pushController(
+ RouterTransaction.with(RingtoneSelectionController(bundle))
+ .pushChangeHandler(HorizontalChangeHandler())
+ .popChangeHandler(HorizontalChangeHandler())
+ )
+ }
+
+ override fun onDestroy() {
+ appPreferences.unregisterThemeChangeListener(themeChangeListener)
+ super.onDestroy()
+ }
+
+ override fun onOptionsItemSelected(item: MenuItem): Boolean {
+ if (item.itemId == android.R.id.home) {
+ router.popController(this)
+ return true
+ }
+
+ return super.onOptionsItemSelected(item)
+ }
+
+ override fun getLayoutId(): Int {
+ return R.layout.settings_looknfeel_view
+ }
+
+ override fun getTitle(): String? {
+ return resources?.getString(R.string.nc_look_and_feel)
+ }
+
+ private inner class ThemeChangeListener : OnPreferenceValueChangedListener {
+ override fun onChanged(newValue: String) {
+ NextcloudTalkApplication.setAppTheme(newValue)
+ activity?.recreate()
+ }
+ }
+}
diff --git a/app/src/main/java/com/nextcloud/talk/newarch/features/settingsflow/privacy/SettingsPrivacyView.kt b/app/src/main/java/com/nextcloud/talk/newarch/features/settingsflow/privacy/SettingsPrivacyView.kt
new file mode 100644
index 000000000..dac9e3987
--- /dev/null
+++ b/app/src/main/java/com/nextcloud/talk/newarch/features/settingsflow/privacy/SettingsPrivacyView.kt
@@ -0,0 +1,178 @@
+/*
+ *
+ * * Nextcloud Talk application
+ * *
+ * * @author Mario Danic
+ * * Copyright (C) 2017-2020 Mario Danic
+ * *
+ * * This program is free software: you can redistribute it and/or modify
+ * * it under the terms of the GNU General Public License as published by
+ * * the Free Software Foundation, either version 3 of the License, or
+ * * at your option) any later version.
+ * *
+ * * This program is distributed in the hope that it will be useful,
+ * * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * * GNU General Public License for more details.
+ * *
+ * * You should have received a copy of the GNU General Public License
+ * * along with this program. If not, see .
+ *
+ */
+package com.nextcloud.talk.newarch.features.settingsflow.privacy
+
+import android.app.KeyguardManager
+import android.content.Context
+import android.os.Build
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.MenuItem
+import android.view.View
+import android.view.ViewGroup
+import androidx.core.view.isVisible
+import com.bluelinelabs.conductor.archlifecycle.ControllerLifecycleOwner
+import com.bluelinelabs.conductor.autodispose.ControllerScopeProvider
+import com.nextcloud.talk.R
+import com.nextcloud.talk.newarch.mvvm.BaseView
+import com.nextcloud.talk.utils.preferences.MagicUserInputModule
+import com.uber.autodispose.lifecycle.LifecycleScopeProvider
+import kotlinx.android.synthetic.main.settings_privacy_view.view.*
+import net.orange_box.storebox.listeners.OnPreferenceValueChangedListener
+import java.util.*
+
+class SettingsPrivacyView(private val bundle: Bundle? = null) : BaseView() {
+ override val scopeProvider: LifecycleScopeProvider<*> = ControllerScopeProvider.from(this)
+ override val lifecycleOwner = ControllerLifecycleOwner(this)
+
+ private var proxyTypeChangeListener: OnPreferenceValueChangedListener = ProxyTypeChangeListener()
+ private var proxyCredentialsChangeListener: OnPreferenceValueChangedListener = ProxyCredentialsChangeListener()
+
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup): View {
+ setHasOptionsMenu(true)
+ val view = super.onCreateView(inflater, container)
+
+ view.settings_incognito_keyboard.isVisible = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
+ view.settings_screen_lock.isVisible = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
+ view.settings_screen_lock_timeout.isVisible = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ view.settings_screen_lock.setSummary(
+ String.format(
+ Locale.getDefault(),
+ resources!!.getString(R.string.nc_settings_screen_lock_desc),
+ resources!!.getString(R.string.nc_app_name)
+ )
+ )
+
+ val keyguardManager = context.getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager
+ val keyguardIsSecure = keyguardManager.isKeyguardSecure
+ view.settings_screen_lock.isEnabled = keyguardIsSecure
+ view.settings_screen_lock_timeout.isEnabled = keyguardIsSecure
+
+ if (keyguardIsSecure) {
+ if (appPreferences.isScreenLocked) {
+ view.settings_screen_lock_timeout.alpha = 1.0f
+ } else {
+ view.settings_screen_lock_timeout.alpha = 0.38f
+ }
+
+ view.settings_screen_lock.alpha = 1.0f
+ } else {
+ view.settings_screen_lock.alpha = 0.38f
+ view.settings_screen_lock_timeout.alpha = 0.38f
+ }
+ }
+
+ val listWithIntFields = ArrayList()
+ listWithIntFields.add("proxy_port")
+ view.privacy_screen.setUserInputModule(MagicUserInputModule(activity, listWithIntFields))
+
+ appPreferences.registerProxyTypeListener(proxyTypeChangeListener)
+ appPreferences.registerProxyCredentialsListener(proxyCredentialsChangeListener)
+
+ setupProxySection(view)
+ return view
+ }
+
+ override fun onDestroy() {
+ appPreferences.unregisterProxyCredentialsListener(proxyCredentialsChangeListener)
+ appPreferences.unregisterProxyTypeListener(proxyTypeChangeListener)
+ super.onDestroy()
+ }
+
+ override fun onOptionsItemSelected(item: MenuItem): Boolean {
+ if (item.itemId == android.R.id.home) {
+ router.popController(this)
+ return true
+ }
+
+ return super.onOptionsItemSelected(item)
+ }
+
+ override fun getLayoutId(): Int {
+ return R.layout.settings_privacy_view
+ }
+
+ override fun getTitle(): String? {
+ return resources?.getString(R.string.nc_privacy)
+ }
+
+ private fun setupProxySection(view: View?) {
+ if ("No proxy" == appPreferences.proxyType || appPreferences.proxyType == null) {
+ toggleProxySettingsVisibility(view, false)
+ } else {
+ toggleCredentialsSettingsVisibility(view, appPreferences.proxyCredentials)
+ }
+ }
+
+ private fun toggleProxySettingsVisibility(view: View?, shouldBeVisible: Boolean) {
+ view?.settings_proxy_host_edit?.isVisible = shouldBeVisible
+ view?.settings_proxy_port_edit?.isVisible = shouldBeVisible
+ view?.settings_proxy_use_credentials?.isVisible = shouldBeVisible
+
+ if (!shouldBeVisible) {
+ appPreferences.setProxyNeedsCredentials(false)
+ }
+ }
+
+ private fun toggleCredentialsSettingsVisibility(view: View?, shouldBeVisible: Boolean) {
+ view?.settings_proxy_username_edit?.isVisible = shouldBeVisible
+ view?.settings_proxy_password_edit?.isVisible = shouldBeVisible
+ }
+
+ private inner class ProxyCredentialsChangeListener : OnPreferenceValueChangedListener {
+
+ override fun onChanged(newValue: Boolean) {
+ toggleCredentialsSettingsVisibility(view, newValue)
+ if (!newValue) {
+ appPreferences.proxyUsername = ""
+ appPreferences.proxyPassword = ""
+ }
+ }
+ }
+
+ private inner class ProxyTypeChangeListener : OnPreferenceValueChangedListener {
+
+ override fun onChanged(newValue: String) {
+ if ("No proxy" == newValue) {
+ toggleProxySettingsVisibility(view, false)
+ } else {
+ when (newValue) {
+ "HTTP" -> {
+ view?.settings_proxy_port_edit?.value = "3128"
+ }
+ "DIRECT" -> {
+ view?.settings_proxy_port_edit?.value = "8080"
+ }
+ "SOCKS" -> {
+ view?.settings_proxy_port_edit?.value = "1080"
+ }
+ else -> {
+ }
+ }
+
+ toggleProxySettingsVisibility(view, true)
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/com/nextcloud/talk/newarch/features/settingsflow/settings/SettingsPresenter.kt b/app/src/main/java/com/nextcloud/talk/newarch/features/settingsflow/settings/SettingsPresenter.kt
new file mode 100644
index 000000000..d2bce2cb9
--- /dev/null
+++ b/app/src/main/java/com/nextcloud/talk/newarch/features/settingsflow/settings/SettingsPresenter.kt
@@ -0,0 +1,88 @@
+/*
+ *
+ * * Nextcloud Talk application
+ * *
+ * * @author Mario Danic
+ * * Copyright (C) 2017-2020 Mario Danic
+ * *
+ * * This program is free software: you can redistribute it and/or modify
+ * * it under the terms of the GNU General Public License as published by
+ * * the Free Software Foundation, either version 3 of the License, or
+ * * at your option) any later version.
+ * *
+ * * This program is distributed in the hope that it will be useful,
+ * * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * * GNU General Public License for more details.
+ * *
+ * * You should have received a copy of the GNU General Public License
+ * * along with this program. If not, see .
+ *
+ */
+package com.nextcloud.talk.newarch.features.settingsflow.settings
+
+import android.content.Context
+import android.graphics.drawable.BitmapDrawable
+import android.view.View
+import android.view.ViewGroup
+import androidx.core.view.isVisible
+import coil.api.load
+import com.nextcloud.talk.R
+import com.nextcloud.talk.newarch.local.models.User
+import com.nextcloud.talk.newarch.local.models.getCredentials
+import com.nextcloud.talk.newarch.local.models.other.UserStatus
+import com.nextcloud.talk.newarch.utils.Images
+import com.nextcloud.talk.utils.ApiUtils
+import com.otaliastudios.elements.Element
+import com.otaliastudios.elements.Page
+import com.otaliastudios.elements.Presenter
+import kotlinx.android.synthetic.main.user_item.view.*
+import kotlinx.android.synthetic.main.user_item.view.avatarImageView
+import org.koin.core.KoinComponent
+
+open class SettingsPresenter(context: Context, onElementClick: ((Page, Holder, Element) -> Unit)?, private val onMoreOptionsClick: ((User) -> Unit)?) : Presenter(context, onElementClick), KoinComponent {
+ override val elementTypes: Collection
+ get() = listOf(SettingsElementType.USER.ordinal, SettingsElementType.NEW_USER.ordinal)
+
+ override fun onCreate(parent: ViewGroup, elementType: Int): Holder {
+ return Holder(getLayoutInflater().inflate(R.layout.user_item, parent, false))
+ }
+
+ override fun onBind(page: Page, holder: Holder, element: Element, payloads: List) {
+ super.onBind(page, holder, element, payloads)
+
+ if (element.type == SettingsElementType.USER.ordinal) {
+ val user = element.data as User
+ holder.itemView.userProgressBar.isVisible = user.status == UserStatus.PENDING_DELETE
+
+ if (user.status == UserStatus.PENDING_DELETE) {
+ holder.itemView.setBackgroundResource(0)
+ holder.itemView.userMoreOptionsView.visibility = View.INVISIBLE
+ } else {
+ if (user.status == UserStatus.ACTIVE) {
+ holder.itemView.setBackgroundColor(context.resources.getColor(R.color.colorPrimary))
+ holder.itemView.background.alpha = 191
+ } else {
+ holder.itemView.setBackgroundColor(0)
+ }
+ holder.itemView.userMoreOptionsView.visibility = View.VISIBLE
+ holder.itemView.userMoreOptionsView.setOnClickListener {
+ onMoreOptionsClick?.invoke(user)
+ }
+ }
+ val baseUrl = if (user.status == UserStatus.ACTIVE) "" else " (${user.baseUrl.replace("http://", "").replace("https://", "")})"
+ val displayName = "${user.displayName}$baseUrl"
+ holder.itemView.userDisplayName.text = displayName
+ holder.itemView.avatarImageView.load(ApiUtils.getUrlForAvatarWithName(user.baseUrl, user.userId, R.dimen.avatar_size)) {
+ addHeader("Authorization", user.getCredentials())
+ placeholder(BitmapDrawable(Images().getImageWithBackground(context, R.drawable.ic_user)))
+ fallback(BitmapDrawable(Images().getImageWithBackground(context, R.drawable.ic_user)))
+ }
+ } else {
+ holder.itemView.userDisplayName.text = context.resources.getString(R.string.nc_settings_new_account)
+ holder.itemView.avatarImageView.load(Images().getImageWithBackground(context = context, drawableId = R.drawable.ic_add_white_24px, foregroundColorTint = R.color.colorPrimary))
+ holder.itemView.userProgressBar.isVisible = false
+ holder.itemView.userMoreOptionsView.visibility = View.GONE
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/nextcloud/talk/newarch/features/settingsflow/settings/SettingsUtils.kt b/app/src/main/java/com/nextcloud/talk/newarch/features/settingsflow/settings/SettingsUtils.kt
new file mode 100644
index 000000000..b6d4e718a
--- /dev/null
+++ b/app/src/main/java/com/nextcloud/talk/newarch/features/settingsflow/settings/SettingsUtils.kt
@@ -0,0 +1,6 @@
+package com.nextcloud.talk.newarch.features.settingsflow.settings
+
+enum class SettingsElementType {
+ USER,
+ NEW_USER,
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/nextcloud/talk/newarch/features/settingsflow/settings/SettingsView.kt b/app/src/main/java/com/nextcloud/talk/newarch/features/settingsflow/settings/SettingsView.kt
new file mode 100644
index 000000000..a39107125
--- /dev/null
+++ b/app/src/main/java/com/nextcloud/talk/newarch/features/settingsflow/settings/SettingsView.kt
@@ -0,0 +1,255 @@
+/*
+ *
+ * * Nextcloud Talk application
+ * *
+ * * @author Mario Danic
+ * * Copyright (C) 2017-2020 Mario Danic
+ * *
+ * * This program is free software: you can redistribute it and/or modify
+ * * it under the terms of the GNU General Public License as published by
+ * * the Free Software Foundation, either version 3 of the License, or
+ * * at your option) any later version.
+ * *
+ * * This program is distributed in the hope that it will be useful,
+ * * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * * GNU General Public License for more details.
+ * *
+ * * You should have received a copy of the GNU General Public License
+ * * along with this program. If not, see .
+ *
+ */
+package com.nextcloud.talk.newarch.features.settingsflow.settings
+
+import android.content.Context
+import android.content.Intent
+import android.graphics.drawable.BitmapDrawable
+import android.net.Uri
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.MenuItem
+import android.view.View
+import android.view.ViewGroup
+import android.widget.ImageView
+import androidx.core.view.isVisible
+import androidx.lifecycle.observe
+import androidx.recyclerview.widget.LinearLayoutManager
+import coil.Coil
+import coil.api.load
+import coil.transform.CircleCropTransformation
+import com.afollestad.materialdialogs.LayoutMode
+import com.afollestad.materialdialogs.MaterialDialog
+import com.afollestad.materialdialogs.bottomsheets.BottomSheet
+import com.bluelinelabs.conductor.RouterTransaction
+import com.bluelinelabs.conductor.archlifecycle.ControllerLifecycleOwner
+import com.bluelinelabs.conductor.autodispose.ControllerScopeProvider
+import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler
+import com.bluelinelabs.conductor.changehandler.VerticalChangeHandler
+import com.nextcloud.talk.BuildConfig
+import com.nextcloud.talk.R
+import com.nextcloud.talk.controllers.bottomsheet.items.BasicListItemWithImage
+import com.nextcloud.talk.controllers.bottomsheet.items.listItemsWithImage
+import com.nextcloud.talk.newarch.features.account.serverentry.ServerEntryView
+import com.nextcloud.talk.newarch.features.settingsflow.looknfeel.SettingsLookNFeelView
+import com.nextcloud.talk.newarch.features.settingsflow.privacy.SettingsPrivacyView
+import com.nextcloud.talk.newarch.local.models.User
+import com.nextcloud.talk.newarch.local.models.getCredentials
+import com.nextcloud.talk.newarch.local.models.toUser
+import com.nextcloud.talk.newarch.mvvm.BaseView
+import com.nextcloud.talk.newarch.mvvm.ext.initRecyclerView
+import com.nextcloud.talk.newarch.utils.Images
+import com.nextcloud.talk.utils.ApiUtils
+import com.otaliastudios.elements.Adapter
+import com.otaliastudios.elements.Element
+import com.otaliastudios.elements.Page
+import com.otaliastudios.elements.Presenter
+import com.uber.autodispose.lifecycle.LifecycleScopeProvider
+import kotlinx.android.synthetic.main.settings_view.view.*
+import org.koin.android.ext.android.inject
+
+class SettingsView(private val bundle: Bundle? = null) : BaseView() {
+ override val scopeProvider: LifecycleScopeProvider<*> = ControllerScopeProvider.from(this)
+ override val lifecycleOwner = ControllerLifecycleOwner(this)
+
+ private lateinit var viewModel: SettingsViewModel
+ val factory: SettingsViewModelFactory by inject()
+
+ private lateinit var settingsUsersAdapter: Adapter
+
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup): View {
+ viewModel = viewModelProvider(factory).get(SettingsViewModel::class.java)
+ val view = super.onCreateView(inflater, container)
+ setHasOptionsMenu(true)
+
+ setupAboutSection(view)
+ view.settings_privacy_options.setOnClickListener {
+ router.pushController(RouterTransaction.with(SettingsPrivacyView())
+ .pushChangeHandler(HorizontalChangeHandler())
+ .popChangeHandler(HorizontalChangeHandler())
+ )
+ }
+
+ view.settings_look_n_feel.setOnClickListener {
+ router.pushController(RouterTransaction.with(SettingsLookNFeelView())
+ .pushChangeHandler(HorizontalChangeHandler())
+ .popChangeHandler(HorizontalChangeHandler())
+ )
+ }
+
+ showFallbackAvatar(view.avatar_image)
+
+ viewModel.activeUser.observe(this@SettingsView) { user ->
+ view.display_name_text.text = user?.displayName ?: ""
+ view.base_url_text.text = user?.baseUrl?.replace("http://", "")?.replace("https://", "")
+ ?: ""
+ loadAvatar(user?.toUser(), view.avatar_image)
+ }
+
+ settingsUsersAdapter = Adapter.builder(this)
+ .addSource(SettingsViewSource(viewModel.users))
+ .addSource(SettingsViewFooterSource(activity as Context))
+ .addPresenter(Presenter.forLoadingIndicator(activity as Context, R.layout.loading_state))
+ .addPresenter(SettingsPresenter(activity as Context, ::onElementClick, ::onMoreOptionsClick))
+ .into(view.settingsRecyclerView)
+
+ view.settingsRecyclerView.initRecyclerView(LinearLayoutManager(activity), settingsUsersAdapter, false)
+
+ return view
+ }
+
+ override fun onOptionsItemSelected(item: MenuItem): Boolean {
+ if (item.itemId == android.R.id.home) {
+ router.popController(this)
+ return true
+ }
+
+ return super.onOptionsItemSelected(item)
+ }
+
+ private fun showFallbackAvatar(target: ImageView) {
+ val fallbackImage = BitmapDrawable(Images().getImageWithBackground(activity as Context, R.drawable.ic_user))
+ Coil.load(context, fallbackImage) {
+ target(target)
+ transformations(CircleCropTransformation())
+ }
+ }
+
+ private fun loadAvatar(user: User?, target: ImageView) {
+ user?.let {
+ val imageLoader = viewModel.networkComponents.getImageLoader(it)
+ imageLoader.load(activity as Context, ApiUtils.getUrlForAvatarWithName(it.baseUrl, it.userId, R.dimen.avatar_size_big)) {
+ target(target)
+ addHeader("Authorization", user.getCredentials())
+ transformations(CircleCropTransformation())
+ fallback(BitmapDrawable(Images().getImageWithBackground(activity as Context, R.drawable.ic_user)))
+ error(BitmapDrawable(Images().getImageWithBackground(activity as Context, R.drawable.ic_user)))
+ }
+ } ?: run {
+ showFallbackAvatar(target)
+ }
+ }
+
+ private fun setupAboutSection(view: View) {
+ val privacyUrl = resources?.getString(R.string.nc_privacy_url)
+ privacyUrl?.let { privacyUrlString ->
+ view.settings_privacy.setOnClickListener {
+ val browserIntent =
+ Intent(Intent.ACTION_VIEW, Uri.parse(privacyUrlString))
+ startActivity(browserIntent)
+ }
+ }
+
+ view.settings_privacy.isVisible = !privacyUrl.isNullOrEmpty()
+
+ val sourceCodeUrl = resources?.getString(R.string.nc_source_code_url)
+ sourceCodeUrl?.let { sourceCodeUrlString ->
+ view.settings_source_code.setOnClickListener {
+ val browserIntent =
+ Intent(Intent.ACTION_VIEW, Uri.parse(sourceCodeUrlString))
+ startActivity(browserIntent)
+ }
+ }
+ view.settings_source_code.isVisible = !sourceCodeUrl.isNullOrEmpty()
+
+ val licenceUrl = resources?.getString(R.string.nc_gpl3_url)
+ licenceUrl?.let { licenceUrlString ->
+ view.settings_licence.setOnClickListener {
+ val browserIntent =
+ Intent(Intent.ACTION_VIEW, Uri.parse(licenceUrlString))
+ startActivity(browserIntent)
+ }
+ }
+ view.settings_licence.isVisible = !licenceUrl.isNullOrEmpty()
+
+ view.settings_version.setSummary("v" + BuildConfig.VERSION_NAME)
+ }
+
+ private fun onMoreOptionsClick(user: User) {
+ activity?.let { activity ->
+ MaterialDialog(activity, BottomSheet(LayoutMode.WRAP_CONTENT)).show {
+ cornerRadius(res = R.dimen.corner_radius)
+ title(text = user.displayName)
+ listItemsWithImage(getSettingsMenuItemForUser(user)) { _, _, item ->
+ when (item.iconRes) {
+ R.drawable.ic_baseline_clear_24 -> {
+ val weHaveActiveUser = viewModel.removeUser(user)
+ if (!weHaveActiveUser) {
+ router.setRoot(RouterTransaction.with(ServerEntryView())
+ .popChangeHandler(HorizontalChangeHandler())
+ .popChangeHandler(HorizontalChangeHandler()))
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private fun getSettingsMenuItemForUser(user: User): MutableList {
+ val items = mutableListOf()
+
+ resources?.let {
+ /*items.add(
+ BasicListItemWithImage(
+ R.drawable.ic_baseline_clear_24,
+ it.getString(R.string.nc_settings_reauthorize)
+ )
+ )
+ items.add(
+ BasicListItemWithImage(
+ R.drawable.ic_baseline_clear_24,
+ it.getString(R.string.nc_client_cert_setup)
+ )
+ )*/
+ items.add(
+ BasicListItemWithImage(
+ R.drawable.ic_baseline_clear_24,
+ it.getString(R.string.nc_settings_remove_account)
+ )
+ )
+ }
+
+ return items
+ }
+
+ private fun onElementClick(page: Page, holder: Presenter.Holder, element: Element) {
+ if (element.type == SettingsElementType.USER.ordinal) {
+ if (viewModel.setUserAsActive(element.data as User)) {
+ router.popController(this)
+ }
+ } else {
+ router.pushController(RouterTransaction.with(ServerEntryView())
+ .pushChangeHandler(VerticalChangeHandler())
+ .popChangeHandler(VerticalChangeHandler())
+ )
+ }
+ }
+
+ override fun getLayoutId(): Int {
+ return R.layout.settings_view
+ }
+
+ override fun getTitle(): String? {
+ return resources?.getString(R.string.nc_settings)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/nextcloud/talk/newarch/features/settingsflow/settings/SettingsViewFooterSource.kt b/app/src/main/java/com/nextcloud/talk/newarch/features/settingsflow/settings/SettingsViewFooterSource.kt
new file mode 100644
index 000000000..7d3459446
--- /dev/null
+++ b/app/src/main/java/com/nextcloud/talk/newarch/features/settingsflow/settings/SettingsViewFooterSource.kt
@@ -0,0 +1,59 @@
+/*
+ *
+ * * Nextcloud Talk application
+ * *
+ * * @author Mario Danic
+ * * Copyright (C) 2017-2020 Mario Danic
+ * *
+ * * This program is free software: you can redistribute it and/or modify
+ * * it under the terms of the GNU General Public License as published by
+ * * the Free Software Foundation, either version 3 of the License, or
+ * * at your option) any later version.
+ * *
+ * * This program is distributed in the hope that it will be useful,
+ * * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * * GNU General Public License for more details.
+ * *
+ * * You should have received a copy of the GNU General Public License
+ * * along with this program. If not, see .
+ *
+ */
+package com.nextcloud.talk.newarch.features.settingsflow.settings
+
+import android.content.Context
+import com.nextcloud.talk.R
+import com.nextcloud.talk.newarch.local.models.User
+import com.otaliastudios.elements.Page
+import com.otaliastudios.elements.Source
+import com.otaliastudios.elements.extensions.FooterSource
+
+class SettingsViewFooterSource(private val context: Context) : FooterSource() {
+ private var lastAnchor: User? = null
+
+ override fun areItemsTheSame(first: Data, second: Data): Boolean {
+ return first == second
+ }
+
+ override fun getElementType(data: Data): Int {
+ return SettingsElementType.NEW_USER.ordinal
+ }
+
+ override fun dependsOn(source: Source<*>): Boolean {
+ return source is SettingsViewSource
+ }
+
+ override fun computeFooters(page: Page, list: List): List> {
+ val results = arrayListOf>()
+ lastAnchor = if (list.isNotEmpty()) {
+ val user = list.takeLast(1)[0]
+ results.add(Data(user, context.resources.getString(R.string.nc_settings_new_account)))
+ user
+ } else {
+ null
+ }
+
+ return results
+ }
+
+}
diff --git a/app/src/main/java/com/nextcloud/talk/newarch/features/settingsflow/settings/SettingsViewModel.kt b/app/src/main/java/com/nextcloud/talk/newarch/features/settingsflow/settings/SettingsViewModel.kt
new file mode 100644
index 000000000..7caf75756
--- /dev/null
+++ b/app/src/main/java/com/nextcloud/talk/newarch/features/settingsflow/settings/SettingsViewModel.kt
@@ -0,0 +1,85 @@
+/*
+ *
+ * * Nextcloud Talk application
+ * *
+ * * @author Mario Danic
+ * * Copyright (C) 2017-2020 Mario Danic
+ * *
+ * * This program is free software: you can redistribute it and/or modify
+ * * it under the terms of the GNU General Public License as published by
+ * * the Free Software Foundation, either version 3 of the License, or
+ * * at your option) any later version.
+ * *
+ * * This program is distributed in the hope that it will be useful,
+ * * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * * GNU General Public License for more details.
+ * *
+ * * You should have received a copy of the GNU General Public License
+ * * along with this program. If not, see .
+ *
+ */
+package com.nextcloud.talk.newarch.features.settingsflow.settings
+
+import android.app.Application
+import androidx.lifecycle.viewModelScope
+import com.nextcloud.talk.newarch.data.source.remote.ApiErrorHandler
+import com.nextcloud.talk.newarch.domain.repository.offline.UsersRepository
+import com.nextcloud.talk.newarch.local.models.User
+import com.nextcloud.talk.newarch.local.models.other.UserStatus
+import com.nextcloud.talk.newarch.mvvm.BaseViewModel
+import com.nextcloud.talk.newarch.services.GlobalService
+import com.nextcloud.talk.newarch.utils.NetworkComponents
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.withContext
+
+class SettingsViewModel constructor(
+ application: Application,
+ private val usersRepository: UsersRepository,
+ val networkComponents: NetworkComponents,
+ private val apiErrorHandler: ApiErrorHandler,
+ private val globalService: GlobalService
+) : BaseViewModel(application) {
+ val users = usersRepository.getUsersLiveData()
+ val activeUser = globalService.currentUserLiveData
+
+ fun setUserAsActive(user: User): Boolean {
+ if (user.status == UserStatus.DORMANT) {
+ val job = runBlocking {
+ viewModelScope.launch {
+ user.id?.let {
+ usersRepository.setUserAsActiveWithId(it)
+ }
+ }
+ }
+
+ job.start()
+ return true
+ }
+
+ return false
+ }
+
+ private suspend fun removeUserWithId(id: Long): Boolean {
+ return usersRepository.markUserForDeletion(id)
+ }
+
+ fun removeUser(user: User): Boolean = runBlocking {
+ var weHaveActiveUser = true
+ if (user.status != UserStatus.PENDING_DELETE) {
+ val userId = user.id
+ if (userId != null) {
+ weHaveActiveUser = withContext(Dispatchers.Default) {
+ runBlocking {
+ removeUserWithId(userId)
+ }
+ }
+ }
+ }
+
+ weHaveActiveUser
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/nextcloud/talk/newarch/features/settingsflow/settings/SettingsViewModelFactory.kt b/app/src/main/java/com/nextcloud/talk/newarch/features/settingsflow/settings/SettingsViewModelFactory.kt
new file mode 100644
index 000000000..60bfc549d
--- /dev/null
+++ b/app/src/main/java/com/nextcloud/talk/newarch/features/settingsflow/settings/SettingsViewModelFactory.kt
@@ -0,0 +1,45 @@
+/*
+ *
+ * * Nextcloud Talk application
+ * *
+ * * @author Mario Danic
+ * * Copyright (C) 2017-2020 Mario Danic
+ * *
+ * * This program is free software: you can redistribute it and/or modify
+ * * it under the terms of the GNU General Public License as published by
+ * * the Free Software Foundation, either version 3 of the License, or
+ * * at your option) any later version.
+ * *
+ * * This program is distributed in the hope that it will be useful,
+ * * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * * GNU General Public License for more details.
+ * *
+ * * You should have received a copy of the GNU General Public License
+ * * along with this program. If not, see .
+ *
+ */
+package com.nextcloud.talk.newarch.features.settingsflow.settings
+
+import android.app.Application
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.ViewModelProvider
+import com.nextcloud.talk.newarch.data.source.remote.ApiErrorHandler
+import com.nextcloud.talk.newarch.domain.repository.offline.UsersRepository
+import com.nextcloud.talk.newarch.services.GlobalService
+import com.nextcloud.talk.newarch.utils.NetworkComponents
+
+class SettingsViewModelFactory constructor(
+ private val application: Application,
+ private val usersRepository: UsersRepository,
+ private val networkComponents: NetworkComponents,
+ private val apiErrorHandler: ApiErrorHandler,
+ private val globalService: GlobalService
+) : ViewModelProvider.Factory {
+
+ override fun create(modelClass: Class): T {
+ return SettingsViewModel(
+ application, usersRepository, networkComponents, apiErrorHandler, globalService
+ ) as T
+ }
+}
diff --git a/app/src/main/java/com/nextcloud/talk/newarch/features/settingsflow/settings/SettingsViewSource.kt b/app/src/main/java/com/nextcloud/talk/newarch/features/settingsflow/settings/SettingsViewSource.kt
new file mode 100644
index 000000000..2c39377b7
--- /dev/null
+++ b/app/src/main/java/com/nextcloud/talk/newarch/features/settingsflow/settings/SettingsViewSource.kt
@@ -0,0 +1,47 @@
+/*
+ *
+ * * Nextcloud Talk application
+ * *
+ * * @author Mario Danic
+ * * Copyright (C) 2017-2020 Mario Danic
+ * *
+ * * This program is free software: you can redistribute it and/or modify
+ * * it under the terms of the GNU General Public License as published by
+ * * the Free Software Foundation, either version 3 of the License, or
+ * * at your option) any later version.
+ * *
+ * * This program is distributed in the hope that it will be useful,
+ * * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * * GNU General Public License for more details.
+ * *
+ * * You should have received a copy of the GNU General Public License
+ * * along with this program. If not, see .
+ *
+ */
+package com.nextcloud.talk.newarch.features.settingsflow.settings
+
+import androidx.lifecycle.LiveData
+import com.nextcloud.talk.newarch.local.models.User
+import com.otaliastudios.elements.Element
+import com.otaliastudios.elements.Page
+import com.otaliastudios.elements.extensions.MainSource
+
+class SettingsViewSource(private val data: LiveData>, loadingIndicatorsEnabled: Boolean = true, errorIndicatorEnabled: Boolean = false, emptyIndicatorEnabled: Boolean = false) : MainSource(loadingIndicatorsEnabled, errorIndicatorEnabled, emptyIndicatorEnabled) {
+ private var currentPage: Page? = null
+ override fun onPageOpened(page: Page, dependencies: List>) {
+ super.onPageOpened(page, dependencies)
+ if (page.previous() == null) {
+ currentPage = page
+ postResult(page, data)
+ }
+ }
+
+ override fun areItemsTheSame(first: T, second: T): Boolean {
+ return first.id == second.id
+ }
+
+ override fun getElementType(data: T): Int {
+ return SettingsElementType.USER.ordinal
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/nextcloud/talk/newarch/features/settingsflow/settings/SettingsViewUserPresenter.kt b/app/src/main/java/com/nextcloud/talk/newarch/features/settingsflow/settings/SettingsViewUserPresenter.kt
new file mode 100644
index 000000000..94830bad1
--- /dev/null
+++ b/app/src/main/java/com/nextcloud/talk/newarch/features/settingsflow/settings/SettingsViewUserPresenter.kt
@@ -0,0 +1,23 @@
+/*
+ *
+ * * Nextcloud Talk application
+ * *
+ * * @author Mario Danic
+ * * Copyright (C) 2017-2020 Mario Danic
+ * *
+ * * This program is free software: you can redistribute it and/or modify
+ * * it under the terms of the GNU General Public License as published by
+ * * the Free Software Foundation, either version 3 of the License, or
+ * * at your option) any later version.
+ * *
+ * * This program is distributed in the hope that it will be useful,
+ * * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * * GNU General Public License for more details.
+ * *
+ * * You should have received a copy of the GNU General Public License
+ * * along with this program. If not, see .
+ *
+ */
+package com.nextcloud.talk.newarch.features.settingsflow.settings
+
diff --git a/app/src/main/java/com/nextcloud/talk/newarch/local/converters/UserStatusConverter.kt b/app/src/main/java/com/nextcloud/talk/newarch/local/converters/UserStatusConverter.kt
index 6082b6f19..4ab75284f 100644
--- a/app/src/main/java/com/nextcloud/talk/newarch/local/converters/UserStatusConverter.kt
+++ b/app/src/main/java/com/nextcloud/talk/newarch/local/converters/UserStatusConverter.kt
@@ -39,9 +39,9 @@ class UserStatusConverter {
@TypeConverter
fun fromIntToUserStatus(value: Int): UserStatus? {
return when (value) {
- 0 -> DORMANT
- 1 -> ACTIVE
- else -> PENDING_DELETE
+ 0 -> PENDING_DELETE
+ 1 -> DORMANT
+ else -> ACTIVE
}
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/nextcloud/talk/newarch/local/dao/UsersDao.kt b/app/src/main/java/com/nextcloud/talk/newarch/local/dao/UsersDao.kt
index 09e15a712..6d0cc3300 100644
--- a/app/src/main/java/com/nextcloud/talk/newarch/local/dao/UsersDao.kt
+++ b/app/src/main/java/com/nextcloud/talk/newarch/local/dao/UsersDao.kt
@@ -30,12 +30,15 @@ import com.nextcloud.talk.newarch.local.models.other.UserStatus
@Dao
abstract class UsersDao {
// get active user
- @Query("SELECT * FROM users where status = 1")
+ @Query("SELECT * FROM users where status = 2")
abstract fun getActiveUser(): UserNgEntity?
- @Query("SELECT * FROM users WHERE status = 1")
+ @Query("SELECT * FROM users WHERE status = 2")
abstract fun getActiveUserLiveData(): LiveData
+ @Query("SELECT * from users ORDER BY status DESC")
+ abstract fun getUsersLiveData(): LiveData>
+
@Query("DELETE FROM users WHERE id = :id")
abstract suspend fun deleteUserWithId(id: Long)
@@ -49,13 +52,13 @@ abstract class UsersDao {
abstract suspend fun saveUsers(vararg users: UserNgEntity): List
// get all users not scheduled for deletion
- @Query("SELECT * FROM users where status != 2")
+ @Query("SELECT * FROM users where status != 0")
abstract fun getUsers(): List
@Query("SELECT * FROM users where id = :id")
abstract fun getUserWithId(id: Long): UserNgEntity
- @Query("SELECT * FROM users where status = 2")
+ @Query("SELECT * FROM users where status = 0")
abstract fun getUsersScheduledForDeletion(): List
@Query("SELECT * FROM users WHERE username = :username AND base_url = :server")
@@ -75,6 +78,20 @@ abstract class UsersDao {
}
}
+ @Transaction
+ open suspend fun markUserForDeletion(id: Long): Boolean {
+ val users = getUsers()
+ for (user in users) {
+ if (user.id == id) {
+ user.status = UserStatus.PENDING_DELETE
+ updateUser(user)
+ break
+ }
+ }
+
+ return setAnyUserAsActive()
+ }
+
@Transaction
open suspend fun setAnyUserAsActive(): Boolean {
val users = getUsers()
diff --git a/app/src/main/java/com/nextcloud/talk/newarch/local/models/other/UserStatus.kt b/app/src/main/java/com/nextcloud/talk/newarch/local/models/other/UserStatus.kt
index da3bb09ed..10d0e6cbc 100644
--- a/app/src/main/java/com/nextcloud/talk/newarch/local/models/other/UserStatus.kt
+++ b/app/src/main/java/com/nextcloud/talk/newarch/local/models/other/UserStatus.kt
@@ -23,12 +23,12 @@
package com.nextcloud.talk.newarch.local.models.other
enum class UserStatus {
+ // account that will be deleted in the near future
+ PENDING_DELETE,
+
// account that is NOT actively used by the UI, but might be used by background tasks
DORMANT,
// currently active account
ACTIVE,
-
- // account that will be deleted in the near future
- PENDING_DELETE
}
diff --git a/app/src/main/java/com/nextcloud/talk/newarch/utils/Images.kt b/app/src/main/java/com/nextcloud/talk/newarch/utils/Images.kt
index 7ccfe8fd4..b6e82d47e 100644
--- a/app/src/main/java/com/nextcloud/talk/newarch/utils/Images.kt
+++ b/app/src/main/java/com/nextcloud/talk/newarch/utils/Images.kt
@@ -75,7 +75,7 @@ class Images {
val layers = arrayOfNulls(2)
layers[0] = context.getDrawable(backgroundDrawableId)
var scale = 0.25f
- if (drawableId == R.drawable.ic_baseline_email_24 || drawableId == R.drawable.ic_link_white_24px) {
+ if (drawableId == R.drawable.ic_baseline_email_24 || drawableId == R.drawable.ic_link_white_24px || drawableId == R.drawable.ic_add_white_24px) {
scale = 0.5f
} else if (drawableId == R.drawable.ic_user) {
scale = 0.625f
diff --git a/app/src/main/java/com/nextcloud/talk/utils/preferences/AppPreferences.java b/app/src/main/java/com/nextcloud/talk/utils/preferences/AppPreferences.java
index 916212a9e..b6c78243a 100644
--- a/app/src/main/java/com/nextcloud/talk/utils/preferences/AppPreferences.java
+++ b/app/src/main/java/com/nextcloud/talk/utils/preferences/AppPreferences.java
@@ -142,6 +142,14 @@ public interface AppPreferences {
@RemoveMethod
void removePushToTalkIntroShown();
+ @KeyByString("call_ringtone")
+ @RegisterChangeListenerMethod
+ void registerCallRingtoneListener(OnPreferenceValueChangedListener listener);
+
+ @KeyByString("call_ringtone")
+ @UnregisterChangeListenerMethod
+ void unregisterCallRingtoneListener(OnPreferenceValueChangedListener listener);
+
@KeyByString("call_ringtone")
String getCallRingtoneUri();
@@ -152,6 +160,14 @@ public interface AppPreferences {
@RemoveMethod
void removeCallRingtoneUri();
+ @KeyByString("message_ringtone")
+ @RegisterChangeListenerMethod
+ void registerMessageRingtoneListener(OnPreferenceValueChangedListener listener);
+
+ @KeyByString("message_ringtone")
+ @UnregisterChangeListenerMethod
+ void unregisterMessageRingtoneListener(OnPreferenceValueChangedListener listener);
+
@KeyByString("message_ringtone")
String getMessageRingtoneUri();
diff --git a/app/src/main/res/drawable/ic_baseline_more_vert_24.xml b/app/src/main/res/drawable/ic_baseline_more_vert_24.xml
new file mode 100644
index 000000000..9f6859b77
--- /dev/null
+++ b/app/src/main/res/drawable/ic_baseline_more_vert_24.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/layout/controller_settings.xml b/app/src/main/res/layout/controller_settings.xml
index 10bf1c4fe..f23e56584 100644
--- a/app/src/main/res/layout/controller_settings.xml
+++ b/app/src/main/res/layout/controller_settings.xml
@@ -20,6 +20,7 @@
@@ -53,6 +54,7 @@
android:layout_below="@id/avatar_image"
android:layout_centerHorizontal="true"
android:layout_marginTop="@dimen/margin_between_elements"
+ tools:text="Important user"
android:textColor="@color/nc_incoming_text_default" />
@@ -164,120 +168,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/settings_privacy_view.xml b/app/src/main/res/layout/settings_privacy_view.xml
new file mode 100644
index 000000000..081923eb6
--- /dev/null
+++ b/app/src/main/res/layout/settings_privacy_view.xml
@@ -0,0 +1,140 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/settings_view.xml b/app/src/main/res/layout/settings_view.xml
new file mode 100644
index 000000000..9bdf59288
--- /dev/null
+++ b/app/src/main/res/layout/settings_view.xml
@@ -0,0 +1,134 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/user_item.xml b/app/src/main/res/layout/user_item.xml
new file mode 100644
index 000000000..2a1b22972
--- /dev/null
+++ b/app/src/main/res/layout/user_item.xml
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index c8b1a1377..00c1f1de4 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -75,6 +75,7 @@
Please confirm your intent to remove the current account.
Remove account
Add a new account
+ New account
Add
Only current account can be reauthorized
Talk app is not installed on the server you tried to authenticate against
@@ -347,4 +348,8 @@
Reject
You were silenced by a moderator
Failed to send - tap to retry sending.
+ Preferences
+ Look&Feel
+ Calls sound
+ Notifications sound