- Add threads to lab settings

- Disable thread awareness due to the new fallback mechanism
This commit is contained in:
ariskotsomitopoulos 2022-01-19 12:28:00 +02:00
parent 4cff3938e7
commit 8cc96e27bc
23 changed files with 116 additions and 58 deletions

View file

@ -96,6 +96,11 @@ class Matrix private constructor(context: Context, matrixConfiguration: MatrixCo
companion object {
/**
* Determines whether or not thread messages are enabled
*/
var areThreadMessagesEnabled: Boolean = false
private lateinit var instance: Matrix
private val isInit = AtomicBoolean(false)

View file

@ -40,7 +40,6 @@ internal fun Map<String, EventEntity>.updateThreadSummaryIfNeeded(
roomId: String,
realm: Realm, currentUserId: String,
shouldUpdateNotifications: Boolean = true) {
if (!BuildConfig.THREADING_ENABLED) return
for ((rootThreadEventId, eventEntity) in this) {
eventEntity.findAllThreadsForRootEventId(eventEntity.realm, rootThreadEventId).let {

View file

@ -295,7 +295,8 @@ internal class TimelineChunk(private val chunkEntity: ChunkEntity,
.orEmpty()
if (timelineEvents.isEmpty()) return LoadedFromStorage()
fetchRootThreadEventsIfNeeded(timelineEvents)
// Disabled due to the new fallback
// fetchRootThreadEventsIfNeeded(timelineEvents)
if (direction == Timeline.Direction.FORWARDS) {
builtEventsIndexes.entries.forEach { it.setValue(it.value + timelineEvents.size) }
}
@ -332,7 +333,7 @@ internal class TimelineChunk(private val chunkEntity: ChunkEntity,
* in order to be able to display the event to the user appropriately
*/
private suspend fun fetchRootThreadEventsIfNeeded(offsetResults: List<TimelineEventEntity>) {
if (BuildConfig.THREADING_ENABLED) return
// if (BuildConfig.THREADING_ENABLED) return
val eventEntityList = offsetResults
.mapNotNull {
it.root

View file

@ -116,15 +116,16 @@ internal class TimelineEventDecryptor @Inject constructor(
eventEntity?.apply {
val decryptedPayload =
if (!BuildConfig.THREADING_ENABLED) {
threadsAwarenessHandler.handleIfNeededDuringDecryption(
it,
roomId = event.roomId,
event,
result)
} else {
// Disabled due to the new fallback
// if (!BuildConfig.THREADING_ENABLED) {
// threadsAwarenessHandler.handleIfNeededDuringDecryption(
// it,
// roomId = event.roomId,
// event,
// result)
// } else {
null
}
// }
setDecryptionResult(result, decryptedPayload)
}
}

View file

@ -19,6 +19,8 @@ package org.matrix.android.sdk.internal.session.room.timeline
import com.zhuinden.monarchy.Monarchy
import dagger.Lazy
import io.realm.Realm
import org.matrix.android.sdk.api.Matrix
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.toModel
import org.matrix.android.sdk.api.session.room.model.RoomMemberContent
@ -50,6 +52,7 @@ import javax.inject.Inject
internal class TokenChunkEventPersistor @Inject constructor(
@SessionDatabase private val monarchy: Monarchy,
@UserId private val userId: String,
private val matrixConfiguration: MatrixConfiguration,
private val liveEventManager: Lazy<StreamEventsManager>) {
enum class Result {
@ -182,6 +185,7 @@ internal class TokenChunkEventPersistor @Inject constructor(
}
liveEventManager.get().dispatchPaginatedEventReceived(event, roomId)
currentChunk.addTimelineEvent(roomId, eventEntity, direction, roomMemberContentsByUser)
if(Matrix.areThreadMessagesEnabled) {
eventEntity.rootThreadEventId?.let {
// This is a thread event
optimizedThreadSummaryMap[it] = eventEntity
@ -191,9 +195,12 @@ internal class TokenChunkEventPersistor @Inject constructor(
}
}
}
}
if (currentChunk.isValid) {
RoomEntity.where(realm, roomId).findFirst()?.addIfNecessary(currentChunk)
}
if(Matrix.areThreadMessagesEnabled) {
optimizedThreadSummaryMap.updateThreadSummaryIfNeeded(roomId = roomId, realm = realm, currentUserId = userId)
}
}
}

View file

@ -102,9 +102,10 @@ internal class SyncResponseHandler @Inject constructor(
val aggregator = SyncResponsePostTreatmentAggregator()
// Prerequisite for thread events handling in RoomSyncHandler
if (!BuildConfig.THREADING_ENABLED) {
threadsAwarenessHandler.fetchRootThreadEventsIfNeeded(syncResponse)
}
// Disabled due to the new fallback
// if (!BuildConfig.THREADING_ENABLED) {
// threadsAwarenessHandler.fetchRootThreadEventsIfNeeded(syncResponse)
// }
// Start one big transaction
monarchy.awaitTransaction { realm ->

View file

@ -19,7 +19,8 @@ package org.matrix.android.sdk.internal.session.sync.handler.room
import dagger.Lazy
import io.realm.Realm
import io.realm.kotlin.createObject
import org.matrix.android.sdk.BuildConfig
import org.matrix.android.sdk.api.Matrix
import org.matrix.android.sdk.api.MatrixConfiguration
import org.matrix.android.sdk.api.session.crypto.MXCryptoError
import org.matrix.android.sdk.api.session.events.model.Event
import org.matrix.android.sdk.api.session.events.model.EventType
@ -82,6 +83,7 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle
private val roomMemberEventHandler: RoomMemberEventHandler,
private val roomTypingUsersHandler: RoomTypingUsersHandler,
private val threadsAwarenessHandler: ThreadsAwarenessHandler,
private val matrixConfiguration: MatrixConfiguration,
private val roomChangeMembershipStateDataSource: RoomChangeMembershipStateDataSource,
@UserId private val userId: String,
private val timelineInput: TimelineInput,
@ -379,13 +381,13 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle
if (event.isEncrypted() && !isInitialSync) {
decryptIfNeeded(event, roomId)
}
if (!BuildConfig.THREADING_ENABLED) {
threadsAwarenessHandler.handleIfNeeded(
realm = realm,
roomId = roomId,
event = event)
}
// Disabled due to the new fallback
// if (!BuildConfig.THREADING_ENABLED) {
// threadsAwarenessHandler.handleIfNeeded(
// realm = realm,
// roomId = roomId,
// event = event)
// }
val ageLocalTs = event.unsignedData?.age?.let { syncLocalTimestampMillis - it }
val eventEntity = event.toEntity(roomId, SendState.SYNCED, ageLocalTs).copyToRealmOrIgnore(realm, insertType)
@ -408,6 +410,7 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle
}
chunkEntity.addTimelineEvent(roomId, eventEntity, PaginationDirection.FORWARDS, roomMemberContentsByUser)
if(Matrix.areThreadMessagesEnabled) {
eventEntity.rootThreadEventId?.let {
// This is a thread event
optimizedThreadSummaryMap[it] = eventEntity
@ -415,6 +418,7 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle
// This is a normal event or a root thread one
optimizedThreadSummaryMap[eventEntity.eventId] = eventEntity
}
}
// Give info to crypto module
cryptoService.onLiveEvent(roomEntity.roomId, event)
@ -442,10 +446,12 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle
}
// Handle deletion of [stuck] local echos if needed
deleteLocalEchosIfNeeded(insertType, roomEntity, eventList)
if(Matrix.areThreadMessagesEnabled) {
optimizedThreadSummaryMap.updateThreadSummaryIfNeeded(
roomId = roomId,
realm = realm,
currentUserId = userId)
}
// posting new events to timeline if any is registered
timelineInput.onNewTimelineEvents(roomId = roomId, eventIds = eventIds)

View file

@ -83,6 +83,7 @@ import im.vector.app.features.themes.ThemeUtils
import im.vector.app.receivers.DebugReceiver
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import org.matrix.android.sdk.api.Matrix
import org.matrix.android.sdk.api.extensions.tryOrNull
import org.matrix.android.sdk.api.failure.GlobalError
import reactivecircus.flowbinding.android.view.clicks
@ -193,6 +194,7 @@ abstract class VectorBaseActivity<VB : ViewBinding> : AppCompatActivity(), Maver
navigator = singletonEntryPoint.navigator()
activeSessionHolder = singletonEntryPoint.activeSessionHolder()
vectorPreferences = singletonEntryPoint.vectorPreferences()
Matrix.areThreadMessagesEnabled = vectorPreferences.areThreadMessagesEnabled()
configurationViewModel.activityRestarter.observe(this) {
if (!it.hasBeenHandled) {
// Recreate the Activity because configuration has changed

View file

@ -52,4 +52,8 @@ class UserPreferencesProvider @Inject constructor(private val vectorPreferences:
fun shouldShowPolls(): Boolean {
return vectorPreferences.labsEnablePolls()
}
fun areThreadMessagesEnabled(): Boolean {
return vectorPreferences.areThreadMessagesEnabled()
}
}

View file

@ -57,7 +57,7 @@ class AutocompleteCommandPresenter @AssistedInject constructor(
!it.isDevCommand || vectorPreferences.developerMode()
}
.filter {
if (BuildConfig.THREADING_ENABLED && isInThreadTimeline) {
if (vectorPreferences.areThreadMessagesEnabled() && isInThreadTimeline) {
it.isThreadCommand
} else {
true

View file

@ -65,7 +65,7 @@ object CommandParser {
val slashCommand = messageParts.first()
val message = textMessage.substring(slashCommand.length).trim()
if (BuildConfig.THREADING_ENABLED && isInThreadTimeline) {
if (isInThreadTimeline) {
val notSupportedCommandsInThreads = Command.values().filter {
!it.isThreadCommand
}.map {

View file

@ -1958,7 +1958,7 @@ class TimelineFragment @Inject constructor(
}
override fun onThreadSummaryClicked(eventId: String, isRootThreadEvent: Boolean) {
if (BuildConfig.THREADING_ENABLED && isRootThreadEvent && !isThreadTimeLine()) {
if (vectorPreferences.areThreadMessagesEnabled() && isRootThreadEvent && !isThreadTimeLine()) {
navigateToThreadTimeline(eventId)
}
}

View file

@ -695,7 +695,7 @@ class TimelineViewModel @AssistedInject constructor(
// Show Join conference button only if there is an active conf id not joined. Otherwise fallback to default video disabled. ^
R.id.join_conference -> !state.isWebRTCCallOptionAvailable() && state.jitsiState.confId != null && !state.jitsiState.hasJoined
R.id.search -> true
R.id.menu_timeline_thread_list -> BuildConfig.THREADING_ENABLED
R.id.menu_timeline_thread_list -> vectorPreferences.areThreadMessagesEnabled()
R.id.dev_tools -> vectorPreferences.developerMode()
else -> false
}

View file

@ -30,6 +30,7 @@ import im.vector.app.core.epoxy.charsequence.toEpoxyCharSequence
import im.vector.app.core.epoxy.loadingItem
import im.vector.app.core.epoxy.noResultItem
import im.vector.app.core.resources.StringProvider
import im.vector.app.core.resources.UserPreferencesProvider
import im.vector.app.core.ui.list.GenericHeaderItem_
import im.vector.app.features.home.AvatarRenderer
import org.matrix.android.sdk.api.session.Session
@ -43,7 +44,8 @@ class SearchResultController @Inject constructor(
private val session: Session,
private val avatarRenderer: AvatarRenderer,
private val stringProvider: StringProvider,
private val dateFormatter: VectorDateFormatter
private val dateFormatter: VectorDateFormatter,
private val userPreferencesProvider: UserPreferencesProvider
) : TypedEpoxyController<SearchViewState>() {
var listener: Listener? = null
@ -123,6 +125,7 @@ class SearchResultController @Inject constructor(
.sender(eventAndSender.sender
?: eventAndSender.event.senderId?.let { session.getRoomMember(it, data.roomId) }?.toMatrixItem())
.threadDetails(event.threadDetails)
.areThreadMessagesEnabled(userPreferencesProvider.areThreadMessagesEnabled())
.listener { listener?.onItemClicked(eventAndSender.event) }
.let { result.add(it) }
}

View file

@ -43,6 +43,7 @@ abstract class SearchResultItem : VectorEpoxyModel<SearchResultItem.Holder>() {
@EpoxyAttribute lateinit var spannable: EpoxyCharSequence
@EpoxyAttribute var sender: MatrixItem? = null
@EpoxyAttribute var threadDetails: ThreadDetails? = null
@EpoxyAttribute var areThreadMessagesEnabled: Boolean = false
@EpoxyAttribute(EpoxyAttribute.Option.DoNotHash) var listener: ClickListener? = null
@ -55,7 +56,7 @@ abstract class SearchResultItem : VectorEpoxyModel<SearchResultItem.Holder>() {
holder.timeView.text = formattedDate
holder.contentView.text = spannable.charSequence
if (BuildConfig.THREADING_ENABLED) {
if (areThreadMessagesEnabled) {
threadDetails?.let {
if (it.isRootThread) {
showThreadSummary(holder)

View file

@ -447,7 +447,7 @@ class MessageActionsViewModel @AssistedInject constructor(@Assisted
private fun canReplyInThread(event: TimelineEvent,
messageContent: MessageContent?,
actionPermissions: ActionPermissions): Boolean {
if (!BuildConfig.THREADING_ENABLED) return false
if (!vectorPreferences.areThreadMessagesEnabled()) return false
if (initialState.isFromThreadTimeline) return false
if (event.root.getClearType() != EventType.MESSAGE &&
!event.isSticker() && !event.isPoll()) return false
@ -472,7 +472,7 @@ class MessageActionsViewModel @AssistedInject constructor(@Assisted
private fun canViewInRoom(event: TimelineEvent,
messageContent: MessageContent?,
actionPermissions: ActionPermissions): Boolean {
if (!BuildConfig.THREADING_ENABLED) return false
if (!vectorPreferences.areThreadMessagesEnabled()) return false
if (!initialState.isFromThreadTimeline) return false
if (event.root.getClearType() != EventType.MESSAGE &&
!event.isSticker() && !event.isPoll()) return false

View file

@ -18,6 +18,7 @@ package im.vector.app.features.home.room.detail.timeline.helper
import im.vector.app.EmojiCompatFontProvider
import im.vector.app.R
import im.vector.app.core.resources.StringProvider
import im.vector.app.core.resources.UserPreferencesProvider
import im.vector.app.features.home.AvatarRenderer
import im.vector.app.features.home.room.detail.timeline.MessageColorProvider
import im.vector.app.features.home.room.detail.timeline.TimelineEventController
@ -31,6 +32,7 @@ class MessageItemAttributesFactory @Inject constructor(
private val messageColorProvider: MessageColorProvider,
private val avatarSizeProvider: AvatarSizeProvider,
private val stringProvider: StringProvider,
private val preferencesProvider: UserPreferencesProvider,
private val emojiCompatFontProvider: EmojiCompatFontProvider) {
fun create(messageContent: Any?,
@ -57,7 +59,8 @@ class MessageItemAttributesFactory @Inject constructor(
readReceiptsCallback = callback,
emojiTypeFace = emojiCompatFontProvider.typeface,
decryptionErrorMessage = stringProvider.getString(R.string.encrypted_message),
threadDetails = threadDetails
threadDetails = threadDetails,
areThreadMessagesEnabled = preferencesProvider.areThreadMessagesEnabled()
)
}
}

View file

@ -152,12 +152,11 @@ class TimelineEventVisibilityHelper @Inject constructor(private val userPreferen
return true
}
if (BuildConfig.THREADING_ENABLED && !isFromThreadTimeline && root.isThread()) {
if (userPreferencesProvider.areThreadMessagesEnabled() && !isFromThreadTimeline && root.isThread()) {
return true
}
if (BuildConfig.THREADING_ENABLED && isFromThreadTimeline) {
// //
if (userPreferencesProvider.areThreadMessagesEnabled() && isFromThreadTimeline) {
return if (root.getRootThreadEventId() == rootThreadEventId) {
false
} else root.eventId != rootThreadEventId

View file

@ -113,7 +113,7 @@ abstract class AbsMessageItem<H : AbsMessageItem.Holder> : AbsBaseMessageItem<H>
holder.eventSendingIndicator.isVisible = attributes.informationData.sendStateDecoration == SendStateDecoration.SENDING_MEDIA
// Threads
if (BuildConfig.THREADING_ENABLED) {
if (attributes.areThreadMessagesEnabled) {
holder.threadSummaryConstraintLayout.onClick(_threadClickListener)
attributes.threadDetails?.let { threadDetails ->
holder.threadSummaryConstraintLayout.isVisible = threadDetails.isRootThread
@ -186,7 +186,8 @@ abstract class AbsMessageItem<H : AbsMessageItem.Holder> : AbsBaseMessageItem<H>
override val readReceiptsCallback: TimelineEventController.ReadReceiptsCallback? = null,
val emojiTypeFace: Typeface? = null,
val decryptionErrorMessage: String? = null,
val threadDetails: ThreadDetails? = null
val threadDetails: ThreadDetails? = null,
val areThreadMessagesEnabled: Boolean = false
) : AbsBaseMessageItem.Attributes {
// Have to override as it's used to diff epoxy items

View file

@ -197,6 +197,7 @@ class VectorPreferences @Inject constructor(private val context: Context) {
private const val TAKE_PHOTO_VIDEO_MODE = "TAKE_PHOTO_VIDEO_MODE"
private const val SETTINGS_LABS_ENABLE_POLLS = "SETTINGS_LABS_ENABLE_POLLS"
const val SETTINGS_LABS_ENABLE_THREAD_MESSAGES = "SETTINGS_LABS_ENABLE_THREAD_MESSAGES"
// Possible values for TAKE_PHOTO_VIDEO_MODE
const val TAKE_PHOTO_VIDEO_MODE_ALWAYS_ASK = 0
@ -995,4 +996,8 @@ class VectorPreferences @Inject constructor(private val context: Context) {
fun labsEnablePolls(): Boolean {
return defaultPrefs.getBoolean(SETTINGS_LABS_ENABLE_POLLS, false)
}
fun areThreadMessagesEnabled(): Boolean {
return defaultPrefs.getBoolean(SETTINGS_LABS_ENABLE_THREAD_MESSAGES, false)
}
}

View file

@ -16,8 +16,11 @@
package im.vector.app.features.settings
import androidx.preference.Preference
import im.vector.app.R
import im.vector.app.core.preference.VectorSwitchPreference
import im.vector.app.features.MainActivity
import im.vector.app.features.MainActivityArgs
import javax.inject.Inject
class VectorSettingsLabsFragment @Inject constructor(
@ -32,5 +35,15 @@ class VectorSettingsLabsFragment @Inject constructor(
// ensure correct default
pref.isChecked = vectorPreferences.labsAutoReportUISI()
}
// clear cache
findPreference<VectorSwitchPreference>(VectorPreferences.SETTINGS_LABS_ENABLE_THREAD_MESSAGES)?.let {
it.onPreferenceClickListener = Preference.OnPreferenceClickListener {
displayLoadingView()
MainActivity.restartApp(requireActivity(), MainActivityArgs(clearCache = true))
false
}
}
}
}

View file

@ -3600,6 +3600,8 @@
<string name="labs_auto_report_uisi">Auto Report Decryption Errors.</string>
<string name="labs_auto_report_uisi_desc">Your system will automatically send logs when an unable to decrypt error occurs</string>
<string name="labs_enable_thread_messages">Enable Thread Messages</string>
<string name="labs_enable_thread_messages_desc">Note: app will be restarted</string>
<string name="user_invites_you">%s invites you</string>

View file

@ -56,11 +56,16 @@
android:key="SETTINGS_LABS_ENABLE_POLLS"
android:title="@string/labs_enable_polls" />
<im.vector.app.core.preference.VectorSwitchPreference
android:defaultValue="false"
android:key="SETTINGS_LABS_ENABLE_THREAD_MESSAGES"
android:summary="@string/labs_enable_thread_messages_desc"
android:title="@string/labs_enable_thread_messages" />
<im.vector.app.core.preference.VectorSwitchPreference
android:defaultValue="false"
android:key="SETTINGS_LABS_AUTO_REPORT_UISI"
android:title="@string/labs_auto_report_uisi"
android:summary="@string/labs_auto_report_uisi_desc"/>
android:summary="@string/labs_auto_report_uisi_desc"
android:title="@string/labs_auto_report_uisi" />
</androidx.preference.PreferenceScreen>