mirror of
https://github.com/nextcloud/talk-android
synced 2025-06-21 04:29:45 +01:00
Also add an option to not show the hint, when user doesn't want to ignore battery optimization. Only show these features when gplay services are available. Otherwise don't show them as it would pretend notifications would be possible without gplay. Signed-off-by: Marcel Hibbe <dev@mhibbe.de>
1365 lines
58 KiB
Kotlin
1365 lines
58 KiB
Kotlin
/*
|
|
* Nextcloud Talk - Android Client
|
|
*
|
|
* SPDX-FileCopyrightText: 2023 Marcel Hibbe <dev@mhibbe.de>
|
|
* SPDX-FileCopyrightText: 2023 Ezhil Shanmugham <ezhil56x.contact@gmail.com>
|
|
* SPDX-FileCopyrightText: 2021-2022 Andy Scherzinger <info@andy-scherzinger.de>
|
|
* SPDX-FileCopyrightText: 2021 Tim Krüger <t@timkrueger.me>
|
|
* SPDX-FileCopyrightText: 2017 Mario Danic <mario@lovelyhq.com>
|
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
*/
|
|
package com.nextcloud.talk.settings
|
|
|
|
import android.Manifest
|
|
import android.animation.Animator
|
|
import android.animation.AnimatorListenerAdapter
|
|
import android.annotation.SuppressLint
|
|
import android.app.KeyguardManager
|
|
import android.content.Context
|
|
import android.content.DialogInterface
|
|
import android.content.Intent
|
|
import android.content.pm.PackageManager
|
|
import android.graphics.PorterDuff
|
|
import android.graphics.drawable.ColorDrawable
|
|
import android.media.RingtoneManager
|
|
import android.net.Uri
|
|
import android.os.Build
|
|
import android.os.Bundle
|
|
import android.provider.Settings
|
|
import android.security.KeyChain
|
|
import android.text.TextUtils
|
|
import android.util.Log
|
|
import android.view.View
|
|
import android.view.WindowManager
|
|
import android.widget.Toast
|
|
import androidx.appcompat.app.AlertDialog
|
|
import androidx.core.content.ContextCompat
|
|
import androidx.core.content.res.ResourcesCompat
|
|
import androidx.core.view.ViewCompat
|
|
import androidx.lifecycle.lifecycleScope
|
|
import androidx.work.OneTimeWorkRequest
|
|
import androidx.work.WorkInfo
|
|
import androidx.work.WorkManager
|
|
import autodagger.AutoInjector
|
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
|
import com.google.android.material.snackbar.Snackbar
|
|
import com.google.android.material.textfield.TextInputLayout
|
|
import com.nextcloud.android.common.ui.theme.utils.ColorRole
|
|
import com.nextcloud.talk.BuildConfig
|
|
import com.nextcloud.talk.R
|
|
import com.nextcloud.talk.activities.BaseActivity
|
|
import com.nextcloud.talk.activities.MainActivity
|
|
import com.nextcloud.talk.api.NcApi
|
|
import com.nextcloud.talk.api.NcApiCoroutines
|
|
import com.nextcloud.talk.application.NextcloudTalkApplication
|
|
import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.setAppTheme
|
|
import com.nextcloud.talk.conversationlist.ConversationsListActivity
|
|
import com.nextcloud.talk.data.user.model.User
|
|
import com.nextcloud.talk.databinding.ActivitySettingsBinding
|
|
import com.nextcloud.talk.diagnose.DiagnoseActivity
|
|
import com.nextcloud.talk.jobs.AccountRemovalWorker
|
|
import com.nextcloud.talk.jobs.CapabilitiesWorker
|
|
import com.nextcloud.talk.jobs.ContactAddressBookWorker
|
|
import com.nextcloud.talk.jobs.ContactAddressBookWorker.Companion.checkPermission
|
|
import com.nextcloud.talk.jobs.ContactAddressBookWorker.Companion.deleteAll
|
|
import com.nextcloud.talk.models.json.generic.GenericOverall
|
|
import com.nextcloud.talk.models.json.userprofile.UserProfileOverall
|
|
import com.nextcloud.talk.profile.ProfileActivity
|
|
import com.nextcloud.talk.ui.dialog.SetPhoneNumberDialogFragment
|
|
import com.nextcloud.talk.users.UserManager
|
|
import com.nextcloud.talk.utils.ApiUtils
|
|
import com.nextcloud.talk.utils.CapabilitiesUtil
|
|
import com.nextcloud.talk.utils.ClosedInterfaceImpl
|
|
import com.nextcloud.talk.utils.DisplayUtils
|
|
import com.nextcloud.talk.utils.LoggingUtils.sendMailWithAttachment
|
|
import com.nextcloud.talk.utils.NotificationUtils
|
|
import com.nextcloud.talk.utils.NotificationUtils.getCallRingtoneUri
|
|
import com.nextcloud.talk.utils.NotificationUtils.getMessageRingtoneUri
|
|
import com.nextcloud.talk.utils.SecurityUtils
|
|
import com.nextcloud.talk.utils.SpreedFeatures
|
|
import com.nextcloud.talk.utils.permissions.PlatformPermissionUtil
|
|
import com.nextcloud.talk.utils.power.PowerManagerUtils
|
|
import com.nextcloud.talk.utils.preferences.AppPreferencesImpl
|
|
import com.nextcloud.talk.utils.singletons.ApplicationWideMessageHolder
|
|
import io.reactivex.Observer
|
|
import io.reactivex.android.schedulers.AndroidSchedulers
|
|
import io.reactivex.disposables.Disposable
|
|
import io.reactivex.schedulers.Schedulers
|
|
import kotlinx.coroutines.CoroutineScope
|
|
import kotlinx.coroutines.Dispatchers
|
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
|
import kotlinx.coroutines.flow.Flow
|
|
import kotlinx.coroutines.launch
|
|
import kotlinx.coroutines.withContext
|
|
import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
|
import okhttp3.RequestBody.Companion.toRequestBody
|
|
import retrofit2.HttpException
|
|
import java.net.URI
|
|
import java.net.URISyntaxException
|
|
import java.util.Locale
|
|
import javax.inject.Inject
|
|
|
|
@Suppress("LargeClass", "TooManyFunctions")
|
|
@AutoInjector(NextcloudTalkApplication::class)
|
|
class SettingsActivity : BaseActivity(), SetPhoneNumberDialogFragment.SetPhoneNumberDialogClickListener {
|
|
private lateinit var binding: ActivitySettingsBinding
|
|
|
|
@Inject
|
|
lateinit var ncApi: NcApi
|
|
|
|
@Inject
|
|
lateinit var ncApiCoroutines: NcApiCoroutines
|
|
|
|
@Inject
|
|
lateinit var userManager: UserManager
|
|
|
|
@Inject
|
|
lateinit var platformPermissionUtil: PlatformPermissionUtil
|
|
|
|
private var currentUser: User? = null
|
|
private var credentials: String? = null
|
|
private lateinit var proxyTypeFlow: Flow<String>
|
|
private lateinit var proxyCredentialFlow: Flow<Boolean>
|
|
private lateinit var screenSecurityFlow: Flow<Boolean>
|
|
private lateinit var screenLockFlow: Flow<Boolean>
|
|
private lateinit var screenLockTimeoutFlow: Flow<String>
|
|
private lateinit var themeFlow: Flow<String>
|
|
private lateinit var readPrivacyFlow: Flow<Boolean>
|
|
private lateinit var typingStatusFlow: Flow<Boolean>
|
|
private lateinit var phoneBookIntegrationFlow: Flow<Boolean>
|
|
private var profileQueryDisposable: Disposable? = null
|
|
private var dbQueryDisposable: Disposable? = null
|
|
|
|
@SuppressLint("StringFormatInvalid")
|
|
override fun onCreate(savedInstanceState: Bundle?) {
|
|
super.onCreate(savedInstanceState)
|
|
NextcloudTalkApplication.sharedApplication!!.componentApplication.inject(this)
|
|
|
|
binding = ActivitySettingsBinding.inflate(layoutInflater)
|
|
setupActionBar()
|
|
setContentView(binding.root)
|
|
setupSystemColors()
|
|
|
|
binding.avatarImage.let { ViewCompat.setTransitionName(it, "userAvatar.transitionTag") }
|
|
|
|
getCurrentUser()
|
|
|
|
setupLicenceSetting()
|
|
|
|
binding.settingsScreenLockSummary.text = String.format(
|
|
Locale.getDefault(),
|
|
resources!!.getString(R.string.nc_settings_screen_lock_desc),
|
|
resources!!.getString(R.string.nc_app_product_name)
|
|
)
|
|
|
|
setupDiagnose()
|
|
setupPrivacyUrl()
|
|
setupSourceCodeUrl()
|
|
binding.settingsVersionSummary.text = String.format("v" + BuildConfig.VERSION_NAME)
|
|
|
|
setupPhoneBookIntegration()
|
|
|
|
setupClientCertView()
|
|
}
|
|
|
|
override fun onResume() {
|
|
super.onResume()
|
|
supportActionBar?.show()
|
|
dispose(null)
|
|
|
|
loadCapabilitiesAndUpdateSettings()
|
|
|
|
binding.settingsVersion.setOnClickListener {
|
|
sendLogs()
|
|
}
|
|
|
|
if (!TextUtils.isEmpty(currentUser!!.clientCertificate)) {
|
|
binding.settingsClientCertTitle.setText(R.string.nc_client_cert_change)
|
|
} else {
|
|
binding.settingsClientCertTitle.setText(R.string.nc_client_cert_setup)
|
|
}
|
|
|
|
setupCheckables()
|
|
setupScreenLockSetting()
|
|
setupNotificationSettings()
|
|
setupProxyTypeSettings()
|
|
setupProxyCredentialSettings()
|
|
registerChangeListeners()
|
|
|
|
if (currentUser != null) {
|
|
binding.domainText.text = Uri.parse(currentUser!!.baseUrl).host
|
|
setupServerAgeWarning()
|
|
if (currentUser!!.displayName != null) {
|
|
binding.nameText.text = currentUser!!.displayName
|
|
}
|
|
DisplayUtils.loadAvatarImage(currentUser, binding.avatarImage, false)
|
|
|
|
setupProfileQueryDisposable()
|
|
|
|
binding.settingsRemoveAccount.setOnClickListener {
|
|
showRemoveAccountWarning()
|
|
}
|
|
}
|
|
setupMessageView()
|
|
|
|
binding.settingsName.visibility = View.VISIBLE
|
|
binding.settingsName.setOnClickListener {
|
|
val intent = Intent(this, ProfileActivity::class.java)
|
|
startActivity(intent)
|
|
}
|
|
|
|
themeTitles()
|
|
themeSwitchPreferences()
|
|
}
|
|
|
|
private fun loadCapabilitiesAndUpdateSettings() {
|
|
val capabilitiesWork = OneTimeWorkRequest.Builder(CapabilitiesWorker::class.java).build()
|
|
WorkManager.getInstance(context).enqueue(capabilitiesWork)
|
|
|
|
WorkManager.getInstance(context).getWorkInfoByIdLiveData(capabilitiesWork.id)
|
|
.observe(this) { workInfo ->
|
|
if (workInfo?.state == WorkInfo.State.SUCCEEDED) {
|
|
getCurrentUser()
|
|
setupCheckables()
|
|
}
|
|
}
|
|
}
|
|
|
|
private fun setupActionBar() {
|
|
setSupportActionBar(binding.settingsToolbar)
|
|
binding.settingsToolbar.setNavigationOnClickListener {
|
|
onBackPressedDispatcher.onBackPressed()
|
|
}
|
|
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
|
supportActionBar?.setDisplayShowHomeEnabled(true)
|
|
supportActionBar?.setIcon(ColorDrawable(resources!!.getColor(android.R.color.transparent, null)))
|
|
supportActionBar?.title = context.getString(R.string.nc_settings)
|
|
viewThemeUtils.material.themeToolbar(binding.settingsToolbar)
|
|
}
|
|
|
|
private fun getCurrentUser() {
|
|
currentUser = currentUserProvider.currentUser.blockingGet()
|
|
credentials = ApiUtils.getCredentials(currentUser!!.username, currentUser!!.token)
|
|
}
|
|
|
|
private fun setupPhoneBookIntegration() {
|
|
if (CapabilitiesUtil.hasSpreedFeatureCapability(
|
|
currentUser?.capabilities?.spreedCapability!!,
|
|
SpreedFeatures.PHONEBOOK_SEARCH
|
|
)
|
|
) {
|
|
binding.settingsPhoneBookIntegration.visibility = View.VISIBLE
|
|
} else {
|
|
binding.settingsPhoneBookIntegration.visibility = View.GONE
|
|
}
|
|
}
|
|
|
|
private fun setupNotificationSettings() {
|
|
binding.settingsNotificationsTitle.text = resources!!.getString(
|
|
R.string.nc_settings_notification_sounds_post_oreo
|
|
)
|
|
setupNotificationSoundsSettings()
|
|
setupNotificationPermissionSettings()
|
|
}
|
|
|
|
@SuppressLint("StringFormatInvalid")
|
|
@Suppress("LongMethod")
|
|
private fun setupNotificationPermissionSettings() {
|
|
if (ClosedInterfaceImpl().isGooglePlayServicesAvailable) {
|
|
binding.settingsGplayOnlyWrapper.visibility = View.VISIBLE
|
|
|
|
setTroubleshootingClickListenersIfNecessary()
|
|
|
|
if (PowerManagerUtils().isIgnoringBatteryOptimizations()) {
|
|
binding.batteryOptimizationIgnored.text =
|
|
resources!!.getString(R.string.nc_diagnose_battery_optimization_ignored)
|
|
binding.batteryOptimizationIgnored.setTextColor(
|
|
resources.getColor(R.color.high_emphasis_text, null)
|
|
)
|
|
} else {
|
|
binding.batteryOptimizationIgnored.text =
|
|
resources!!.getString(R.string.nc_diagnose_battery_optimization_not_ignored)
|
|
binding.batteryOptimizationIgnored.setTextColor(resources.getColor(R.color.nc_darkRed, null))
|
|
|
|
binding.settingsBatteryOptimizationWrapper.setOnClickListener {
|
|
val dialogText = String.format(
|
|
context.resources.getString(R.string.nc_ignore_battery_optimization_dialog_text),
|
|
context.resources.getString(R.string.nc_app_name)
|
|
)
|
|
|
|
val dialogBuilder = MaterialAlertDialogBuilder(this)
|
|
.setTitle(R.string.nc_ignore_battery_optimization_dialog_title)
|
|
.setMessage(dialogText)
|
|
.setPositiveButton(R.string.nc_ok) { _, _ ->
|
|
startActivity(
|
|
Intent(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS)
|
|
)
|
|
}
|
|
.setNegativeButton(R.string.nc_common_dismiss, null)
|
|
viewThemeUtils.dialog.colorMaterialAlertDialogBackground(this, dialogBuilder)
|
|
val dialog = dialogBuilder.show()
|
|
viewThemeUtils.platform.colorTextButtons(
|
|
dialog.getButton(AlertDialog.BUTTON_POSITIVE),
|
|
dialog.getButton(AlertDialog.BUTTON_NEGATIVE)
|
|
)
|
|
}
|
|
}
|
|
|
|
// handle notification permission on API level >= 33
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
|
if (platformPermissionUtil.isPostNotificationsPermissionGranted()) {
|
|
binding.ncDiagnoseNotificationPermissionSubtitle.text =
|
|
resources.getString(R.string.nc_settings_notifications_granted)
|
|
binding.ncDiagnoseNotificationPermissionSubtitle.setTextColor(
|
|
resources.getColor(R.color.high_emphasis_text, null)
|
|
)
|
|
} else {
|
|
binding.ncDiagnoseNotificationPermissionSubtitle.text =
|
|
resources.getString(R.string.nc_settings_notifications_declined)
|
|
binding.ncDiagnoseNotificationPermissionSubtitle.setTextColor(
|
|
resources.getColor(R.color.nc_darkRed, null)
|
|
)
|
|
binding.settingsNotificationsPermissionWrapper.setOnClickListener {
|
|
requestPermissions(
|
|
arrayOf(Manifest.permission.POST_NOTIFICATIONS),
|
|
ConversationsListActivity.REQUEST_POST_NOTIFICATIONS_PERMISSION
|
|
)
|
|
}
|
|
}
|
|
} else {
|
|
binding.settingsNotificationsPermissionWrapper.visibility = View.GONE
|
|
}
|
|
} else {
|
|
binding.settingsGplayOnlyWrapper.visibility = View.GONE
|
|
binding.settingsGplayNotAvailable.visibility = View.VISIBLE
|
|
}
|
|
}
|
|
|
|
private fun setupNotificationSoundsSettings() {
|
|
if (NotificationUtils.isCallsNotificationChannelEnabled(this)) {
|
|
val callRingtoneUri = getCallRingtoneUri(context, (appPreferences))
|
|
|
|
binding.callsRingtone.setTextColor(resources.getColor(R.color.high_emphasis_text, null))
|
|
binding.callsRingtone.text = getRingtoneName(context, callRingtoneUri)
|
|
} else {
|
|
binding.callsRingtone.setTextColor(
|
|
ResourcesCompat.getColor(context.resources, R.color.nc_darkRed, null)
|
|
)
|
|
binding.callsRingtone.text = resources!!.getString(R.string.nc_common_disabled)
|
|
}
|
|
|
|
if (NotificationUtils.isMessagesNotificationChannelEnabled(this)) {
|
|
val messageRingtoneUri = getMessageRingtoneUri(context, (appPreferences))
|
|
binding.messagesRingtone.setTextColor(resources.getColor(R.color.high_emphasis_text, null))
|
|
binding.messagesRingtone.text = getRingtoneName(context, messageRingtoneUri)
|
|
} else {
|
|
binding.messagesRingtone.setTextColor(
|
|
ResourcesCompat.getColor(context.resources, R.color.nc_darkRed, null)
|
|
)
|
|
binding.messagesRingtone.text = resources!!.getString(R.string.nc_common_disabled)
|
|
}
|
|
|
|
binding.settingsCallSound.setOnClickListener {
|
|
val intent = Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS)
|
|
intent.putExtra(Settings.EXTRA_APP_PACKAGE, BuildConfig.APPLICATION_ID)
|
|
intent.putExtra(
|
|
Settings.EXTRA_CHANNEL_ID,
|
|
NotificationUtils.NotificationChannels.NOTIFICATION_CHANNEL_CALLS_V4.name
|
|
)
|
|
|
|
startActivity(intent)
|
|
}
|
|
binding.settingsMessageSound.setOnClickListener {
|
|
val intent = Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS)
|
|
intent.putExtra(Settings.EXTRA_APP_PACKAGE, BuildConfig.APPLICATION_ID)
|
|
intent.putExtra(
|
|
Settings.EXTRA_CHANNEL_ID,
|
|
NotificationUtils.NotificationChannels.NOTIFICATION_CHANNEL_MESSAGES_V4.name
|
|
)
|
|
startActivity(intent)
|
|
}
|
|
}
|
|
|
|
private fun setTroubleshootingClickListenersIfNecessary() {
|
|
fun click() {
|
|
val dialogBuilder = MaterialAlertDialogBuilder(this)
|
|
.setTitle(R.string.nc_notifications_troubleshooting_dialog_title)
|
|
.setMessage(R.string.nc_notifications_troubleshooting_dialog_text)
|
|
.setNegativeButton(R.string.nc_diagnose_dialog_open_checklist) { _, _ ->
|
|
startActivity(
|
|
Intent(
|
|
Intent.ACTION_VIEW,
|
|
Uri.parse(resources.getString(R.string.notification_checklist_url))
|
|
)
|
|
)
|
|
}
|
|
.setPositiveButton(R.string.nc_diagnose_dialog_open_dontkillmyapp_website) { _, _ ->
|
|
startActivity(
|
|
Intent(
|
|
Intent.ACTION_VIEW,
|
|
Uri.parse(resources.getString(R.string.dontkillmyapp_url))
|
|
)
|
|
)
|
|
}
|
|
.setNeutralButton(R.string.nc_diagnose_dialog_open_diagnose) { _, _ ->
|
|
val intent = Intent(context, DiagnoseActivity::class.java)
|
|
startActivity(intent)
|
|
}
|
|
viewThemeUtils.dialog.colorMaterialAlertDialogBackground(this, dialogBuilder)
|
|
val dialog = dialogBuilder.show()
|
|
viewThemeUtils.platform.colorTextButtons(
|
|
dialog.getButton(AlertDialog.BUTTON_POSITIVE),
|
|
dialog.getButton(AlertDialog.BUTTON_NEGATIVE),
|
|
dialog.getButton(AlertDialog.BUTTON_NEUTRAL)
|
|
)
|
|
}
|
|
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
|
if (platformPermissionUtil.isPostNotificationsPermissionGranted() &&
|
|
PowerManagerUtils().isIgnoringBatteryOptimizations()
|
|
) {
|
|
binding.settingsNotificationsPermissionWrapper.setOnClickListener { click() }
|
|
binding.settingsBatteryOptimizationWrapper.setOnClickListener { click() }
|
|
}
|
|
} else if (PowerManagerUtils().isIgnoringBatteryOptimizations()) {
|
|
binding.settingsBatteryOptimizationWrapper.setOnClickListener { click() }
|
|
}
|
|
}
|
|
|
|
private fun setupSourceCodeUrl() {
|
|
if (!TextUtils.isEmpty(resources!!.getString(R.string.nc_source_code_url))) {
|
|
binding.settingsSourceCode.setOnClickListener {
|
|
startActivity(
|
|
Intent(
|
|
Intent.ACTION_VIEW,
|
|
Uri.parse(resources!!.getString(R.string.nc_source_code_url))
|
|
)
|
|
)
|
|
}
|
|
} else {
|
|
binding.settingsSourceCode.visibility = View.GONE
|
|
}
|
|
}
|
|
|
|
private fun setupDiagnose() {
|
|
binding.diagnoseWrapper.setOnClickListener {
|
|
val intent = Intent(context, DiagnoseActivity::class.java)
|
|
startActivity(intent)
|
|
}
|
|
}
|
|
|
|
private fun setupPrivacyUrl() {
|
|
if (!TextUtils.isEmpty(resources!!.getString(R.string.nc_privacy_url))) {
|
|
binding.settingsPrivacy.setOnClickListener {
|
|
startActivity(
|
|
Intent(
|
|
Intent.ACTION_VIEW,
|
|
Uri.parse(resources!!.getString(R.string.nc_privacy_url))
|
|
)
|
|
)
|
|
}
|
|
} else {
|
|
binding.settingsPrivacy.visibility = View.GONE
|
|
}
|
|
}
|
|
|
|
private fun setupLicenceSetting() {
|
|
if (!TextUtils.isEmpty(resources!!.getString(R.string.nc_gpl3_url))) {
|
|
binding.settingsLicence.setOnClickListener {
|
|
startActivity(
|
|
Intent(
|
|
Intent.ACTION_VIEW,
|
|
Uri.parse(resources!!.getString(R.string.nc_gpl3_url))
|
|
)
|
|
)
|
|
}
|
|
} else {
|
|
binding.settingsLicence.visibility = View.GONE
|
|
}
|
|
}
|
|
|
|
private fun setupClientCertView() {
|
|
var host: String? = null
|
|
var port = -1
|
|
val uri: URI
|
|
try {
|
|
uri = URI(currentUser!!.baseUrl!!)
|
|
host = uri.host
|
|
port = uri.port
|
|
Log.d(TAG, "uri is $uri")
|
|
} catch (e: URISyntaxException) {
|
|
Log.e(TAG, "Failed to create uri")
|
|
}
|
|
|
|
binding.settingsClientCert.setOnClickListener {
|
|
KeyChain.choosePrivateKeyAlias(
|
|
this,
|
|
{ alias: String? ->
|
|
var finalAlias: String? = alias
|
|
|
|
runOnUiThread {
|
|
if (finalAlias != null) {
|
|
binding.settingsClientCertTitle.setText(R.string.nc_client_cert_change)
|
|
} else {
|
|
binding.settingsClientCertTitle.setText(R.string.nc_client_cert_setup)
|
|
}
|
|
}
|
|
|
|
if (finalAlias == null) {
|
|
finalAlias = ""
|
|
}
|
|
Log.d(TAG, "host: $host and port: $port")
|
|
currentUser!!.clientCertificate = finalAlias
|
|
userManager.updateOrCreateUser(currentUser!!)
|
|
},
|
|
arrayOf("RSA", "EC"),
|
|
null,
|
|
host,
|
|
port,
|
|
currentUser!!.clientCertificate
|
|
)
|
|
}
|
|
}
|
|
|
|
@OptIn(ExperimentalCoroutinesApi::class)
|
|
private fun registerChangeListeners() {
|
|
val appPreferences = AppPreferencesImpl(context)
|
|
proxyTypeFlow = appPreferences.readString(AppPreferencesImpl.PROXY_TYPE)
|
|
proxyCredentialFlow = appPreferences.readBoolean(AppPreferencesImpl.PROXY_CRED)
|
|
screenSecurityFlow = appPreferences.readBoolean(AppPreferencesImpl.SCREEN_SECURITY)
|
|
screenLockFlow = appPreferences.readBoolean(AppPreferencesImpl.SCREEN_LOCK)
|
|
screenLockTimeoutFlow = appPreferences.readString(AppPreferencesImpl.SCREEN_LOCK_TIMEOUT)
|
|
|
|
val themeKey = context.resources.getString(R.string.nc_settings_theme_key)
|
|
themeFlow = appPreferences.readString(themeKey)
|
|
|
|
val privacyKey = context.resources.getString(R.string.nc_settings_read_privacy_key)
|
|
readPrivacyFlow = appPreferences.readBoolean(privacyKey)
|
|
|
|
typingStatusFlow = appPreferences.readBoolean(AppPreferencesImpl.TYPING_STATUS)
|
|
phoneBookIntegrationFlow = appPreferences.readBoolean(AppPreferencesImpl.PHONE_BOOK_INTEGRATION)
|
|
|
|
var pos = resources.getStringArray(R.array.screen_lock_timeout_entry_values).indexOf(
|
|
appPreferences.screenLockTimeout
|
|
)
|
|
binding.settingsScreenLockTimeoutLayoutDropdown.setText(
|
|
resources.getStringArray(R.array.screen_lock_timeout_descriptions)[pos]
|
|
)
|
|
|
|
binding.settingsScreenLockTimeoutLayoutDropdown.setSimpleItems(R.array.screen_lock_timeout_descriptions)
|
|
binding.settingsScreenLockTimeoutLayoutDropdown.setOnItemClickListener { _, _, position, _ ->
|
|
val entryVal: String = resources.getStringArray(R.array.screen_lock_timeout_entry_values)[position]
|
|
appPreferences.screenLockTimeout = entryVal
|
|
SecurityUtils.createKey(entryVal)
|
|
}
|
|
pos = resources.getStringArray(R.array.theme_entry_values).indexOf(appPreferences.theme)
|
|
binding.settingsTheme.setText(resources.getStringArray(R.array.theme_descriptions)[pos])
|
|
|
|
binding.settingsTheme.setSimpleItems(R.array.theme_descriptions)
|
|
binding.settingsTheme.setOnItemClickListener { _, _, position, _ ->
|
|
val entryVal: String = resources.getStringArray(R.array.theme_entry_values)[position]
|
|
appPreferences.theme = entryVal
|
|
}
|
|
|
|
observeProxyType()
|
|
observeProxyCredential()
|
|
observeScreenSecurity()
|
|
observeScreenLock()
|
|
observeTheme()
|
|
observeReadPrivacy()
|
|
observeTypingStatus()
|
|
}
|
|
|
|
fun sendLogs() {
|
|
if (resources!!.getBoolean(R.bool.nc_is_debug)) {
|
|
sendMailWithAttachment((context))
|
|
}
|
|
}
|
|
|
|
private fun showRemoveAccountWarning() {
|
|
binding.messageText.context?.let {
|
|
val materialAlertDialogBuilder = MaterialAlertDialogBuilder(it)
|
|
.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) { _, _ ->
|
|
// unused atm
|
|
}
|
|
|
|
viewThemeUtils.dialog.colorMaterialAlertDialogBackground(
|
|
it,
|
|
materialAlertDialogBuilder
|
|
)
|
|
|
|
val dialog = materialAlertDialogBuilder.show()
|
|
|
|
viewThemeUtils.platform.colorTextButtons(
|
|
dialog.getButton(AlertDialog.BUTTON_POSITIVE),
|
|
dialog.getButton(AlertDialog.BUTTON_NEGATIVE)
|
|
)
|
|
}
|
|
}
|
|
|
|
@SuppressLint("CheckResult", "StringFormatInvalid")
|
|
private fun removeCurrentAccount() {
|
|
userManager.scheduleUserForDeletionWithId(currentUser!!.id!!).blockingGet()
|
|
val accountRemovalWork = OneTimeWorkRequest.Builder(AccountRemovalWorker::class.java).build()
|
|
WorkManager.getInstance(applicationContext).enqueue(accountRemovalWork)
|
|
|
|
WorkManager.getInstance(context).getWorkInfoByIdLiveData(accountRemovalWork.id)
|
|
.observeForever { workInfo: WorkInfo ->
|
|
|
|
when (workInfo.state) {
|
|
WorkInfo.State.SUCCEEDED -> {
|
|
val text = String.format(
|
|
context.resources.getString(R.string.nc_deleted_user),
|
|
currentUser!!.displayName
|
|
)
|
|
Toast.makeText(
|
|
context,
|
|
text,
|
|
Toast.LENGTH_LONG
|
|
).show()
|
|
restartApp()
|
|
}
|
|
|
|
WorkInfo.State.FAILED, WorkInfo.State.CANCELLED -> {
|
|
Toast.makeText(
|
|
context,
|
|
context.resources.getString(R.string.nc_common_error_sorry),
|
|
Toast.LENGTH_LONG
|
|
).show()
|
|
Log.e(TAG, "something went wrong when deleting user with id " + currentUser!!.userId)
|
|
restartApp()
|
|
}
|
|
|
|
else -> {}
|
|
}
|
|
}
|
|
}
|
|
|
|
private fun restartApp() {
|
|
val intent = Intent(context, MainActivity::class.java)
|
|
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
|
|
startActivity(intent)
|
|
}
|
|
|
|
private fun getRingtoneName(context: Context, ringtoneUri: Uri?): String {
|
|
return if (ringtoneUri == null) {
|
|
resources!!.getString(R.string.nc_settings_no_ringtone)
|
|
} else if ((NotificationUtils.DEFAULT_CALL_RINGTONE_URI == ringtoneUri.toString()) ||
|
|
(NotificationUtils.DEFAULT_MESSAGE_RINGTONE_URI == ringtoneUri.toString())
|
|
) {
|
|
resources!!.getString(R.string.nc_settings_default_ringtone)
|
|
} else {
|
|
val r = RingtoneManager.getRingtone(context, ringtoneUri)
|
|
r.getTitle(context)
|
|
}
|
|
}
|
|
|
|
private fun themeSwitchPreferences() {
|
|
binding.run {
|
|
listOf(
|
|
settingsShowIgnoreBatteryOptimizationHintSwitch,
|
|
settingsScreenLockSwitch,
|
|
settingsScreenSecuritySwitch,
|
|
settingsIncognitoKeyboardSwitch,
|
|
settingsPhoneBookIntegrationSwitch,
|
|
settingsReadPrivacySwitch,
|
|
settingsTypingStatusSwitch,
|
|
settingsProxyUseCredentialsSwitch
|
|
).forEach(viewThemeUtils.talk::colorSwitch)
|
|
}
|
|
}
|
|
|
|
private fun themeTitles() {
|
|
binding.run {
|
|
listOf(
|
|
settingsNotificationsTitle,
|
|
settingsAboutTitle,
|
|
settingsAdvancedTitle,
|
|
settingsAppearanceTitle,
|
|
settingsPrivacyTitle
|
|
).forEach(viewThemeUtils.platform::colorTextView)
|
|
}
|
|
}
|
|
|
|
private fun setupProxyTypeSettings() {
|
|
if (appPreferences.proxyType == null) {
|
|
appPreferences.proxyType = resources.getString(R.string.nc_no_proxy)
|
|
}
|
|
binding.settingsProxyChoice.setText(appPreferences.proxyType)
|
|
binding.settingsProxyChoice.setSimpleItems(R.array.proxy_type_descriptions)
|
|
binding.settingsProxyChoice.setOnItemClickListener { _, _, position, _ ->
|
|
val entryVal = resources.getStringArray(R.array.proxy_type_descriptions)[position]
|
|
appPreferences.proxyType = entryVal
|
|
}
|
|
|
|
binding.settingsProxyHostEdit.setText(appPreferences.proxyHost)
|
|
binding.settingsProxyHostEdit.setOnFocusChangeListener { _, hasFocus ->
|
|
if (!hasFocus) {
|
|
appPreferences.proxyHost = binding.settingsProxyHostEdit.text.toString()
|
|
}
|
|
}
|
|
|
|
binding.settingsProxyPortEdit.setText(appPreferences.proxyPort)
|
|
binding.settingsProxyPortEdit.setOnFocusChangeListener { _, hasFocus ->
|
|
if (!hasFocus) {
|
|
appPreferences.proxyPort = binding.settingsProxyPortEdit.text.toString()
|
|
}
|
|
}
|
|
binding.settingsProxyUsernameEdit.setText(appPreferences.proxyUsername)
|
|
binding.settingsProxyUsernameEdit.setOnFocusChangeListener { _, hasFocus ->
|
|
if (!hasFocus) {
|
|
appPreferences.proxyUsername = binding.settingsProxyUsernameEdit.text.toString()
|
|
}
|
|
}
|
|
binding.settingsProxyPasswordEdit.setText(appPreferences.proxyPassword)
|
|
binding.settingsProxyPasswordEdit.setOnFocusChangeListener { _, hasFocus ->
|
|
if (!hasFocus) {
|
|
appPreferences.proxyPassword = binding.settingsProxyPasswordEdit.text.toString()
|
|
}
|
|
}
|
|
|
|
if (((context.resources.getString(R.string.nc_no_proxy)) == appPreferences.proxyType) ||
|
|
appPreferences.proxyType == null
|
|
) {
|
|
hideProxySettings()
|
|
} else {
|
|
showProxySettings()
|
|
}
|
|
}
|
|
|
|
private fun setupProxyCredentialSettings() {
|
|
if (appPreferences.proxyCredentials) {
|
|
showProxyCredentials()
|
|
} else {
|
|
hideProxyCredentials()
|
|
}
|
|
}
|
|
|
|
private fun setupMessageView() {
|
|
if (ApplicationWideMessageHolder.getInstance().messageType != null) {
|
|
when (ApplicationWideMessageHolder.getInstance().messageType) {
|
|
ApplicationWideMessageHolder.MessageType.ACCOUNT_UPDATED_NOT_ADDED -> {
|
|
binding.messageText.let {
|
|
viewThemeUtils.platform.colorTextView(it, ColorRole.PRIMARY)
|
|
it.text = resources!!.getString(R.string.nc_settings_account_updated)
|
|
binding.messageText.visibility = View.VISIBLE
|
|
}
|
|
}
|
|
|
|
ApplicationWideMessageHolder.MessageType.SERVER_WITHOUT_TALK -> {
|
|
binding.messageText.let {
|
|
it.setTextColor(resources!!.getColor(R.color.nc_darkRed, null))
|
|
it.text = resources!!.getString(R.string.nc_settings_wrong_account)
|
|
binding.messageText.visibility = View.VISIBLE
|
|
viewThemeUtils.platform.colorTextView(it, ColorRole.PRIMARY)
|
|
it.text = resources!!.getString(R.string.nc_Server_account_imported)
|
|
binding.messageText.visibility = View.VISIBLE
|
|
}
|
|
}
|
|
|
|
ApplicationWideMessageHolder.MessageType.ACCOUNT_WAS_IMPORTED -> {
|
|
binding.messageText.let {
|
|
viewThemeUtils.platform.colorTextView(it, ColorRole.PRIMARY)
|
|
it.text = resources!!.getString(R.string.nc_Server_account_imported)
|
|
binding.messageText.visibility = View.VISIBLE
|
|
}
|
|
}
|
|
|
|
ApplicationWideMessageHolder.MessageType.FAILED_TO_IMPORT_ACCOUNT -> {
|
|
binding.messageText.let {
|
|
it.setTextColor(resources!!.getColor(R.color.nc_darkRed, null))
|
|
it.text = resources!!.getString(R.string.nc_server_failed_to_import_account)
|
|
binding.messageText.visibility = View.VISIBLE
|
|
}
|
|
}
|
|
|
|
else -> binding.messageText.visibility = View.GONE
|
|
}
|
|
ApplicationWideMessageHolder.getInstance().messageType = null
|
|
binding.messageText.animate()
|
|
?.translationY(0f)
|
|
?.alpha(0.0f)
|
|
?.setDuration(DURATION)
|
|
?.setStartDelay(START_DELAY)
|
|
?.setListener(object : AnimatorListenerAdapter() {
|
|
override fun onAnimationEnd(animation: Animator) {
|
|
super.onAnimationEnd(animation)
|
|
binding.messageText.visibility = View.GONE
|
|
}
|
|
})
|
|
} else {
|
|
binding.messageText.visibility = View.GONE
|
|
}
|
|
}
|
|
|
|
private fun setupProfileQueryDisposable() {
|
|
profileQueryDisposable = ncApi.getUserProfile(
|
|
credentials,
|
|
ApiUtils.getUrlForUserProfile(currentUser!!.baseUrl!!)
|
|
)
|
|
.subscribeOn(Schedulers.io())
|
|
.observeOn(AndroidSchedulers.mainThread())
|
|
.subscribe(
|
|
{ userProfileOverall: UserProfileOverall ->
|
|
var displayName: String? = null
|
|
if (!TextUtils.isEmpty(
|
|
userProfileOverall.ocs!!.data!!.displayName
|
|
)
|
|
) {
|
|
displayName = userProfileOverall.ocs!!.data!!.displayName
|
|
} else if (!TextUtils.isEmpty(
|
|
userProfileOverall.ocs!!.data!!.displayNameAlt
|
|
)
|
|
) {
|
|
displayName = userProfileOverall.ocs!!.data!!.displayNameAlt
|
|
}
|
|
if ((!TextUtils.isEmpty(displayName) && !(displayName == currentUser!!.displayName))) {
|
|
currentUser!!.displayName = displayName
|
|
userManager.updateOrCreateUser(currentUser!!)
|
|
binding.nameText.text = currentUser!!.displayName
|
|
}
|
|
},
|
|
{ dispose(profileQueryDisposable) },
|
|
{ dispose(profileQueryDisposable) }
|
|
)
|
|
}
|
|
|
|
private fun setupServerAgeWarning() {
|
|
when {
|
|
CapabilitiesUtil.isServerEOL(currentUser!!.serverVersion?.major) -> {
|
|
binding.serverAgeWarningText.setTextColor(ContextCompat.getColor((context), R.color.nc_darkRed))
|
|
binding.serverAgeWarningText.setText(R.string.nc_settings_server_eol)
|
|
binding.serverAgeWarningIcon.setColorFilter(
|
|
ContextCompat.getColor((context), R.color.nc_darkRed),
|
|
PorterDuff.Mode.SRC_IN
|
|
)
|
|
}
|
|
|
|
CapabilitiesUtil.isServerAlmostEOL(currentUser!!.serverVersion?.major) -> {
|
|
binding.serverAgeWarningText.setTextColor(
|
|
ContextCompat.getColor((context), R.color.nc_darkYellow)
|
|
)
|
|
binding.serverAgeWarningText.setText(R.string.nc_settings_server_almost_eol)
|
|
binding.serverAgeWarningIcon.setColorFilter(
|
|
ContextCompat.getColor((context), R.color.nc_darkYellow),
|
|
PorterDuff.Mode.SRC_IN
|
|
)
|
|
}
|
|
|
|
else -> {
|
|
binding.serverAgeWarningTextCard.visibility = View.GONE
|
|
}
|
|
}
|
|
}
|
|
|
|
private fun setupCheckables() {
|
|
binding.settingsShowIgnoreBatteryOptimizationHintSwitch.isChecked =
|
|
appPreferences.showIgnoreBatteryOptimizationHint
|
|
|
|
if (ClosedInterfaceImpl().isGooglePlayServicesAvailable) {
|
|
binding.settingsShowIgnoreBatteryOptimizationHint.setOnClickListener {
|
|
val isChecked = binding.settingsShowIgnoreBatteryOptimizationHintSwitch.isChecked
|
|
binding.settingsShowIgnoreBatteryOptimizationHintSwitch.isChecked = !isChecked
|
|
appPreferences.setShowIgnoreBatteryOptimizationHint(!isChecked)
|
|
}
|
|
} else {
|
|
binding.settingsShowIgnoreBatteryOptimizationHint.visibility = View.GONE
|
|
}
|
|
|
|
binding.settingsScreenSecuritySwitch.isChecked = appPreferences.isScreenSecured
|
|
|
|
binding.settingsIncognitoKeyboardSwitch.isChecked = appPreferences.isKeyboardIncognito
|
|
|
|
if (CapabilitiesUtil.isReadStatusAvailable(currentUser!!.capabilities!!.spreedCapability!!)) {
|
|
binding.settingsReadPrivacySwitch.isChecked = !CapabilitiesUtil.isReadStatusPrivate(currentUser!!)
|
|
} else {
|
|
binding.settingsReadPrivacy.visibility = View.GONE
|
|
}
|
|
|
|
setupTypingStatusSetting()
|
|
|
|
binding.settingsPhoneBookIntegrationSwitch.isChecked = appPreferences.isPhoneBookIntegrationEnabled
|
|
|
|
binding.settingsProxyUseCredentialsSwitch.isChecked = appPreferences.proxyCredentials
|
|
binding.settingsProxyUseCredentials.setOnClickListener {
|
|
val isChecked = binding.settingsProxyUseCredentialsSwitch.isChecked
|
|
binding.settingsProxyUseCredentialsSwitch.isChecked = !isChecked
|
|
appPreferences.setProxyNeedsCredentials(!isChecked)
|
|
}
|
|
|
|
binding.settingsScreenLockSwitch.isChecked = appPreferences.isScreenLocked
|
|
binding.settingsScreenLock.setOnClickListener {
|
|
val isChecked = binding.settingsScreenLockSwitch.isChecked
|
|
binding.settingsScreenLockSwitch.isChecked = !isChecked
|
|
appPreferences.setScreenLock(!isChecked)
|
|
}
|
|
|
|
binding.settingsReadPrivacy.setOnClickListener {
|
|
val isChecked = binding.settingsReadPrivacySwitch.isChecked
|
|
binding.settingsReadPrivacySwitch.isChecked = !isChecked
|
|
appPreferences.setReadPrivacy(!isChecked)
|
|
}
|
|
|
|
binding.settingsIncognitoKeyboard.setOnClickListener {
|
|
val isChecked = binding.settingsIncognitoKeyboardSwitch.isChecked
|
|
binding.settingsIncognitoKeyboardSwitch.isChecked = !isChecked
|
|
appPreferences.setIncognitoKeyboard(!isChecked)
|
|
}
|
|
|
|
binding.settingsPhoneBookIntegration.setOnClickListener {
|
|
val isChecked = binding.settingsPhoneBookIntegrationSwitch.isChecked
|
|
binding.settingsPhoneBookIntegrationSwitch.isChecked = !isChecked
|
|
appPreferences.setPhoneBookIntegration(!isChecked)
|
|
if (!isChecked) {
|
|
if (checkPermission(this@SettingsActivity, (context))) {
|
|
checkForPhoneNumber()
|
|
}
|
|
} else {
|
|
deleteAll()
|
|
}
|
|
}
|
|
|
|
binding.settingsScreenSecurity.setOnClickListener {
|
|
val isChecked = binding.settingsScreenSecuritySwitch.isChecked
|
|
binding.settingsScreenSecuritySwitch.isChecked = !isChecked
|
|
appPreferences.setScreenSecurity(!isChecked)
|
|
}
|
|
|
|
binding.settingsTypingStatus.setOnClickListener {
|
|
val isChecked = binding.settingsTypingStatusSwitch.isChecked
|
|
binding.settingsTypingStatusSwitch.isChecked = !isChecked
|
|
appPreferences.setTypingStatus(!isChecked)
|
|
}
|
|
}
|
|
|
|
private fun setupTypingStatusSetting() {
|
|
if (currentUser!!.externalSignalingServer?.externalSignalingServer?.isNotEmpty() == true) {
|
|
binding.settingsTypingStatusOnlyWithHpb.visibility = View.GONE
|
|
Log.i(TAG, "Typing Status Available: ${CapabilitiesUtil.isTypingStatusAvailable(currentUser!!)}")
|
|
|
|
if (CapabilitiesUtil.isTypingStatusAvailable(currentUser!!)) {
|
|
binding.settingsTypingStatusSwitch.isChecked = !CapabilitiesUtil.isTypingStatusPrivate(currentUser!!)
|
|
} else {
|
|
binding.settingsTypingStatus.visibility = View.GONE
|
|
}
|
|
} else {
|
|
Log.i(TAG, "Typing Status not Available")
|
|
binding.settingsTypingStatusSwitch.isChecked = false
|
|
binding.settingsTypingStatusOnlyWithHpb.visibility = View.VISIBLE
|
|
binding.settingsTypingStatus.isEnabled = false
|
|
binding.settingsTypingStatusOnlyWithHpb.alpha = DISABLED_ALPHA
|
|
binding.settingsTypingStatus.alpha = DISABLED_ALPHA
|
|
}
|
|
}
|
|
|
|
private fun setupScreenLockSetting() {
|
|
val keyguardManager = context.getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager
|
|
if (keyguardManager.isKeyguardSecure) {
|
|
binding.settingsScreenLock.isEnabled = true
|
|
binding.settingsScreenLockTimeout.isEnabled = true
|
|
binding.settingsScreenLockSwitch.isChecked = appPreferences.isScreenLocked
|
|
binding.settingsScreenLockTimeoutLayoutDropdown.isEnabled = appPreferences.isScreenLocked
|
|
if (appPreferences.isScreenLocked) {
|
|
binding.settingsScreenLockTimeout.alpha = ENABLED_ALPHA
|
|
} else {
|
|
binding.settingsScreenLockTimeout.alpha = DISABLED_ALPHA
|
|
}
|
|
binding.settingsScreenLock.alpha = ENABLED_ALPHA
|
|
} else {
|
|
binding.settingsScreenLock.isEnabled = false
|
|
binding.settingsScreenLockTimeoutLayoutDropdown.isEnabled = false
|
|
appPreferences.removeScreenLock()
|
|
appPreferences.removeScreenLockTimeout()
|
|
binding.settingsScreenLockSwitch.isChecked = false
|
|
binding.settingsScreenLock.alpha = DISABLED_ALPHA
|
|
binding.settingsScreenLockTimeout.alpha = DISABLED_ALPHA
|
|
}
|
|
}
|
|
|
|
public override fun onDestroy() {
|
|
// appPreferences.unregisterProxyTypeListener(proxyTypeChangeListener)
|
|
// appPreferences.unregisterProxyCredentialsListener(proxyCredentialsChangeListener)
|
|
// appPreferences.unregisterScreenSecurityListener(screenSecurityChangeListener)
|
|
// appPreferences.unregisterScreenLockListener(screenLockChangeListener)
|
|
// appPreferences.unregisterScreenLockTimeoutListener(screenLockTimeoutChangeListener)
|
|
// appPreferences.unregisterThemeChangeListener(themeChangeListener)
|
|
// appPreferences.unregisterReadPrivacyChangeListener(readPrivacyChangeListener)
|
|
// appPreferences.unregisterTypingStatusChangeListener(typingStatusChangeListener)
|
|
// appPreferences.unregisterPhoneBookIntegrationChangeListener(phoneBookIntegrationChangeListener)
|
|
|
|
super.onDestroy()
|
|
}
|
|
|
|
private fun hideProxySettings() {
|
|
appPreferences.removeProxyHost()
|
|
appPreferences.removeProxyPort()
|
|
appPreferences.removeProxyCredentials()
|
|
appPreferences.removeProxyUsername()
|
|
appPreferences.removeProxyPassword()
|
|
binding.settingsProxyHostLayout.visibility = View.GONE
|
|
binding.settingsProxyPortLayout.visibility = View.GONE
|
|
binding.settingsProxyUseCredentials.visibility = View.GONE
|
|
hideProxyCredentials()
|
|
}
|
|
|
|
private fun showProxySettings() {
|
|
binding.settingsProxyHostLayout.visibility =
|
|
View.VISIBLE
|
|
binding.settingsProxyPortLayout.visibility =
|
|
View.VISIBLE
|
|
binding.settingsProxyUseCredentials.visibility =
|
|
View.VISIBLE
|
|
if (binding.settingsProxyUseCredentialsSwitch.isChecked) showProxyCredentials()
|
|
}
|
|
|
|
private fun showProxyCredentials() {
|
|
binding.settingsProxyUsernameLayout.visibility =
|
|
View.VISIBLE
|
|
binding.settingsProxyPasswordLayout.visibility =
|
|
View.VISIBLE
|
|
}
|
|
|
|
private fun hideProxyCredentials() {
|
|
appPreferences.removeProxyUsername()
|
|
appPreferences.removeProxyPassword()
|
|
binding.settingsProxyUsernameLayout.visibility = View.GONE
|
|
binding.settingsProxyPasswordLayout.visibility = View.GONE
|
|
}
|
|
|
|
private fun dispose(disposable: Disposable?) {
|
|
if (disposable != null && !disposable.isDisposed) {
|
|
disposable.dispose()
|
|
} else if (disposable == null) {
|
|
disposeProfileQueryDisposable()
|
|
disposeDbQueryDisposable()
|
|
}
|
|
}
|
|
|
|
private fun disposeDbQueryDisposable() {
|
|
if (dbQueryDisposable != null && !dbQueryDisposable!!.isDisposed) {
|
|
dbQueryDisposable!!.dispose()
|
|
dbQueryDisposable = null
|
|
} else if (dbQueryDisposable != null) {
|
|
dbQueryDisposable = null
|
|
}
|
|
}
|
|
|
|
private fun disposeProfileQueryDisposable() {
|
|
if (profileQueryDisposable != null && !profileQueryDisposable!!.isDisposed) {
|
|
profileQueryDisposable!!.dispose()
|
|
profileQueryDisposable = null
|
|
} else if (profileQueryDisposable != null) {
|
|
profileQueryDisposable = null
|
|
}
|
|
}
|
|
|
|
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
|
|
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
|
|
|
when (requestCode) {
|
|
ContactAddressBookWorker.REQUEST_PERMISSION -> {
|
|
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
|
WorkManager
|
|
.getInstance(this)
|
|
.enqueue(OneTimeWorkRequest.Builder(ContactAddressBookWorker::class.java).build())
|
|
checkForPhoneNumber()
|
|
} else {
|
|
appPreferences.setPhoneBookIntegration(false)
|
|
binding.settingsPhoneBookIntegrationSwitch.isChecked = appPreferences.isPhoneBookIntegrationEnabled
|
|
Snackbar.make(
|
|
binding.root,
|
|
context.resources.getString(R.string.no_phone_book_integration_due_to_permissions),
|
|
Snackbar.LENGTH_LONG
|
|
).show()
|
|
}
|
|
}
|
|
|
|
ConversationsListActivity.REQUEST_POST_NOTIFICATIONS_PERMISSION -> {
|
|
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_DENIED) {
|
|
Snackbar.make(
|
|
binding.root,
|
|
context.resources.getString(R.string.nc_settings_notifications_declined_hint),
|
|
Snackbar.LENGTH_LONG
|
|
).show()
|
|
Log.d(
|
|
TAG,
|
|
"Notification permission is denied. Either because user denied it when being asked. " +
|
|
"Or permission is already denied and android decided to not offer the dialog."
|
|
)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private fun observeScreenLock() {
|
|
CoroutineScope(Dispatchers.Main).launch {
|
|
var state = appPreferences.isScreenLocked
|
|
screenLockFlow.collect { newBoolean ->
|
|
if (newBoolean != state) {
|
|
state = newBoolean
|
|
binding.settingsScreenLockTimeout.isEnabled = newBoolean
|
|
if (newBoolean) {
|
|
binding.settingsScreenLockTimeout.alpha = ENABLED_ALPHA
|
|
} else {
|
|
binding.settingsScreenLockTimeout.alpha = DISABLED_ALPHA
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private fun observeScreenSecurity() {
|
|
CoroutineScope(Dispatchers.Main).launch {
|
|
var state = appPreferences.isScreenSecured
|
|
screenSecurityFlow.collect { newBoolean ->
|
|
if (newBoolean != state) {
|
|
state = newBoolean
|
|
if (newBoolean) {
|
|
window.addFlags(WindowManager.LayoutParams.FLAG_SECURE)
|
|
} else {
|
|
window.clearFlags(WindowManager.LayoutParams.FLAG_SECURE)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private fun observeProxyCredential() {
|
|
CoroutineScope(Dispatchers.Main).launch {
|
|
var state = appPreferences.proxyCredentials
|
|
proxyCredentialFlow.collect { newBoolean ->
|
|
if (newBoolean != state) {
|
|
state = newBoolean
|
|
if (newBoolean) {
|
|
showProxyCredentials()
|
|
} else {
|
|
hideProxyCredentials()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private fun observeProxyType() {
|
|
CoroutineScope(Dispatchers.Main).launch {
|
|
var state = appPreferences.proxyType
|
|
proxyTypeFlow.collect { newString ->
|
|
if (newString != state) {
|
|
state = newString
|
|
if (((context.resources.getString(R.string.nc_no_proxy)) == newString) || newString.isEmpty()) {
|
|
hideProxySettings()
|
|
} else {
|
|
when (newString) {
|
|
"HTTP" -> {
|
|
binding.settingsProxyPortEdit.setText(getString(R.string.nc_settings_http_value))
|
|
appPreferences.proxyPort = getString(R.string.nc_settings_http_value)
|
|
}
|
|
|
|
"DIRECT" -> {
|
|
binding.settingsProxyPortEdit.setText(getString(R.string.nc_settings_direct_value))
|
|
appPreferences.proxyPort = getString(R.string.nc_settings_direct_value)
|
|
}
|
|
|
|
"SOCKS" -> {
|
|
binding.settingsProxyPortEdit.setText(getString(R.string.nc_settings_socks_value))
|
|
appPreferences.proxyPort = getString(R.string.nc_settings_socks_value)
|
|
}
|
|
|
|
else -> {
|
|
}
|
|
}
|
|
showProxySettings()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private fun observeTheme() {
|
|
CoroutineScope(Dispatchers.Main).launch {
|
|
var state = appPreferences.theme
|
|
themeFlow.collect { newString ->
|
|
if (newString != state) {
|
|
state = newString
|
|
setAppTheme(newString)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private fun checkForPhoneNumber() {
|
|
ncApi.getUserData(
|
|
ApiUtils.getCredentials(currentUser!!.username, currentUser!!.token),
|
|
ApiUtils.getUrlForUserProfile(currentUser!!.baseUrl!!)
|
|
).subscribeOn(Schedulers.io())
|
|
.observeOn(AndroidSchedulers.mainThread())
|
|
.subscribe(object : Observer<UserProfileOverall> {
|
|
override fun onSubscribe(d: Disposable) {
|
|
// unused atm
|
|
}
|
|
|
|
override fun onNext(userProfileOverall: UserProfileOverall) {
|
|
if (userProfileOverall.ocs!!.data!!.phone?.isEmpty() == true) {
|
|
askForPhoneNumber()
|
|
} else {
|
|
Log.d(TAG, "phone number already set")
|
|
}
|
|
}
|
|
|
|
override fun onError(e: Throwable) {
|
|
// unused atm
|
|
}
|
|
|
|
override fun onComplete() {
|
|
// unused atm
|
|
}
|
|
})
|
|
}
|
|
|
|
private fun askForPhoneNumber() {
|
|
val dialog = SetPhoneNumberDialogFragment.newInstance()
|
|
dialog.show(supportFragmentManager, SetPhoneNumberDialogFragment.TAG)
|
|
}
|
|
|
|
override fun onSubmitClick(textInputLayout: TextInputLayout, dialog: DialogInterface) {
|
|
setPhoneNumber(textInputLayout, dialog)
|
|
}
|
|
|
|
private fun setPhoneNumber(textInputLayout: TextInputLayout, dialog: DialogInterface) {
|
|
val phoneNumber = textInputLayout.editText!!.text.toString()
|
|
ncApi.setUserData(
|
|
ApiUtils.getCredentials(currentUser!!.username, currentUser!!.token),
|
|
ApiUtils.getUrlForUserData(currentUser!!.baseUrl!!, currentUser!!.userId!!),
|
|
"phone",
|
|
phoneNumber
|
|
).subscribeOn(Schedulers.io())
|
|
.observeOn(AndroidSchedulers.mainThread())
|
|
.subscribe(object : Observer<GenericOverall> {
|
|
override fun onSubscribe(d: Disposable) {
|
|
// unused atm
|
|
}
|
|
|
|
override fun onNext(genericOverall: GenericOverall) {
|
|
when (val statusCode = genericOverall.ocs?.meta?.statusCode) {
|
|
HTTP_CODE_OK -> {
|
|
dialog.dismiss()
|
|
Snackbar.make(
|
|
binding.root,
|
|
getString(
|
|
R.string.nc_settings_phone_book_integration_phone_number_dialog_success
|
|
),
|
|
Snackbar.LENGTH_LONG
|
|
).show()
|
|
}
|
|
|
|
else -> {
|
|
textInputLayout.helperText = getString(
|
|
R.string.nc_settings_phone_book_integration_phone_number_dialog_invalid
|
|
)
|
|
Log.d(TAG, "failed to set phoneNumber. statusCode=$statusCode")
|
|
}
|
|
}
|
|
}
|
|
|
|
override fun onError(e: Throwable) {
|
|
textInputLayout.helperText = getString(
|
|
R.string.nc_settings_phone_book_integration_phone_number_dialog_invalid
|
|
)
|
|
Log.e(SetPhoneNumberDialogFragment.TAG, "setPhoneNumber error", e)
|
|
}
|
|
|
|
override fun onComplete() {
|
|
// unused atm
|
|
}
|
|
})
|
|
}
|
|
|
|
private fun observeReadPrivacy() {
|
|
lifecycleScope.launch {
|
|
var state = appPreferences.readPrivacy
|
|
readPrivacyFlow.collect { newBoolean ->
|
|
if (state != newBoolean) {
|
|
state = newBoolean
|
|
val booleanValue = if (newBoolean) "0" else "1"
|
|
val json = "{\"key\": \"read_status_privacy\", \"value\" : $booleanValue}"
|
|
withContext(Dispatchers.IO) {
|
|
try {
|
|
credentials?.let { credentials ->
|
|
ncApiCoroutines.setReadStatusPrivacy(
|
|
credentials,
|
|
ApiUtils.getUrlForUserSettings(currentUser!!.baseUrl!!),
|
|
json.toRequestBody("application/json".toMediaTypeOrNull())
|
|
)
|
|
Log.i(TAG, "reading status set")
|
|
}
|
|
} catch (e: Exception) {
|
|
withContext(Dispatchers.Main) {
|
|
appPreferences.setReadPrivacy(!newBoolean)
|
|
binding.settingsReadPrivacySwitch.isChecked = !newBoolean
|
|
}
|
|
if (e is HttpException && e.code() == HTTP_ERROR_CODE_BAD_REQUEST) {
|
|
Log.e(TAG, "read_status_privacy : Key or value is invalid")
|
|
} else {
|
|
Log.e(TAG, "Error setting read status", e)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private fun observeTypingStatus() {
|
|
lifecycleScope.launch {
|
|
var state = appPreferences.typingStatus
|
|
typingStatusFlow.collect { newBoolean ->
|
|
if (state != newBoolean) {
|
|
state = newBoolean
|
|
val booleanValue = if (newBoolean) "0" else "1"
|
|
val json = "{\"key\": \"typing_privacy\", \"value\" : $booleanValue}"
|
|
withContext(Dispatchers.IO) {
|
|
try {
|
|
credentials?.let { credentials ->
|
|
ncApiCoroutines.setTypingStatusPrivacy(
|
|
credentials,
|
|
ApiUtils.getUrlForUserSettings(currentUser!!.baseUrl!!),
|
|
json.toRequestBody("application/json".toMediaTypeOrNull())
|
|
)
|
|
}
|
|
withContext(Dispatchers.Main) {
|
|
loadCapabilitiesAndUpdateSettings()
|
|
Log.i(TAG, "typing status set")
|
|
}
|
|
} catch (e: Exception) {
|
|
withContext(Dispatchers.Main) {
|
|
appPreferences.typingStatus = !newBoolean
|
|
binding.settingsTypingStatusSwitch.isChecked = !newBoolean
|
|
}
|
|
if (e is HttpException && e.code() == HTTP_ERROR_CODE_BAD_REQUEST) {
|
|
Log.e(TAG, "typing_privacy : Key or value is invalid")
|
|
} else {
|
|
Log.e(TAG, "Error setting typing status", e)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
companion object {
|
|
private val TAG = SettingsActivity::class.java.simpleName
|
|
private const val DURATION: Long = 2500
|
|
private const val START_DELAY: Long = 5000
|
|
private const val DISABLED_ALPHA: Float = 0.38f
|
|
private const val ENABLED_ALPHA: Float = 1.0f
|
|
const val HTTP_CODE_OK: Int = 200
|
|
const val HTTP_ERROR_CODE_BAD_REQUEST: Int = 400
|
|
}
|
|
}
|