mirror of
https://github.com/SchildiChat/SchildiChat-android.git
synced 2024-11-25 02:45:53 +03:00
parent
a03f69fb98
commit
16bd642ae8
8 changed files with 301 additions and 61 deletions
|
@ -10,6 +10,7 @@ Improvements 🙌:
|
||||||
- Handle `/op`, `/deop`, and `/nick` commands (#12)
|
- Handle `/op`, `/deop`, and `/nick` commands (#12)
|
||||||
- Prioritising Recovery key over Recovery passphrase (#1463)
|
- Prioritising Recovery key over Recovery passphrase (#1463)
|
||||||
- Room Settings: Name, Topic, Photo, Aliases, History Visibility (#1455)
|
- Room Settings: Name, Topic, Photo, Aliases, History Visibility (#1455)
|
||||||
|
- Update user avatar (#1054)
|
||||||
|
|
||||||
Bugfix 🐛:
|
Bugfix 🐛:
|
||||||
- Fix dark theme issue on login screen (#1097)
|
- Fix dark theme issue on login screen (#1097)
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
|
|
||||||
package im.vector.matrix.android.api.session.profile
|
package im.vector.matrix.android.api.session.profile
|
||||||
|
|
||||||
|
import android.net.Uri
|
||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.LiveData
|
||||||
import im.vector.matrix.android.api.MatrixCallback
|
import im.vector.matrix.android.api.MatrixCallback
|
||||||
import im.vector.matrix.android.api.session.identity.ThreePid
|
import im.vector.matrix.android.api.session.identity.ThreePid
|
||||||
|
@ -48,6 +49,14 @@ interface ProfileService {
|
||||||
*/
|
*/
|
||||||
fun setDisplayName(userId: String, newDisplayName: String, matrixCallback: MatrixCallback<Unit>): Cancelable
|
fun setDisplayName(userId: String, newDisplayName: String, matrixCallback: MatrixCallback<Unit>): Cancelable
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the avatar for this user
|
||||||
|
* @param userId the userId to update the avatar of
|
||||||
|
* @param newAvatarUri the new avatar uri of the user
|
||||||
|
* @param fileName the fileName of selected image
|
||||||
|
*/
|
||||||
|
fun updateAvatar(userId: String, newAvatarUri: Uri, fileName: String, matrixCallback: MatrixCallback<Unit>): Cancelable
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the current avatarUrl for this user.
|
* Return the current avatarUrl for this user.
|
||||||
* @param userId the userId param to look for
|
* @param userId the userId param to look for
|
||||||
|
|
|
@ -17,26 +17,44 @@
|
||||||
|
|
||||||
package im.vector.matrix.android.internal.session.profile
|
package im.vector.matrix.android.internal.session.profile
|
||||||
|
|
||||||
|
import android.net.Uri
|
||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.LiveData
|
||||||
|
import androidx.work.BackoffPolicy
|
||||||
|
import androidx.work.ExistingWorkPolicy
|
||||||
import com.zhuinden.monarchy.Monarchy
|
import com.zhuinden.monarchy.Monarchy
|
||||||
import im.vector.matrix.android.api.MatrixCallback
|
import im.vector.matrix.android.api.MatrixCallback
|
||||||
import im.vector.matrix.android.api.session.identity.ThreePid
|
import im.vector.matrix.android.api.session.identity.ThreePid
|
||||||
import im.vector.matrix.android.api.session.profile.ProfileService
|
import im.vector.matrix.android.api.session.profile.ProfileService
|
||||||
import im.vector.matrix.android.api.util.Cancelable
|
import im.vector.matrix.android.api.util.Cancelable
|
||||||
|
import im.vector.matrix.android.api.util.CancelableBag
|
||||||
import im.vector.matrix.android.api.util.JsonDict
|
import im.vector.matrix.android.api.util.JsonDict
|
||||||
import im.vector.matrix.android.api.util.Optional
|
import im.vector.matrix.android.api.util.Optional
|
||||||
import im.vector.matrix.android.internal.database.model.UserThreePidEntity
|
import im.vector.matrix.android.internal.database.model.UserThreePidEntity
|
||||||
import im.vector.matrix.android.internal.di.SessionDatabase
|
import im.vector.matrix.android.internal.di.SessionDatabase
|
||||||
|
import im.vector.matrix.android.internal.di.SessionId
|
||||||
|
import im.vector.matrix.android.internal.di.WorkManagerProvider
|
||||||
|
import im.vector.matrix.android.internal.session.content.UploadAvatarWorker
|
||||||
import im.vector.matrix.android.internal.task.TaskExecutor
|
import im.vector.matrix.android.internal.task.TaskExecutor
|
||||||
import im.vector.matrix.android.internal.task.configureWith
|
import im.vector.matrix.android.internal.task.configureWith
|
||||||
|
import im.vector.matrix.android.internal.util.CancelableWork
|
||||||
|
import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers
|
||||||
|
import im.vector.matrix.android.internal.worker.WorkerParamsFactory
|
||||||
import io.realm.kotlin.where
|
import io.realm.kotlin.where
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
private const val UPLOAD_AVATAR_WORK = "UPLOAD_AVATAR_WORK"
|
||||||
|
|
||||||
internal class DefaultProfileService @Inject constructor(private val taskExecutor: TaskExecutor,
|
internal class DefaultProfileService @Inject constructor(private val taskExecutor: TaskExecutor,
|
||||||
@SessionDatabase private val monarchy: Monarchy,
|
@SessionDatabase private val monarchy: Monarchy,
|
||||||
|
@SessionId private val sessionId: String,
|
||||||
|
private val workManagerProvider: WorkManagerProvider,
|
||||||
|
private val coroutineDispatchers: MatrixCoroutineDispatchers,
|
||||||
private val refreshUserThreePidsTask: RefreshUserThreePidsTask,
|
private val refreshUserThreePidsTask: RefreshUserThreePidsTask,
|
||||||
private val getProfileInfoTask: GetProfileInfoTask,
|
private val getProfileInfoTask: GetProfileInfoTask,
|
||||||
private val setDisplayNameTask: SetDisplayNameTask) : ProfileService {
|
private val setDisplayNameTask: SetDisplayNameTask,
|
||||||
|
private val setAvatarUrlTask: SetAvatarUrlTask) : ProfileService {
|
||||||
|
|
||||||
override fun getDisplayName(userId: String, matrixCallback: MatrixCallback<Optional<String>>): Cancelable {
|
override fun getDisplayName(userId: String, matrixCallback: MatrixCallback<Optional<String>>): Cancelable {
|
||||||
val params = GetProfileInfoTask.Params(userId)
|
val params = GetProfileInfoTask.Params(userId)
|
||||||
|
@ -64,6 +82,41 @@ internal class DefaultProfileService @Inject constructor(private val taskExecuto
|
||||||
.executeBy(taskExecutor)
|
.executeBy(taskExecutor)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun updateAvatar(userId: String, newAvatarUri: Uri, fileName: String, matrixCallback: MatrixCallback<Unit>): Cancelable {
|
||||||
|
val cancelableBag = CancelableBag()
|
||||||
|
val workerParams = UploadAvatarWorker.Params(sessionId, newAvatarUri, fileName)
|
||||||
|
val workerData = WorkerParamsFactory.toData(workerParams)
|
||||||
|
|
||||||
|
val uploadAvatarWork = workManagerProvider.matrixOneTimeWorkRequestBuilder<UploadAvatarWorker>()
|
||||||
|
.setConstraints(WorkManagerProvider.workConstraints)
|
||||||
|
.setInputData(workerData)
|
||||||
|
.setBackoffCriteria(BackoffPolicy.LINEAR, WorkManagerProvider.BACKOFF_DELAY, TimeUnit.MILLISECONDS)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
workManagerProvider.workManager
|
||||||
|
.beginUniqueWork("${userId}_$UPLOAD_AVATAR_WORK", ExistingWorkPolicy.REPLACE, uploadAvatarWork)
|
||||||
|
.enqueue()
|
||||||
|
|
||||||
|
cancelableBag.add(CancelableWork(workManagerProvider.workManager, uploadAvatarWork.id))
|
||||||
|
|
||||||
|
taskExecutor.executorScope.launch(coroutineDispatchers.main) {
|
||||||
|
workManagerProvider.workManager.getWorkInfoByIdLiveData(uploadAvatarWork.id)
|
||||||
|
.observeForever { info ->
|
||||||
|
if (info != null && info.state.isFinished) {
|
||||||
|
val result = WorkerParamsFactory.fromData<UploadAvatarWorker.OutputParams>(info.outputData)
|
||||||
|
cancelableBag.add(
|
||||||
|
setAvatarUrlTask
|
||||||
|
.configureWith(SetAvatarUrlTask.Params(userId = userId, newAvatarUrl = result?.imageUrl!!)) {
|
||||||
|
callback = matrixCallback
|
||||||
|
}
|
||||||
|
.executeBy(taskExecutor)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cancelableBag
|
||||||
|
}
|
||||||
|
|
||||||
override fun getAvatarUrl(userId: String, matrixCallback: MatrixCallback<Optional<String>>): Cancelable {
|
override fun getAvatarUrl(userId: String, matrixCallback: MatrixCallback<Optional<String>>): Cancelable {
|
||||||
val params = GetProfileInfoTask.Params(userId)
|
val params = GetProfileInfoTask.Params(userId)
|
||||||
return getProfileInfoTask
|
return getProfileInfoTask
|
||||||
|
|
|
@ -49,6 +49,12 @@ internal interface ProfileAPI {
|
||||||
@PUT(NetworkConstants.URI_API_PREFIX_PATH_R0 + "profile/{userId}/displayname")
|
@PUT(NetworkConstants.URI_API_PREFIX_PATH_R0 + "profile/{userId}/displayname")
|
||||||
fun setDisplayName(@Path("userId") userId: String, @Body body: SetDisplayNameBody): Call<Unit>
|
fun setDisplayName(@Path("userId") userId: String, @Body body: SetDisplayNameBody): Call<Unit>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Change user avatar url.
|
||||||
|
*/
|
||||||
|
@PUT(NetworkConstants.URI_API_PREFIX_PATH_R0 + "profile/{userId}/avatar_url")
|
||||||
|
fun setAvatarUrl(@Path("userId") userId: String, @Body body: SetAvatarUrlBody): Call<Unit>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bind a threePid
|
* Bind a threePid
|
||||||
* Ref: https://matrix.org/docs/spec/client_server/latest#post-matrix-client-r0-account-3pid-bind
|
* Ref: https://matrix.org/docs/spec/client_server/latest#post-matrix-client-r0-account-3pid-bind
|
||||||
|
|
|
@ -54,4 +54,7 @@ internal abstract class ProfileModule {
|
||||||
|
|
||||||
@Binds
|
@Binds
|
||||||
abstract fun bindSetDisplayNameTask(task: DefaultSetDisplayNameTask): SetDisplayNameTask
|
abstract fun bindSetDisplayNameTask(task: DefaultSetDisplayNameTask): SetDisplayNameTask
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
abstract fun bindSetAvatarUrlTask(task: DefaultSetAvatarUrlTask): SetAvatarUrlTask
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 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.matrix.android.internal.session.profile
|
||||||
|
|
||||||
|
import com.squareup.moshi.Json
|
||||||
|
import com.squareup.moshi.JsonClass
|
||||||
|
|
||||||
|
@JsonClass(generateAdapter = true)
|
||||||
|
internal data class SetAvatarUrlBody(
|
||||||
|
/**
|
||||||
|
* The new avatar url for this user.
|
||||||
|
*/
|
||||||
|
@Json(name = "avatar_url")
|
||||||
|
val avatarUrl: String
|
||||||
|
)
|
|
@ -0,0 +1,43 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 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.matrix.android.internal.session.profile
|
||||||
|
|
||||||
|
import im.vector.matrix.android.internal.network.executeRequest
|
||||||
|
import im.vector.matrix.android.internal.task.Task
|
||||||
|
import org.greenrobot.eventbus.EventBus
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
internal abstract class SetAvatarUrlTask : Task<SetAvatarUrlTask.Params, Unit> {
|
||||||
|
data class Params(
|
||||||
|
val userId: String,
|
||||||
|
val newAvatarUrl: String
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class DefaultSetAvatarUrlTask @Inject constructor(
|
||||||
|
private val profileAPI: ProfileAPI,
|
||||||
|
private val eventBus: EventBus) : SetAvatarUrlTask() {
|
||||||
|
|
||||||
|
override suspend fun execute(params: Params) {
|
||||||
|
return executeRequest(eventBus) {
|
||||||
|
val body = SetAvatarUrlBody(
|
||||||
|
avatarUrl = params.newAvatarUrl
|
||||||
|
)
|
||||||
|
apiCall = profileAPI.setAvatarUrl(params.userId, body)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -20,13 +20,17 @@ package im.vector.riotx.features.settings
|
||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.graphics.Color
|
||||||
|
import android.net.Uri
|
||||||
import android.text.Editable
|
import android.text.Editable
|
||||||
import android.util.Patterns
|
import android.util.Patterns
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
|
import android.widget.Toast
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
|
import androidx.core.net.toUri
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.preference.EditTextPreference
|
import androidx.preference.EditTextPreference
|
||||||
import androidx.preference.Preference
|
import androidx.preference.Preference
|
||||||
|
@ -36,6 +40,8 @@ import com.bumptech.glide.Glide
|
||||||
import com.bumptech.glide.load.engine.cache.DiskCache
|
import com.bumptech.glide.load.engine.cache.DiskCache
|
||||||
import com.google.android.material.textfield.TextInputEditText
|
import com.google.android.material.textfield.TextInputEditText
|
||||||
import com.google.android.material.textfield.TextInputLayout
|
import com.google.android.material.textfield.TextInputLayout
|
||||||
|
import com.yalantis.ucrop.UCrop
|
||||||
|
import com.yalantis.ucrop.UCropActivity
|
||||||
import im.vector.matrix.android.api.MatrixCallback
|
import im.vector.matrix.android.api.MatrixCallback
|
||||||
import im.vector.matrix.android.api.NoOpMatrixCallback
|
import im.vector.matrix.android.api.NoOpMatrixCallback
|
||||||
import im.vector.matrix.android.api.failure.isInvalidPassword
|
import im.vector.matrix.android.api.failure.isInvalidPassword
|
||||||
|
@ -44,27 +50,34 @@ import im.vector.matrix.android.api.session.integrationmanager.IntegrationManage
|
||||||
import im.vector.riotx.R
|
import im.vector.riotx.R
|
||||||
import im.vector.riotx.core.extensions.hideKeyboard
|
import im.vector.riotx.core.extensions.hideKeyboard
|
||||||
import im.vector.riotx.core.extensions.showPassword
|
import im.vector.riotx.core.extensions.showPassword
|
||||||
|
import im.vector.riotx.core.intent.getFilenameFromUri
|
||||||
import im.vector.riotx.core.platform.SimpleTextWatcher
|
import im.vector.riotx.core.platform.SimpleTextWatcher
|
||||||
import im.vector.riotx.core.preference.UserAvatarPreference
|
import im.vector.riotx.core.preference.UserAvatarPreference
|
||||||
import im.vector.riotx.core.preference.VectorPreference
|
import im.vector.riotx.core.preference.VectorPreference
|
||||||
import im.vector.riotx.core.preference.VectorSwitchPreference
|
import im.vector.riotx.core.preference.VectorSwitchPreference
|
||||||
|
import im.vector.riotx.core.utils.PERMISSIONS_FOR_TAKING_PHOTO
|
||||||
import im.vector.riotx.core.utils.PERMISSION_REQUEST_CODE_LAUNCH_CAMERA
|
import im.vector.riotx.core.utils.PERMISSION_REQUEST_CODE_LAUNCH_CAMERA
|
||||||
import im.vector.riotx.core.utils.TextUtils
|
import im.vector.riotx.core.utils.TextUtils
|
||||||
import im.vector.riotx.core.utils.allGranted
|
import im.vector.riotx.core.utils.allGranted
|
||||||
|
import im.vector.riotx.core.utils.checkPermissions
|
||||||
import im.vector.riotx.core.utils.copyToClipboard
|
import im.vector.riotx.core.utils.copyToClipboard
|
||||||
import im.vector.riotx.core.utils.getSizeOfFiles
|
import im.vector.riotx.core.utils.getSizeOfFiles
|
||||||
import im.vector.riotx.core.utils.toast
|
import im.vector.riotx.core.utils.toast
|
||||||
import im.vector.riotx.features.MainActivity
|
import im.vector.riotx.features.MainActivity
|
||||||
import im.vector.riotx.features.MainActivityArgs
|
import im.vector.riotx.features.MainActivityArgs
|
||||||
|
import im.vector.riotx.features.roomprofile.AvatarSelectorView
|
||||||
import im.vector.riotx.features.themes.ThemeUtils
|
import im.vector.riotx.features.themes.ThemeUtils
|
||||||
import im.vector.riotx.features.workers.signout.SignOutUiWorker
|
import im.vector.riotx.features.workers.signout.SignOutUiWorker
|
||||||
|
import im.vector.riotx.multipicker.MultiPicker
|
||||||
|
import im.vector.riotx.multipicker.entity.MultiPickerImageType
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.GlobalScope
|
import kotlinx.coroutines.GlobalScope
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import java.util.UUID
|
||||||
|
|
||||||
class VectorSettingsGeneralFragment : VectorSettingsBaseFragment() {
|
class VectorSettingsGeneralFragment : VectorSettingsBaseFragment(), AvatarSelectorView.Callback {
|
||||||
|
|
||||||
override var titleRes = R.string.settings_general_title
|
override var titleRes = R.string.settings_general_title
|
||||||
override val preferenceXmlRes = R.xml.vector_settings_general
|
override val preferenceXmlRes = R.xml.vector_settings_general
|
||||||
|
@ -72,6 +85,9 @@ class VectorSettingsGeneralFragment : VectorSettingsBaseFragment() {
|
||||||
private var mDisplayedEmails = ArrayList<String>()
|
private var mDisplayedEmails = ArrayList<String>()
|
||||||
private var mDisplayedPhoneNumber = ArrayList<String>()
|
private var mDisplayedPhoneNumber = ArrayList<String>()
|
||||||
|
|
||||||
|
private lateinit var avatarSelector: AvatarSelectorView
|
||||||
|
private var avatarCameraUri: Uri? = null
|
||||||
|
|
||||||
private val mUserSettingsCategory by lazy {
|
private val mUserSettingsCategory by lazy {
|
||||||
findPreference<PreferenceCategory>(VectorPreferences.SETTINGS_USER_SETTINGS_PREFERENCE_KEY)!!
|
findPreference<PreferenceCategory>(VectorPreferences.SETTINGS_USER_SETTINGS_PREFERENCE_KEY)!!
|
||||||
}
|
}
|
||||||
|
@ -281,7 +297,7 @@ class VectorSettingsGeneralFragment : VectorSettingsBaseFragment() {
|
||||||
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
|
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
|
||||||
if (allGranted(grantResults)) {
|
if (allGranted(grantResults)) {
|
||||||
if (requestCode == PERMISSION_REQUEST_CODE_LAUNCH_CAMERA) {
|
if (requestCode == PERMISSION_REQUEST_CODE_LAUNCH_CAMERA) {
|
||||||
changeAvatar()
|
onTypeSelected(AvatarSelectorView.Type.CAMERA)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -291,8 +307,27 @@ class VectorSettingsGeneralFragment : VectorSettingsBaseFragment() {
|
||||||
|
|
||||||
if (resultCode == Activity.RESULT_OK) {
|
if (resultCode == Activity.RESULT_OK) {
|
||||||
when (requestCode) {
|
when (requestCode) {
|
||||||
REQUEST_NEW_PHONE_NUMBER -> refreshPhoneNumbersList()
|
REQUEST_NEW_PHONE_NUMBER -> refreshPhoneNumbersList()
|
||||||
REQUEST_PHONEBOOK_COUNTRY -> onPhonebookCountryUpdate(data)
|
REQUEST_PHONEBOOK_COUNTRY -> onPhonebookCountryUpdate(data)
|
||||||
|
MultiPicker.REQUEST_CODE_TAKE_PHOTO -> {
|
||||||
|
avatarCameraUri?.let { uri ->
|
||||||
|
MultiPicker.get(MultiPicker.CAMERA)
|
||||||
|
.getTakenPhoto(requireContext(), requestCode, resultCode, uri)
|
||||||
|
?.let {
|
||||||
|
onAvatarSelected(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MultiPicker.REQUEST_CODE_PICK_IMAGE -> {
|
||||||
|
MultiPicker
|
||||||
|
.get(MultiPicker.IMAGE)
|
||||||
|
.getSelectedFiles(requireContext(), requestCode, resultCode, data)
|
||||||
|
.firstOrNull()?.let {
|
||||||
|
// TODO. UCrop library cannot read from Gallery. For now, we will set avatar as it is.
|
||||||
|
onAvatarCropped(it.contentUri)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
UCrop.REQUEST_CROP -> data?.let { onAvatarCropped(UCrop.getOutput(it)) }
|
||||||
/* TODO
|
/* TODO
|
||||||
VectorUtils.TAKE_IMAGE -> {
|
VectorUtils.TAKE_IMAGE -> {
|
||||||
val thumbnailUri = VectorUtils.getThumbnailUriFromIntent(activity, data, session.mediaCache)
|
val thumbnailUri = VectorUtils.getThumbnailUriFromIntent(activity, data, session.mediaCache)
|
||||||
|
@ -370,26 +405,88 @@ class VectorSettingsGeneralFragment : VectorSettingsBaseFragment() {
|
||||||
* Update the avatar.
|
* Update the avatar.
|
||||||
*/
|
*/
|
||||||
private fun onUpdateAvatarClick() {
|
private fun onUpdateAvatarClick() {
|
||||||
notImplemented()
|
if (!::avatarSelector.isInitialized) {
|
||||||
|
avatarSelector = AvatarSelectorView(activity!!, activity!!.layoutInflater, this)
|
||||||
/* TODO
|
}
|
||||||
if (checkPermissions(PERMISSIONS_FOR_TAKING_PHOTO, this, PERMISSION_REQUEST_CODE_LAUNCH_CAMERA)) {
|
mUserAvatarPreference.mAvatarView?.let {
|
||||||
changeAvatar()
|
avatarSelector.show(it, false)
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun changeAvatar() {
|
override fun onTypeSelected(type: AvatarSelectorView.Type) {
|
||||||
/* TODO
|
when (type) {
|
||||||
val intent = Intent(activity, VectorMediaPickerActivity::class.java)
|
AvatarSelectorView.Type.CAMERA -> {
|
||||||
intent.putExtra(VectorMediaPickerActivity.EXTRA_AVATAR_MODE, true)
|
if (checkPermissions(PERMISSIONS_FOR_TAKING_PHOTO, this, PERMISSION_REQUEST_CODE_LAUNCH_CAMERA)) {
|
||||||
startActivityForResult(intent, VectorUtils.TAKE_IMAGE)
|
avatarCameraUri = MultiPicker.get(MultiPicker.CAMERA).startWithExpectingFile(this)
|
||||||
*/
|
}
|
||||||
|
}
|
||||||
|
AvatarSelectorView.Type.GALLERY -> {
|
||||||
|
MultiPicker.get(MultiPicker.IMAGE).single().startWith(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==============================================================================================================
|
private fun onAvatarSelected(image: MultiPickerImageType) {
|
||||||
// contacts management
|
val destinationFile = File(requireContext().cacheDir, "${image.displayName}_edited_image_${System.currentTimeMillis()}")
|
||||||
// ==============================================================================================================
|
val uri = image.contentUri
|
||||||
|
UCrop.of(uri, destinationFile.toUri())
|
||||||
|
.withOptions(
|
||||||
|
UCrop.Options()
|
||||||
|
.apply {
|
||||||
|
setAllowedGestures(
|
||||||
|
/* tabScale = */ UCropActivity.SCALE,
|
||||||
|
/* tabRotate = */ UCropActivity.ALL,
|
||||||
|
/* tabAspectRatio = */ UCropActivity.SCALE
|
||||||
|
)
|
||||||
|
setToolbarTitle(image.displayName)
|
||||||
|
// Disable freestyle crop, usability was not easy
|
||||||
|
// setFreeStyleCropEnabled(true)
|
||||||
|
// Color used for toolbar icon and text
|
||||||
|
setToolbarColor(ThemeUtils.getColor(requireContext(), R.attr.riotx_background))
|
||||||
|
setToolbarWidgetColor(ThemeUtils.getColor(requireContext(), R.attr.vctr_toolbar_primary_text_color))
|
||||||
|
// Background
|
||||||
|
setRootViewBackgroundColor(ThemeUtils.getColor(requireContext(), R.attr.riotx_background))
|
||||||
|
// Status bar color (pb in dark mode, icon of the status bar are dark)
|
||||||
|
setStatusBarColor(ThemeUtils.getColor(requireContext(), R.attr.riotx_header_panel_background))
|
||||||
|
// Known issue: there is still orange color used by the lib
|
||||||
|
// https://github.com/Yalantis/uCrop/issues/602
|
||||||
|
setActiveControlsWidgetColor(ContextCompat.getColor(requireContext(), R.color.riotx_accent))
|
||||||
|
// Hide the logo (does not work)
|
||||||
|
setLogoColor(Color.TRANSPARENT)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.start(requireContext(), this)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun onAvatarCropped(uri: Uri?) {
|
||||||
|
if (uri != null) {
|
||||||
|
uploadAvatar(uri)
|
||||||
|
} else {
|
||||||
|
Toast.makeText(requireContext(), "Cannot retrieve cropped value", Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun uploadAvatar(uri: Uri) {
|
||||||
|
displayLoadingView()
|
||||||
|
|
||||||
|
session.updateAvatar(session.myUserId, uri, getFilenameFromUri(context, uri) ?: UUID.randomUUID().toString(), object : MatrixCallback<Unit> {
|
||||||
|
override fun onSuccess(data: Unit) {
|
||||||
|
if (!isAdded) return
|
||||||
|
|
||||||
|
mUserAvatarPreference.refreshAvatar()
|
||||||
|
onCommonDone(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onFailure(failure: Throwable) {
|
||||||
|
if (!isAdded) return
|
||||||
|
onCommonDone(failure.localizedMessage)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==============================================================================================================
|
||||||
|
// contacts management
|
||||||
|
// ==============================================================================================================
|
||||||
|
|
||||||
private fun setContactsPreferences() {
|
private fun setContactsPreferences() {
|
||||||
/* TODO
|
/* TODO
|
||||||
|
@ -422,9 +519,9 @@ class VectorSettingsGeneralFragment : VectorSettingsBaseFragment() {
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==============================================================================================================
|
// ==============================================================================================================
|
||||||
// Phone number management
|
// Phone number management
|
||||||
// ==============================================================================================================
|
// ==============================================================================================================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Refresh phone number list
|
* Refresh phone number list
|
||||||
|
@ -505,9 +602,9 @@ class VectorSettingsGeneralFragment : VectorSettingsBaseFragment() {
|
||||||
} */
|
} */
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==============================================================================================================
|
// ==============================================================================================================
|
||||||
// Email management
|
// Email management
|
||||||
// ==============================================================================================================
|
// ==============================================================================================================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Refresh the emails list
|
* Refresh the emails list
|
||||||
|
@ -632,47 +729,47 @@ class VectorSettingsGeneralFragment : VectorSettingsBaseFragment() {
|
||||||
*
|
*
|
||||||
* @param pid the used pid.
|
* @param pid the used pid.
|
||||||
*/
|
*/
|
||||||
/* TODO
|
/* TODO
|
||||||
private fun showEmailValidationDialog(pid: ThreePid) {
|
private fun showEmailValidationDialog(pid: ThreePid) {
|
||||||
activity?.let {
|
activity?.let {
|
||||||
AlertDialog.Builder(it)
|
AlertDialog.Builder(it)
|
||||||
.setTitle(R.string.account_email_validation_title)
|
.setTitle(R.string.account_email_validation_title)
|
||||||
.setMessage(R.string.account_email_validation_message)
|
.setMessage(R.string.account_email_validation_message)
|
||||||
.setPositiveButton(R.string._continue) { _, _ ->
|
.setPositiveButton(R.string._continue) { _, _ ->
|
||||||
session.myUser.add3Pid(pid, true, object : MatrixCallback<Unit> {
|
session.myUser.add3Pid(pid, true, object : MatrixCallback<Unit> {
|
||||||
override fun onSuccess(info: Void?) {
|
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 {
|
it.runOnUiThread {
|
||||||
hideLoadingView()
|
hideLoadingView()
|
||||||
refreshEmailsList()
|
it.toast(R.string.account_email_validation_error)
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
|
|
||||||
override fun onNetworkError(e: Exception) {
|
|
||||||
onCommonDone(e.localizedMessage)
|
onCommonDone(e.localizedMessage)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onMatrixError(e: MatrixError) {
|
override fun onUnexpectedError(e: Exception) {
|
||||||
if (TextUtils.equals(e.errcode, MatrixError.THREEPID_AUTH_FAILED)) {
|
onCommonDone(e.localizedMessage)
|
||||||
it.runOnUiThread {
|
}
|
||||||
hideLoadingView()
|
})
|
||||||
it.toast(R.string.account_email_validation_error)
|
}
|
||||||
}
|
.setNegativeButton(R.string.cancel) { _, _ ->
|
||||||
} else {
|
hideLoadingView()
|
||||||
onCommonDone(e.localizedMessage)
|
}
|
||||||
}
|
.show()
|
||||||
}
|
}
|
||||||
|
} */
|
||||||
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
|
* Display a dialog which asks confirmation for the deletion of a 3pid
|
||||||
|
|
Loading…
Reference in a new issue