mirror of
https://github.com/SchildiChat/SchildiChat-android.git
synced 2025-01-02 22:37:40 +03:00
[issue-2610] implement setting to override nick color
- allow changing the nick color by clicking the dispay-name in the room member detail page. - the ovirride-color can be specified as a hex string (#rrggbb) or as palette index (2) - entering an invalid color code or leaving the field blank reverts to the default hash-based nick color - the setting is stored in `account_data` as `im.vector.setting.override_colors` - future improvements / notes: - replace the text-based color entry with a proper color picker dialog - make the feature more discoverable - the color change listener is now in AppStateHandler, not sure if this is the best place - implement override color support in element-web / element-desktop, too Signed-off-by: Péter Radics <mitchnull@gmail.com>
This commit is contained in:
parent
4a5dbde8d3
commit
7aaebd493b
6 changed files with 107 additions and 3 deletions
|
@ -2,6 +2,7 @@ Changes in Element 1.0.14 (2020-XX-XX)
|
|||
===================================================
|
||||
|
||||
Features ✨:
|
||||
- Allow changing nick colors (#2610)
|
||||
- Enable url previews for notices (#2562)
|
||||
|
||||
Improvements 🙌:
|
||||
|
|
|
@ -27,4 +27,5 @@ object UserAccountDataTypes {
|
|||
const val TYPE_ALLOWED_WIDGETS = "im.vector.setting.allowed_widgets"
|
||||
const val TYPE_IDENTITY_SERVER = "m.identity_server"
|
||||
const val TYPE_ACCEPTED_TERMS = "m.accepted_terms"
|
||||
const val TYPE_OVERRIDE_COLORS = "im.vector.setting.override_colors"
|
||||
}
|
||||
|
|
|
@ -23,12 +23,15 @@ import arrow.core.Option
|
|||
import im.vector.app.features.grouplist.ALL_COMMUNITIES_GROUP_ID
|
||||
import im.vector.app.features.grouplist.SelectedGroupDataSource
|
||||
import im.vector.app.features.home.HomeRoomListDataSource
|
||||
import im.vector.app.features.home.room.detail.timeline.helper.MatrixItemColorProvider
|
||||
import im.vector.app.features.home.room.list.ChronologicalRoomComparator
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import io.reactivex.functions.BiFunction
|
||||
import io.reactivex.rxkotlin.addTo
|
||||
import org.matrix.android.sdk.api.session.accountdata.UserAccountDataTypes
|
||||
import org.matrix.android.sdk.api.session.events.model.toModel
|
||||
import org.matrix.android.sdk.api.session.group.model.GroupSummary
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||
import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
|
||||
|
@ -46,13 +49,15 @@ class AppStateHandler @Inject constructor(
|
|||
private val sessionDataSource: ActiveSessionDataSource,
|
||||
private val homeRoomListDataSource: HomeRoomListDataSource,
|
||||
private val selectedGroupDataSource: SelectedGroupDataSource,
|
||||
private val chronologicalRoomComparator: ChronologicalRoomComparator) : LifecycleObserver {
|
||||
private val chronologicalRoomComparator: ChronologicalRoomComparator,
|
||||
private val matrixItemColorProvider: MatrixItemColorProvider) : LifecycleObserver {
|
||||
|
||||
private val compositeDisposable = CompositeDisposable()
|
||||
|
||||
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
|
||||
fun entersForeground() {
|
||||
observeRoomsAndGroup()
|
||||
observeUserAccountData()
|
||||
}
|
||||
|
||||
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
|
||||
|
@ -93,4 +98,19 @@ class AppStateHandler @Inject constructor(
|
|||
}
|
||||
.addTo(compositeDisposable)
|
||||
}
|
||||
|
||||
private fun observeUserAccountData() {
|
||||
sessionDataSource.observe()
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.switchMap {
|
||||
it.orNull()?.rx()?.liveAccountData(setOf(UserAccountDataTypes.TYPE_OVERRIDE_COLORS))
|
||||
?: Observable.just(emptyList())
|
||||
}
|
||||
.distinctUntilChanged()
|
||||
.subscribe {
|
||||
val overrideColorSpecs = it?.first()?.content?.toModel<Map<String, String>>()
|
||||
matrixItemColorProvider.setOverrideColors(overrideColorSpecs)
|
||||
}
|
||||
.addTo(compositeDisposable)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,6 +44,39 @@ class MatrixItemColorProvider @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
fun setOverrideColors(overrideColors: Map<String, String>?) {
|
||||
overrideColors?.forEach() {
|
||||
setOverrideColor(it.key, it.value)
|
||||
}
|
||||
}
|
||||
|
||||
fun setOverrideColor(id: String, colorSpec: String?) : Boolean {
|
||||
val color = parseUserColorSpec(colorSpec)
|
||||
if (color == null) {
|
||||
cache.remove(id)
|
||||
return false
|
||||
} else {
|
||||
cache.put(id, color)
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
@ColorInt
|
||||
private fun parseUserColorSpec(colorText: String?): Int? {
|
||||
if (colorText.isNullOrBlank()) {
|
||||
return null
|
||||
}
|
||||
try {
|
||||
if (colorText.first() == '#') {
|
||||
return (colorText.substring(1).toLong(radix = 16) or 0xff000000L).toInt()
|
||||
} else {
|
||||
return colorProvider.getColor(getUserColorByIndex(colorText.toInt()))
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
@ColorRes
|
||||
@VisibleForTesting
|
||||
|
@ -52,7 +85,12 @@ class MatrixItemColorProvider @Inject constructor(
|
|||
|
||||
userId?.toList()?.map { chr -> hash = (hash shl 5) - hash + chr.toInt() }
|
||||
|
||||
return when (abs(hash) % 8) {
|
||||
return getUserColorByIndex(abs(hash))
|
||||
}
|
||||
|
||||
@ColorRes
|
||||
private fun getUserColorByIndex(index: Int): Int {
|
||||
return when (index % 8) {
|
||||
1 -> R.color.riotx_username_2
|
||||
2 -> R.color.riotx_username_3
|
||||
3 -> R.color.riotx_username_4
|
||||
|
|
|
@ -43,6 +43,7 @@ import im.vector.app.core.extensions.setTextOrHide
|
|||
import im.vector.app.core.platform.StateView
|
||||
import im.vector.app.core.platform.VectorBaseFragment
|
||||
import im.vector.app.core.utils.startSharePlainTextIntent
|
||||
import im.vector.app.databinding.DialogBaseEditTextBinding
|
||||
import im.vector.app.databinding.DialogShareQrCodeBinding
|
||||
import im.vector.app.databinding.FragmentMatrixProfileBinding
|
||||
import im.vector.app.databinding.ViewStubRoomMemberProfileHeaderBinding
|
||||
|
@ -50,9 +51,11 @@ import im.vector.app.features.crypto.verification.VerificationBottomSheet
|
|||
import im.vector.app.features.home.AvatarRenderer
|
||||
import im.vector.app.features.home.room.detail.RoomDetailPendingAction
|
||||
import im.vector.app.features.home.room.detail.RoomDetailPendingActionStore
|
||||
import im.vector.app.features.home.room.detail.timeline.helper.MatrixItemColorProvider
|
||||
import im.vector.app.features.roommemberprofile.devices.DeviceListBottomSheet
|
||||
import im.vector.app.features.roommemberprofile.powerlevel.EditPowerLevelDialogs
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import org.matrix.android.sdk.api.session.accountdata.UserAccountDataTypes
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.Role
|
||||
import org.matrix.android.sdk.api.util.MatrixItem
|
||||
import javax.inject.Inject
|
||||
|
@ -67,7 +70,8 @@ class RoomMemberProfileFragment @Inject constructor(
|
|||
val viewModelFactory: RoomMemberProfileViewModel.Factory,
|
||||
private val roomMemberProfileController: RoomMemberProfileController,
|
||||
private val avatarRenderer: AvatarRenderer,
|
||||
private val roomDetailPendingActionStore: RoomDetailPendingActionStore
|
||||
private val roomDetailPendingActionStore: RoomDetailPendingActionStore,
|
||||
private val matrixItemColorProvider: MatrixItemColorProvider
|
||||
) : VectorBaseFragment<FragmentMatrixProfileBinding>(),
|
||||
RoomMemberProfileController.Callback {
|
||||
|
||||
|
@ -199,6 +203,7 @@ class RoomMemberProfileFragment @Inject constructor(
|
|||
headerViews.memberProfileIdView.text = userMatrixItem.id
|
||||
val bestName = userMatrixItem.getBestName()
|
||||
headerViews.memberProfileNameView.text = bestName
|
||||
headerViews.memberProfileNameView.setTextColor(matrixItemColorProvider.getColor(userMatrixItem))
|
||||
views.matrixProfileToolbarTitleView.text = bestName
|
||||
avatarRenderer.render(userMatrixItem, headerViews.memberProfileAvatarView)
|
||||
avatarRenderer.render(userMatrixItem, views.matrixProfileToolbarAvatarImageView)
|
||||
|
@ -237,6 +242,9 @@ class RoomMemberProfileFragment @Inject constructor(
|
|||
headerViews.memberProfileAvatarView.setOnClickListener { view ->
|
||||
onAvatarClicked(view, userMatrixItem)
|
||||
}
|
||||
headerViews.memberProfileNameView.setOnClickListener { _ ->
|
||||
onProfileNameClicked(userMatrixItem)
|
||||
}
|
||||
views.matrixProfileToolbarAvatarImageView.setOnClickListener { view ->
|
||||
onAvatarClicked(view, userMatrixItem)
|
||||
}
|
||||
|
@ -323,6 +331,40 @@ class RoomMemberProfileFragment @Inject constructor(
|
|||
navigator.openBigImageViewer(requireActivity(), view, userMatrixItem)
|
||||
}
|
||||
|
||||
private fun onProfileNameClicked(userMatrixItem: MatrixItem) {
|
||||
val inflater = requireActivity().layoutInflater
|
||||
val layout = inflater.inflate(R.layout.dialog_base_edit_text, null)
|
||||
val views = DialogBaseEditTextBinding.bind(layout)
|
||||
val session = injector().activeSessionHolder().getActiveSession()
|
||||
val overrideColorsSetting = session.getAccountDataEvent(UserAccountDataTypes.TYPE_OVERRIDE_COLORS)
|
||||
val overrideColorSpecs = overrideColorsSetting?.content?.toMap().orEmpty()
|
||||
val overrideColorSpec = overrideColorSpecs[userMatrixItem.id]?.toString()
|
||||
views.editText.setText(overrideColorSpec)
|
||||
views.editText.hint = "#000000"
|
||||
|
||||
AlertDialog.Builder(requireActivity())
|
||||
.setTitle(R.string.room_member_override_color)
|
||||
.setView(layout)
|
||||
.setPositiveButton(R.string.ok) { _, _ ->
|
||||
val newOverrideColorSpec = views.editText.text.toString()
|
||||
if (newOverrideColorSpec != overrideColorSpec) {
|
||||
val newOverrideColorSpecs = overrideColorSpecs.toMutableMap()
|
||||
if (matrixItemColorProvider.setOverrideColor(userMatrixItem.id, newOverrideColorSpec)) {
|
||||
newOverrideColorSpecs[userMatrixItem.id] = newOverrideColorSpec
|
||||
} else {
|
||||
newOverrideColorSpecs.remove(userMatrixItem.id)
|
||||
}
|
||||
session.updateAccountData(
|
||||
type = UserAccountDataTypes.TYPE_OVERRIDE_COLORS,
|
||||
content = newOverrideColorSpecs
|
||||
)
|
||||
headerViews.memberProfileNameView.setTextColor(matrixItemColorProvider.getColor(userMatrixItem))
|
||||
}
|
||||
}
|
||||
.setNegativeButton(R.string.cancel, null)
|
||||
.show()
|
||||
}
|
||||
|
||||
override fun onEditPowerLevel(currentRole: Role) {
|
||||
EditPowerLevelDialogs.showChoice(requireActivity(), currentRole) { newPowerLevel ->
|
||||
viewModel.handle(RoomMemberProfileAction.SetPowerLevel(currentRole.value, newPowerLevel, true))
|
||||
|
|
|
@ -2241,6 +2241,8 @@
|
|||
<string name="direct_room_profile_section_more_leave">Leave</string>
|
||||
<string name="room_profile_leaving_room">"Leaving the room…"</string>
|
||||
|
||||
<string name="room_member_override_color">Override color</string>
|
||||
|
||||
<string name="room_member_power_level_admins">Admins</string>
|
||||
<string name="room_member_power_level_moderators">Moderators</string>
|
||||
<string name="room_member_power_level_custom">Custom</string>
|
||||
|
|
Loading…
Reference in a new issue