Merge branch 'develop' into feature/aris/thread_labs_notice_users
# Conflicts: # matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/MatrixConfiguration.kt # vector/src/main/java/im/vector/app/core/di/SingletonModule.kt
This commit is contained in:
commit
a0e6dd5f6c
1
changelog.d/5378.misc
Normal file
1
changelog.d/5378.misc
Normal file
@ -0,0 +1 @@
|
||||
Add analytics support for threads
|
1
changelog.d/5540.bugfix
Normal file
1
changelog.d/5540.bugfix
Normal file
@ -0,0 +1 @@
|
||||
Fixes crash when tapping the timeline verification surround box instead of the buttons
|
1
changelog.d/5547.bugfix
Normal file
1
changelog.d/5547.bugfix
Normal file
@ -0,0 +1 @@
|
||||
[Notification mode] Wrong mode is displayed when the mention only is selected on the web client
|
1
changelog.d/5563.misc
Normal file
1
changelog.d/5563.misc
Normal file
@ -0,0 +1 @@
|
||||
Add a presence sync enabling build config
|
@ -61,6 +61,10 @@ data class MatrixConfiguration(
|
||||
* RoomDisplayNameFallbackProvider to provide default room display name.
|
||||
*/
|
||||
val roomDisplayNameFallbackProvider: RoomDisplayNameFallbackProvider,
|
||||
/**
|
||||
* True to enable presence information sync (if available). False to disable regardless of server setting.
|
||||
*/
|
||||
val presenceSyncEnabled: Boolean = true,
|
||||
/**
|
||||
* Thread messages default enable/disabled value
|
||||
*/
|
||||
|
@ -17,6 +17,7 @@
|
||||
package org.matrix.android.sdk.api.session.room.timeline
|
||||
|
||||
import org.matrix.android.sdk.BuildConfig
|
||||
import org.matrix.android.sdk.api.extensions.orFalse
|
||||
import org.matrix.android.sdk.api.session.events.model.Event
|
||||
import org.matrix.android.sdk.api.session.events.model.EventType
|
||||
import org.matrix.android.sdk.api.session.events.model.RelationType
|
||||
@ -159,6 +160,13 @@ fun TimelineEvent.isSticker(): Boolean {
|
||||
return root.isSticker()
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not the event is a root thread event
|
||||
*/
|
||||
fun TimelineEvent.isRootThread(): Boolean {
|
||||
return root.threadDetails?.isRootThread.orFalse()
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the latest message body, after a possible edition, stripping the reply prefix if necessary
|
||||
*/
|
||||
|
@ -17,6 +17,7 @@
|
||||
package org.matrix.android.sdk.internal.session.sync.handler
|
||||
|
||||
import io.realm.Realm
|
||||
import org.matrix.android.sdk.api.MatrixConfiguration
|
||||
import org.matrix.android.sdk.api.session.events.model.EventType
|
||||
import org.matrix.android.sdk.api.session.events.model.getPresenceContent
|
||||
import org.matrix.android.sdk.api.session.sync.model.PresenceSyncResponse
|
||||
@ -27,27 +28,29 @@ import org.matrix.android.sdk.internal.database.query.updateDirectUserPresence
|
||||
import org.matrix.android.sdk.internal.database.query.updateUserPresence
|
||||
import javax.inject.Inject
|
||||
|
||||
internal class PresenceSyncHandler @Inject constructor() {
|
||||
internal class PresenceSyncHandler @Inject constructor(private val matrixConfiguration: MatrixConfiguration) {
|
||||
|
||||
fun handle(realm: Realm, presenceSyncResponse: PresenceSyncResponse?) {
|
||||
presenceSyncResponse?.events
|
||||
?.filter { event -> event.type == EventType.PRESENCE }
|
||||
?.forEach { event ->
|
||||
val content = event.getPresenceContent() ?: return@forEach
|
||||
val userId = event.senderId ?: return@forEach
|
||||
val userPresenceEntity = UserPresenceEntity(
|
||||
userId = userId,
|
||||
lastActiveAgo = content.lastActiveAgo,
|
||||
statusMessage = content.statusMessage,
|
||||
isCurrentlyActive = content.isCurrentlyActive,
|
||||
avatarUrl = content.avatarUrl,
|
||||
displayName = content.displayName
|
||||
).also {
|
||||
it.presence = content.presence
|
||||
}
|
||||
if (matrixConfiguration.presenceSyncEnabled) {
|
||||
presenceSyncResponse?.events
|
||||
?.filter { event -> event.type == EventType.PRESENCE }
|
||||
?.forEach { event ->
|
||||
val content = event.getPresenceContent() ?: return@forEach
|
||||
val userId = event.senderId ?: return@forEach
|
||||
val userPresenceEntity = UserPresenceEntity(
|
||||
userId = userId,
|
||||
lastActiveAgo = content.lastActiveAgo,
|
||||
statusMessage = content.statusMessage,
|
||||
isCurrentlyActive = content.isCurrentlyActive,
|
||||
avatarUrl = content.avatarUrl,
|
||||
displayName = content.displayName
|
||||
).also {
|
||||
it.presence = content.presence
|
||||
}
|
||||
|
||||
storePresenceToDB(realm, userPresenceEntity)
|
||||
}
|
||||
storePresenceToDB(realm, userPresenceEntity)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -151,6 +151,7 @@ android {
|
||||
|
||||
buildConfigField "Boolean", "enableLocationSharing", "true"
|
||||
buildConfigField "String", "mapTilerKey", "\"fU3vlMsMn4Jb6dnEIFsx\""
|
||||
buildConfigField "Boolean", "PRESENCE_SYNC_ENABLED", "true"
|
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
|
||||
|
@ -120,7 +120,8 @@ object VectorStaticModule {
|
||||
return MatrixConfiguration(
|
||||
applicationFlavor = BuildConfig.FLAVOR_DESCRIPTION,
|
||||
roomDisplayNameFallbackProvider = vectorRoomDisplayNameFallbackProvider,
|
||||
threadMessagesEnabledDefault = vectorPreferences.areThreadMessagesEnabled()
|
||||
threadMessagesEnabledDefault = vectorPreferences.areThreadMessagesEnabled(),
|
||||
presenceSyncEnabled = BuildConfig.PRESENCE_SYNC_ENABLED
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -25,10 +25,11 @@ import org.matrix.android.sdk.api.session.presence.model.UserPresence
|
||||
@EpoxyModelClass(layout = R.layout.item_profile_matrix_item)
|
||||
abstract class ProfileMatrixItemWithPowerLevelWithPresence : ProfileMatrixItemWithPowerLevel() {
|
||||
|
||||
@EpoxyAttribute var showPresence: Boolean = true
|
||||
@EpoxyAttribute var userPresence: UserPresence? = null
|
||||
|
||||
override fun bind(holder: Holder) {
|
||||
super.bind(holder)
|
||||
holder.presenceImageView.render(userPresence = userPresence)
|
||||
holder.presenceImageView.render(showPresence, userPresence)
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (c) 2022 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.app.features.analytics.extensions
|
||||
|
||||
import im.vector.app.features.analytics.plan.Composer
|
||||
import im.vector.app.features.home.room.detail.composer.MessageComposerViewState
|
||||
import im.vector.app.features.home.room.detail.composer.SendMode
|
||||
|
||||
fun MessageComposerViewState.toAnalyticsComposer(): Composer =
|
||||
Composer(
|
||||
inThread = isInThreadTimeline(),
|
||||
isEditing = sendMode is SendMode.Edit,
|
||||
isReply = sendMode is SendMode.Reply,
|
||||
startsThread = startsThread
|
||||
)
|
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (c) 2022 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.app.features.analytics.extensions
|
||||
|
||||
import im.vector.app.features.analytics.plan.Interaction
|
||||
|
||||
fun Interaction.Name.toAnalyticsInteraction(interactionType: Interaction.InteractionType = Interaction.InteractionType.Touch) =
|
||||
Interaction(
|
||||
name = this,
|
||||
interactionType = interactionType
|
||||
)
|
@ -118,7 +118,8 @@ import im.vector.app.core.utils.startInstallFromSourceIntent
|
||||
import im.vector.app.core.utils.toast
|
||||
import im.vector.app.databinding.DialogReportContentBinding
|
||||
import im.vector.app.databinding.FragmentTimelineBinding
|
||||
import im.vector.app.features.analytics.plan.Composer
|
||||
import im.vector.app.features.analytics.extensions.toAnalyticsInteraction
|
||||
import im.vector.app.features.analytics.plan.Interaction
|
||||
import im.vector.app.features.analytics.plan.MobileScreen
|
||||
import im.vector.app.features.attachments.AttachmentTypeSelectorView
|
||||
import im.vector.app.features.attachments.AttachmentsHelper
|
||||
@ -205,6 +206,7 @@ import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.billcarsonfr.jsonviewer.JSonViewerDialog
|
||||
import org.commonmark.parser.Parser
|
||||
import org.matrix.android.sdk.api.MatrixConfiguration
|
||||
import org.matrix.android.sdk.api.session.Session
|
||||
import org.matrix.android.sdk.api.session.content.ContentAttachmentData
|
||||
import org.matrix.android.sdk.api.session.events.model.EventType
|
||||
@ -259,7 +261,8 @@ class TimelineFragment @Inject constructor(
|
||||
private val pillsPostProcessorFactory: PillsPostProcessor.Factory,
|
||||
private val callManager: WebRtcCallManager,
|
||||
private val voiceMessagePlaybackTracker: VoiceMessagePlaybackTracker,
|
||||
private val clock: Clock
|
||||
private val clock: Clock,
|
||||
private val matrixConfiguration: MatrixConfiguration
|
||||
) :
|
||||
VectorBaseFragment<FragmentTimelineBinding>(),
|
||||
TimelineEventController.Callback,
|
||||
@ -1491,9 +1494,6 @@ class TimelineFragment @Inject constructor(
|
||||
return
|
||||
}
|
||||
if (text.isNotBlank()) {
|
||||
withState(messageComposerViewModel) { state ->
|
||||
analyticsTracker.capture(Composer(isThreadTimeLine(), isEditing = state.sendMode is SendMode.Edit, isReply = state.sendMode is SendMode.Reply))
|
||||
}
|
||||
// We collapse ASAP, if not there will be a slight annoying delay
|
||||
views.composerLayout.collapse(true)
|
||||
lockSendButton = true
|
||||
@ -1613,7 +1613,10 @@ class TimelineFragment @Inject constructor(
|
||||
views.includeRoomToolbar.roomToolbarTitleView.text = roomSummary.displayName
|
||||
avatarRenderer.render(roomSummary.toMatrixItem(), views.includeRoomToolbar.roomToolbarAvatarImageView)
|
||||
views.includeRoomToolbar.roomToolbarDecorationImageView.render(roomSummary.roomEncryptionTrustLevel)
|
||||
views.includeRoomToolbar.roomToolbarPresenceImageView.render(roomSummary.isDirect, roomSummary.directUserPresence)
|
||||
views.includeRoomToolbar.roomToolbarPresenceImageView.render(
|
||||
roomSummary.isDirect && matrixConfiguration.presenceSyncEnabled,
|
||||
roomSummary.directUserPresence
|
||||
)
|
||||
views.includeRoomToolbar.roomToolbarPublicImageView.isVisible = roomSummary.isPublic && !roomSummary.isDirect
|
||||
}
|
||||
} else {
|
||||
@ -1773,13 +1776,11 @@ class TimelineFragment @Inject constructor(
|
||||
}
|
||||
is RoomDetailAction.ResumeVerification -> {
|
||||
val otherUserId = data.otherUserId ?: return
|
||||
VerificationBottomSheet().apply {
|
||||
setArguments(VerificationBottomSheet.VerificationArgs(
|
||||
otherUserId = otherUserId,
|
||||
verificationId = data.transactionId,
|
||||
roomId = timelineArgs.roomId
|
||||
))
|
||||
}.show(parentFragmentManager, "REQ")
|
||||
VerificationBottomSheet.withArgs(
|
||||
roomId = timelineArgs.roomId,
|
||||
otherUserId = otherUserId,
|
||||
transactionId = data.transactionId,
|
||||
).show(parentFragmentManager, "REQ")
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2174,7 +2175,7 @@ class TimelineFragment @Inject constructor(
|
||||
}
|
||||
is EventSharedAction.ReplyInThread -> {
|
||||
if (withState(messageComposerViewModel) { it.isVoiceMessageIdle }) {
|
||||
navigateToThreadTimeline(action.eventId)
|
||||
navigateToThreadTimeline(action.eventId, action.startsThread)
|
||||
} else {
|
||||
requireActivity().toast(R.string.error_voice_message_cannot_reply_or_edit)
|
||||
}
|
||||
@ -2333,9 +2334,11 @@ class TimelineFragment @Inject constructor(
|
||||
* using the ThreadsActivity
|
||||
*/
|
||||
|
||||
private fun navigateToThreadTimeline(rootThreadEventId: String) {
|
||||
private fun navigateToThreadTimeline(rootThreadEventId: String, startsThread: Boolean = false) {
|
||||
analyticsTracker.capture(Interaction.Name.MobileRoomThreadSummaryItem.toAnalyticsInteraction())
|
||||
context?.let {
|
||||
val roomThreadDetailArgs = ThreadTimelineArgs(
|
||||
startsThread = startsThread,
|
||||
roomId = timelineArgs.roomId,
|
||||
displayName = timelineViewModel.getRoomSummary()?.displayName,
|
||||
avatarUrl = timelineViewModel.getRoomSummary()?.avatarUrl,
|
||||
@ -2351,6 +2354,7 @@ class TimelineFragment @Inject constructor(
|
||||
*/
|
||||
|
||||
private fun navigateToThreadList() {
|
||||
analyticsTracker.capture(Interaction.Name.MobileRoomThreadListButton.toAnalyticsInteraction())
|
||||
context?.let {
|
||||
val roomThreadDetailArgs = ThreadTimelineArgs(
|
||||
roomId = timelineArgs.roomId,
|
||||
|
@ -27,6 +27,7 @@ import im.vector.app.core.extensions.exhaustive
|
||||
import im.vector.app.core.platform.VectorViewModel
|
||||
import im.vector.app.core.resources.StringProvider
|
||||
import im.vector.app.features.analytics.AnalyticsTracker
|
||||
import im.vector.app.features.analytics.extensions.toAnalyticsComposer
|
||||
import im.vector.app.features.analytics.extensions.toAnalyticsJoinedRoom
|
||||
import im.vector.app.features.attachments.toContentAttachmentData
|
||||
import im.vector.app.features.command.CommandParser
|
||||
@ -188,6 +189,9 @@ class MessageComposerViewModel @AssistedInject constructor(
|
||||
|
||||
private fun handleSendMessage(action: MessageComposerAction.SendMessage) {
|
||||
withState { state ->
|
||||
analyticsTracker.capture(state.toAnalyticsComposer()).also {
|
||||
setState { copy(startsThread = false) }
|
||||
}
|
||||
when (state.sendMode) {
|
||||
is SendMode.Regular -> {
|
||||
when (val slashCommandResult = commandParser.parseSlashCommand(
|
||||
|
@ -19,6 +19,7 @@ package im.vector.app.features.home.room.detail.composer
|
||||
import com.airbnb.mvrx.MavericksState
|
||||
import im.vector.app.features.home.room.detail.arguments.TimelineArgs
|
||||
import im.vector.app.features.home.room.detail.composer.voice.VoiceMessageRecorderView
|
||||
import org.matrix.android.sdk.api.extensions.orFalse
|
||||
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
|
||||
|
||||
/**
|
||||
@ -62,6 +63,7 @@ data class MessageComposerViewState(
|
||||
val canSendMessage: CanSendStatus = CanSendStatus.Allowed,
|
||||
val isSendButtonVisible: Boolean = false,
|
||||
val rootThreadEventId: String? = null,
|
||||
val startsThread: Boolean = false,
|
||||
val sendMode: SendMode = SendMode.Regular("", false),
|
||||
val voiceRecordingUiState: VoiceMessageRecorderView.RecordingUiState = VoiceMessageRecorderView.RecordingUiState.Idle
|
||||
) : MavericksState {
|
||||
@ -80,6 +82,7 @@ data class MessageComposerViewState(
|
||||
|
||||
constructor(args: TimelineArgs) : this(
|
||||
roomId = args.roomId,
|
||||
startsThread = args.threadTimelineArgs?.startsThread.orFalse(),
|
||||
rootThreadEventId = args.threadTimelineArgs?.rootThreadEventId)
|
||||
|
||||
fun isInThreadTimeline(): Boolean = rootThreadEventId != null
|
||||
|
@ -48,7 +48,7 @@ sealed class EventSharedAction(@StringRes val titleRes: Int,
|
||||
data class Reply(val eventId: String) :
|
||||
EventSharedAction(R.string.reply, R.drawable.ic_reply)
|
||||
|
||||
data class ReplyInThread(val eventId: String) :
|
||||
data class ReplyInThread(val eventId: String, val startsThread: Boolean) :
|
||||
EventSharedAction(R.string.reply_in_thread, R.drawable.ic_reply_in_thread)
|
||||
|
||||
object ViewInRoom :
|
||||
|
@ -61,6 +61,7 @@ import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
|
||||
import org.matrix.android.sdk.api.session.room.timeline.getLastMessageContent
|
||||
import org.matrix.android.sdk.api.session.room.timeline.hasBeenEdited
|
||||
import org.matrix.android.sdk.api.session.room.timeline.isPoll
|
||||
import org.matrix.android.sdk.api.session.room.timeline.isRootThread
|
||||
import org.matrix.android.sdk.api.session.room.timeline.isSticker
|
||||
import org.matrix.android.sdk.flow.flow
|
||||
import org.matrix.android.sdk.flow.unwrap
|
||||
@ -329,7 +330,7 @@ class MessageActionsViewModel @AssistedInject constructor(@Assisted
|
||||
}
|
||||
|
||||
if (canReplyInThread(timelineEvent, messageContent, actionPermissions)) {
|
||||
add(EventSharedAction.ReplyInThread(eventId))
|
||||
add(EventSharedAction.ReplyInThread(eventId, !timelineEvent.isRootThread()))
|
||||
}
|
||||
|
||||
if (canViewInRoom(timelineEvent, messageContent, actionPermissions)) {
|
||||
|
@ -155,7 +155,7 @@ class MessageItemFactory @Inject constructor(
|
||||
|
||||
if (event.root.isRedacted()) {
|
||||
// message is redacted
|
||||
val attributes = messageItemAttributesFactory.create(null, informationData, callback, params.reactionsSummaryEvents)
|
||||
val attributes = messageItemAttributesFactory.create(null, informationData, callback, params.reactionsSummaryEvents, threadDetails)
|
||||
return buildRedactedItem(attributes, highlight)
|
||||
}
|
||||
|
||||
|
@ -29,6 +29,7 @@ import im.vector.app.features.home.AvatarRenderer
|
||||
import im.vector.app.features.home.room.detail.timeline.format.DisplayableEventFormatter
|
||||
import im.vector.app.features.home.room.typing.TypingHelper
|
||||
import im.vector.lib.core.utils.epoxy.charsequence.toEpoxyCharSequence
|
||||
import org.matrix.android.sdk.api.MatrixConfiguration
|
||||
import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState
|
||||
import org.matrix.android.sdk.api.session.room.model.Membership
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||
@ -41,7 +42,8 @@ class RoomSummaryItemFactory @Inject constructor(private val displayableEventFor
|
||||
private val stringProvider: StringProvider,
|
||||
private val typingHelper: TypingHelper,
|
||||
private val avatarRenderer: AvatarRenderer,
|
||||
private val errorFormatter: ErrorFormatter) {
|
||||
private val errorFormatter: ErrorFormatter,
|
||||
private val matrixConfiguration: MatrixConfiguration) {
|
||||
|
||||
fun create(roomSummary: RoomSummary,
|
||||
roomChangeMembershipStates: Map<String, ChangeMembershipState>,
|
||||
@ -125,7 +127,7 @@ class RoomSummaryItemFactory @Inject constructor(private val displayableEventFor
|
||||
// We do not display shield in the room list anymore
|
||||
// .encryptionTrustLevel(roomSummary.roomEncryptionTrustLevel)
|
||||
.izPublic(roomSummary.isPublic)
|
||||
.showPresence(roomSummary.isDirect)
|
||||
.showPresence(roomSummary.isDirect && matrixConfiguration.presenceSyncEnabled)
|
||||
.userPresence(roomSummary.directUserPresence)
|
||||
.matrixItem(roomSummary.toMatrixItem())
|
||||
.lastEventTime(latestEventTime)
|
||||
|
@ -26,6 +26,8 @@ import im.vector.app.core.extensions.addFragmentToBackstack
|
||||
import im.vector.app.core.extensions.replaceFragment
|
||||
import im.vector.app.core.platform.VectorBaseActivity
|
||||
import im.vector.app.databinding.ActivityThreadsBinding
|
||||
import im.vector.app.features.analytics.extensions.toAnalyticsInteraction
|
||||
import im.vector.app.features.analytics.plan.Interaction
|
||||
import im.vector.app.features.home.AvatarRenderer
|
||||
import im.vector.app.features.home.room.detail.TimelineFragment
|
||||
import im.vector.app.features.home.room.detail.arguments.TimelineArgs
|
||||
@ -92,6 +94,7 @@ class ThreadsActivity : VectorBaseActivity<ActivityThreadsBinding>() {
|
||||
* One usage of that is from the Threads Activity
|
||||
*/
|
||||
fun navigateToThreadTimeline(threadTimelineArgs: ThreadTimelineArgs) {
|
||||
analyticsTracker.capture(Interaction.Name.MobileThreadListThreadItem.toAnalyticsInteraction())
|
||||
val commonOption: (FragmentTransaction) -> Unit = {
|
||||
it.setCustomAnimations(
|
||||
R.anim.animation_slide_in_right,
|
||||
|
@ -26,5 +26,6 @@ data class ThreadTimelineArgs(
|
||||
val displayName: String?,
|
||||
val avatarUrl: String?,
|
||||
val roomEncryptionTrustLevel: RoomEncryptionTrustLevel?,
|
||||
val rootThreadEventId: String? = null
|
||||
val rootThreadEventId: String? = null,
|
||||
val startsThread: Boolean = false
|
||||
) : Parcelable
|
||||
|
@ -25,6 +25,9 @@ import dagger.assisted.AssistedInject
|
||||
import im.vector.app.core.platform.EmptyAction
|
||||
import im.vector.app.core.platform.EmptyViewEvents
|
||||
import im.vector.app.core.platform.VectorViewModel
|
||||
import im.vector.app.features.analytics.AnalyticsTracker
|
||||
import im.vector.app.features.analytics.extensions.toAnalyticsInteraction
|
||||
import im.vector.app.features.analytics.plan.Interaction
|
||||
import im.vector.app.features.home.room.threads.list.views.ThreadListFragment
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.flow.map
|
||||
@ -34,6 +37,7 @@ import org.matrix.android.sdk.api.session.threads.ThreadTimelineEvent
|
||||
import org.matrix.android.sdk.flow.flow
|
||||
|
||||
class ThreadListViewModel @AssistedInject constructor(@Assisted val initialState: ThreadListViewState,
|
||||
private val analyticsTracker: AnalyticsTracker,
|
||||
private val session: Session) :
|
||||
VectorViewModel<ThreadListViewState, EmptyAction, EmptyViewEvents>(initialState) {
|
||||
|
||||
@ -113,9 +117,10 @@ class ThreadListViewModel @AssistedInject constructor(@Assisted val initialState
|
||||
}
|
||||
}
|
||||
|
||||
fun canHomeserverUseThreading() = session.getHomeServerCapabilities().canUseThreading
|
||||
fun canHomeserverUseThreading() = session.getHomeServerCapabilities().canUseThreading
|
||||
|
||||
fun applyFiltering(shouldFilterThreads: Boolean) {
|
||||
analyticsTracker.capture(Interaction.Name.MobileThreadListFilterItem.toAnalyticsInteraction())
|
||||
setState {
|
||||
copy(shouldFilterThreads = shouldFilterThreads)
|
||||
}
|
||||
|
@ -30,6 +30,7 @@ import im.vector.app.core.extensions.cleanup
|
||||
import im.vector.app.core.extensions.configureWith
|
||||
import im.vector.app.core.platform.VectorBaseFragment
|
||||
import im.vector.app.databinding.FragmentThreadListBinding
|
||||
import im.vector.app.features.analytics.plan.MobileScreen
|
||||
import im.vector.app.features.home.AvatarRenderer
|
||||
import im.vector.app.features.home.room.detail.timeline.animation.TimelineItemAnimator
|
||||
import im.vector.app.features.home.room.threads.ThreadsActivity
|
||||
@ -62,6 +63,7 @@ class ThreadListFragment @Inject constructor(
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
analyticsScreenName = MobileScreen.ScreenName.ThreadList
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
|
@ -54,6 +54,7 @@ import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedA
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import org.matrix.android.sdk.api.MatrixConfiguration
|
||||
import org.matrix.android.sdk.api.session.room.notification.RoomNotificationState
|
||||
import org.matrix.android.sdk.api.util.toMatrixItem
|
||||
import timber.log.Timber
|
||||
@ -67,7 +68,8 @@ data class RoomProfileArgs(
|
||||
class RoomProfileFragment @Inject constructor(
|
||||
private val roomProfileController: RoomProfileController,
|
||||
private val avatarRenderer: AvatarRenderer,
|
||||
private val roomDetailPendingActionStore: RoomDetailPendingActionStore
|
||||
private val roomDetailPendingActionStore: RoomDetailPendingActionStore,
|
||||
private val matrixConfiguration: MatrixConfiguration
|
||||
) :
|
||||
VectorBaseFragment<FragmentMatrixProfileBinding>(),
|
||||
RoomProfileController.Callback {
|
||||
@ -222,7 +224,7 @@ class RoomProfileFragment @Inject constructor(
|
||||
avatarRenderer.render(matrixItem, views.matrixProfileToolbarAvatarImageView)
|
||||
headerViews.roomProfileDecorationImageView.render(it.roomEncryptionTrustLevel)
|
||||
views.matrixProfileDecorationToolbarAvatarImageView.render(it.roomEncryptionTrustLevel)
|
||||
headerViews.roomProfilePresenceImageView.render(it.isDirect, it.directUserPresence)
|
||||
headerViews.roomProfilePresenceImageView.render(it.isDirect && matrixConfiguration.presenceSyncEnabled, it.directUserPresence)
|
||||
headerViews.roomProfilePublicImageView.isVisible = it.isPublic && !it.isDirect
|
||||
}
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ import im.vector.app.core.resources.ColorProvider
|
||||
import im.vector.app.core.resources.StringProvider
|
||||
import im.vector.app.features.home.AvatarRenderer
|
||||
import me.gujun.android.span.span
|
||||
import org.matrix.android.sdk.api.MatrixConfiguration
|
||||
import org.matrix.android.sdk.api.session.events.model.Event
|
||||
import org.matrix.android.sdk.api.session.events.model.toModel
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomMemberSummary
|
||||
@ -39,7 +40,8 @@ class RoomMemberListController @Inject constructor(
|
||||
private val avatarRenderer: AvatarRenderer,
|
||||
private val stringProvider: StringProvider,
|
||||
private val colorProvider: ColorProvider,
|
||||
private val roomMemberSummaryFilter: RoomMemberSummaryFilter
|
||||
private val roomMemberSummaryFilter: RoomMemberSummaryFilter,
|
||||
private val matrixConfiguration: MatrixConfiguration
|
||||
) : TypedEpoxyController<RoomMemberListViewState>() {
|
||||
|
||||
interface Callback {
|
||||
@ -122,6 +124,7 @@ class RoomMemberListController @Inject constructor(
|
||||
host: RoomMemberListController,
|
||||
data: RoomMemberListViewState) {
|
||||
val powerLabel = stringProvider.getString(powerLevelCategory.titleRes)
|
||||
val presenceSyncEnabled = matrixConfiguration.presenceSyncEnabled
|
||||
|
||||
profileMatrixItemWithPowerLevelWithPresence {
|
||||
id(roomMember.userId)
|
||||
@ -131,6 +134,7 @@ class RoomMemberListController @Inject constructor(
|
||||
clickListener {
|
||||
host.callback?.onRoomMemberClicked(roomMember)
|
||||
}
|
||||
showPresence(presenceSyncEnabled)
|
||||
userPresence(roomMember.userPresence)
|
||||
powerLevelLabel(
|
||||
span {
|
||||
|
@ -40,14 +40,16 @@ data class RoomNotificationSettingsViewState(
|
||||
*/
|
||||
val RoomNotificationSettingsViewState.notificationStateMapped: Async<RoomNotificationState>
|
||||
get() {
|
||||
if ((roomSummary()?.isEncrypted == true && notificationState() == RoomNotificationState.MENTIONS_ONLY) ||
|
||||
notificationState() == RoomNotificationState.ALL_MESSAGES) {
|
||||
/** if in an encrypted room, mentions notifications are not supported so show "All Messages" as selected.
|
||||
return when {
|
||||
/**
|
||||
* if in an encrypted room, mentions notifications are not supported so show "None" as selected.
|
||||
* Also in the new settings there is no notion of notifications without sound so it maps to noisy also
|
||||
*/
|
||||
return Success(RoomNotificationState.ALL_MESSAGES_NOISY)
|
||||
(roomSummary()?.isEncrypted == true && notificationState() == RoomNotificationState.MENTIONS_ONLY)
|
||||
-> Success(RoomNotificationState.MUTE)
|
||||
notificationState() == RoomNotificationState.ALL_MESSAGES -> Success(RoomNotificationState.ALL_MESSAGES_NOISY)
|
||||
else -> notificationState
|
||||
}
|
||||
return notificationState
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
x
Reference in New Issue
Block a user