mirror of
https://github.com/nextcloud/talk-android
synced 2025-07-13 15:54:59 +01:00
parent
29933202d8
commit
07ea11f216
@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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")
|
||||
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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<String>
|
||||
lateinit var proxyCredentialsChangeListener: OnPreferenceValueChangedListener<Boolean>
|
||||
lateinit var screenSecurityChangeListener: OnPreferenceValueChangedListener<Boolean>
|
||||
lateinit var screenLockChangeListener: OnPreferenceValueChangedListener<Boolean>
|
||||
lateinit var screenLockTimeoutChangeListener: OnPreferenceValueChangedListener<String>
|
||||
lateinit var themeChangeListener: OnPreferenceValueChangedListener<String>
|
||||
|
||||
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<String>()
|
||||
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>(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<View>(
|
||||
R.id.mp_checkable
|
||||
) as Checkable).isChecked = appPreferences.shouldVibrateSetting
|
||||
}
|
||||
|
||||
(screenSecuritySwitchPreference!!.findViewById<View>(
|
||||
R.id.mp_checkable
|
||||
) as Checkable).isChecked = appPreferences.isScreenSecured
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
(incognitoKeyboardSwitchPreference!!.findViewById<View>(
|
||||
R.id.mp_checkable
|
||||
) as Checkable).isChecked =
|
||||
appPreferences.isKeyboardIncognito
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
(incognitoKeyboardSwitchPreference!!.findViewById<View>(
|
||||
R.id.mp_checkable
|
||||
) as Checkable).isChecked =
|
||||
appPreferences.isKeyboardIncognito
|
||||
}
|
||||
|
||||
(linkPreviewsSwitchPreference!!.findViewById<View>(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<View>(
|
||||
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<View>(
|
||||
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`<ObservableSubscribeProxy<UserProfileOverall>>(
|
||||
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<View>(R.id.settings_proxy_host_edit)
|
||||
.visibility = View.GONE
|
||||
settingsScreen!!.findViewById<View>(R.id.settings_proxy_port_edit)
|
||||
.visibility = View.GONE
|
||||
settingsScreen!!.findViewById<View>(R.id.settings_proxy_use_credentials)
|
||||
.visibility = View.GONE
|
||||
settingsScreen!!.findViewById<View>(R.id.settings_proxy_username_edit)
|
||||
.visibility = View.GONE
|
||||
settingsScreen!!.findViewById<View>(R.id.settings_proxy_password_edit)
|
||||
.visibility = View.GONE
|
||||
}
|
||||
|
||||
private fun showProxySettings() {
|
||||
settingsScreen!!.findViewById<View>(R.id.settings_proxy_host_edit)
|
||||
.visibility = View.VISIBLE
|
||||
settingsScreen!!.findViewById<View>(R.id.settings_proxy_port_edit)
|
||||
.visibility = View.VISIBLE
|
||||
settingsScreen!!.findViewById<View>(R.id.settings_proxy_use_credentials)
|
||||
.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
private fun showProxyCredentials() {
|
||||
settingsScreen!!.findViewById<View>(R.id.settings_proxy_username_edit)
|
||||
.visibility = View.VISIBLE
|
||||
settingsScreen!!.findViewById<View>(R.id.settings_proxy_password_edit)
|
||||
.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
private fun hideProxyCredentials() {
|
||||
appPreferences.removeProxyUsername()
|
||||
appPreferences.removeProxyPassword()
|
||||
settingsScreen!!.findViewById<View>(R.id.settings_proxy_username_edit)
|
||||
.visibility = View.GONE
|
||||
settingsScreen!!.findViewById<View>(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<String> {
|
||||
|
||||
override fun onChanged(newValue: String) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
SecurityUtils.createKey(appPreferences.screenLockTimeout)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private inner class ScreenLockListener : OnPreferenceValueChangedListener<Boolean> {
|
||||
|
||||
override fun onChanged(newValue: Boolean?) {
|
||||
screenLockTimeoutChoicePreference!!.isEnabled = newValue!!
|
||||
|
||||
if (newValue) {
|
||||
screenLockTimeoutChoicePreference!!.alpha = 1.0f
|
||||
} else {
|
||||
screenLockTimeoutChoicePreference!!.alpha = 0.38f
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private inner class ScreenSecurityChangeListener : OnPreferenceValueChangedListener<Boolean> {
|
||||
|
||||
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<Boolean> {
|
||||
|
||||
override fun onChanged(newValue: Boolean) {
|
||||
if (newValue) {
|
||||
showProxyCredentials()
|
||||
} else {
|
||||
hideProxyCredentials()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private inner class ProxyTypeChangeListener : OnPreferenceValueChangedListener<String> {
|
||||
|
||||
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<String> {
|
||||
override fun onChanged(newValue: String) {
|
||||
NextcloudTalkApplication.setAppTheme(newValue)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
val TAG = "SettingsController"
|
||||
private val ID_REMOVE_ACCOUNT_WARNING_DIALOG = 0
|
||||
}
|
||||
}
|
@ -1,266 +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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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<AbstractFlexibleItem<*>>? = null
|
||||
private val userItems = ArrayList<AbstractFlexibleItem<*>>()
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
@ -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<String>()
|
||||
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)
|
||||
|
||||
|
@ -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<UserNgEntity?> {
|
||||
@ -45,6 +48,14 @@ class UsersRepositoryImpl(private val usersDao: UsersDao) : UsersRepository {
|
||||
return usersDao.getUserWithId(id)
|
||||
}
|
||||
|
||||
override fun getUsersLiveData(): LiveData<List<User>> {
|
||||
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)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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<UserNgEntity>
|
||||
fun getUserWithId(id: Long): UserNgEntity
|
||||
fun getUsersLiveData(): LiveData<List<User>>
|
||||
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
|
||||
}
|
@ -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 -> {
|
||||
|
@ -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())
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
@ -0,0 +1,149 @@
|
||||
/*
|
||||
*
|
||||
* * Nextcloud Talk application
|
||||
* *
|
||||
* * @author Mario Danic
|
||||
* * Copyright (C) 2017-2020 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.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<String> = 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<String> {
|
||||
override fun onChanged(newValue: String) {
|
||||
NextcloudTalkApplication.setAppTheme(newValue)
|
||||
activity?.recreate()
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,178 @@
|
||||
/*
|
||||
*
|
||||
* * Nextcloud Talk application
|
||||
* *
|
||||
* * @author Mario Danic
|
||||
* * Copyright (C) 2017-2020 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.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<String> = ProxyTypeChangeListener()
|
||||
private var proxyCredentialsChangeListener: OnPreferenceValueChangedListener<Boolean> = 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<String>()
|
||||
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<Boolean> {
|
||||
|
||||
override fun onChanged(newValue: Boolean) {
|
||||
toggleCredentialsSettingsVisibility(view, newValue)
|
||||
if (!newValue) {
|
||||
appPreferences.proxyUsername = ""
|
||||
appPreferences.proxyPassword = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private inner class ProxyTypeChangeListener : OnPreferenceValueChangedListener<String> {
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,88 @@
|
||||
/*
|
||||
*
|
||||
* * Nextcloud Talk application
|
||||
* *
|
||||
* * @author Mario Danic
|
||||
* * Copyright (C) 2017-2020 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.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<T : Any>(context: Context, onElementClick: ((Page, Holder, Element<T>) -> Unit)?, private val onMoreOptionsClick: ((User) -> Unit)?) : Presenter<T>(context, onElementClick), KoinComponent {
|
||||
override val elementTypes: Collection<Int>
|
||||
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<T>, payloads: List<Any>) {
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
package com.nextcloud.talk.newarch.features.settingsflow.settings
|
||||
|
||||
enum class SettingsElementType {
|
||||
USER,
|
||||
NEW_USER,
|
||||
}
|
@ -0,0 +1,255 @@
|
||||
/*
|
||||
*
|
||||
* * Nextcloud Talk application
|
||||
* *
|
||||
* * @author Mario Danic
|
||||
* * Copyright (C) 2017-2020 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.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<BasicListItemWithImage> {
|
||||
val items = mutableListOf<BasicListItemWithImage>()
|
||||
|
||||
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<Any>) {
|
||||
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)
|
||||
}
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
/*
|
||||
*
|
||||
* * Nextcloud Talk application
|
||||
* *
|
||||
* * @author Mario Danic
|
||||
* * Copyright (C) 2017-2020 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.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<User, String>() {
|
||||
private var lastAnchor: User? = null
|
||||
|
||||
override fun areItemsTheSame(first: Data<User, String>, second: Data<User, String>): Boolean {
|
||||
return first == second
|
||||
}
|
||||
|
||||
override fun getElementType(data: Data<User, String>): Int {
|
||||
return SettingsElementType.NEW_USER.ordinal
|
||||
}
|
||||
|
||||
override fun dependsOn(source: Source<*>): Boolean {
|
||||
return source is SettingsViewSource
|
||||
}
|
||||
|
||||
override fun computeFooters(page: Page, list: List<User>): List<Data<User, String>> {
|
||||
val results = arrayListOf<Data<User, String>>()
|
||||
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
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,85 @@
|
||||
/*
|
||||
*
|
||||
* * Nextcloud Talk application
|
||||
* *
|
||||
* * @author Mario Danic
|
||||
* * Copyright (C) 2017-2020 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.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<SettingsView>(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
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
/*
|
||||
*
|
||||
* * Nextcloud Talk application
|
||||
* *
|
||||
* * @author Mario Danic
|
||||
* * Copyright (C) 2017-2020 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.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 <T : ViewModel?> create(modelClass: Class<T>): T {
|
||||
return SettingsViewModel(
|
||||
application, usersRepository, networkComponents, apiErrorHandler, globalService
|
||||
) as T
|
||||
}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
/*
|
||||
*
|
||||
* * Nextcloud Talk application
|
||||
* *
|
||||
* * @author Mario Danic
|
||||
* * Copyright (C) 2017-2020 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.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<T : User>(private val data: LiveData<List<T>>, loadingIndicatorsEnabled: Boolean = true, errorIndicatorEnabled: Boolean = false, emptyIndicatorEnabled: Boolean = false) : MainSource<T>(loadingIndicatorsEnabled, errorIndicatorEnabled, emptyIndicatorEnabled) {
|
||||
private var currentPage: Page? = null
|
||||
override fun onPageOpened(page: Page, dependencies: List<Element<*>>) {
|
||||
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
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
/*
|
||||
*
|
||||
* * Nextcloud Talk application
|
||||
* *
|
||||
* * @author Mario Danic
|
||||
* * Copyright (C) 2017-2020 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.newarch.features.settingsflow.settings
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
@ -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<UserNgEntity?>
|
||||
|
||||
@Query("SELECT * from users ORDER BY status DESC")
|
||||
abstract fun getUsersLiveData(): LiveData<List<UserNgEntity>>
|
||||
|
||||
@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<Long>
|
||||
|
||||
// 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<UserNgEntity>
|
||||
|
||||
@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<UserNgEntity>
|
||||
|
||||
@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()
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -75,7 +75,7 @@ class Images {
|
||||
val layers = arrayOfNulls<Drawable>(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
|
||||
|
@ -142,6 +142,14 @@ public interface AppPreferences {
|
||||
@RemoveMethod
|
||||
void removePushToTalkIntroShown();
|
||||
|
||||
@KeyByString("call_ringtone")
|
||||
@RegisterChangeListenerMethod
|
||||
void registerCallRingtoneListener(OnPreferenceValueChangedListener<String> listener);
|
||||
|
||||
@KeyByString("call_ringtone")
|
||||
@UnregisterChangeListenerMethod
|
||||
void unregisterCallRingtoneListener(OnPreferenceValueChangedListener<String> listener);
|
||||
|
||||
@KeyByString("call_ringtone")
|
||||
String getCallRingtoneUri();
|
||||
|
||||
@ -152,6 +160,14 @@ public interface AppPreferences {
|
||||
@RemoveMethod
|
||||
void removeCallRingtoneUri();
|
||||
|
||||
@KeyByString("message_ringtone")
|
||||
@RegisterChangeListenerMethod
|
||||
void registerMessageRingtoneListener(OnPreferenceValueChangedListener<String> listener);
|
||||
|
||||
@KeyByString("message_ringtone")
|
||||
@UnregisterChangeListenerMethod
|
||||
void unregisterMessageRingtoneListener(OnPreferenceValueChangedListener<String> listener);
|
||||
|
||||
@KeyByString("message_ringtone")
|
||||
String getMessageRingtoneUri();
|
||||
|
||||
|
5
app/src/main/res/drawable/ic_baseline_more_vert_24.xml
Normal file
5
app/src/main/res/drawable/ic_baseline_more_vert_24.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<vector android:autoMirrored="true" android:height="24dp"
|
||||
android:tint="?attr/colorControlNormal" android:viewportHeight="24"
|
||||
android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="@android:color/white" android:pathData="M12,8c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM12,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM12,16c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2z"/>
|
||||
</vector>
|
@ -20,6 +20,7 @@
|
||||
|
||||
<com.yarolegovich.mp.MaterialPreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:apc="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/settings_screen"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
@ -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" />
|
||||
|
||||
<TextView
|
||||
@ -62,6 +64,7 @@
|
||||
android:layout_below="@id/display_name_text"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_margin="4dp"
|
||||
tools:text="nextcloud.com"
|
||||
android:textColor="@color/nc_incoming_text_default" />
|
||||
|
||||
<ImageView
|
||||
@ -69,6 +72,7 @@
|
||||
android:layout_width="@dimen/avatar_size_big"
|
||||
android:layout_height="@dimen/avatar_size_big"
|
||||
android:layout_centerHorizontal="true"
|
||||
tools:src="@tools:sample/avatars[0]"
|
||||
android:transitionName="userAvatar.transitionTag" />
|
||||
|
||||
|
||||
@ -164,120 +168,6 @@
|
||||
|
||||
</com.yarolegovich.mp.MaterialPreferenceCategory>
|
||||
|
||||
<com.yarolegovich.mp.MaterialPreferenceCategory
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:animateLayoutChanges="true"
|
||||
apc:mpc_title="@string/nc_settings_privacy"
|
||||
apc:mpc_title_color="@color/colorPrimary">
|
||||
|
||||
<com.yarolegovich.mp.MaterialChoicePreference
|
||||
android:id="@+id/settings_screen_lock_timeout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
apc:mp_default_value="@string/nc_screen_lock_timeout_sixty"
|
||||
apc:mp_entry_descriptions="@array/screen_lock_timeout_descriptions"
|
||||
apc:mp_entry_values="@array/screen_lock_timeout_entry_values"
|
||||
apc:mp_key="@string/nc_settings_screen_lock_timeout_key"
|
||||
apc:mp_show_value="onBottom"
|
||||
apc:mp_title="@string/nc_settings_screen_lock_timeout_title" />
|
||||
|
||||
<com.yarolegovich.mp.MaterialSwitchPreference
|
||||
android:id="@+id/settings_screen_lock"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
apc:mp_default_value="@bool/value_false"
|
||||
apc:mp_key="@string/nc_settings_screen_lock_key"
|
||||
apc:mp_title="@string/nc_settings_screen_lock_title" />
|
||||
|
||||
<com.yarolegovich.mp.MaterialSwitchPreference
|
||||
android:id="@+id/settings_screen_security"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
apc:mp_default_value="@bool/value_false"
|
||||
apc:mp_key="@string/nc_settings_screen_security_key"
|
||||
apc:mp_summary="@string/nc_settings_screen_security_desc"
|
||||
apc:mp_title="@string/nc_settings_screen_security_title" />
|
||||
|
||||
<com.yarolegovich.mp.MaterialSwitchPreference
|
||||
android:id="@+id/settings_incognito_keyboard"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
apc:mp_default_value="@bool/value_true"
|
||||
apc:mp_key="@string/nc_settings_incognito_keyboard_key"
|
||||
apc:mp_summary="@string/nc_settings_incognito_keyboard_desc"
|
||||
apc:mp_title="@string/nc_settings_incognito_keyboard_title" />
|
||||
|
||||
<com.yarolegovich.mp.MaterialSwitchPreference
|
||||
android:id="@+id/settings_link_previews"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
apc:mp_default_value="@bool/value_true"
|
||||
apc:mp_key="@string/nc_settings_link_previews_key"
|
||||
apc:mp_summary="@string/nc_settings_link_previews_desc"
|
||||
apc:mp_title="@string/nc_settings_link_previews_title" />
|
||||
</com.yarolegovich.mp.MaterialPreferenceCategory>
|
||||
|
||||
<com.yarolegovich.mp.MaterialPreferenceCategory
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:animateLayoutChanges="true"
|
||||
apc:mpc_title="@string/nc_settings_proxy_title"
|
||||
apc:mpc_title_color="@color/colorPrimary">
|
||||
|
||||
<com.yarolegovich.mp.MaterialChoicePreference
|
||||
android:id="@+id/settings_proxy_choice"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
apc:mp_default_value="@string/nc_no_proxy"
|
||||
apc:mp_entry_descriptions="@array/proxy_type_descriptions"
|
||||
apc:mp_key="@string/nc_settings_proxy_type_key"
|
||||
apc:mp_show_value="onRight"
|
||||
apc:mp_title="@string/nc_settings_proxy_type_title"></com.yarolegovich.mp.MaterialChoicePreference>
|
||||
|
||||
<com.yarolegovich.mp.MaterialEditTextPreference
|
||||
android:id="@+id/settings_proxy_host_edit"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
apc:mp_key="@string/nc_settings_proxy_host_key"
|
||||
apc:mp_show_value="onRight"
|
||||
apc:mp_title="@string/nc_settings_proxy_host_title" />
|
||||
|
||||
<com.yarolegovich.mp.MaterialEditTextPreference
|
||||
android:id="@+id/settings_proxy_port_edit"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
apc:mp_key="@string/nc_settings_proxy_port_key"
|
||||
apc:mp_show_value="onRight"
|
||||
apc:mp_title="@string/nc_settings_proxy_port_title" />
|
||||
|
||||
<com.yarolegovich.mp.MaterialEditTextPreference
|
||||
android:id="@+id/settings_proxy_username_edit"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
apc:mp_key="@string/nc_settings_proxy_username_key"
|
||||
apc:mp_show_value="onRight"
|
||||
apc:mp_title="@string/nc_username" />
|
||||
|
||||
<com.yarolegovich.mp.MaterialEditTextPreference
|
||||
android:id="@+id/settings_proxy_password_edit"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
apc:mp_key="@string/nc_settings_proxy_password_key"
|
||||
apc:mp_show_value="onRight"
|
||||
apc:mp_title="@string/nc_password" />
|
||||
|
||||
<com.yarolegovich.mp.MaterialSwitchPreference
|
||||
android:id="@+id/settings_proxy_use_credentials"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
apc:mp_default_value="false"
|
||||
apc:mp_key="@string/nc_settings_use_credentials_key"
|
||||
apc:mp_show_value="onRight"
|
||||
apc:mp_title="@string/nc_settings_use_credentials_title">
|
||||
|
||||
</com.yarolegovich.mp.MaterialSwitchPreference>
|
||||
</com.yarolegovich.mp.MaterialPreferenceCategory>
|
||||
|
||||
<com.yarolegovich.mp.MaterialPreferenceCategory
|
||||
android:layout_width="match_parent"
|
||||
|
79
app/src/main/res/layout/settings_looknfeel_view.xml
Normal file
79
app/src/main/res/layout/settings_looknfeel_view.xml
Normal file
@ -0,0 +1,79 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ 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 <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<com.yarolegovich.mp.MaterialPreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:apc="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/lookNFeelScreen"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<com.yarolegovich.mp.MaterialPreferenceCategory
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:animateLayoutChanges="true"
|
||||
apc:mpc_title="@string/nc_settings_appearance"
|
||||
apc:mpc_title_color="@color/colorPrimary">
|
||||
|
||||
<com.yarolegovich.mp.MaterialChoicePreference
|
||||
android:id="@+id/settings_theme"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
apc:mp_default_value="@string/nc_default_theme"
|
||||
apc:mp_entry_descriptions="@array/theme_descriptions"
|
||||
apc:mp_entry_values="@array/theme_entry_values"
|
||||
apc:mp_key="@string/nc_settings_theme_key"
|
||||
apc:mp_show_value="onBottom"
|
||||
apc:mp_title="@string/nc_settings_theme_title" />
|
||||
|
||||
</com.yarolegovich.mp.MaterialPreferenceCategory>
|
||||
|
||||
<com.yarolegovich.mp.MaterialPreferenceCategory
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:animateLayoutChanges="true"
|
||||
apc:mpc_title="@string/nc_settings_notification_sounds"
|
||||
apc:mpc_title_color="@color/colorPrimary">
|
||||
|
||||
<com.yarolegovich.mp.MaterialStandardPreference
|
||||
android:id="@+id/settings_call_sound"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
apc:mp_key="@string/nc_settings_call_ringtone_key"
|
||||
apc:mp_title="@string/nc_settings_call_ringtone" />
|
||||
|
||||
<com.yarolegovich.mp.MaterialStandardPreference
|
||||
android:id="@+id/settings_message_sound"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
apc:mp_key="@string/nc_settings_message_ringtone_key"
|
||||
apc:mp_title="@string/nc_settings_other_notifications_ringtone" />
|
||||
|
||||
<com.yarolegovich.mp.MaterialSwitchPreference
|
||||
android:id="@+id/settings_always_vibrate"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
apc:mp_default_value="@bool/value_true"
|
||||
apc:mp_key="@string/nc_settings_vibrate_key"
|
||||
apc:mp_summary="@string/nc_settings_vibrate_desc"
|
||||
apc:mp_title="@string/nc_settings_vibrate" />
|
||||
|
||||
</com.yarolegovich.mp.MaterialPreferenceCategory>
|
||||
|
||||
</com.yarolegovich.mp.MaterialPreferenceScreen>
|
140
app/src/main/res/layout/settings_privacy_view.xml
Normal file
140
app/src/main/res/layout/settings_privacy_view.xml
Normal file
@ -0,0 +1,140 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ 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 <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<com.yarolegovich.mp.MaterialPreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:apc="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/privacy_screen"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<com.yarolegovich.mp.MaterialPreferenceCategory
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:animateLayoutChanges="true"
|
||||
apc:mpc_title="@string/nc_settings_privacy"
|
||||
apc:mpc_title_color="@color/colorPrimary">
|
||||
|
||||
<com.yarolegovich.mp.MaterialChoicePreference
|
||||
android:id="@+id/settings_screen_lock_timeout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
apc:mp_default_value="@string/nc_screen_lock_timeout_sixty"
|
||||
apc:mp_entry_descriptions="@array/screen_lock_timeout_descriptions"
|
||||
apc:mp_entry_values="@array/screen_lock_timeout_entry_values"
|
||||
apc:mp_key="@string/nc_settings_screen_lock_timeout_key"
|
||||
apc:mp_show_value="onBottom"
|
||||
apc:mp_title="@string/nc_settings_screen_lock_timeout_title" />
|
||||
|
||||
<com.yarolegovich.mp.MaterialSwitchPreference
|
||||
android:id="@+id/settings_screen_lock"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
apc:mp_default_value="@bool/value_false"
|
||||
apc:mp_key="@string/nc_settings_screen_lock_key"
|
||||
apc:mp_title="@string/nc_settings_screen_lock_title" />
|
||||
|
||||
<com.yarolegovich.mp.MaterialSwitchPreference
|
||||
android:id="@+id/settings_screen_security"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
apc:mp_default_value="@bool/value_false"
|
||||
apc:mp_key="@string/nc_settings_screen_security_key"
|
||||
apc:mp_summary="@string/nc_settings_screen_security_desc"
|
||||
apc:mp_title="@string/nc_settings_screen_security_title" />
|
||||
|
||||
<com.yarolegovich.mp.MaterialSwitchPreference
|
||||
android:id="@+id/settings_incognito_keyboard"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
apc:mp_default_value="@bool/value_true"
|
||||
apc:mp_key="@string/nc_settings_incognito_keyboard_key"
|
||||
apc:mp_summary="@string/nc_settings_incognito_keyboard_desc"
|
||||
apc:mp_title="@string/nc_settings_incognito_keyboard_title" />
|
||||
|
||||
<com.yarolegovich.mp.MaterialSwitchPreference
|
||||
android:id="@+id/settings_link_previews"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
apc:mp_default_value="@bool/value_true"
|
||||
apc:mp_key="@string/nc_settings_link_previews_key"
|
||||
apc:mp_summary="@string/nc_settings_link_previews_desc"
|
||||
apc:mp_title="@string/nc_settings_link_previews_title" />
|
||||
</com.yarolegovich.mp.MaterialPreferenceCategory>
|
||||
|
||||
<com.yarolegovich.mp.MaterialPreferenceCategory
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:animateLayoutChanges="true"
|
||||
apc:mpc_title="@string/nc_settings_proxy_title"
|
||||
apc:mpc_title_color="@color/colorPrimary">
|
||||
|
||||
<com.yarolegovich.mp.MaterialChoicePreference
|
||||
android:id="@+id/settings_proxy_choice"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
apc:mp_default_value="@string/nc_no_proxy"
|
||||
apc:mp_entry_descriptions="@array/proxy_type_descriptions"
|
||||
apc:mp_key="@string/nc_settings_proxy_type_key"
|
||||
apc:mp_show_value="onRight"
|
||||
apc:mp_title="@string/nc_settings_proxy_type_title"></com.yarolegovich.mp.MaterialChoicePreference>
|
||||
|
||||
<com.yarolegovich.mp.MaterialEditTextPreference
|
||||
android:id="@+id/settings_proxy_host_edit"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
apc:mp_key="@string/nc_settings_proxy_host_key"
|
||||
apc:mp_show_value="onRight"
|
||||
apc:mp_title="@string/nc_settings_proxy_host_title" />
|
||||
|
||||
<com.yarolegovich.mp.MaterialEditTextPreference
|
||||
android:id="@+id/settings_proxy_port_edit"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
apc:mp_key="@string/nc_settings_proxy_port_key"
|
||||
apc:mp_show_value="onRight"
|
||||
apc:mp_title="@string/nc_settings_proxy_port_title" />
|
||||
|
||||
<com.yarolegovich.mp.MaterialSwitchPreference
|
||||
android:id="@+id/settings_proxy_use_credentials"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
apc:mp_default_value="false"
|
||||
apc:mp_key="@string/nc_settings_use_credentials_key"
|
||||
apc:mp_show_value="onRight"
|
||||
apc:mp_title="@string/nc_settings_use_credentials_title"/>
|
||||
|
||||
<com.yarolegovich.mp.MaterialEditTextPreference
|
||||
android:id="@+id/settings_proxy_username_edit"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
apc:mp_key="@string/nc_settings_proxy_username_key"
|
||||
apc:mp_show_value="onRight"
|
||||
apc:mp_title="@string/nc_username" />
|
||||
|
||||
<com.yarolegovich.mp.MaterialEditTextPreference
|
||||
android:id="@+id/settings_proxy_password_edit"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
apc:mp_key="@string/nc_settings_proxy_password_key"
|
||||
apc:mp_show_value="onRight"
|
||||
apc:mp_title="@string/nc_password" />
|
||||
</com.yarolegovich.mp.MaterialPreferenceCategory>
|
||||
|
||||
</com.yarolegovich.mp.MaterialPreferenceScreen>
|
134
app/src/main/res/layout/settings_view.xml
Normal file
134
app/src/main/res/layout/settings_view.xml
Normal file
@ -0,0 +1,134 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ 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 <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<com.yarolegovich.mp.MaterialPreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:apc="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/settings_screen"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<com.yarolegovich.mp.MaterialPreferenceCategory
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:animateLayoutChanges="true">
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/avatar_image"
|
||||
android:layout_width="@dimen/avatar_size_big"
|
||||
android:layout_height="@dimen/avatar_size_big"
|
||||
android:focusable="true"
|
||||
android:layout_centerHorizontal="true"
|
||||
tools:src="@tools:sample/avatars[0]"
|
||||
android:transitionName="userAvatar.transitionTag" />
|
||||
|
||||
<androidx.emoji.widget.EmojiTextView
|
||||
android:id="@+id/display_name_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
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" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/base_url_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/display_name_text"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_margin="4dp"
|
||||
tools:text="nextcloud.com"
|
||||
android:textColor="@color/nc_incoming_text_default"
|
||||
android:layout_marginBottom="8dp"/>
|
||||
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
tools:listitem="@layout/user_item"
|
||||
tools:itemCount="5"
|
||||
android:layout_below="@id/base_url_text"
|
||||
android:id="@+id/settingsRecyclerView"/>
|
||||
</RelativeLayout>
|
||||
|
||||
</com.yarolegovich.mp.MaterialPreferenceCategory>
|
||||
|
||||
<com.yarolegovich.mp.MaterialPreferenceCategory
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:animateLayoutChanges="true"
|
||||
apc:mpc_title="@string/nc_preferences"
|
||||
apc:mpc_title_color="@color/colorPrimary">
|
||||
|
||||
<com.yarolegovich.mp.MaterialStandardPreference
|
||||
android:id="@+id/settings_look_n_feel"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
apc:mp_title="@string/nc_look_and_feel" />
|
||||
|
||||
<com.yarolegovich.mp.MaterialStandardPreference
|
||||
android:id="@+id/settings_privacy_options"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
apc:mp_title="@string/nc_privacy" />
|
||||
|
||||
</com.yarolegovich.mp.MaterialPreferenceCategory>
|
||||
|
||||
<com.yarolegovich.mp.MaterialPreferenceCategory
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:animateLayoutChanges="true"
|
||||
apc:mpc_title="@string/nc_about"
|
||||
apc:mpc_title_color="@color/colorPrimary">
|
||||
|
||||
<com.yarolegovich.mp.MaterialStandardPreference
|
||||
android:id="@+id/settings_privacy"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
apc:mp_title="@string/nc_privacy" />
|
||||
|
||||
<com.yarolegovich.mp.MaterialStandardPreference
|
||||
android:id="@+id/settings_source_code"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
apc:mp_title="@string/nc_get_source_code"/>
|
||||
|
||||
<com.yarolegovich.mp.MaterialStandardPreference
|
||||
android:id="@+id/settings_licence"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
apc:mp_summary="@string/nc_license_summary"
|
||||
apc:mp_title="@string/nc_license_title"/>
|
||||
|
||||
<com.yarolegovich.mp.MaterialStandardPreference
|
||||
android:id="@+id/settings_version"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
apc:mp_summary="v0.1"
|
||||
apc:mp_title="@string/nc_app_name"/>
|
||||
|
||||
</com.yarolegovich.mp.MaterialPreferenceCategory>
|
||||
</com.yarolegovich.mp.MaterialPreferenceScreen>
|
50
app/src/main/res/layout/user_item.xml
Normal file
50
app/src/main/res/layout/user_item.xml
Normal file
@ -0,0 +1,50 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<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:layout_width="match_parent"
|
||||
android:paddingVertical="8dp"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.google.android.material.imageview.ShapeableImageView
|
||||
android:id="@+id/avatarImageView"
|
||||
android:layout_width="@dimen/small_item_height"
|
||||
android:layout_height="@dimen/small_item_height"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginHorizontal="8dp"
|
||||
app:shapeAppearanceOverlay="@style/circleImageView"
|
||||
tools:srcCompat="@tools:sample/avatars[1]" />
|
||||
|
||||
<androidx.emoji.widget.EmojiTextView
|
||||
android:id="@+id/userDisplayName"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_toStartOf="@id/userMoreOptionsView"
|
||||
android:layout_toEndOf="@id/avatarImageView"
|
||||
android:ellipsize="end"
|
||||
android:singleLine="true"
|
||||
android:lines="1"
|
||||
tools:text="Awesome user" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/userMoreOptionsView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_marginHorizontal="8dp"
|
||||
android:layout_centerVertical="true"
|
||||
android:scaleType="center"
|
||||
android:src="@drawable/ic_baseline_more_vert_24" />
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/userProgressBar"
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:indeterminateTint="@color/colorPrimary"
|
||||
android:visibility="gone" />
|
||||
|
||||
</RelativeLayout>
|
@ -75,6 +75,7 @@
|
||||
<string name="nc_settings_remove_confirmation">Please confirm your intent to remove the current account.</string>
|
||||
<string name="nc_settings_remove_account">Remove account</string>
|
||||
<string name="nc_settings_add_account">Add a new account</string>
|
||||
<string name="nc_settings_new_account">New account</string>
|
||||
<string name="nc_add">Add</string>
|
||||
<string name="nc_settings_wrong_account">Only current account can be reauthorized</string>
|
||||
<string name="nc_settings_no_talk_installed">Talk app is not installed on the server you tried to authenticate against</string>
|
||||
@ -347,4 +348,8 @@
|
||||
<string name="nc_reject_call">Reject</string>
|
||||
<string name="silenced_by_moderator">You were silenced by a moderator</string>
|
||||
<string name="nc_failed_to_send">Failed to send - tap to retry sending.</string>
|
||||
<string name="nc_preferences">Preferences</string>
|
||||
<string name="nc_look_and_feel">Look&Feel</string>
|
||||
<string name="nc_settings_calls_sound">Calls sound</string>
|
||||
<string name="nc_settings_notifications_sound">Notifications sound</string>
|
||||
</resources>
|
||||
|
Loading…
Reference in New Issue
Block a user