mirror of
https://github.com/SchildiChat/SchildiChat-android.git
synced 2024-11-27 03:49:04 +03:00
split preference (Kotlin)
This commit is contained in:
parent
e63f51821f
commit
7c47c6a033
17 changed files with 3017 additions and 2650 deletions
|
@ -48,20 +48,15 @@ class VectorSettingsActivity : VectorBaseActivity(),
|
|||
override fun initUiAndData() {
|
||||
configureToolbar(settingsToolbar)
|
||||
|
||||
var vectorSettingsPreferencesFragment: Fragment? = null
|
||||
if (isFirstCreation()) {
|
||||
vectorSettingsPreferencesFragment = VectorSettingsPreferencesFragmentV2.newInstance()
|
||||
val vectorSettingsPreferencesFragment = VectorSettingsRoot.newInstance()
|
||||
// display the fragment
|
||||
supportFragmentManager.beginTransaction()
|
||||
.replace(R.id.vector_settings_page, vectorSettingsPreferencesFragment, FRAGMENT_TAG)
|
||||
.commit()
|
||||
} else {
|
||||
vectorSettingsPreferencesFragment = supportFragmentManager.findFragmentByTag(FRAGMENT_TAG)
|
||||
}
|
||||
|
||||
|
||||
supportFragmentManager.addOnBackStackChangedListener(this)
|
||||
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
|
@ -78,9 +73,7 @@ class VectorSettingsActivity : VectorBaseActivity(),
|
|||
override fun onPreferenceStartFragment(caller: PreferenceFragmentCompat?, pref: Preference?): Boolean {
|
||||
var oFragment: Fragment? = null
|
||||
|
||||
if ("Legacy" == pref?.title) {
|
||||
oFragment = VectorSettingsPreferencesFragment.newInstance(session.sessionParams.credentials.userId)
|
||||
} else if (PreferencesManager.SETTINGS_NOTIFICATION_TROUBLESHOOT_PREFERENCE_KEY == pref?.key) {
|
||||
if (PreferencesManager.SETTINGS_NOTIFICATION_TROUBLESHOOT_PREFERENCE_KEY == pref?.key) {
|
||||
oFragment = VectorSettingsNotificationsTroubleshootFragment.newInstance(session.sessionParams.credentials.userId)
|
||||
} else if (PreferencesManager.SETTINGS_NOTIFICATION_ADVANCED_PREFERENCE_KEY == pref?.key) {
|
||||
oFragment = VectorSettingsAdvancedNotificationPreferenceFragment.newInstance(session.sessionParams.credentials.userId)
|
||||
|
|
|
@ -0,0 +1,112 @@
|
|||
/*
|
||||
* Copyright 2019 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.riotredesign.features.settings
|
||||
|
||||
import android.os.Bundle
|
||||
import android.text.TextUtils
|
||||
import android.view.View
|
||||
import androidx.annotation.CallSuper
|
||||
import im.vector.matrix.android.api.session.Session
|
||||
import im.vector.riotredesign.R
|
||||
import im.vector.riotredesign.core.platform.VectorPreferenceFragment
|
||||
import im.vector.riotredesign.core.utils.toast
|
||||
import org.koin.android.ext.android.inject
|
||||
|
||||
abstract class VectorSettingsBaseFragment : VectorPreferenceFragment() {
|
||||
|
||||
private var mLoadingView: View? = null
|
||||
|
||||
|
||||
// members
|
||||
protected val mSession by inject<Session>()
|
||||
|
||||
abstract val preferenceXmlRes: Int
|
||||
|
||||
@CallSuper
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
addPreferencesFromResource(preferenceXmlRes)
|
||||
|
||||
bindPref()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
|
||||
// find the view from parent activity
|
||||
mLoadingView = activity?.findViewById(R.id.vector_settings_spinner_views)
|
||||
}
|
||||
|
||||
abstract fun bindPref()
|
||||
|
||||
|
||||
/**
|
||||
* Display the loading view.
|
||||
*/
|
||||
protected fun displayLoadingView() {
|
||||
// search the loading view from the upper view
|
||||
if (null == mLoadingView) {
|
||||
var parent = view
|
||||
|
||||
while (parent != null && mLoadingView == null) {
|
||||
mLoadingView = parent.findViewById(R.id.vector_settings_spinner_views)
|
||||
parent = parent.parent as View
|
||||
}
|
||||
} else {
|
||||
mLoadingView?.visibility = View.VISIBLE
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide the loading view.
|
||||
*/
|
||||
protected fun hideLoadingView() {
|
||||
mLoadingView?.visibility = View.GONE
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide the loading view and refresh the preferences.
|
||||
*
|
||||
* @param refresh true to refresh the display
|
||||
*/
|
||||
protected fun hideLoadingView(refresh: Boolean) {
|
||||
mLoadingView?.visibility = View.GONE
|
||||
|
||||
if (refresh) {
|
||||
// TODO refreshDisplay()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A request has been processed.
|
||||
* Display a toast if there is a an error message
|
||||
*
|
||||
* @param errorMessage the error message
|
||||
*/
|
||||
protected fun onCommonDone(errorMessage: String?) {
|
||||
if (!isAdded) {
|
||||
return
|
||||
}
|
||||
activity?.runOnUiThread {
|
||||
if (!TextUtils.isEmpty(errorMessage) && errorMessage != null) {
|
||||
activity?.toast(errorMessage!!)
|
||||
}
|
||||
hideLoadingView()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,171 @@
|
|||
/*
|
||||
* Copyright 2019 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.riotredesign.features.settings
|
||||
|
||||
import androidx.preference.PreferenceCategory
|
||||
import im.vector.riotredesign.R
|
||||
import im.vector.riotredesign.core.preference.ProgressBarPreference
|
||||
|
||||
class VectorSettingsFlair : VectorSettingsBaseFragment() {
|
||||
|
||||
override var titleRes = R.string.settings_flair
|
||||
override val preferenceXmlRes = R.xml.vector_settings_flair
|
||||
|
||||
// current publicised group list
|
||||
private var mPublicisedGroups: MutableSet<String>? = null
|
||||
|
||||
// Group Flairs
|
||||
private val mGroupsFlairCategory by lazy {
|
||||
findPreference(PreferencesManager.SETTINGS_GROUPS_FLAIR_KEY) as PreferenceCategory
|
||||
}
|
||||
|
||||
override fun bindPref() {
|
||||
// Flair
|
||||
refreshGroupFlairsList()
|
||||
}
|
||||
|
||||
//==============================================================================================================
|
||||
// Group flairs management
|
||||
//==============================================================================================================
|
||||
|
||||
/**
|
||||
* Force the refresh of the devices list.<br></br>
|
||||
* The devices list is the list of the devices where the user as looged in.
|
||||
* It can be any mobile device, as any browser.
|
||||
*/
|
||||
private fun refreshGroupFlairsList() {
|
||||
// display a spinner while refreshing
|
||||
if (0 == mGroupsFlairCategory.preferenceCount) {
|
||||
activity?.let {
|
||||
val preference = ProgressBarPreference(it)
|
||||
mGroupsFlairCategory.addPreference(preference)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
TODO
|
||||
session.groupsManager.getUserPublicisedGroups(session.myUserId, true, object : MatrixCallback<Set<String>> {
|
||||
override fun onSuccess(publicisedGroups: Set<String>) {
|
||||
// clear everything
|
||||
mGroupsFlairCategory.removeAll()
|
||||
|
||||
if (publicisedGroups.isEmpty()) {
|
||||
val vectorGroupPreference = Preference(activity)
|
||||
vectorGroupPreference.title = resources.getString(R.string.settings_without_flair)
|
||||
mGroupsFlairCategory.addPreference(vectorGroupPreference)
|
||||
} else {
|
||||
buildGroupsList(publicisedGroups)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onNetworkError(e: Exception) {
|
||||
// NOP
|
||||
}
|
||||
|
||||
override fun onMatrixError(e: MatrixError) {
|
||||
// NOP
|
||||
}
|
||||
|
||||
override fun onUnexpectedError(e: Exception) {
|
||||
// NOP
|
||||
}
|
||||
})
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the groups list.
|
||||
*
|
||||
* @param publicisedGroups the publicised groups list.
|
||||
*/
|
||||
private fun buildGroupsList(publicisedGroups: Set<String>) {
|
||||
var isNewList = true
|
||||
|
||||
mPublicisedGroups?.let {
|
||||
if (it.size == publicisedGroups.size) {
|
||||
isNewList = !it.containsAll(publicisedGroups)
|
||||
}
|
||||
}
|
||||
|
||||
if (isNewList) {
|
||||
/*
|
||||
TODO
|
||||
val joinedGroups = ArrayList(session.groupsManager.joinedGroups)
|
||||
Collections.sort(joinedGroups, Group.mGroupsComparator)
|
||||
|
||||
mPublicisedGroups = publicisedGroups.toMutableSet()
|
||||
|
||||
for ((prefIndex, group) in joinedGroups.withIndex()) {
|
||||
val vectorGroupPreference = VectorGroupPreference(activity!!)
|
||||
vectorGroupPreference.key = DEVICES_PREFERENCE_KEY_BASE + prefIndex
|
||||
|
||||
vectorGroupPreference.setGroup(group, session)
|
||||
vectorGroupPreference.title = group.displayName
|
||||
vectorGroupPreference.summary = group.groupId
|
||||
|
||||
vectorGroupPreference.isChecked = publicisedGroups.contains(group.groupId)
|
||||
mGroupsFlairCategory.addPreference(vectorGroupPreference)
|
||||
|
||||
vectorGroupPreference.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue ->
|
||||
if (newValue is Boolean) {
|
||||
/*
|
||||
* if mPublicisedGroup is null somehow, then
|
||||
* we cant check it contains groupId or not
|
||||
* so set isFlaired to false
|
||||
*/
|
||||
val isFlaired = mPublicisedGroups?.contains(group.groupId) ?: false
|
||||
|
||||
if (newValue != isFlaired) {
|
||||
displayLoadingView()
|
||||
session.groupsManager.updateGroupPublicity(group.groupId, newValue, object : MatrixCallback<Unit> {
|
||||
override fun onSuccess(info: Void?) {
|
||||
hideLoadingView()
|
||||
if (newValue) {
|
||||
mPublicisedGroups?.add(group.groupId)
|
||||
} else {
|
||||
mPublicisedGroups?.remove(group.groupId)
|
||||
}
|
||||
}
|
||||
|
||||
private fun onError() {
|
||||
hideLoadingView()
|
||||
// restore default value
|
||||
vectorGroupPreference.isChecked = publicisedGroups.contains(group.groupId)
|
||||
}
|
||||
|
||||
override fun onNetworkError(e: Exception) {
|
||||
onError()
|
||||
}
|
||||
|
||||
override fun onMatrixError(e: MatrixError) {
|
||||
onError()
|
||||
}
|
||||
|
||||
override fun onUnexpectedError(e: Exception) {
|
||||
onError()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,822 @@
|
|||
/*
|
||||
* Copyright 2019 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.riotredesign.features.settings
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.text.Editable
|
||||
import android.text.TextUtils
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import android.widget.ImageView
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.preference.EditTextPreference
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceCategory
|
||||
import com.google.android.material.textfield.TextInputEditText
|
||||
import com.google.android.material.textfield.TextInputLayout
|
||||
import im.vector.riotredesign.R
|
||||
import im.vector.riotredesign.core.extensions.showPassword
|
||||
import im.vector.riotredesign.core.platform.SimpleTextWatcher
|
||||
import im.vector.riotredesign.core.preference.UserAvatarPreference
|
||||
import im.vector.riotredesign.core.preference.VectorPreference
|
||||
import im.vector.riotredesign.core.utils.PERMISSION_REQUEST_CODE_LAUNCH_CAMERA
|
||||
import im.vector.riotredesign.core.utils.allGranted
|
||||
import im.vector.riotredesign.core.utils.copyToClipboard
|
||||
import im.vector.riotredesign.core.utils.toast
|
||||
import im.vector.riotredesign.features.MainActivity
|
||||
import im.vector.riotredesign.features.themes.ThemeUtils
|
||||
import java.util.*
|
||||
|
||||
class VectorSettingsGeneral : VectorSettingsBaseFragment() {
|
||||
|
||||
override var titleRes = R.string.settings_general_title
|
||||
override val preferenceXmlRes = R.xml.vector_settings_general
|
||||
|
||||
private var mDisplayedEmails = ArrayList<String>()
|
||||
private var mDisplayedPhoneNumber = ArrayList<String>()
|
||||
|
||||
private val mUserSettingsCategory by lazy {
|
||||
findPreference(PreferencesManager.SETTINGS_USER_SETTINGS_PREFERENCE_KEY) as PreferenceCategory
|
||||
}
|
||||
private val mUserAvatarPreference by lazy {
|
||||
findPreference(PreferencesManager.SETTINGS_PROFILE_PICTURE_PREFERENCE_KEY) as UserAvatarPreference
|
||||
}
|
||||
private val mDisplayNamePreference by lazy {
|
||||
findPreference(PreferencesManager.SETTINGS_DISPLAY_NAME_PREFERENCE_KEY) as EditTextPreference
|
||||
}
|
||||
private val mPasswordPreference by lazy {
|
||||
findPreference(PreferencesManager.SETTINGS_CHANGE_PASSWORD_PREFERENCE_KEY)
|
||||
}
|
||||
|
||||
// Local contacts
|
||||
private val mContactSettingsCategory by lazy {
|
||||
findPreference(PreferencesManager.SETTINGS_CONTACT_PREFERENCE_KEYS) as PreferenceCategory
|
||||
}
|
||||
|
||||
private val mContactPhonebookCountryPreference by lazy {
|
||||
findPreference(PreferencesManager.SETTINGS_CONTACTS_PHONEBOOK_COUNTRY_PREFERENCE_KEY)
|
||||
}
|
||||
|
||||
|
||||
override fun bindPref() {
|
||||
// Avatar
|
||||
mUserAvatarPreference.let {
|
||||
it.setSession(mSession)
|
||||
it.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
onUpdateAvatarClick()
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
// Display name
|
||||
mDisplayNamePreference.let {
|
||||
it.summary = "TODO" // session.myUser.displayname
|
||||
it.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue ->
|
||||
onDisplayNameClick(newValue?.let { (it as String).trim() })
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
// Password
|
||||
mPasswordPreference.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
onPasswordUpdateClick()
|
||||
false
|
||||
}
|
||||
|
||||
// Add Email
|
||||
(findPreference(ADD_EMAIL_PREFERENCE_KEY) as EditTextPreference).let {
|
||||
// It does not work on XML, do it here
|
||||
it.icon = activity?.let {
|
||||
ThemeUtils.tintDrawable(it,
|
||||
ContextCompat.getDrawable(it, R.drawable.ic_add_black)!!, R.attr.vctr_settings_icon_tint_color)
|
||||
}
|
||||
|
||||
// Unfortunately, this is not supported in lib v7
|
||||
// it.editText.inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS
|
||||
|
||||
it.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue ->
|
||||
addEmail((newValue as String).trim())
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
// Add phone number
|
||||
findPreference(ADD_PHONE_NUMBER_PREFERENCE_KEY).let {
|
||||
// It does not work on XML, do it here
|
||||
it.icon = activity?.let {
|
||||
ThemeUtils.tintDrawable(it,
|
||||
ContextCompat.getDrawable(it, R.drawable.ic_add_black)!!, R.attr.vctr_settings_icon_tint_color)
|
||||
}
|
||||
|
||||
it.setOnPreferenceClickListener {
|
||||
notImplemented()
|
||||
// TODO val intent = PhoneNumberAdditionActivity.getIntent(activity, session.credentials.userId)
|
||||
// startActivityForResult(intent, REQUEST_NEW_PHONE_NUMBER)
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
// Advanced settings
|
||||
|
||||
// user account
|
||||
findPreference(PreferencesManager.SETTINGS_LOGGED_IN_PREFERENCE_KEY)
|
||||
.summary = mSession.sessionParams.credentials.userId
|
||||
|
||||
// home server
|
||||
findPreference(PreferencesManager.SETTINGS_HOME_SERVER_PREFERENCE_KEY)
|
||||
.summary = mSession.sessionParams.homeServerConnectionConfig.homeServerUri.toString()
|
||||
|
||||
// identity server
|
||||
findPreference(PreferencesManager.SETTINGS_IDENTITY_SERVER_PREFERENCE_KEY)
|
||||
.summary = mSession.sessionParams.homeServerConnectionConfig.identityServerUri.toString()
|
||||
|
||||
|
||||
refreshEmailsList()
|
||||
refreshPhoneNumbersList()
|
||||
// Contacts
|
||||
setContactsPreferences()
|
||||
|
||||
// clear cache
|
||||
findPreference(PreferencesManager.SETTINGS_CLEAR_CACHE_PREFERENCE_KEY).let {
|
||||
/*
|
||||
TODO
|
||||
MXSession.getApplicationSizeCaches(activity, object : SimpleApiCallback<Long>() {
|
||||
override fun onSuccess(size: Long) {
|
||||
if (null != activity) {
|
||||
it.summary = android.text.format.Formatter.formatFileSize(activity, size)
|
||||
}
|
||||
}
|
||||
})
|
||||
*/
|
||||
|
||||
it.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
displayLoadingView()
|
||||
MainActivity.restartApp(activity!!, clearCache = true, clearCredentials = false)
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
// clear medias cache
|
||||
findPreference(PreferencesManager.SETTINGS_CLEAR_MEDIA_CACHE_PREFERENCE_KEY).let {
|
||||
/*
|
||||
TODO
|
||||
MXMediaCache.getCachesSize(activity, object : SimpleApiCallback<Long>() {
|
||||
override fun onSuccess(size: Long) {
|
||||
if (null != activity) {
|
||||
it.summary = android.text.format.Formatter.formatFileSize(activity, size)
|
||||
}
|
||||
}
|
||||
})
|
||||
*/
|
||||
|
||||
it.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
notImplemented()
|
||||
/* TODO
|
||||
displayLoadingView()
|
||||
|
||||
val task = ClearMediaCacheAsyncTask(
|
||||
backgroundTask = {
|
||||
session.mediaCache.clear()
|
||||
activity?.let { it -> Glide.get(it).clearDiskCache() }
|
||||
},
|
||||
onCompleteTask = {
|
||||
hideLoadingView()
|
||||
|
||||
MXMediaCache.getCachesSize(activity, object : SimpleApiCallback<Long>() {
|
||||
override fun onSuccess(size: Long) {
|
||||
it.summary = Formatter.formatFileSize(activity, size)
|
||||
}
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
try {
|
||||
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR)
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "## session.getMediaCache().clear() failed " + e.message)
|
||||
task.cancel(true)
|
||||
hideLoadingView()
|
||||
}
|
||||
*/
|
||||
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
// Deactivate account section
|
||||
|
||||
// deactivate account
|
||||
findPreference(PreferencesManager.SETTINGS_DEACTIVATE_ACCOUNT_KEY)
|
||||
.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
activity?.let {
|
||||
notImplemented()
|
||||
// TODO startActivity(DeactivateAccountActivity.getIntent(it))
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
|
||||
if (allGranted(grantResults)) {
|
||||
if (requestCode == PERMISSION_REQUEST_CODE_LAUNCH_CAMERA) {
|
||||
changeAvatar()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
when (requestCode) {
|
||||
REQUEST_NEW_PHONE_NUMBER -> refreshPhoneNumbersList()
|
||||
REQUEST_PHONEBOOK_COUNTRY -> onPhonebookCountryUpdate(data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the avatar.
|
||||
*/
|
||||
private fun onUpdateAvatarClick() {
|
||||
notImplemented()
|
||||
|
||||
/* TODO
|
||||
if (checkPermissions(PERMISSIONS_FOR_TAKING_PHOTO, this, PERMISSION_REQUEST_CODE_LAUNCH_CAMERA)) {
|
||||
changeAvatar()
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
private fun changeAvatar() {
|
||||
/* TODO
|
||||
val intent = Intent(activity, VectorMediaPickerActivity::class.java)
|
||||
intent.putExtra(VectorMediaPickerActivity.EXTRA_AVATAR_MODE, true)
|
||||
startActivityForResult(intent, VectorUtils.TAKE_IMAGE)
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
//==============================================================================================================
|
||||
// contacts management
|
||||
//==============================================================================================================
|
||||
|
||||
private fun setContactsPreferences() {
|
||||
/* TODO
|
||||
// Permission
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
// on Android >= 23, use the system one
|
||||
mContactSettingsCategory.removePreference(findPreference(ContactsManager.CONTACTS_BOOK_ACCESS_KEY))
|
||||
}
|
||||
// Phonebook country
|
||||
mContactPhonebookCountryPreference.summary = PhoneNumberUtils.getHumanCountryCode(PhoneNumberUtils.getCountryCode(activity))
|
||||
|
||||
mContactPhonebookCountryPreference.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
val intent = CountryPickerActivity.getIntent(activity, true)
|
||||
startActivityForResult(intent, REQUEST_PHONEBOOK_COUNTRY)
|
||||
true
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
private fun onPhonebookCountryUpdate(data: Intent?) {
|
||||
/* TODO
|
||||
if (data != null && data.hasExtra(CountryPickerActivity.EXTRA_OUT_COUNTRY_NAME)
|
||||
&& data.hasExtra(CountryPickerActivity.EXTRA_OUT_COUNTRY_CODE)) {
|
||||
val countryCode = data.getStringExtra(CountryPickerActivity.EXTRA_OUT_COUNTRY_CODE)
|
||||
if (!TextUtils.equals(countryCode, PhoneNumberUtils.getCountryCode(activity))) {
|
||||
PhoneNumberUtils.setCountryCode(activity, countryCode)
|
||||
mContactPhonebookCountryPreference.summary = data.getStringExtra(CountryPickerActivity.EXTRA_OUT_COUNTRY_NAME)
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
//==============================================================================================================
|
||||
// Phone number management
|
||||
//==============================================================================================================
|
||||
|
||||
/**
|
||||
* Refresh phone number list
|
||||
*/
|
||||
private fun refreshPhoneNumbersList() {
|
||||
/* TODO
|
||||
val currentPhoneNumber3PID = ArrayList(session.myUser.getlinkedPhoneNumbers())
|
||||
|
||||
val phoneNumberList = ArrayList<String>()
|
||||
for (identifier in currentPhoneNumber3PID) {
|
||||
phoneNumberList.add(identifier.address)
|
||||
}
|
||||
|
||||
// check first if there is an update
|
||||
var isNewList = true
|
||||
if (phoneNumberList.size == mDisplayedPhoneNumber.size) {
|
||||
isNewList = !mDisplayedPhoneNumber.containsAll(phoneNumberList)
|
||||
}
|
||||
|
||||
if (isNewList) {
|
||||
// remove the displayed one
|
||||
run {
|
||||
var index = 0
|
||||
while (true) {
|
||||
val preference = mUserSettingsCategory.findPreference(PHONE_NUMBER_PREFERENCE_KEY_BASE + index)
|
||||
|
||||
if (null != preference) {
|
||||
mUserSettingsCategory.removePreference(preference)
|
||||
} else {
|
||||
break
|
||||
}
|
||||
index++
|
||||
}
|
||||
}
|
||||
|
||||
// add new phone number list
|
||||
mDisplayedPhoneNumber = phoneNumberList
|
||||
|
||||
val addPhoneBtn = mUserSettingsCategory.findPreference(ADD_PHONE_NUMBER_PREFERENCE_KEY)
|
||||
?: return
|
||||
|
||||
var order = addPhoneBtn.order
|
||||
|
||||
for ((index, phoneNumber3PID) in currentPhoneNumber3PID.withIndex()) {
|
||||
val preference = VectorPreference(activity!!)
|
||||
|
||||
preference.title = getString(R.string.settings_phone_number)
|
||||
var phoneNumberFormatted = phoneNumber3PID.address
|
||||
try {
|
||||
// Attempt to format phone number
|
||||
val phoneNumber = PhoneNumberUtil.getInstance().parse("+$phoneNumberFormatted", null)
|
||||
phoneNumberFormatted = PhoneNumberUtil.getInstance().format(phoneNumber, PhoneNumberUtil.PhoneNumberFormat.INTERNATIONAL)
|
||||
} catch (e: NumberParseException) {
|
||||
// Do nothing, we will display raw version
|
||||
}
|
||||
|
||||
preference.summary = phoneNumberFormatted
|
||||
preference.key = PHONE_NUMBER_PREFERENCE_KEY_BASE + index
|
||||
preference.order = order
|
||||
|
||||
preference.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
displayDelete3PIDConfirmationDialog(phoneNumber3PID, preference.summary)
|
||||
true
|
||||
}
|
||||
|
||||
preference.onPreferenceLongClickListener = object : VectorPreference.OnPreferenceLongClickListener {
|
||||
override fun onPreferenceLongClick(preference: Preference): Boolean {
|
||||
activity?.let { copyToClipboard(it, phoneNumber3PID.address) }
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
order++
|
||||
mUserSettingsCategory.addPreference(preference)
|
||||
}
|
||||
|
||||
addPhoneBtn.order = order
|
||||
} */
|
||||
}
|
||||
|
||||
//==============================================================================================================
|
||||
// Email management
|
||||
//==============================================================================================================
|
||||
|
||||
/**
|
||||
* Refresh the emails list
|
||||
*/
|
||||
private fun refreshEmailsList() {
|
||||
val currentEmail3PID = emptyList<String>() // TODO ArrayList(session.myUser.getlinkedEmails())
|
||||
|
||||
val newEmailsList = ArrayList<String>()
|
||||
for (identifier in currentEmail3PID) {
|
||||
// TODO newEmailsList.add(identifier.address)
|
||||
}
|
||||
|
||||
// check first if there is an update
|
||||
var isNewList = true
|
||||
if (newEmailsList.size == mDisplayedEmails.size) {
|
||||
isNewList = !mDisplayedEmails.containsAll(newEmailsList)
|
||||
}
|
||||
|
||||
if (isNewList) {
|
||||
// remove the displayed one
|
||||
run {
|
||||
var index = 0
|
||||
while (true) {
|
||||
val preference = mUserSettingsCategory.findPreference(EMAIL_PREFERENCE_KEY_BASE + index)
|
||||
|
||||
if (null != preference) {
|
||||
mUserSettingsCategory.removePreference(preference)
|
||||
} else {
|
||||
break
|
||||
}
|
||||
index++
|
||||
}
|
||||
}
|
||||
|
||||
// add new emails list
|
||||
mDisplayedEmails = newEmailsList
|
||||
|
||||
val addEmailBtn = mUserSettingsCategory.findPreference(ADD_EMAIL_PREFERENCE_KEY)
|
||||
?: return
|
||||
|
||||
var order = addEmailBtn.order
|
||||
|
||||
for ((index, email3PID) in currentEmail3PID.withIndex()) {
|
||||
val preference = VectorPreference(activity!!)
|
||||
|
||||
preference.title = getString(R.string.settings_email_address)
|
||||
preference.summary = "TODO" // email3PID.address
|
||||
preference.key = EMAIL_PREFERENCE_KEY_BASE + index
|
||||
preference.order = order
|
||||
|
||||
preference.onPreferenceClickListener = Preference.OnPreferenceClickListener { pref ->
|
||||
displayDelete3PIDConfirmationDialog(/* TODO email3PID, */ pref.summary)
|
||||
true
|
||||
}
|
||||
|
||||
preference.onPreferenceLongClickListener = object : VectorPreference.OnPreferenceLongClickListener {
|
||||
override fun onPreferenceLongClick(preference: Preference): Boolean {
|
||||
activity?.let { copyToClipboard(it, "TODO") } //email3PID.address) }
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
mUserSettingsCategory.addPreference(preference)
|
||||
|
||||
order++
|
||||
}
|
||||
|
||||
addEmailBtn.order = order
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to add a new email to the account
|
||||
*
|
||||
* @param email the email to add.
|
||||
*/
|
||||
private fun addEmail(email: String) {
|
||||
// check first if the email syntax is valid
|
||||
// if email is null , then also its invalid email
|
||||
if (TextUtils.isEmpty(email) || !android.util.Patterns.EMAIL_ADDRESS.matcher(email).matches()) {
|
||||
activity?.toast(R.string.auth_invalid_email)
|
||||
return
|
||||
}
|
||||
|
||||
// check first if the email syntax is valid
|
||||
if (mDisplayedEmails.indexOf(email) >= 0) {
|
||||
activity?.toast(R.string.auth_email_already_defined)
|
||||
return
|
||||
}
|
||||
|
||||
notImplemented()
|
||||
/* TODO
|
||||
val pid = ThreePid(email, ThreePid.MEDIUM_EMAIL)
|
||||
|
||||
displayLoadingView()
|
||||
|
||||
session.myUser.requestEmailValidationToken(pid, object : MatrixCallback<Unit> {
|
||||
override fun onSuccess(info: Void?) {
|
||||
activity?.runOnUiThread { showEmailValidationDialog(pid) }
|
||||
}
|
||||
|
||||
override fun onNetworkError(e: Exception) {
|
||||
onCommonDone(e.localizedMessage)
|
||||
}
|
||||
|
||||
override fun onMatrixError(e: MatrixError) {
|
||||
if (TextUtils.equals(MatrixError.THREEPID_IN_USE, e.errcode)) {
|
||||
onCommonDone(getString(R.string.account_email_already_used_error))
|
||||
} else {
|
||||
onCommonDone(e.localizedMessage)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onUnexpectedError(e: Exception) {
|
||||
onCommonDone(e.localizedMessage)
|
||||
}
|
||||
})
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Show an email validation dialog to warn the user tho valid his email link.
|
||||
*
|
||||
* @param pid the used pid.
|
||||
*/
|
||||
/* TODO
|
||||
private fun showEmailValidationDialog(pid: ThreePid) {
|
||||
activity?.let {
|
||||
AlertDialog.Builder(it)
|
||||
.setTitle(R.string.account_email_validation_title)
|
||||
.setMessage(R.string.account_email_validation_message)
|
||||
.setPositiveButton(R.string._continue) { _, _ ->
|
||||
session.myUser.add3Pid(pid, true, object : MatrixCallback<Unit> {
|
||||
override fun onSuccess(info: Void?) {
|
||||
it.runOnUiThread {
|
||||
hideLoadingView()
|
||||
refreshEmailsList()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onNetworkError(e: Exception) {
|
||||
onCommonDone(e.localizedMessage)
|
||||
}
|
||||
|
||||
override fun onMatrixError(e: MatrixError) {
|
||||
if (TextUtils.equals(e.errcode, MatrixError.THREEPID_AUTH_FAILED)) {
|
||||
it.runOnUiThread {
|
||||
hideLoadingView()
|
||||
it.toast(R.string.account_email_validation_error)
|
||||
}
|
||||
} else {
|
||||
onCommonDone(e.localizedMessage)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onUnexpectedError(e: Exception) {
|
||||
onCommonDone(e.localizedMessage)
|
||||
}
|
||||
})
|
||||
}
|
||||
.setNegativeButton(R.string.cancel) { _, _ ->
|
||||
hideLoadingView()
|
||||
}
|
||||
.show()
|
||||
}
|
||||
} */
|
||||
|
||||
|
||||
/**
|
||||
* Display a dialog which asks confirmation for the deletion of a 3pid
|
||||
*
|
||||
* @param pid the 3pid to delete
|
||||
* @param preferenceSummary the displayed 3pid
|
||||
*/
|
||||
private fun displayDelete3PIDConfirmationDialog(/* TODO pid: ThirdPartyIdentifier,*/ preferenceSummary: CharSequence) {
|
||||
val mediumFriendlyName = "TODO" // ThreePid.getMediumFriendlyName(pid.medium, activity).toLowerCase(VectorLocale.applicationLocale)
|
||||
val dialogMessage = getString(R.string.settings_delete_threepid_confirmation, mediumFriendlyName, preferenceSummary)
|
||||
|
||||
activity?.let {
|
||||
AlertDialog.Builder(it)
|
||||
.setTitle(R.string.dialog_title_confirmation)
|
||||
.setMessage(dialogMessage)
|
||||
.setPositiveButton(R.string.remove) { _, _ ->
|
||||
notImplemented()
|
||||
/* TODO
|
||||
displayLoadingView()
|
||||
|
||||
session.myUser.delete3Pid(pid, object : MatrixCallback<Unit> {
|
||||
override fun onSuccess(info: Void?) {
|
||||
when (pid.medium) {
|
||||
ThreePid.MEDIUM_EMAIL -> refreshEmailsList()
|
||||
ThreePid.MEDIUM_MSISDN -> refreshPhoneNumbersList()
|
||||
}
|
||||
onCommonDone(null)
|
||||
}
|
||||
|
||||
override fun onNetworkError(e: Exception) {
|
||||
onCommonDone(e.localizedMessage)
|
||||
}
|
||||
|
||||
override fun onMatrixError(e: MatrixError) {
|
||||
onCommonDone(e.localizedMessage)
|
||||
}
|
||||
|
||||
override fun onUnexpectedError(e: Exception) {
|
||||
onCommonDone(e.localizedMessage)
|
||||
}
|
||||
})
|
||||
*/
|
||||
}
|
||||
.setNegativeButton(R.string.cancel, null)
|
||||
.show()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Update the password.
|
||||
*/
|
||||
private fun onPasswordUpdateClick() {
|
||||
activity?.let { activity ->
|
||||
val view: ViewGroup = activity.layoutInflater.inflate(R.layout.dialog_change_password, null) as ViewGroup
|
||||
|
||||
val showPassword: ImageView = view.findViewById(R.id.change_password_show_passwords)
|
||||
val oldPasswordTil: TextInputLayout = view.findViewById(R.id.change_password_old_pwd_til)
|
||||
val oldPasswordText: TextInputEditText = view.findViewById(R.id.change_password_old_pwd_text)
|
||||
val newPasswordText: TextInputEditText = view.findViewById(R.id.change_password_new_pwd_text)
|
||||
val confirmNewPasswordTil: TextInputLayout = view.findViewById(R.id.change_password_confirm_new_pwd_til)
|
||||
val confirmNewPasswordText: TextInputEditText = view.findViewById(R.id.change_password_confirm_new_pwd_text)
|
||||
val changePasswordLoader: View = view.findViewById(R.id.change_password_loader)
|
||||
|
||||
var passwordShown = false
|
||||
|
||||
showPassword.setOnClickListener(object : View.OnClickListener {
|
||||
override fun onClick(v: View?) {
|
||||
passwordShown = !passwordShown
|
||||
|
||||
oldPasswordText.showPassword(passwordShown)
|
||||
newPasswordText.showPassword(passwordShown)
|
||||
confirmNewPasswordText.showPassword(passwordShown)
|
||||
|
||||
showPassword.setImageResource(if (passwordShown) R.drawable.ic_eye_closed_black else R.drawable.ic_eye_black)
|
||||
}
|
||||
})
|
||||
|
||||
val dialog = AlertDialog.Builder(activity)
|
||||
.setView(view)
|
||||
.setPositiveButton(R.string.settings_change_password_submit, null)
|
||||
.setNegativeButton(R.string.cancel, null)
|
||||
.setOnDismissListener {
|
||||
val imm = activity.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
imm.hideSoftInputFromWindow(view.applicationWindowToken, 0)
|
||||
}
|
||||
.create()
|
||||
|
||||
dialog.setOnShowListener {
|
||||
val updateButton = dialog.getButton(AlertDialog.BUTTON_POSITIVE)
|
||||
updateButton.isEnabled = false
|
||||
|
||||
fun updateUi() {
|
||||
val oldPwd = oldPasswordText.text.toString().trim()
|
||||
val newPwd = newPasswordText.text.toString().trim()
|
||||
val newConfirmPwd = confirmNewPasswordText.text.toString().trim()
|
||||
|
||||
updateButton.isEnabled = oldPwd.isNotEmpty() && newPwd.isNotEmpty() && TextUtils.equals(newPwd, newConfirmPwd)
|
||||
|
||||
if (newPwd.isNotEmpty() && newConfirmPwd.isNotEmpty() && !TextUtils.equals(newPwd, newConfirmPwd)) {
|
||||
confirmNewPasswordTil.error = getString(R.string.passwords_do_not_match)
|
||||
}
|
||||
}
|
||||
|
||||
oldPasswordText.addTextChangedListener(object : SimpleTextWatcher() {
|
||||
override fun afterTextChanged(s: Editable) {
|
||||
oldPasswordTil.error = null
|
||||
updateUi()
|
||||
}
|
||||
})
|
||||
|
||||
newPasswordText.addTextChangedListener(object : SimpleTextWatcher() {
|
||||
override fun afterTextChanged(s: Editable) {
|
||||
confirmNewPasswordTil.error = null
|
||||
updateUi()
|
||||
}
|
||||
})
|
||||
|
||||
confirmNewPasswordText.addTextChangedListener(object : SimpleTextWatcher() {
|
||||
override fun afterTextChanged(s: Editable) {
|
||||
confirmNewPasswordTil.error = null
|
||||
updateUi()
|
||||
}
|
||||
})
|
||||
|
||||
fun showPasswordLoadingView(toShow: Boolean) {
|
||||
if (toShow) {
|
||||
showPassword.isEnabled = false
|
||||
oldPasswordText.isEnabled = false
|
||||
newPasswordText.isEnabled = false
|
||||
confirmNewPasswordText.isEnabled = false
|
||||
changePasswordLoader.isVisible = true
|
||||
updateButton.isEnabled = false
|
||||
} else {
|
||||
showPassword.isEnabled = true
|
||||
oldPasswordText.isEnabled = true
|
||||
newPasswordText.isEnabled = true
|
||||
confirmNewPasswordText.isEnabled = true
|
||||
changePasswordLoader.isVisible = false
|
||||
updateButton.isEnabled = true
|
||||
}
|
||||
}
|
||||
|
||||
updateButton.setOnClickListener {
|
||||
if (passwordShown) {
|
||||
// Hide passwords during processing
|
||||
showPassword.performClick()
|
||||
}
|
||||
|
||||
val imm = activity.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
imm.hideSoftInputFromWindow(view.applicationWindowToken, 0)
|
||||
|
||||
val oldPwd = oldPasswordText.text.toString().trim()
|
||||
val newPwd = newPasswordText.text.toString().trim()
|
||||
|
||||
notImplemented()
|
||||
/* TODO
|
||||
showPasswordLoadingView(true)
|
||||
|
||||
session.updatePassword(oldPwd, newPwd, object : MatrixCallback<Unit> {
|
||||
private fun onDone(@StringRes textResId: Int) {
|
||||
showPasswordLoadingView(false)
|
||||
|
||||
if (textResId == R.string.settings_fail_to_update_password_invalid_current_password) {
|
||||
oldPasswordTil.error = getString(textResId)
|
||||
} else {
|
||||
dialog.dismiss()
|
||||
activity.toast(textResId, Toast.LENGTH_LONG)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSuccess(info: Void?) {
|
||||
onDone(R.string.settings_password_updated)
|
||||
}
|
||||
|
||||
override fun onNetworkError(e: Exception) {
|
||||
onDone(R.string.settings_fail_to_update_password)
|
||||
}
|
||||
|
||||
override fun onMatrixError(e: MatrixError) {
|
||||
if (e.error == "Invalid password") {
|
||||
onDone(R.string.settings_fail_to_update_password_invalid_current_password)
|
||||
} else {
|
||||
dialog.dismiss()
|
||||
onDone(R.string.settings_fail_to_update_password)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onUnexpectedError(e: Exception) {
|
||||
onDone(R.string.settings_fail_to_update_password)
|
||||
}
|
||||
})
|
||||
*/
|
||||
}
|
||||
}
|
||||
dialog.show()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the displayname.
|
||||
*/
|
||||
private fun onDisplayNameClick(value: String?) {
|
||||
notImplemented()
|
||||
/* TODO
|
||||
if (!TextUtils.equals(session.myUser.displayname, value)) {
|
||||
displayLoadingView()
|
||||
|
||||
session.myUser.updateDisplayName(value, object : MatrixCallback<Unit> {
|
||||
override fun onSuccess(info: Void?) {
|
||||
// refresh the settings value
|
||||
PreferenceManager.getDefaultSharedPreferences(activity).edit {
|
||||
putString(PreferencesManager.SETTINGS_DISPLAY_NAME_PREFERENCE_KEY, value)
|
||||
}
|
||||
|
||||
onCommonDone(null)
|
||||
|
||||
refreshDisplay()
|
||||
}
|
||||
|
||||
override fun onNetworkError(e: Exception) {
|
||||
onCommonDone(e.localizedMessage)
|
||||
}
|
||||
|
||||
override fun onMatrixError(e: MatrixError) {
|
||||
if (MatrixError.M_CONSENT_NOT_GIVEN == e.errcode) {
|
||||
activity?.runOnUiThread {
|
||||
hideLoadingView()
|
||||
(activity as VectorAppCompatActivity).consentNotGivenHelper.displayDialog(e)
|
||||
}
|
||||
} else {
|
||||
onCommonDone(e.localizedMessage)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onUnexpectedError(e: Exception) {
|
||||
onCommonDone(e.localizedMessage)
|
||||
}
|
||||
})
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
companion object {
|
||||
private const val ADD_EMAIL_PREFERENCE_KEY = "ADD_EMAIL_PREFERENCE_KEY"
|
||||
private const val ADD_PHONE_NUMBER_PREFERENCE_KEY = "ADD_PHONE_NUMBER_PREFERENCE_KEY"
|
||||
|
||||
private const val EMAIL_PREFERENCE_KEY_BASE = "EMAIL_PREFERENCE_KEY_BASE"
|
||||
private const val PHONE_NUMBER_PREFERENCE_KEY_BASE = "PHONE_NUMBER_PREFERENCE_KEY_BASE"
|
||||
|
||||
private const val REQUEST_NEW_PHONE_NUMBER = 456
|
||||
private const val REQUEST_PHONEBOOK_COUNTRY = 789
|
||||
}
|
||||
}
|
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
* Copyright 2019 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.riotredesign.features.settings
|
||||
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.provider.Settings
|
||||
import androidx.preference.Preference
|
||||
import com.google.android.gms.oss.licenses.OssLicensesMenuActivity
|
||||
import im.vector.matrix.android.api.Matrix
|
||||
import im.vector.riotredesign.R
|
||||
import im.vector.riotredesign.core.utils.copyToClipboard
|
||||
import im.vector.riotredesign.core.utils.displayInWebView
|
||||
import im.vector.riotredesign.features.version.getVersion
|
||||
|
||||
class VectorSettingsHelpAbout : VectorSettingsBaseFragment() {
|
||||
|
||||
override var titleRes = R.string.preference_root_help_about
|
||||
override val preferenceXmlRes = R.xml.vector_settings_help_about
|
||||
|
||||
override fun bindPref() {
|
||||
// preference to start the App info screen, to facilitate App permissions access
|
||||
findPreference(APP_INFO_LINK_PREFERENCE_KEY)
|
||||
.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
|
||||
activity?.let {
|
||||
val intent = Intent().apply {
|
||||
action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
|
||||
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
|
||||
val uri = Uri.fromParts("package", requireContext().packageName, null)
|
||||
|
||||
data = uri
|
||||
}
|
||||
it.applicationContext.startActivity(intent)
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
// application version
|
||||
(findPreference(PreferencesManager.SETTINGS_VERSION_PREFERENCE_KEY)).let {
|
||||
it.summary = getVersion(longFormat = false, useBuildNumber = true)
|
||||
|
||||
it.setOnPreferenceClickListener { pref ->
|
||||
copyToClipboard(requireContext(), pref.summary)
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
// SDK version
|
||||
(findPreference(PreferencesManager.SETTINGS_SDK_VERSION_PREFERENCE_KEY)).let {
|
||||
it.summary = Matrix.getSdkVersion()
|
||||
|
||||
it.setOnPreferenceClickListener { pref ->
|
||||
copyToClipboard(requireContext(), pref.summary)
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
// olm version
|
||||
findPreference(PreferencesManager.SETTINGS_OLM_VERSION_PREFERENCE_KEY)
|
||||
.summary = mSession.getCryptoVersion(requireContext(), false)
|
||||
|
||||
// copyright
|
||||
findPreference(PreferencesManager.SETTINGS_COPYRIGHT_PREFERENCE_KEY)
|
||||
.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
activity?.displayInWebView(VectorSettingsUrls.COPYRIGHT)
|
||||
false
|
||||
}
|
||||
|
||||
// terms & conditions
|
||||
findPreference(PreferencesManager.SETTINGS_APP_TERM_CONDITIONS_PREFERENCE_KEY)
|
||||
.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
activity?.displayInWebView(VectorSettingsUrls.TAC)
|
||||
false
|
||||
}
|
||||
|
||||
// privacy policy
|
||||
findPreference(PreferencesManager.SETTINGS_PRIVACY_POLICY_PREFERENCE_KEY)
|
||||
.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
activity?.displayInWebView(VectorSettingsUrls.PRIVACY_POLICY)
|
||||
false
|
||||
}
|
||||
|
||||
// third party notice
|
||||
findPreference(PreferencesManager.SETTINGS_THIRD_PARTY_NOTICES_PREFERENCE_KEY)
|
||||
.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
activity?.displayInWebView(VectorSettingsUrls.THIRD_PARTY_LICENSES)
|
||||
false
|
||||
}
|
||||
|
||||
findPreference(PreferencesManager.SETTINGS_OTHER_THIRD_PARTY_NOTICES_PREFERENCE_KEY)
|
||||
.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
// See https://developers.google.com/android/guides/opensource
|
||||
startActivity(Intent(requireActivity(), OssLicensesMenuActivity::class.java))
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val APP_INFO_LINK_PREFERENCE_KEY = "APP_INFO_LINK_PREFERENCE_KEY"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
* Copyright 2019 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.riotredesign.features.settings
|
||||
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceCategory
|
||||
import im.vector.riotredesign.R
|
||||
import java.util.ArrayList
|
||||
import kotlin.Comparator
|
||||
import kotlin.String
|
||||
import kotlin.getValue
|
||||
import kotlin.lazy
|
||||
import kotlin.let
|
||||
|
||||
class VectorSettingsIgnoredUsers : VectorSettingsBaseFragment() {
|
||||
|
||||
override var titleRes = R.string.settings_ignored_users
|
||||
override val preferenceXmlRes = R.xml.vector_settings_ignored_users
|
||||
|
||||
// displayed the ignored users list
|
||||
private val mIgnoredUserSettingsCategoryDivider by lazy {
|
||||
findPreference(PreferencesManager.SETTINGS_IGNORE_USERS_DIVIDER_PREFERENCE_KEY)
|
||||
}
|
||||
private val mIgnoredUserSettingsCategory by lazy {
|
||||
findPreference(PreferencesManager.SETTINGS_IGNORED_USERS_PREFERENCE_KEY) as PreferenceCategory
|
||||
}
|
||||
|
||||
override fun bindPref() {
|
||||
// Ignore users
|
||||
refreshIgnoredUsersList()
|
||||
}
|
||||
|
||||
//==============================================================================================================
|
||||
// ignored users list management
|
||||
//==============================================================================================================
|
||||
|
||||
/**
|
||||
* Refresh the ignored users list
|
||||
*/
|
||||
private fun refreshIgnoredUsersList() {
|
||||
val ignoredUsersList = mutableListOf<String>() // TODO session.dataHandler.ignoredUserIds
|
||||
|
||||
ignoredUsersList.sortWith(Comparator { u1, u2 ->
|
||||
u1.toLowerCase(VectorLocale.applicationLocale).compareTo(u2.toLowerCase(VectorLocale.applicationLocale))
|
||||
})
|
||||
|
||||
val preferenceScreen = preferenceScreen
|
||||
|
||||
preferenceScreen.removePreference(mIgnoredUserSettingsCategory)
|
||||
preferenceScreen.removePreference(mIgnoredUserSettingsCategoryDivider)
|
||||
mIgnoredUserSettingsCategory.removeAll()
|
||||
|
||||
if (ignoredUsersList.size > 0) {
|
||||
preferenceScreen.addPreference(mIgnoredUserSettingsCategoryDivider)
|
||||
preferenceScreen.addPreference(mIgnoredUserSettingsCategory)
|
||||
|
||||
for (userId in ignoredUsersList) {
|
||||
val preference = Preference(activity)
|
||||
|
||||
preference.title = userId
|
||||
preference.key = IGNORED_USER_KEY_BASE + userId
|
||||
|
||||
preference.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
activity?.let {
|
||||
AlertDialog.Builder(it)
|
||||
.setMessage(getString(R.string.settings_unignore_user, userId))
|
||||
.setPositiveButton(R.string.yes) { _, _ ->
|
||||
displayLoadingView()
|
||||
|
||||
val idsList = ArrayList<String>()
|
||||
idsList.add(userId)
|
||||
|
||||
notImplemented()
|
||||
/* TODO
|
||||
session.unIgnoreUsers(idsList, object : MatrixCallback<Unit> {
|
||||
override fun onSuccess(info: Void?) {
|
||||
onCommonDone(null)
|
||||
}
|
||||
|
||||
override fun onNetworkError(e: Exception) {
|
||||
onCommonDone(e.localizedMessage)
|
||||
}
|
||||
|
||||
override fun onMatrixError(e: MatrixError) {
|
||||
onCommonDone(e.localizedMessage)
|
||||
}
|
||||
|
||||
override fun onUnexpectedError(e: Exception) {
|
||||
onCommonDone(e.localizedMessage)
|
||||
}
|
||||
})
|
||||
*/
|
||||
}
|
||||
.setNegativeButton(R.string.no, null)
|
||||
.show()
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
mIgnoredUserSettingsCategory.addPreference(preference)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val IGNORED_USER_KEY_BASE = "IGNORED_USER_KEY_BASE"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
* Copyright 2019 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.riotredesign.features.settings
|
||||
|
||||
import android.text.TextUtils
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceCategory
|
||||
import androidx.preference.SwitchPreference
|
||||
import im.vector.riotredesign.R
|
||||
|
||||
class VectorSettingsLabs : VectorSettingsBaseFragment() {
|
||||
|
||||
override var titleRes = R.string.room_settings_labs_pref_title
|
||||
override val preferenceXmlRes = R.xml.vector_settings_labs
|
||||
|
||||
private val mLabsCategory by lazy {
|
||||
findPreference(PreferencesManager.SETTINGS_LABS_PREFERENCE_KEY) as PreferenceCategory
|
||||
}
|
||||
|
||||
override fun bindPref() {
|
||||
// Lab
|
||||
val useCryptoPref = findPreference(PreferencesManager.SETTINGS_ROOM_SETTINGS_LABS_END_TO_END_PREFERENCE_KEY) as SwitchPreference
|
||||
val cryptoIsEnabledPref = findPreference(PreferencesManager.SETTINGS_ROOM_SETTINGS_LABS_END_TO_END_IS_ACTIVE_PREFERENCE_KEY)
|
||||
|
||||
|
||||
if (mSession.isCryptoEnabled()) {
|
||||
mLabsCategory.removePreference(useCryptoPref)
|
||||
|
||||
cryptoIsEnabledPref.isEnabled = false
|
||||
} else {
|
||||
mLabsCategory.removePreference(cryptoIsEnabledPref)
|
||||
|
||||
useCryptoPref.isChecked = false
|
||||
|
||||
useCryptoPref.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValueAsVoid ->
|
||||
if (TextUtils.isEmpty(mSession.sessionParams.credentials.deviceId)) {
|
||||
activity?.let { activity ->
|
||||
AlertDialog.Builder(activity)
|
||||
.setMessage(R.string.room_settings_labs_end_to_end_warnings)
|
||||
.setPositiveButton(R.string.logout) { _, _ ->
|
||||
notImplemented()
|
||||
// TODO CommonActivityUtils.logout(activity)
|
||||
}
|
||||
.setNegativeButton(R.string.cancel) { _, _ ->
|
||||
useCryptoPref.isChecked = false
|
||||
}
|
||||
.setOnCancelListener {
|
||||
useCryptoPref.isChecked = false
|
||||
}
|
||||
.show()
|
||||
}
|
||||
} else {
|
||||
val newValue = newValueAsVoid as Boolean
|
||||
|
||||
if (mSession.isCryptoEnabled() != newValue) {
|
||||
notImplemented()
|
||||
/* TODO
|
||||
displayLoadingView()
|
||||
|
||||
session.enableCrypto(newValue, object : MatrixCallback<Unit> {
|
||||
private fun refresh() {
|
||||
activity?.runOnUiThread {
|
||||
hideLoadingView()
|
||||
useCryptoPref.isChecked = session.isCryptoEnabled
|
||||
|
||||
if (session.isCryptoEnabled) {
|
||||
mLabsCategory.removePreference(useCryptoPref)
|
||||
mLabsCategory.addPreference(cryptoIsEnabledPref)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSuccess(info: Void?) {
|
||||
useCryptoPref.isEnabled = false
|
||||
refresh()
|
||||
}
|
||||
|
||||
override fun onNetworkError(e: Exception) {
|
||||
useCryptoPref.isChecked = false
|
||||
}
|
||||
|
||||
override fun onMatrixError(e: MatrixError) {
|
||||
useCryptoPref.isChecked = false
|
||||
}
|
||||
|
||||
override fun onUnexpectedError(e: Exception) {
|
||||
useCryptoPref.isChecked = false
|
||||
}
|
||||
})
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
// SaveMode Management
|
||||
findPreference(PreferencesManager.SETTINGS_DATA_SAVE_MODE_PREFERENCE_KEY)
|
||||
.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue ->
|
||||
notImplemented()
|
||||
/* TODO
|
||||
val sessions = Matrix.getMXSessions(activity)
|
||||
for (session in sessions) {
|
||||
session.setUseDataSaveMode(newValue as Boolean)
|
||||
}
|
||||
*/
|
||||
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -16,28 +16,79 @@
|
|||
|
||||
package im.vector.riotredesign.features.settings
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.preference.EditTextPreference
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceCategory
|
||||
import androidx.preference.SwitchPreference
|
||||
import im.vector.matrix.android.api.Matrix
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.riotredesign.R
|
||||
import im.vector.riotredesign.core.platform.VectorPreferenceFragment
|
||||
import im.vector.riotredesign.core.preference.BingRule
|
||||
import im.vector.riotredesign.core.pushers.PushersManager
|
||||
import im.vector.riotredesign.push.fcm.FcmHelper
|
||||
import org.koin.android.ext.android.inject
|
||||
|
||||
// Referenced in vector_settings_preferences_root.xml
|
||||
class VectorSettingsNotificationPreferenceFragment : VectorPreferenceFragment() {
|
||||
class VectorSettingsNotificationPreferenceFragment : VectorSettingsBaseFragment() {
|
||||
|
||||
override var titleRes: Int = R.string.settings_notifications
|
||||
override val preferenceXmlRes = R.xml.vector_settings_notifications
|
||||
|
||||
val pushManager: PushersManager by inject()
|
||||
|
||||
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
addPreferencesFromResource(R.xml.vector_settings_notifications)
|
||||
// background sync category
|
||||
private val mSyncRequestTimeoutPreference by lazy {
|
||||
// ? Cause it can be removed
|
||||
findPreference(PreferencesManager.SETTINGS_SET_SYNC_TIMEOUT_PREFERENCE_KEY) as EditTextPreference?
|
||||
}
|
||||
private val mSyncRequestDelayPreference by lazy {
|
||||
// ? Cause it can be removed
|
||||
findPreference(PreferencesManager.SETTINGS_SET_SYNC_DELAY_PREFERENCE_KEY) as EditTextPreference?
|
||||
}
|
||||
|
||||
private val backgroundSyncCategory by lazy {
|
||||
findPreference(PreferencesManager.SETTINGS_BACKGROUND_SYNC_PREFERENCE_KEY)
|
||||
}
|
||||
private val backgroundSyncDivider by lazy {
|
||||
findPreference(PreferencesManager.SETTINGS_BACKGROUND_SYNC_DIVIDER_PREFERENCE_KEY)
|
||||
}
|
||||
private val backgroundSyncPreference by lazy {
|
||||
findPreference(PreferencesManager.SETTINGS_ENABLE_BACKGROUND_SYNC_PREFERENCE_KEY) as SwitchPreference
|
||||
}
|
||||
|
||||
private val notificationsSettingsCategory by lazy {
|
||||
findPreference(PreferencesManager.SETTINGS_NOTIFICATIONS_KEY) as PreferenceCategory
|
||||
}
|
||||
private val mNotificationPrivacyPreference by lazy {
|
||||
findPreference(PreferencesManager.SETTINGS_NOTIFICATION_PRIVACY_PREFERENCE_KEY)
|
||||
}
|
||||
|
||||
override fun bindPref() {
|
||||
// Notification privacy
|
||||
mNotificationPrivacyPreference.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
notImplemented()
|
||||
// TODO startActivity(NotificationPrivacyActivity.getIntent(activity))
|
||||
true
|
||||
}
|
||||
refreshNotificationPrivacy()
|
||||
|
||||
for (preferenceKey in mPrefKeyToBingRuleId.keys) {
|
||||
val preference = findPreference(preferenceKey)
|
||||
|
||||
if (null != preference) {
|
||||
if (preference is SwitchPreference) {
|
||||
preference.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValueAsVoid ->
|
||||
// on some old android APIs,
|
||||
// the callback is called even if there is no user interaction
|
||||
// so the value will be checked to ensure there is really no update.
|
||||
onPushRuleClick(preference.key, newValueAsVoid as Boolean)
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
|
@ -69,4 +120,221 @@ class VectorSettingsNotificationPreferenceFragment : VectorPreferenceFragment()
|
|||
}
|
||||
return super.onPreferenceTreeClick(preference)
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a push rule.
|
||||
*/
|
||||
private fun onPushRuleClick(preferenceKey: String, newValue: Boolean) {
|
||||
notImplemented()
|
||||
/* TODO
|
||||
val matrixInstance = Matrix.getInstance(context)
|
||||
val pushManager = matrixInstance.pushManager
|
||||
|
||||
Timber.v("onPushRuleClick $preferenceKey : set to $newValue")
|
||||
|
||||
when (preferenceKey) {
|
||||
|
||||
PreferencesManager.SETTINGS_TURN_SCREEN_ON_PREFERENCE_KEY -> {
|
||||
if (pushManager.isScreenTurnedOn != newValue) {
|
||||
pushManager.isScreenTurnedOn = newValue
|
||||
}
|
||||
}
|
||||
|
||||
PreferencesManager.SETTINGS_ENABLE_THIS_DEVICE_PREFERENCE_KEY -> {
|
||||
val isConnected = matrixInstance.isConnected
|
||||
val isAllowed = pushManager.areDeviceNotificationsAllowed()
|
||||
|
||||
// avoid useless update
|
||||
if (isAllowed == newValue) {
|
||||
return
|
||||
}
|
||||
|
||||
pushManager.setDeviceNotificationsAllowed(!isAllowed)
|
||||
|
||||
// when using FCM
|
||||
// need to register on servers
|
||||
if (isConnected && pushManager.useFcm() && (pushManager.isServerRegistered || pushManager.isServerUnRegistered)) {
|
||||
val listener = object : MatrixCallback<Unit> {
|
||||
|
||||
private fun onDone() {
|
||||
activity?.runOnUiThread {
|
||||
hideLoadingView(true)
|
||||
refreshPushersList()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSuccess(info: Void?) {
|
||||
onDone()
|
||||
}
|
||||
|
||||
override fun onMatrixError(e: MatrixError?) {
|
||||
// Set again the previous state
|
||||
pushManager.setDeviceNotificationsAllowed(isAllowed)
|
||||
onDone()
|
||||
}
|
||||
|
||||
override fun onNetworkError(e: java.lang.Exception?) {
|
||||
// Set again the previous state
|
||||
pushManager.setDeviceNotificationsAllowed(isAllowed)
|
||||
onDone()
|
||||
}
|
||||
|
||||
override fun onUnexpectedError(e: java.lang.Exception?) {
|
||||
// Set again the previous state
|
||||
pushManager.setDeviceNotificationsAllowed(isAllowed)
|
||||
onDone()
|
||||
}
|
||||
}
|
||||
|
||||
displayLoadingView()
|
||||
if (pushManager.isServerRegistered) {
|
||||
pushManager.unregister(listener)
|
||||
} else {
|
||||
pushManager.register(listener)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check if there is an update
|
||||
|
||||
// on some old android APIs,
|
||||
// the callback is called even if there is no user interaction
|
||||
// so the value will be checked to ensure there is really no update.
|
||||
else -> {
|
||||
|
||||
val ruleId = mPrefKeyToBingRuleId[preferenceKey]
|
||||
val rule = session.dataHandler.pushRules()?.findDefaultRule(ruleId)
|
||||
|
||||
// check if there is an update
|
||||
var curValue = null != rule && rule.isEnabled
|
||||
|
||||
if (TextUtils.equals(ruleId, BingRule.RULE_ID_DISABLE_ALL) || TextUtils.equals(ruleId, BingRule.RULE_ID_SUPPRESS_BOTS_NOTIFICATIONS)) {
|
||||
curValue = !curValue
|
||||
}
|
||||
|
||||
// on some old android APIs,
|
||||
// the callback is called even if there is no user interaction
|
||||
// so the value will be checked to ensure there is really no update.
|
||||
if (newValue == curValue) {
|
||||
return
|
||||
}
|
||||
|
||||
if (null != rule) {
|
||||
displayLoadingView()
|
||||
session.dataHandler.bingRulesManager.updateEnableRuleStatus(rule, !rule.isEnabled, object : BingRulesManager.onBingRuleUpdateListener {
|
||||
private fun onDone() {
|
||||
refreshDisplay()
|
||||
hideLoadingView()
|
||||
}
|
||||
|
||||
override fun onBingRuleUpdateSuccess() {
|
||||
onDone()
|
||||
}
|
||||
|
||||
override fun onBingRuleUpdateFailure(errorMessage: String) {
|
||||
activity?.toast(errorMessage)
|
||||
onDone()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh the notification privacy setting
|
||||
*/
|
||||
private fun refreshNotificationPrivacy() {
|
||||
/* TODO
|
||||
val pushManager = Matrix.getInstance(activity).pushManager
|
||||
|
||||
// this setting apply only with FCM for the moment
|
||||
if (pushManager.useFcm()) {
|
||||
val notificationPrivacyString = NotificationPrivacyActivity.getNotificationPrivacyString(activity,
|
||||
pushManager.notificationPrivacy)
|
||||
mNotificationPrivacyPreference.summary = notificationPrivacyString
|
||||
} else {
|
||||
notificationsSettingsCategory.removePreference(mNotificationPrivacyPreference)
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh the background sync preference
|
||||
*/
|
||||
private fun refreshBackgroundSyncPrefs() {
|
||||
/* TODO
|
||||
activity?.let { activity ->
|
||||
val pushManager = Matrix.getInstance(activity).pushManager
|
||||
|
||||
val timeout = pushManager.backgroundSyncTimeOut / 1000
|
||||
val delay = pushManager.backgroundSyncDelay / 1000
|
||||
|
||||
// update the settings
|
||||
PreferenceManager.getDefaultSharedPreferences(activity).edit {
|
||||
putString(PreferencesManager.SETTINGS_SET_SYNC_TIMEOUT_PREFERENCE_KEY, timeout.toString() + "")
|
||||
putString(PreferencesManager.SETTINGS_SET_SYNC_DELAY_PREFERENCE_KEY, delay.toString() + "")
|
||||
}
|
||||
|
||||
mSyncRequestTimeoutPreference?.let {
|
||||
it.summary = secondsToText(timeout)
|
||||
it.text = timeout.toString() + ""
|
||||
|
||||
it.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue ->
|
||||
var newTimeOut = timeout
|
||||
|
||||
try {
|
||||
newTimeOut = Integer.parseInt(newValue as String)
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "## refreshBackgroundSyncPrefs : parseInt failed " + e.message)
|
||||
}
|
||||
|
||||
if (newTimeOut != timeout) {
|
||||
pushManager.backgroundSyncTimeOut = newTimeOut * 1000
|
||||
|
||||
activity.runOnUiThread { refreshBackgroundSyncPrefs() }
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
mSyncRequestDelayPreference?.let {
|
||||
it.summary = secondsToText(delay)
|
||||
it.text = delay.toString() + ""
|
||||
|
||||
it.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue ->
|
||||
var newDelay = delay
|
||||
|
||||
try {
|
||||
newDelay = Integer.parseInt(newValue as String)
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "## refreshBackgroundSyncPrefs : parseInt failed " + e.message)
|
||||
}
|
||||
|
||||
if (newDelay != delay) {
|
||||
pushManager.backgroundSyncDelay = newDelay * 1000
|
||||
|
||||
activity.runOnUiThread { refreshBackgroundSyncPrefs() }
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val DUMMY_RULE = "DUMMY_RULE"
|
||||
|
||||
// preference name <-> rule Id
|
||||
private var mPrefKeyToBingRuleId = mapOf(
|
||||
PreferencesManager.SETTINGS_ENABLE_ALL_NOTIF_PREFERENCE_KEY to BingRule.RULE_ID_DISABLE_ALL,
|
||||
PreferencesManager.SETTINGS_ENABLE_THIS_DEVICE_PREFERENCE_KEY to DUMMY_RULE,
|
||||
PreferencesManager.SETTINGS_TURN_SCREEN_ON_PREFERENCE_KEY to DUMMY_RULE
|
||||
)
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,206 @@
|
|||
/*
|
||||
* Copyright 2019 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.riotredesign.features.settings
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.text.TextUtils
|
||||
import android.widget.CheckedTextView
|
||||
import android.widget.LinearLayout
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.SwitchPreference
|
||||
import im.vector.riotredesign.R
|
||||
import im.vector.riotredesign.features.configuration.VectorConfiguration
|
||||
import im.vector.riotredesign.features.themes.ThemeUtils
|
||||
import org.koin.android.ext.android.inject
|
||||
|
||||
class VectorSettingsPreferences : VectorSettingsBaseFragment() {
|
||||
|
||||
override var titleRes = R.string.settings_preferences
|
||||
override val preferenceXmlRes = R.xml.vector_settings_preferences
|
||||
|
||||
private val selectedLanguagePreference by lazy {
|
||||
findPreference(PreferencesManager.SETTINGS_INTERFACE_LANGUAGE_PREFERENCE_KEY)
|
||||
}
|
||||
private val textSizePreference by lazy {
|
||||
findPreference(PreferencesManager.SETTINGS_INTERFACE_TEXT_SIZE_KEY)
|
||||
}
|
||||
|
||||
private val vectorConfiguration by inject<VectorConfiguration>()
|
||||
|
||||
override fun bindPref() {
|
||||
// user interface preferences
|
||||
setUserInterfacePreferences()
|
||||
|
||||
// Themes
|
||||
findPreference(ThemeUtils.APPLICATION_THEME_KEY)
|
||||
.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue ->
|
||||
if (newValue is String) {
|
||||
vectorConfiguration.updateApplicationTheme(newValue)
|
||||
// Restart the Activity
|
||||
activity?.let {
|
||||
// Note: recreate does not apply the color correctly
|
||||
it.startActivity(it.intent)
|
||||
it.finish()
|
||||
}
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
// Url preview
|
||||
(findPreference(PreferencesManager.SETTINGS_SHOW_URL_PREVIEW_KEY) as SwitchPreference).let {
|
||||
/*
|
||||
TODO
|
||||
it.isChecked = session.isURLPreviewEnabled
|
||||
|
||||
it.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue ->
|
||||
if (null != newValue && newValue as Boolean != session.isURLPreviewEnabled) {
|
||||
displayLoadingView()
|
||||
session.setURLPreviewStatus(newValue, object : MatrixCallback<Unit> {
|
||||
override fun onSuccess(info: Void?) {
|
||||
it.isChecked = session.isURLPreviewEnabled
|
||||
hideLoadingView()
|
||||
}
|
||||
|
||||
private fun onError(errorMessage: String) {
|
||||
activity?.toast(errorMessage)
|
||||
|
||||
onSuccess(null)
|
||||
}
|
||||
|
||||
override fun onNetworkError(e: Exception) {
|
||||
onError(e.localizedMessage)
|
||||
}
|
||||
|
||||
override fun onMatrixError(e: MatrixError) {
|
||||
onError(e.localizedMessage)
|
||||
}
|
||||
|
||||
override fun onUnexpectedError(e: Exception) {
|
||||
onError(e.localizedMessage)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
// update keep medias period
|
||||
findPreference(PreferencesManager.SETTINGS_MEDIA_SAVING_PERIOD_KEY).let {
|
||||
it.summary = PreferencesManager.getSelectedMediasSavingPeriodString(activity)
|
||||
|
||||
it.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
context?.let { context: Context ->
|
||||
AlertDialog.Builder(context)
|
||||
.setSingleChoiceItems(R.array.media_saving_choice,
|
||||
PreferencesManager.getSelectedMediasSavingPeriod(activity)) { d, n ->
|
||||
PreferencesManager.setSelectedMediasSavingPeriod(activity, n)
|
||||
d.cancel()
|
||||
|
||||
it.summary = PreferencesManager.getSelectedMediasSavingPeriodString(activity)
|
||||
}
|
||||
.show()
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
when (requestCode) {
|
||||
REQUEST_LOCALE -> {
|
||||
activity?.let {
|
||||
startActivity(it.intent)
|
||||
it.finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//==============================================================================================================
|
||||
// user interface management
|
||||
//==============================================================================================================
|
||||
|
||||
private fun setUserInterfacePreferences() {
|
||||
// Selected language
|
||||
selectedLanguagePreference.summary = VectorLocale.localeToLocalisedString(VectorLocale.applicationLocale)
|
||||
|
||||
selectedLanguagePreference.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
notImplemented()
|
||||
// TODO startActivityForResult(LanguagePickerActivity.getIntent(activity), REQUEST_LOCALE)
|
||||
true
|
||||
}
|
||||
|
||||
// Text size
|
||||
textSizePreference.summary = FontScale.getFontScaleDescription(activity!!)
|
||||
|
||||
textSizePreference.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
activity?.let { displayTextSizeSelection(it) }
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
private fun displayTextSizeSelection(activity: Activity) {
|
||||
val inflater = activity.layoutInflater
|
||||
val layout = inflater.inflate(R.layout.dialog_select_text_size, null)
|
||||
|
||||
val dialog = AlertDialog.Builder(activity)
|
||||
.setTitle(R.string.font_size)
|
||||
.setView(layout)
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
.setNegativeButton(R.string.cancel, null)
|
||||
.show()
|
||||
|
||||
val linearLayout = layout.findViewById<LinearLayout>(R.id.text_selection_group_view)
|
||||
|
||||
val childCount = linearLayout.childCount
|
||||
|
||||
val scaleText = FontScale.getFontScaleDescription(activity)
|
||||
|
||||
for (i in 0 until childCount) {
|
||||
val v = linearLayout.getChildAt(i)
|
||||
|
||||
if (v is CheckedTextView) {
|
||||
v.isChecked = TextUtils.equals(v.text, scaleText)
|
||||
|
||||
v.setOnClickListener {
|
||||
dialog.dismiss()
|
||||
FontScale.updateFontScale(activity, v.text.toString())
|
||||
activity.startActivity(activity.intent)
|
||||
activity.finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val REQUEST_LOCALE = 777
|
||||
}
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -16,22 +16,20 @@
|
|||
|
||||
package im.vector.riotredesign.features.settings
|
||||
|
||||
import android.os.Bundle
|
||||
import im.vector.riotredesign.R
|
||||
import im.vector.riotredesign.core.extensions.withArgs
|
||||
import im.vector.riotredesign.core.platform.VectorPreferenceFragment
|
||||
|
||||
class VectorSettingsPreferencesFragmentV2 : VectorPreferenceFragment() {
|
||||
class VectorSettingsRoot : VectorSettingsBaseFragment() {
|
||||
|
||||
override var titleRes: Int = R.string.title_activity_settings
|
||||
override val preferenceXmlRes = R.xml.vector_settings_root
|
||||
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
addPreferencesFromResource(R.xml.vector_settings_root)
|
||||
override fun bindPref() {
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
|
||||
companion object {
|
||||
fun newInstance() = VectorSettingsPreferencesFragmentV2()
|
||||
fun newInstance() = VectorSettingsRoot()
|
||||
.withArgs {
|
||||
//putString(ARG_MATRIX_ID, matrixId)
|
||||
}
|
|
@ -0,0 +1,868 @@
|
|||
/*
|
||||
* Copyright 2019 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.riotredesign.features.settings
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.content.DialogInterface
|
||||
import android.content.Intent
|
||||
import android.graphics.Typeface
|
||||
import android.text.TextUtils
|
||||
import android.view.KeyEvent
|
||||
import android.view.View
|
||||
import android.widget.Button
|
||||
import android.widget.EditText
|
||||
import android.widget.TextView
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceCategory
|
||||
import androidx.preference.SwitchPreference
|
||||
import com.google.android.material.textfield.TextInputEditText
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.api.extensions.getFingerprintHumanReadable
|
||||
import im.vector.matrix.android.api.extensions.sortByLastSeen
|
||||
import im.vector.matrix.android.api.failure.Failure
|
||||
import im.vector.matrix.android.internal.auth.data.LoginFlowTypes
|
||||
import im.vector.matrix.android.internal.crypto.model.ImportRoomKeysResult
|
||||
import im.vector.matrix.android.internal.crypto.model.rest.DeviceInfo
|
||||
import im.vector.matrix.android.internal.crypto.model.rest.DevicesListResponse
|
||||
import im.vector.riotredesign.R
|
||||
import im.vector.riotredesign.core.dialogs.ExportKeysDialog
|
||||
import im.vector.riotredesign.core.intent.ExternalIntentData
|
||||
import im.vector.riotredesign.core.intent.analyseIntent
|
||||
import im.vector.riotredesign.core.intent.getFilenameFromUri
|
||||
import im.vector.riotredesign.core.platform.SimpleTextWatcher
|
||||
import im.vector.riotredesign.core.preference.ProgressBarPreference
|
||||
import im.vector.riotredesign.core.preference.VectorPreference
|
||||
import im.vector.riotredesign.core.utils.*
|
||||
import im.vector.riotredesign.features.crypto.keys.KeysExporter
|
||||
import im.vector.riotredesign.features.crypto.keys.KeysImporter
|
||||
import im.vector.riotredesign.features.crypto.keysbackup.settings.KeysBackupManageActivity
|
||||
import timber.log.Timber
|
||||
import java.text.DateFormat
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
class VectorSettingsSecurityPrivacy : VectorSettingsBaseFragment() {
|
||||
|
||||
override var titleRes = R.string.settings_security_and_privacy
|
||||
override val preferenceXmlRes = R.xml.vector_settings_security_privacy
|
||||
|
||||
// used to avoid requesting to enter the password for each deletion
|
||||
private var mAccountPassword: String = ""
|
||||
|
||||
// devices: device IDs and device names
|
||||
private var mDevicesNameList: List<DeviceInfo> = ArrayList()
|
||||
|
||||
private var mMyDeviceInfo: DeviceInfo? = null
|
||||
|
||||
|
||||
// cryptography
|
||||
private val mCryptographyCategory by lazy {
|
||||
findPreference(PreferencesManager.SETTINGS_CRYPTOGRAPHY_PREFERENCE_KEY) as PreferenceCategory
|
||||
}
|
||||
private val mCryptographyCategoryDivider by lazy {
|
||||
findPreference(PreferencesManager.SETTINGS_CRYPTOGRAPHY_DIVIDER_PREFERENCE_KEY)
|
||||
}
|
||||
// cryptography manage
|
||||
private val mCryptographyManageCategory by lazy {
|
||||
findPreference(PreferencesManager.SETTINGS_CRYPTOGRAPHY_MANAGE_PREFERENCE_KEY) as PreferenceCategory
|
||||
}
|
||||
private val mCryptographyManageCategoryDivider by lazy {
|
||||
findPreference(PreferencesManager.SETTINGS_CRYPTOGRAPHY_MANAGE_DIVIDER_PREFERENCE_KEY)
|
||||
}
|
||||
// displayed pushers
|
||||
private val mPushersSettingsDivider by lazy {
|
||||
findPreference(PreferencesManager.SETTINGS_NOTIFICATIONS_TARGET_DIVIDER_PREFERENCE_KEY)
|
||||
}
|
||||
private val mPushersSettingsCategory by lazy {
|
||||
findPreference(PreferencesManager.SETTINGS_NOTIFICATIONS_TARGETS_PREFERENCE_KEY) as PreferenceCategory
|
||||
}
|
||||
private val mDevicesListSettingsCategory by lazy {
|
||||
findPreference(PreferencesManager.SETTINGS_DEVICES_LIST_PREFERENCE_KEY) as PreferenceCategory
|
||||
}
|
||||
private val mDevicesListSettingsCategoryDivider by lazy {
|
||||
findPreference(PreferencesManager.SETTINGS_DEVICES_DIVIDER_PREFERENCE_KEY)
|
||||
}
|
||||
private val cryptoInfoDeviceNamePreference by lazy {
|
||||
findPreference(PreferencesManager.SETTINGS_ENCRYPTION_INFORMATION_DEVICE_NAME_PREFERENCE_KEY) as VectorPreference
|
||||
}
|
||||
|
||||
private val cryptoInfoDeviceIdPreference by lazy {
|
||||
findPreference(PreferencesManager.SETTINGS_ENCRYPTION_INFORMATION_DEVICE_ID_PREFERENCE_KEY)
|
||||
}
|
||||
|
||||
private val manageBackupPref by lazy {
|
||||
findPreference(PreferencesManager.SETTINGS_SECURE_MESSAGE_RECOVERY_PREFERENCE_KEY)
|
||||
}
|
||||
|
||||
private val exportPref by lazy {
|
||||
findPreference(PreferencesManager.SETTINGS_ENCRYPTION_EXPORT_E2E_ROOM_KEYS_PREFERENCE_KEY)
|
||||
}
|
||||
|
||||
private val importPref by lazy {
|
||||
findPreference(PreferencesManager.SETTINGS_ENCRYPTION_IMPORT_E2E_ROOM_KEYS_PREFERENCE_KEY)
|
||||
}
|
||||
|
||||
private val cryptoInfoTextPreference by lazy {
|
||||
findPreference(PreferencesManager.SETTINGS_ENCRYPTION_INFORMATION_DEVICE_KEY_PREFERENCE_KEY)
|
||||
}
|
||||
// encrypt to unverified devices
|
||||
private val sendToUnverifiedDevicesPref by lazy {
|
||||
findPreference(PreferencesManager.SETTINGS_ENCRYPTION_NEVER_SENT_TO_PREFERENCE_KEY) as SwitchPreference
|
||||
}
|
||||
|
||||
override fun bindPref() {
|
||||
// Push target
|
||||
refreshPushersList()
|
||||
|
||||
// Device list
|
||||
refreshDevicesList()
|
||||
|
||||
//Refresh Key Management section
|
||||
refreshKeysManagementSection()
|
||||
|
||||
// Analytics
|
||||
|
||||
// Analytics tracking management
|
||||
(findPreference(PreferencesManager.SETTINGS_USE_ANALYTICS_KEY) as SwitchPreference).let {
|
||||
// On if the analytics tracking is activated
|
||||
it.isChecked = PreferencesManager.useAnalytics(requireContext())
|
||||
|
||||
it.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue ->
|
||||
PreferencesManager.setUseAnalytics(requireContext(), newValue as Boolean)
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
// Rageshake Management
|
||||
(findPreference(PreferencesManager.SETTINGS_USE_RAGE_SHAKE_KEY) as SwitchPreference).let {
|
||||
it.isChecked = PreferencesManager.useRageshake(requireContext())
|
||||
|
||||
it.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue ->
|
||||
PreferencesManager.setUseRageshake(requireContext(), newValue as Boolean)
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
|
||||
if (allGranted(grantResults)) {
|
||||
if (requestCode == PERMISSION_REQUEST_CODE_EXPORT_KEYS) {
|
||||
exportKeys()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
when (requestCode) {
|
||||
REQUEST_E2E_FILE_REQUEST_CODE -> importKeys(data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun refreshKeysManagementSection() {
|
||||
//If crypto is not enabled parent section will be removed
|
||||
//TODO notice that this will not work when no network
|
||||
manageBackupPref.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
context?.let {
|
||||
startActivity(KeysBackupManageActivity.intent(it))
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
exportPref.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
exportKeys()
|
||||
true
|
||||
}
|
||||
|
||||
importPref.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
importKeys()
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Manage the e2e keys export.
|
||||
*/
|
||||
private fun exportKeys() {
|
||||
// We need WRITE_EXTERNAL permission
|
||||
if (checkPermissions(PERMISSIONS_FOR_WRITING_FILES, this, PERMISSION_REQUEST_CODE_EXPORT_KEYS)) {
|
||||
activity?.let { activity ->
|
||||
ExportKeysDialog().show(activity, object : ExportKeysDialog.ExportKeyDialogListener {
|
||||
override fun onPassphrase(passphrase: String) {
|
||||
displayLoadingView()
|
||||
|
||||
KeysExporter(mSession)
|
||||
.export(requireContext(),
|
||||
passphrase,
|
||||
object : MatrixCallback<String> {
|
||||
override fun onSuccess(data: String) {
|
||||
if (isAdded) {
|
||||
hideLoadingView()
|
||||
|
||||
AlertDialog.Builder(activity)
|
||||
.setMessage(getString(R.string.encryption_export_saved_as, data))
|
||||
.setCancelable(false)
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
.show()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailure(failure: Throwable) {
|
||||
onCommonDone(failure.localizedMessage)
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Manage the e2e keys import.
|
||||
*/
|
||||
@SuppressLint("NewApi")
|
||||
private fun importKeys() {
|
||||
activity?.let { openFileSelection(it, this, false, REQUEST_E2E_FILE_REQUEST_CODE) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Manage the e2e keys import.
|
||||
*
|
||||
* @param intent the intent result
|
||||
*/
|
||||
private fun importKeys(intent: Intent?) {
|
||||
// sanity check
|
||||
if (null == intent) {
|
||||
return
|
||||
}
|
||||
|
||||
val sharedDataItems = analyseIntent(intent)
|
||||
val thisActivity = activity
|
||||
|
||||
if (sharedDataItems.isNotEmpty() && thisActivity != null) {
|
||||
val sharedDataItem = sharedDataItems[0]
|
||||
|
||||
val uri = when (sharedDataItem) {
|
||||
is ExternalIntentData.IntentDataUri -> sharedDataItem.uri
|
||||
is ExternalIntentData.IntentDataClipData -> sharedDataItem.clipDataItem.uri
|
||||
else -> null
|
||||
}
|
||||
|
||||
val mimetype = when (sharedDataItem) {
|
||||
is ExternalIntentData.IntentDataClipData -> sharedDataItem.mimeType
|
||||
else -> null
|
||||
}
|
||||
|
||||
if (uri == null) {
|
||||
return
|
||||
}
|
||||
|
||||
val appContext = thisActivity.applicationContext
|
||||
|
||||
val filename = getFilenameFromUri(appContext, uri)
|
||||
|
||||
val dialogLayout = thisActivity.layoutInflater.inflate(R.layout.dialog_import_e2e_keys, null)
|
||||
|
||||
val textView = dialogLayout.findViewById<TextView>(R.id.dialog_e2e_keys_passphrase_filename)
|
||||
|
||||
if (filename.isNullOrBlank()) {
|
||||
textView.isVisible = false
|
||||
} else {
|
||||
textView.isVisible = true
|
||||
textView.text = getString(R.string.import_e2e_keys_from_file, filename)
|
||||
}
|
||||
|
||||
val builder = AlertDialog.Builder(thisActivity)
|
||||
.setTitle(R.string.encryption_import_room_keys)
|
||||
.setView(dialogLayout)
|
||||
|
||||
val passPhraseEditText = dialogLayout.findViewById<TextInputEditText>(R.id.dialog_e2e_keys_passphrase_edit_text)
|
||||
val importButton = dialogLayout.findViewById<Button>(R.id.dialog_e2e_keys_import_button)
|
||||
|
||||
passPhraseEditText.addTextChangedListener(object : SimpleTextWatcher() {
|
||||
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
|
||||
importButton.isEnabled = !TextUtils.isEmpty(passPhraseEditText.text)
|
||||
}
|
||||
})
|
||||
|
||||
val importDialog = builder.show()
|
||||
|
||||
importButton.setOnClickListener(View.OnClickListener {
|
||||
val password = passPhraseEditText.text.toString()
|
||||
|
||||
displayLoadingView()
|
||||
|
||||
KeysImporter(mSession)
|
||||
.import(requireContext(),
|
||||
uri,
|
||||
mimetype,
|
||||
password,
|
||||
object : MatrixCallback<ImportRoomKeysResult> {
|
||||
override fun onSuccess(data: ImportRoomKeysResult) {
|
||||
if (!isAdded) {
|
||||
return
|
||||
}
|
||||
|
||||
hideLoadingView()
|
||||
|
||||
AlertDialog.Builder(thisActivity)
|
||||
.setMessage(getString(R.string.encryption_import_room_keys_success,
|
||||
data.successfullyNumberOfImportedKeys,
|
||||
data.totalNumberOfKeys))
|
||||
.setPositiveButton(R.string.ok) { dialog, _ -> dialog.dismiss() }
|
||||
.show()
|
||||
}
|
||||
|
||||
override fun onFailure(failure: Throwable) {
|
||||
appContext.toast(failure.localizedMessage)
|
||||
hideLoadingView()
|
||||
}
|
||||
})
|
||||
|
||||
importDialog.dismiss()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================================================
|
||||
// Cryptography
|
||||
//==============================================================================================================
|
||||
|
||||
private fun removeCryptographyPreference() {
|
||||
preferenceScreen.let {
|
||||
it.removePreference(mCryptographyCategory)
|
||||
it.removePreference(mCryptographyCategoryDivider)
|
||||
|
||||
// Also remove keys management section
|
||||
it.removePreference(mCryptographyManageCategory)
|
||||
it.removePreference(mCryptographyManageCategoryDivider)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the cryptography preference section.
|
||||
*
|
||||
* @param aMyDeviceInfo the device info
|
||||
*/
|
||||
private fun refreshCryptographyPreference(aMyDeviceInfo: DeviceInfo?) {
|
||||
val userId = mSession.sessionParams.credentials.userId
|
||||
val deviceId = mSession.sessionParams.credentials.deviceId
|
||||
|
||||
// device name
|
||||
if (null != aMyDeviceInfo) {
|
||||
cryptoInfoDeviceNamePreference.summary = aMyDeviceInfo.displayName
|
||||
|
||||
cryptoInfoDeviceNamePreference.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
displayDeviceRenameDialog(aMyDeviceInfo)
|
||||
true
|
||||
}
|
||||
|
||||
cryptoInfoDeviceNamePreference.onPreferenceLongClickListener = object : VectorPreference.OnPreferenceLongClickListener {
|
||||
override fun onPreferenceLongClick(preference: Preference): Boolean {
|
||||
activity?.let { copyToClipboard(it, aMyDeviceInfo.displayName!!) }
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// crypto section: device ID
|
||||
if (!TextUtils.isEmpty(deviceId)) {
|
||||
cryptoInfoDeviceIdPreference.summary = deviceId
|
||||
|
||||
cryptoInfoDeviceIdPreference.setOnPreferenceClickListener {
|
||||
activity?.let { copyToClipboard(it, deviceId!!) }
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
// crypto section: device key (fingerprint)
|
||||
if (!TextUtils.isEmpty(deviceId) && !TextUtils.isEmpty(userId)) {
|
||||
val deviceInfo = mSession.getDeviceInfo(userId, deviceId)
|
||||
|
||||
if (null != deviceInfo && !TextUtils.isEmpty(deviceInfo.fingerprint())) {
|
||||
cryptoInfoTextPreference.summary = deviceInfo.getFingerprintHumanReadable()
|
||||
|
||||
cryptoInfoTextPreference.setOnPreferenceClickListener {
|
||||
deviceInfo.fingerprint()?.let {
|
||||
copyToClipboard(requireActivity(), it)
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sendToUnverifiedDevicesPref.isChecked = false
|
||||
|
||||
sendToUnverifiedDevicesPref.isChecked = mSession.getGlobalBlacklistUnverifiedDevices()
|
||||
|
||||
sendToUnverifiedDevicesPref.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
mSession.setGlobalBlacklistUnverifiedDevices(sendToUnverifiedDevicesPref.isChecked)
|
||||
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//==============================================================================================================
|
||||
// devices list
|
||||
//==============================================================================================================
|
||||
|
||||
private fun removeDevicesPreference() {
|
||||
preferenceScreen.let {
|
||||
it.removePreference(mDevicesListSettingsCategory)
|
||||
it.removePreference(mDevicesListSettingsCategoryDivider)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Force the refresh of the devices list.<br></br>
|
||||
* The devices list is the list of the devices where the user as looged in.
|
||||
* It can be any mobile device, as any browser.
|
||||
*/
|
||||
private fun refreshDevicesList() {
|
||||
if (mSession.isCryptoEnabled() && !TextUtils.isEmpty(mSession.sessionParams.credentials.deviceId)) {
|
||||
// display a spinner while loading the devices list
|
||||
if (0 == mDevicesListSettingsCategory.preferenceCount) {
|
||||
activity?.let {
|
||||
val preference = ProgressBarPreference(it)
|
||||
mDevicesListSettingsCategory.addPreference(preference)
|
||||
}
|
||||
}
|
||||
|
||||
mSession.getDevicesList(object : MatrixCallback<DevicesListResponse> {
|
||||
override fun onSuccess(data: DevicesListResponse) {
|
||||
if (!isAdded) {
|
||||
return
|
||||
}
|
||||
|
||||
if (data.devices?.isEmpty() == true) {
|
||||
removeDevicesPreference()
|
||||
} else {
|
||||
buildDevicesSettings(data.devices!!)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailure(failure: Throwable) {
|
||||
if (!isAdded) {
|
||||
return
|
||||
}
|
||||
|
||||
removeDevicesPreference()
|
||||
onCommonDone(failure.message)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
removeDevicesPreference()
|
||||
removeCryptographyPreference()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the devices portion of the settings.<br></br>
|
||||
* Each row correspond to a device ID and its corresponding device name. Clicking on the row
|
||||
* display a dialog containing: the device ID, the device name and the "last seen" information.
|
||||
*
|
||||
* @param aDeviceInfoList the list of the devices
|
||||
*/
|
||||
private fun buildDevicesSettings(aDeviceInfoList: List<DeviceInfo>) {
|
||||
var preference: VectorPreference
|
||||
var typeFaceHighlight: Int
|
||||
var isNewList = true
|
||||
val myDeviceId = mSession.sessionParams.credentials.deviceId
|
||||
|
||||
if (aDeviceInfoList.size == mDevicesNameList.size) {
|
||||
isNewList = !mDevicesNameList.containsAll(aDeviceInfoList)
|
||||
}
|
||||
|
||||
if (isNewList) {
|
||||
var prefIndex = 0
|
||||
mDevicesNameList = aDeviceInfoList
|
||||
|
||||
// sort before display: most recent first
|
||||
mDevicesNameList.sortByLastSeen()
|
||||
|
||||
// start from scratch: remove the displayed ones
|
||||
mDevicesListSettingsCategory.removeAll()
|
||||
|
||||
for (deviceInfo in mDevicesNameList) {
|
||||
// set bold to distinguish current device ID
|
||||
if (null != myDeviceId && myDeviceId == deviceInfo.deviceId) {
|
||||
mMyDeviceInfo = deviceInfo
|
||||
typeFaceHighlight = Typeface.BOLD
|
||||
} else {
|
||||
typeFaceHighlight = Typeface.NORMAL
|
||||
}
|
||||
|
||||
// add the edit text preference
|
||||
preference = VectorPreference(requireActivity()).apply {
|
||||
mTypeface = typeFaceHighlight
|
||||
}
|
||||
|
||||
if (null == deviceInfo.deviceId && null == deviceInfo.displayName) {
|
||||
continue
|
||||
} else {
|
||||
if (null != deviceInfo.deviceId) {
|
||||
preference.title = deviceInfo.deviceId
|
||||
}
|
||||
|
||||
// display name parameter can be null (new JSON API)
|
||||
if (null != deviceInfo.displayName) {
|
||||
preference.summary = deviceInfo.displayName
|
||||
}
|
||||
}
|
||||
|
||||
preference.key = DEVICES_PREFERENCE_KEY_BASE + prefIndex
|
||||
prefIndex++
|
||||
|
||||
// onClick handler: display device details dialog
|
||||
preference.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
displayDeviceDetailsDialog(deviceInfo)
|
||||
true
|
||||
}
|
||||
|
||||
mDevicesListSettingsCategory.addPreference(preference)
|
||||
}
|
||||
|
||||
refreshCryptographyPreference(mMyDeviceInfo)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a dialog containing the device ID, the device name and the "last seen" information.<>
|
||||
* This dialog allow to delete the corresponding device (see [.displayDeviceDeletionDialog])
|
||||
*
|
||||
* @param aDeviceInfo the device information
|
||||
*/
|
||||
private fun displayDeviceDetailsDialog(aDeviceInfo: DeviceInfo) {
|
||||
|
||||
activity?.let {
|
||||
|
||||
val builder = AlertDialog.Builder(it)
|
||||
val inflater = it.layoutInflater
|
||||
val layout = inflater.inflate(R.layout.dialog_device_details, null)
|
||||
var textView = layout.findViewById<TextView>(R.id.device_id)
|
||||
|
||||
textView.text = aDeviceInfo.deviceId
|
||||
|
||||
// device name
|
||||
textView = layout.findViewById(R.id.device_name)
|
||||
val displayName = if (TextUtils.isEmpty(aDeviceInfo.displayName)) LABEL_UNAVAILABLE_DATA else aDeviceInfo.displayName
|
||||
textView.text = displayName
|
||||
|
||||
// last seen info
|
||||
textView = layout.findViewById(R.id.device_last_seen)
|
||||
|
||||
val lastSeenIp = aDeviceInfo.lastSeenIp?.takeIf { ip -> ip.isNotBlank() } ?: "-"
|
||||
|
||||
val lastSeenTime = aDeviceInfo.lastSeenTs?.let { ts ->
|
||||
val dateFormatTime = SimpleDateFormat("HH:mm:ss")
|
||||
val date = Date(ts)
|
||||
|
||||
val time = dateFormatTime.format(date)
|
||||
val dateFormat = DateFormat.getDateInstance(DateFormat.SHORT, Locale.getDefault())
|
||||
|
||||
dateFormat.format(date) + ", " + time
|
||||
} ?: "-"
|
||||
|
||||
val lastSeenInfo = getString(R.string.devices_details_last_seen_format, lastSeenIp, lastSeenTime)
|
||||
textView.text = lastSeenInfo
|
||||
|
||||
// title & icon
|
||||
builder.setTitle(R.string.devices_details_dialog_title)
|
||||
.setIcon(android.R.drawable.ic_dialog_info)
|
||||
.setView(layout)
|
||||
.setPositiveButton(R.string.rename) { _, _ -> displayDeviceRenameDialog(aDeviceInfo) }
|
||||
|
||||
// disable the deletion for our own device
|
||||
if (!TextUtils.equals(mSession.getMyDevice()?.deviceId, aDeviceInfo.deviceId)) {
|
||||
builder.setNegativeButton(R.string.delete) { _, _ -> deleteDevice(aDeviceInfo) }
|
||||
}
|
||||
|
||||
builder.setNeutralButton(R.string.cancel, null)
|
||||
.setOnKeyListener(DialogInterface.OnKeyListener { dialog, keyCode, event ->
|
||||
if (event.action == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_BACK) {
|
||||
dialog.cancel()
|
||||
return@OnKeyListener true
|
||||
}
|
||||
false
|
||||
})
|
||||
.show()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Display an alert dialog to rename a device
|
||||
*
|
||||
* @param aDeviceInfoToRename device info
|
||||
*/
|
||||
private fun displayDeviceRenameDialog(aDeviceInfoToRename: DeviceInfo) {
|
||||
activity?.let {
|
||||
val inflater = it.layoutInflater
|
||||
val layout = inflater.inflate(R.layout.dialog_base_edit_text, null)
|
||||
|
||||
val input = layout.findViewById<EditText>(R.id.edit_text)
|
||||
input.setText(aDeviceInfoToRename.displayName)
|
||||
|
||||
AlertDialog.Builder(it)
|
||||
.setTitle(R.string.devices_details_device_name)
|
||||
.setView(layout)
|
||||
.setPositiveButton(R.string.ok) { _, _ ->
|
||||
displayLoadingView()
|
||||
|
||||
val newName = input.text.toString()
|
||||
|
||||
mSession.setDeviceName(aDeviceInfoToRename.deviceId!!, newName, object : MatrixCallback<Unit> {
|
||||
override fun onSuccess(data: Unit) {
|
||||
hideLoadingView()
|
||||
|
||||
// search which preference is updated
|
||||
val count = mDevicesListSettingsCategory.preferenceCount
|
||||
|
||||
for (i in 0 until count) {
|
||||
val pref = mDevicesListSettingsCategory.getPreference(i)
|
||||
|
||||
if (TextUtils.equals(aDeviceInfoToRename.deviceId, pref.title)) {
|
||||
pref.summary = newName
|
||||
}
|
||||
}
|
||||
|
||||
// detect if the updated device is the current account one
|
||||
if (TextUtils.equals(cryptoInfoDeviceIdPreference.summary, aDeviceInfoToRename.deviceId)) {
|
||||
cryptoInfoDeviceNamePreference.summary = newName
|
||||
}
|
||||
|
||||
// Also change the display name in aDeviceInfoToRename, in case of multiple renaming
|
||||
aDeviceInfoToRename.displayName = newName
|
||||
}
|
||||
|
||||
override fun onFailure(failure: Throwable) {
|
||||
onCommonDone(failure.localizedMessage)
|
||||
}
|
||||
})
|
||||
}
|
||||
.setNegativeButton(R.string.cancel, null)
|
||||
.show()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to delete a device.
|
||||
*
|
||||
* @param deviceInfo the device to delete
|
||||
*/
|
||||
private fun deleteDevice(deviceInfo: DeviceInfo) {
|
||||
val deviceId = deviceInfo.deviceId
|
||||
if (deviceId == null) {
|
||||
Timber.e("## displayDeviceDeletionDialog(): sanity check failure")
|
||||
return
|
||||
}
|
||||
|
||||
displayLoadingView()
|
||||
mSession.deleteDevice(deviceId, object : MatrixCallback<Unit> {
|
||||
override fun onSuccess(data: Unit) {
|
||||
hideLoadingView()
|
||||
// force settings update
|
||||
refreshDevicesList()
|
||||
}
|
||||
|
||||
override fun onFailure(failure: Throwable) {
|
||||
var isPasswordRequestFound = false
|
||||
|
||||
if (failure is Failure.RegistrationFlowError) {
|
||||
// We only support LoginFlowTypes.PASSWORD
|
||||
// Check if we can provide the user password
|
||||
failure.registrationFlowResponse.flows?.forEach { interactiveAuthenticationFlow ->
|
||||
isPasswordRequestFound = isPasswordRequestFound || interactiveAuthenticationFlow.stages?.any { it == LoginFlowTypes.PASSWORD } == true
|
||||
}
|
||||
|
||||
if (isPasswordRequestFound) {
|
||||
maybeShowDeleteDeviceWithPasswordDialog(deviceId, failure.registrationFlowResponse.session)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!isPasswordRequestFound) {
|
||||
// LoginFlowTypes.PASSWORD not supported, and this is the only one RiotX supports so far...
|
||||
onCommonDone(failure.localizedMessage)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a dialog to ask for user password, or use a previously entered password.
|
||||
*/
|
||||
private fun maybeShowDeleteDeviceWithPasswordDialog(deviceId: String, authSession: String?) {
|
||||
if (!TextUtils.isEmpty(mAccountPassword)) {
|
||||
deleteDeviceWithPassword(deviceId, authSession, mAccountPassword)
|
||||
} else {
|
||||
activity?.let {
|
||||
val inflater = it.layoutInflater
|
||||
val layout = inflater.inflate(R.layout.dialog_device_delete, null)
|
||||
val passwordEditText = layout.findViewById<EditText>(R.id.delete_password)
|
||||
|
||||
AlertDialog.Builder(it)
|
||||
.setIcon(android.R.drawable.ic_dialog_alert)
|
||||
.setTitle(R.string.devices_delete_dialog_title)
|
||||
.setView(layout)
|
||||
.setPositiveButton(R.string.devices_delete_submit_button_label, DialogInterface.OnClickListener { _, _ ->
|
||||
if (TextUtils.isEmpty(passwordEditText.toString())) {
|
||||
it.toast(R.string.error_empty_field_your_password)
|
||||
return@OnClickListener
|
||||
}
|
||||
mAccountPassword = passwordEditText.text.toString()
|
||||
deleteDeviceWithPassword(deviceId, authSession, mAccountPassword)
|
||||
})
|
||||
.setNegativeButton(R.string.cancel) { _, _ ->
|
||||
hideLoadingView()
|
||||
}
|
||||
.setOnKeyListener(DialogInterface.OnKeyListener { dialog, keyCode, event ->
|
||||
if (event.action == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_BACK) {
|
||||
dialog.cancel()
|
||||
hideLoadingView()
|
||||
return@OnKeyListener true
|
||||
}
|
||||
false
|
||||
})
|
||||
.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun deleteDeviceWithPassword(deviceId: String, authSession: String?, accountPassword: String) {
|
||||
mSession.deleteDeviceWithUserPassword(deviceId, authSession, accountPassword, object : MatrixCallback<Unit> {
|
||||
override fun onSuccess(data: Unit) {
|
||||
hideLoadingView()
|
||||
// force settings update
|
||||
refreshDevicesList()
|
||||
}
|
||||
|
||||
override fun onFailure(failure: Throwable) {
|
||||
// Password is maybe not good
|
||||
onCommonDone(failure.localizedMessage)
|
||||
mAccountPassword = ""
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
//==============================================================================================================
|
||||
// pushers list management
|
||||
//==============================================================================================================
|
||||
|
||||
/**
|
||||
* Refresh the pushers list
|
||||
*/
|
||||
private fun refreshPushersList() {
|
||||
activity?.let { activity ->
|
||||
/* TODO
|
||||
val pushManager = Matrix.getInstance(activity).pushManager
|
||||
val pushersList = ArrayList(pushManager.mPushersList)
|
||||
|
||||
if (pushersList.isEmpty()) {
|
||||
preferenceScreen.removePreference(mPushersSettingsCategory)
|
||||
preferenceScreen.removePreference(mPushersSettingsDivider)
|
||||
return
|
||||
}
|
||||
|
||||
// check first if there is an update
|
||||
var isNewList = true
|
||||
if (pushersList.size == mDisplayedPushers.size) {
|
||||
isNewList = !mDisplayedPushers.containsAll(pushersList)
|
||||
}
|
||||
|
||||
if (isNewList) {
|
||||
// remove the displayed one
|
||||
mPushersSettingsCategory.removeAll()
|
||||
|
||||
// add new emails list
|
||||
mDisplayedPushers = pushersList
|
||||
|
||||
var index = 0
|
||||
|
||||
for (pushRule in mDisplayedPushers) {
|
||||
if (null != pushRule.lang) {
|
||||
val isThisDeviceTarget = TextUtils.equals(pushManager.currentRegistrationToken, pushRule.pushkey)
|
||||
|
||||
val preference = VectorPreference(activity).apply {
|
||||
mTypeface = if (isThisDeviceTarget) Typeface.BOLD else Typeface.NORMAL
|
||||
}
|
||||
preference.title = pushRule.deviceDisplayName
|
||||
preference.summary = pushRule.appDisplayName
|
||||
preference.key = PUSHER_PREFERENCE_KEY_BASE + index
|
||||
index++
|
||||
mPushersSettingsCategory.addPreference(preference)
|
||||
|
||||
// the user cannot remove the self device target
|
||||
if (!isThisDeviceTarget) {
|
||||
preference.onPreferenceLongClickListener = object : VectorPreference.OnPreferenceLongClickListener {
|
||||
override fun onPreferenceLongClick(preference: Preference): Boolean {
|
||||
AlertDialog.Builder(activity)
|
||||
.setTitle(R.string.dialog_title_confirmation)
|
||||
.setMessage(R.string.settings_delete_notification_targets_confirmation)
|
||||
.setPositiveButton(R.string.remove)
|
||||
{ _, _ ->
|
||||
displayLoadingView()
|
||||
pushManager.unregister(session, pushRule, object : MatrixCallback<Unit> {
|
||||
override fun onSuccess(info: Void?) {
|
||||
refreshPushersList()
|
||||
onCommonDone(null)
|
||||
}
|
||||
|
||||
override fun onNetworkError(e: Exception) {
|
||||
onCommonDone(e.localizedMessage)
|
||||
}
|
||||
|
||||
override fun onMatrixError(e: MatrixError) {
|
||||
onCommonDone(e.localizedMessage)
|
||||
}
|
||||
|
||||
override fun onUnexpectedError(e: Exception) {
|
||||
onCommonDone(e.localizedMessage)
|
||||
}
|
||||
})
|
||||
}
|
||||
.setNegativeButton(R.string.cancel, null)
|
||||
.show()
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val REQUEST_E2E_FILE_REQUEST_CODE = 123
|
||||
|
||||
private const val PUSHER_PREFERENCE_KEY_BASE = "PUSHER_PREFERENCE_KEY_BASE"
|
||||
private const val DEVICES_PREFERENCE_KEY_BASE = "DEVICES_PREFERENCE_KEY_BASE"
|
||||
|
||||
// TODO i18n
|
||||
private const val LABEL_UNAVAILABLE_DATA = "none"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* Copyright 2019 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.riotredesign.features.settings
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.media.RingtoneManager
|
||||
import android.net.Uri
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.SwitchPreference
|
||||
import im.vector.riotredesign.R
|
||||
import im.vector.riotredesign.core.utils.getCallRingtoneName
|
||||
import im.vector.riotredesign.core.utils.getCallRingtoneUri
|
||||
import im.vector.riotredesign.core.utils.setCallRingtoneUri
|
||||
import im.vector.riotredesign.core.utils.setUseRiotDefaultRingtone
|
||||
|
||||
class VectorSettingsVoiceVideo : VectorSettingsBaseFragment() {
|
||||
|
||||
override var titleRes = R.string.preference_voice_and_video
|
||||
override val preferenceXmlRes = R.xml.vector_settings_voice_video
|
||||
|
||||
private val mUseRiotCallRingtonePreference by lazy {
|
||||
findPreference(PreferencesManager.SETTINGS_CALL_RINGTONE_USE_RIOT_PREFERENCE_KEY) as SwitchPreference
|
||||
}
|
||||
private val mCallRingtonePreference by lazy {
|
||||
findPreference(PreferencesManager.SETTINGS_CALL_RINGTONE_URI_PREFERENCE_KEY)
|
||||
}
|
||||
|
||||
override fun bindPref() {
|
||||
// Incoming call sounds
|
||||
mUseRiotCallRingtonePreference.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
activity?.let { setUseRiotDefaultRingtone(it, mUseRiotCallRingtonePreference.isChecked) }
|
||||
false
|
||||
}
|
||||
|
||||
mCallRingtonePreference.let {
|
||||
activity?.let { activity -> it.summary = getCallRingtoneName(activity) }
|
||||
it.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
displayRingtonePicker()
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
when (requestCode) {
|
||||
REQUEST_CALL_RINGTONE -> {
|
||||
val callRingtoneUri: Uri? = data?.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI)
|
||||
val thisActivity = activity
|
||||
if (callRingtoneUri != null && thisActivity != null) {
|
||||
setCallRingtoneUri(thisActivity, callRingtoneUri)
|
||||
mCallRingtonePreference.summary = getCallRingtoneName(thisActivity)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun displayRingtonePicker() {
|
||||
val intent = Intent(RingtoneManager.ACTION_RINGTONE_PICKER).apply {
|
||||
putExtra(RingtoneManager.EXTRA_RINGTONE_TITLE, getString(R.string.settings_call_ringtone_dialog_title))
|
||||
putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_SILENT, false)
|
||||
putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_DEFAULT, true)
|
||||
putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, RingtoneManager.TYPE_RINGTONE)
|
||||
activity?.let { putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, getCallRingtoneUri(it)) }
|
||||
}
|
||||
startActivityForResult(intent, REQUEST_CALL_RINGTONE)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val REQUEST_CALL_RINGTONE = 999
|
||||
}
|
||||
|
||||
}
|
|
@ -1,12 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.preference.PreferenceScreen 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">
|
||||
<androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<im.vector.riotredesign.core.preference.VectorPreferenceCategory
|
||||
android:key="SETTINGS_GROUPS_FLAIR_KEY"
|
||||
android:title="@string/settings_flair" />
|
||||
|
||||
<im.vector.riotredesign.core.preference.VectorPreferenceDivider />
|
||||
|
||||
</androidx.preference.PreferenceScreen>
|
|
@ -6,13 +6,13 @@
|
|||
android:layout_width="match_parent"
|
||||
android:icon="@drawable/ic_settings_root_general"
|
||||
android:title="@string/settings_general_title"
|
||||
app:fragment="com.example.SyncFragment" />
|
||||
app:fragment="im.vector.riotredesign.features.settings.VectorSettingsGeneral" />
|
||||
|
||||
<im.vector.riotredesign.core.preference.VectorPreference
|
||||
android:layout_width="match_parent"
|
||||
android:icon="@drawable/ic_settings_root_flair"
|
||||
android:title="@string/settings_flair"
|
||||
app:fragment="com.example.SyncFragment" />
|
||||
app:fragment="im.vector.riotredesign.features.settings.VectorSettingsFlair" />
|
||||
|
||||
<im.vector.riotredesign.core.preference.VectorPreference
|
||||
android:layout_width="match_parent"
|
||||
|
@ -25,43 +25,37 @@
|
|||
android:layout_width="match_parent"
|
||||
android:icon="@drawable/ic_settings_root_preferences"
|
||||
android:title="@string/settings_preferences"
|
||||
app:fragment="com.example.SyncFragment" />
|
||||
app:fragment="im.vector.riotredesign.features.settings.VectorSettingsPreferences" />
|
||||
|
||||
<im.vector.riotredesign.core.preference.VectorPreference
|
||||
android:layout_width="match_parent"
|
||||
android:icon="@drawable/ic_settings_root_call"
|
||||
android:title="@string/preference_voice_and_video"
|
||||
app:fragment="com.example.SyncFragment" />
|
||||
app:fragment="im.vector.riotredesign.features.settings.VectorSettingsVoiceVideo" />
|
||||
|
||||
<!-- TODO Ignored users -->
|
||||
<!-- TODO Ignored users icon -->
|
||||
<im.vector.riotredesign.core.preference.VectorPreference
|
||||
android:layout_width="match_parent"
|
||||
android:icon="@drawable/ic_settings_root_security_privacy"
|
||||
android:icon="@drawable/ic_settings_root_legacy"
|
||||
android:title="@string/settings_ignored_users"
|
||||
app:fragment="com.example.SyncFragment" />
|
||||
app:fragment="im.vector.riotredesign.features.settings.VectorSettingsIgnoredUsers" />
|
||||
|
||||
<im.vector.riotredesign.core.preference.VectorPreference
|
||||
android:layout_width="match_parent"
|
||||
android:icon="@drawable/ic_settings_root_security_privacy"
|
||||
android:title="@string/settings_security_and_privacy"
|
||||
app:fragment="com.example.SyncFragment" />
|
||||
app:fragment="im.vector.riotredesign.features.settings.VectorSettingsSecurityPrivacy" />
|
||||
|
||||
<im.vector.riotredesign.core.preference.VectorPreference
|
||||
android:layout_width="match_parent"
|
||||
android:icon="@drawable/ic_settings_root_labs"
|
||||
android:title="@string/room_settings_labs_pref_title"
|
||||
app:fragment="com.example.SyncFragment" />
|
||||
|
||||
<im.vector.riotredesign.core.preference.VectorPreference
|
||||
android:layout_width="match_parent"
|
||||
android:icon="@drawable/ic_settings_root_legacy"
|
||||
android:title="@string/preference_root_legacy"
|
||||
app:fragment="com.example.SyncFragment" />
|
||||
app:fragment="im.vector.riotredesign.features.settings.VectorSettingsLabs" />
|
||||
|
||||
<im.vector.riotredesign.core.preference.VectorPreference
|
||||
android:layout_width="match_parent"
|
||||
android:icon="@drawable/ic_settings_root_help_about"
|
||||
android:title="@string/preference_root_help_about"
|
||||
app:fragment="com.example.SyncFragment" />
|
||||
app:fragment="im.vector.riotredesign.features.settings.VectorSettingsHelpAbout" />
|
||||
|
||||
</androidx.preference.PreferenceScreen>
|
|
@ -72,6 +72,4 @@
|
|||
android:title="@string/send_bug_report_rage_shake" />
|
||||
</im.vector.riotredesign.core.preference.VectorPreferenceCategory>
|
||||
|
||||
<im.vector.riotredesign.core.preference.VectorPreferenceDivider />
|
||||
|
||||
</androidx.preference.PreferenceScreen>
|
Loading…
Reference in a new issue