|
|
|
@ -55,12 +55,12 @@ import kotlinx.coroutines.flow.launchIn
@@ -55,12 +55,12 @@ import kotlinx.coroutines.flow.launchIn
|
|
|
|
|
import kotlinx.coroutines.flow.onEach |
|
|
|
|
import kotlinx.coroutines.launch |
|
|
|
|
import kotlinx.coroutines.withContext |
|
|
|
|
import timber.log.Timber |
|
|
|
|
|
|
|
|
|
const val FOCUS_ON_PINNED_EVENT_DEBOUNCE_DURATION_IN_MILLIS = 200L |
|
|
|
|
|
|
|
|
|
class TimelinePresenter @AssistedInject constructor( |
|
|
|
|
timelineItemsFactoryCreator: TimelineItemsFactory.Creator, |
|
|
|
|
private val timelineItemIndexer: TimelineItemIndexer, |
|
|
|
|
private val room: MatrixRoom, |
|
|
|
|
private val dispatchers: CoroutineDispatchers, |
|
|
|
|
private val appScope: CoroutineScope, |
|
|
|
@ -70,6 +70,7 @@ class TimelinePresenter @AssistedInject constructor(
@@ -70,6 +70,7 @@ class TimelinePresenter @AssistedInject constructor(
|
|
|
|
|
private val endPollAction: EndPollAction, |
|
|
|
|
private val sessionPreferencesStore: SessionPreferencesStore, |
|
|
|
|
private val timelineController: TimelineController, |
|
|
|
|
private val timelineItemIndexer: TimelineItemIndexer = TimelineItemIndexer(), |
|
|
|
|
private val resolveVerifiedUserSendFailurePresenter: Presenter<ResolveVerifiedUserSendFailureState>, |
|
|
|
|
private val typingNotificationPresenter: Presenter<TypingNotificationState>, |
|
|
|
|
) : Presenter<TimelineState> { |
|
|
|
@ -89,13 +90,7 @@ class TimelinePresenter @AssistedInject constructor(
@@ -89,13 +90,7 @@ class TimelinePresenter @AssistedInject constructor(
|
|
|
|
|
@Composable |
|
|
|
|
override fun present(): TimelineState { |
|
|
|
|
val localScope = rememberCoroutineScope() |
|
|
|
|
val focusRequestState: MutableState<FocusRequestState> = remember { |
|
|
|
|
mutableStateOf(FocusRequestState.None) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
LaunchedEffect(Unit) { |
|
|
|
|
timelineItemsFactory.timelineItems.collect { timelineItems = it } |
|
|
|
|
} |
|
|
|
|
var focusRequestState: FocusRequestState by remember { mutableStateOf(FocusRequestState.None) } |
|
|
|
|
|
|
|
|
|
val lastReadReceiptId = rememberSaveable { mutableStateOf<EventId?>(null) } |
|
|
|
|
|
|
|
|
@ -154,13 +149,13 @@ class TimelinePresenter @AssistedInject constructor(
@@ -154,13 +149,13 @@ class TimelinePresenter @AssistedInject constructor(
|
|
|
|
|
navigator.onEditPollClick(event.pollStartId) |
|
|
|
|
} |
|
|
|
|
is TimelineEvents.FocusOnEvent -> { |
|
|
|
|
focusRequestState.value = FocusRequestState.Requested(event.eventId, event.debounce) |
|
|
|
|
focusRequestState = FocusRequestState.Requested(event.eventId, event.debounce) |
|
|
|
|
} |
|
|
|
|
is TimelineEvents.OnFocusEventRender -> { |
|
|
|
|
focusRequestState.value = focusRequestState.value.onFocusEventRender() |
|
|
|
|
focusRequestState = focusRequestState.onFocusEventRender() |
|
|
|
|
} |
|
|
|
|
is TimelineEvents.ClearFocusRequestState -> { |
|
|
|
|
focusRequestState.value = FocusRequestState.None |
|
|
|
|
focusRequestState = FocusRequestState.None |
|
|
|
|
} |
|
|
|
|
is TimelineEvents.JumpToLive -> { |
|
|
|
|
timelineController.focusOnLive() |
|
|
|
@ -173,28 +168,46 @@ class TimelinePresenter @AssistedInject constructor(
@@ -173,28 +168,46 @@ class TimelinePresenter @AssistedInject constructor(
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
LaunchedEffect(focusRequestState.value) { |
|
|
|
|
when (val currentFocusRequestState = focusRequestState.value) { |
|
|
|
|
LaunchedEffect(Unit) { |
|
|
|
|
timelineItemsFactory.timelineItems |
|
|
|
|
.onEach { newTimelineItems -> |
|
|
|
|
timelineItemIndexer.process(newTimelineItems) |
|
|
|
|
timelineItems = newTimelineItems |
|
|
|
|
} |
|
|
|
|
.launchIn(this) |
|
|
|
|
|
|
|
|
|
combine(timelineController.timelineItems(), room.membersStateFlow) { items, membersState -> |
|
|
|
|
timelineItemsFactory.replaceWith( |
|
|
|
|
timelineItems = items, |
|
|
|
|
roomMembers = membersState.roomMembers().orEmpty() |
|
|
|
|
) |
|
|
|
|
items |
|
|
|
|
} |
|
|
|
|
.onEach(redactedVoiceMessageManager::onEachMatrixTimelineItem) |
|
|
|
|
.launchIn(this) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
LaunchedEffect(focusRequestState) { |
|
|
|
|
Timber.d("## focusRequestState: $focusRequestState") |
|
|
|
|
when (val currentFocusRequestState = focusRequestState) { |
|
|
|
|
is FocusRequestState.Requested -> { |
|
|
|
|
delay(currentFocusRequestState.debounce) |
|
|
|
|
if (timelineItemIndexer.isKnown(currentFocusRequestState.eventId)) { |
|
|
|
|
val index = timelineItemIndexer.indexOf(currentFocusRequestState.eventId) |
|
|
|
|
focusRequestState.value = FocusRequestState.Success(eventId = currentFocusRequestState.eventId, index = index) |
|
|
|
|
focusRequestState = FocusRequestState.Success(eventId = currentFocusRequestState.eventId, index = index) |
|
|
|
|
} else { |
|
|
|
|
focusRequestState.value = FocusRequestState.Loading(eventId = currentFocusRequestState.eventId) |
|
|
|
|
focusRequestState = FocusRequestState.Loading(eventId = currentFocusRequestState.eventId) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
is FocusRequestState.Loading -> { |
|
|
|
|
val eventId = currentFocusRequestState.eventId |
|
|
|
|
timelineController.focusOnEvent(eventId) |
|
|
|
|
.fold( |
|
|
|
|
onSuccess = { |
|
|
|
|
focusRequestState.value = FocusRequestState.Success(eventId = eventId) |
|
|
|
|
}, |
|
|
|
|
onFailure = { |
|
|
|
|
focusRequestState.value = FocusRequestState.Failure(throwable = it) |
|
|
|
|
} |
|
|
|
|
) |
|
|
|
|
.onSuccess { |
|
|
|
|
focusRequestState = FocusRequestState.Success(eventId = eventId) |
|
|
|
|
} |
|
|
|
|
.onFailure { |
|
|
|
|
focusRequestState = FocusRequestState.Failure(it) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
else -> Unit |
|
|
|
|
} |
|
|
|
@ -204,29 +217,17 @@ class TimelinePresenter @AssistedInject constructor(
@@ -204,29 +217,17 @@ class TimelinePresenter @AssistedInject constructor(
|
|
|
|
|
computeNewItemState(timelineItems, prevMostRecentItemId, newEventState) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
LaunchedEffect(timelineItems.size, focusRequestState.value) { |
|
|
|
|
val currentFocusRequestState = focusRequestState.value |
|
|
|
|
if (currentFocusRequestState is FocusRequestState.Success && !currentFocusRequestState.isIndexed) { |
|
|
|
|
LaunchedEffect(timelineItems.size, focusRequestState) { |
|
|
|
|
val currentFocusRequestState = focusRequestState |
|
|
|
|
if (currentFocusRequestState is FocusRequestState.Success && !currentFocusRequestState.rendered) { |
|
|
|
|
val eventId = currentFocusRequestState.eventId |
|
|
|
|
if (timelineItemIndexer.isKnown(eventId)) { |
|
|
|
|
val index = timelineItemIndexer.indexOf(eventId) |
|
|
|
|
focusRequestState.value = FocusRequestState.Success(eventId = eventId, index = index) |
|
|
|
|
focusRequestState = FocusRequestState.Success(eventId = eventId, index = index) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
LaunchedEffect(Unit) { |
|
|
|
|
combine(timelineController.timelineItems(), room.membersStateFlow) { items, membersState -> |
|
|
|
|
timelineItemsFactory.replaceWith( |
|
|
|
|
timelineItems = items, |
|
|
|
|
roomMembers = membersState.roomMembers().orEmpty() |
|
|
|
|
) |
|
|
|
|
items |
|
|
|
|
} |
|
|
|
|
.onEach(redactedVoiceMessageManager::onEachMatrixTimelineItem) |
|
|
|
|
.launchIn(this) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
val typingNotificationState = typingNotificationPresenter.present() |
|
|
|
|
val timelineRoomInfo by remember(typingNotificationState) { |
|
|
|
|
derivedStateOf { |
|
|
|
@ -247,7 +248,7 @@ class TimelinePresenter @AssistedInject constructor(
@@ -247,7 +248,7 @@ class TimelinePresenter @AssistedInject constructor(
|
|
|
|
|
renderReadReceipts = renderReadReceipts, |
|
|
|
|
newEventState = newEventState.value, |
|
|
|
|
isLive = isLive, |
|
|
|
|
focusRequestState = focusRequestState.value, |
|
|
|
|
focusRequestState = focusRequestState, |
|
|
|
|
messageShield = messageShield.value, |
|
|
|
|
resolveVerifiedUserSendFailureState = resolveVerifiedUserSendFailureState, |
|
|
|
|
eventSink = { handleEvents(it) } |
|
|
|
|