Merge branch 'develop' into feature/fga/image_loading
This commit is contained in:
commit
4b60b14550
182 changed files with 2492 additions and 884 deletions
|
|
@ -1,38 +0,0 @@
|
|||
/*
|
||||
* 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 io.element.android.features.messages
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
/**
|
||||
* Instrumented test, which will execute on an Android device.
|
||||
*
|
||||
* See [testing documentation](http://d.android.com/tools/testing).
|
||||
*/
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class ExampleInstrumentedTest {
|
||||
@Test
|
||||
fun useAppContext() {
|
||||
// Context of the app under test.
|
||||
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
|
||||
assertEquals("io.element.android.features.messages.test", appContext.packageName)
|
||||
}
|
||||
}
|
||||
|
|
@ -102,6 +102,7 @@ private fun SheetContent(
|
|||
// Crashes if sheetContent size is zero
|
||||
Box(modifier = modifier.size(1.dp))
|
||||
}
|
||||
|
||||
is ActionListState.Target.Success -> {
|
||||
val actions = target.actions
|
||||
LazyColumn(
|
||||
|
|
@ -146,5 +147,11 @@ fun SheetContentDarkPreview(@PreviewParameter(ActionListStateProvider::class) st
|
|||
|
||||
@Composable
|
||||
private fun ContentToPreview(state: ActionListState) {
|
||||
SheetContent(state)
|
||||
ActionListView(
|
||||
state = state,
|
||||
modalBottomSheetState = ModalBottomSheetState(
|
||||
initialValue = ModalBottomSheetValue.Expanded
|
||||
),
|
||||
onActionSelected = { _, _ -> }
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,4 +24,6 @@ sealed interface MessageComposerEvents {
|
|||
object CloseSpecialMode : MessageComposerEvents
|
||||
data class SetMode(val composerMode: MessageComposerMode) : MessageComposerEvents
|
||||
data class UpdateText(val text: CharSequence) : MessageComposerEvents
|
||||
|
||||
object TakePhoto : MessageComposerEvents
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,23 +21,37 @@ import androidx.compose.runtime.LaunchedEffect
|
|||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import io.element.android.libraries.architecture.Presenter
|
||||
import io.element.android.libraries.core.data.StableCharSequence
|
||||
import io.element.android.libraries.core.data.toStableCharSequence
|
||||
import io.element.android.libraries.featureflag.api.FeatureFlagService
|
||||
import io.element.android.libraries.featureflag.api.FeatureFlags
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||
import io.element.android.libraries.mediapickers.PickerProvider
|
||||
import io.element.android.libraries.textcomposer.MessageComposerMode
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
class MessageComposerPresenter @Inject constructor(
|
||||
private val appCoroutineScope: CoroutineScope,
|
||||
private val room: MatrixRoom
|
||||
private val room: MatrixRoom,
|
||||
private val mediaPickerProvider: PickerProvider,
|
||||
private val featureFlagService: FeatureFlagService,
|
||||
) : Presenter<MessageComposerState> {
|
||||
|
||||
@Composable
|
||||
override fun present(): MessageComposerState {
|
||||
val localCoroutineScope = rememberCoroutineScope()
|
||||
|
||||
// Example usage of custom pickers
|
||||
val cameraPhotoPicker = mediaPickerProvider.registerCameraPhotoPicker(onResult = { uri ->
|
||||
Timber.d("Photo saved at $uri")
|
||||
})
|
||||
|
||||
val isFullScreen = rememberSaveable {
|
||||
mutableStateOf(false)
|
||||
}
|
||||
|
|
@ -63,9 +77,14 @@ class MessageComposerPresenter @Inject constructor(
|
|||
text.value = "".toStableCharSequence()
|
||||
composerMode.setToNormal()
|
||||
}
|
||||
|
||||
is MessageComposerEvents.SendMessage -> appCoroutineScope.sendMessage(event.message, composerMode, text)
|
||||
is MessageComposerEvents.SetMode -> composerMode.value = event.composerMode
|
||||
}
|
||||
MessageComposerEvents.TakePhoto -> localCoroutineScope.launch {
|
||||
if (featureFlagService.isFeatureEnabled(FeatureFlags.ShowMediaUploadingFlow)) {
|
||||
cameraPhotoPicker.launch()
|
||||
}
|
||||
}}
|
||||
}
|
||||
|
||||
return MessageComposerState(
|
||||
|
|
@ -92,6 +111,7 @@ class MessageComposerPresenter @Inject constructor(
|
|||
capturedMode.eventId,
|
||||
text
|
||||
)
|
||||
|
||||
is MessageComposerMode.Quote -> TODO()
|
||||
is MessageComposerMode.Reply -> room.replyMessage(
|
||||
capturedMode.eventId,
|
||||
|
|
|
|||
|
|
@ -53,6 +53,9 @@ fun MessageComposerView(
|
|||
composerMode = state.mode,
|
||||
onCloseSpecialMode = ::onCloseSpecialMode,
|
||||
onComposerTextChange = ::onComposerTextChange,
|
||||
onAddAttachment = {
|
||||
state.eventSink(MessageComposerEvents.TakePhoto)
|
||||
},
|
||||
composerCanSendMessage = state.isSendButtonVisible,
|
||||
composerText = state.text?.charSequence?.toString(),
|
||||
isInDarkMode = !ElementTheme.colors.isLight,
|
||||
|
|
|
|||
|
|
@ -80,13 +80,6 @@ class TimelinePresenter @Inject constructor(
|
|||
.launchIn(this)
|
||||
}
|
||||
|
||||
DisposableEffect(Unit) {
|
||||
timeline.initialize()
|
||||
onDispose {
|
||||
timeline.dispose()
|
||||
}
|
||||
}
|
||||
|
||||
return TimelineState(
|
||||
highlightedEventId = highlightedEventId.value,
|
||||
paginationState = paginationState.value,
|
||||
|
|
|
|||
|
|
@ -99,11 +99,11 @@ fun TimelineView(
|
|||
itemsIndexed(
|
||||
items = state.timelineItems,
|
||||
contentType = { _, timelineItem -> timelineItem.contentType() },
|
||||
key = { _, timelineItem -> timelineItem.key() },
|
||||
key = { _, timelineItem -> timelineItem.identifier() },
|
||||
) { index, timelineItem ->
|
||||
TimelineItemRow(
|
||||
timelineItem = timelineItem,
|
||||
isHighlighted = timelineItem.key() == state.highlightedEventId?.value,
|
||||
isHighlighted = timelineItem.identifier() == state.highlightedEventId?.value,
|
||||
onClick = onMessageClicked,
|
||||
onLongClick = onMessageLongClicked
|
||||
)
|
||||
|
|
@ -121,21 +121,6 @@ fun TimelineView(
|
|||
}
|
||||
}
|
||||
|
||||
private fun TimelineItem.key(): String {
|
||||
return when (this) {
|
||||
is TimelineItem.Event -> id
|
||||
is TimelineItem.Virtual -> id
|
||||
}
|
||||
}
|
||||
|
||||
private fun TimelineItem.contentType(): Int {
|
||||
// Todo optimize for each subtype
|
||||
return when (this) {
|
||||
is TimelineItem.Event -> 0
|
||||
is TimelineItem.Virtual -> 1
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun TimelineItemRow(
|
||||
timelineItem: TimelineItem,
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ internal class CacheInvalidator(private val itemStatesCache: MutableList<Timelin
|
|||
ListUpdateCallback {
|
||||
|
||||
override fun onChanged(position: Int, count: Int, payload: Any?) {
|
||||
Timber.v("onChanged(position= $position, count= $count")
|
||||
Timber.d("onChanged(position= $position, count= $count)")
|
||||
(position until position + count).forEach {
|
||||
// Invalidate cache
|
||||
itemStatesCache[it] = null
|
||||
|
|
@ -33,13 +33,13 @@ internal class CacheInvalidator(private val itemStatesCache: MutableList<Timelin
|
|||
}
|
||||
|
||||
override fun onMoved(fromPosition: Int, toPosition: Int) {
|
||||
Timber.v("onMoved(fromPosition= $fromPosition, toPosition= $toPosition")
|
||||
Timber.d("onMoved(fromPosition= $fromPosition, toPosition= $toPosition)")
|
||||
val model = itemStatesCache.removeAt(fromPosition)
|
||||
itemStatesCache.add(toPosition, model)
|
||||
}
|
||||
|
||||
override fun onInserted(position: Int, count: Int) {
|
||||
Timber.v("onInserted(position= $position, count= $count")
|
||||
Timber.d("onInserted(position= $position, count= $count)")
|
||||
itemStatesCache.invalidateLast()
|
||||
repeat(count) {
|
||||
itemStatesCache.add(position, null)
|
||||
|
|
@ -47,7 +47,7 @@ internal class CacheInvalidator(private val itemStatesCache: MutableList<Timelin
|
|||
}
|
||||
|
||||
override fun onRemoved(position: Int, count: Int) {
|
||||
Timber.v("onRemoved(position= $position, count= $count")
|
||||
Timber.d("onRemoved(position= $position, count= $count)")
|
||||
itemStatesCache.invalidateLast()
|
||||
repeat(count) {
|
||||
itemStatesCache.removeAt(position)
|
||||
|
|
|
|||
|
|
@ -31,6 +31,11 @@ sealed interface TimelineItem {
|
|||
is Virtual -> id
|
||||
}
|
||||
|
||||
fun contentType(): String = when (this) {
|
||||
is Event -> content.type
|
||||
is Virtual -> model.type
|
||||
}
|
||||
|
||||
@Immutable
|
||||
data class Virtual(
|
||||
val id: String,
|
||||
|
|
|
|||
|
|
@ -21,4 +21,6 @@ import org.jsoup.nodes.Document
|
|||
data class TimelineItemEmoteContent(
|
||||
override val body: String,
|
||||
override val htmlDocument: Document?
|
||||
) : TimelineItemTextBasedContent
|
||||
) : TimelineItemTextBasedContent {
|
||||
override val type: String = "TimelineItemEmoteContent"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,4 +20,6 @@ import io.element.android.libraries.matrix.api.timeline.item.event.UnableToDecry
|
|||
|
||||
data class TimelineItemEncryptedContent(
|
||||
val data: UnableToDecryptContent.Data
|
||||
) : TimelineItemEventContent
|
||||
) : TimelineItemEventContent {
|
||||
override val type: String = "TimelineItemEncryptedContent"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,4 +19,6 @@ package io.element.android.features.messages.impl.timeline.model.event
|
|||
import androidx.compose.runtime.Immutable
|
||||
|
||||
@Immutable
|
||||
sealed interface TimelineItemEventContent
|
||||
sealed interface TimelineItemEventContent {
|
||||
val type: String
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,4 +23,6 @@ data class TimelineItemImageContent(
|
|||
val mediaRequestData: MediaRequestData,
|
||||
val blurhash: String?,
|
||||
val aspectRatio: Float
|
||||
) : TimelineItemEventContent
|
||||
) : TimelineItemEventContent{
|
||||
override val type: String = "TimelineItemImageContent"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,4 +21,6 @@ import org.jsoup.nodes.Document
|
|||
data class TimelineItemNoticeContent(
|
||||
override val body: String,
|
||||
override val htmlDocument: Document?
|
||||
) : TimelineItemTextBasedContent
|
||||
) : TimelineItemTextBasedContent {
|
||||
override val type: String = "TimelineItemNoticeContent"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,4 +16,6 @@
|
|||
|
||||
package io.element.android.features.messages.impl.timeline.model.event
|
||||
|
||||
object TimelineItemRedactedContent : TimelineItemEventContent
|
||||
object TimelineItemRedactedContent : TimelineItemEventContent{
|
||||
override val type: String = "TimelineItemRedactedContent"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,4 +21,6 @@ import org.jsoup.nodes.Document
|
|||
data class TimelineItemTextContent(
|
||||
override val body: String,
|
||||
override val htmlDocument: Document?
|
||||
) : TimelineItemTextBasedContent
|
||||
) : TimelineItemTextBasedContent{
|
||||
override val type: String = "TimelineItemTextContent"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,4 +16,6 @@
|
|||
|
||||
package io.element.android.features.messages.impl.timeline.model.event
|
||||
|
||||
object TimelineItemUnknownContent : TimelineItemEventContent
|
||||
object TimelineItemUnknownContent : TimelineItemEventContent {
|
||||
override val type: String = "TimelineItemUnknownContent"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,4 +18,6 @@ package io.element.android.features.messages.impl.timeline.model.virtual
|
|||
|
||||
data class TimelineItemDaySeparatorModel(
|
||||
val formattedDate: String
|
||||
) : TimelineItemVirtualModel
|
||||
) : TimelineItemVirtualModel {
|
||||
override val type: String = "TimelineItemDaySeparatorModel"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,4 +16,6 @@
|
|||
|
||||
package io.element.android.features.messages.impl.timeline.model.virtual
|
||||
|
||||
object TimelineItemLoadingModel : TimelineItemVirtualModel
|
||||
object TimelineItemLoadingModel : TimelineItemVirtualModel {
|
||||
override val type: String = "TimelineItemLoadingModel"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,4 +16,6 @@
|
|||
|
||||
package io.element.android.features.messages.impl.timeline.model.virtual
|
||||
|
||||
object TimelineItemReadMarkerModel : TimelineItemVirtualModel
|
||||
object TimelineItemReadMarkerModel : TimelineItemVirtualModel {
|
||||
override val type: String = "TimelineItemReadMarkerModel"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,4 +16,6 @@
|
|||
|
||||
package io.element.android.features.messages.impl.timeline.model.virtual
|
||||
|
||||
object TimelineItemTimelineStartModel : TimelineItemVirtualModel
|
||||
object TimelineItemTimelineStartModel : TimelineItemVirtualModel {
|
||||
override val type: String = "TimelineItemTimelineStartModel"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,4 +16,6 @@
|
|||
|
||||
package io.element.android.features.messages.impl.timeline.model.virtual
|
||||
|
||||
object TimelineItemUnknownVirtualModel : TimelineItemVirtualModel
|
||||
object TimelineItemUnknownVirtualModel : TimelineItemVirtualModel {
|
||||
override val type: String = "TimelineItemUnknownVirtualModel"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,4 +19,6 @@ package io.element.android.features.messages.impl.timeline.model.virtual
|
|||
import androidx.compose.runtime.Immutable
|
||||
|
||||
@Immutable
|
||||
sealed interface TimelineItemVirtualModel
|
||||
sealed interface TimelineItemVirtualModel {
|
||||
val type: String
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,10 +31,12 @@ import io.element.android.features.messages.impl.actionlist.model.TimelineItemAc
|
|||
import io.element.android.features.messages.impl.textcomposer.MessageComposerPresenter
|
||||
import io.element.android.features.messages.impl.timeline.TimelinePresenter
|
||||
import io.element.android.features.networkmonitor.test.FakeNetworkMonitor
|
||||
import io.element.android.libraries.featureflag.test.FakeFeatureFlagService
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||
import io.element.android.libraries.matrix.test.AN_EVENT_ID
|
||||
import io.element.android.libraries.matrix.test.A_ROOM_ID
|
||||
import io.element.android.libraries.matrix.test.room.FakeMatrixRoom
|
||||
import io.element.android.libraries.mediapickers.PickerProvider
|
||||
import io.element.android.libraries.textcomposer.MessageComposerMode
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.test.TestScope
|
||||
|
|
@ -129,9 +131,10 @@ class MessagesPresenterTest {
|
|||
): MessagesPresenter {
|
||||
val messageComposerPresenter = MessageComposerPresenter(
|
||||
appCoroutineScope = this,
|
||||
room = matrixRoom
|
||||
room = matrixRoom,
|
||||
mediaPickerProvider = PickerProvider(isInTest = true),
|
||||
featureFlagService = FakeFeatureFlagService(),
|
||||
)
|
||||
|
||||
val timelinePresenter = TimelinePresenter(
|
||||
timelineItemsFactory = aTimelineItemsFactory(),
|
||||
room = matrixRoom,
|
||||
|
|
|
|||
|
|
@ -1,28 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2023 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 io.element.android.features.messages.fixtures
|
||||
|
||||
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
|
||||
import kotlinx.coroutines.test.UnconfinedTestDispatcher
|
||||
|
||||
// TODO Move to common module to reuse
|
||||
internal fun testCoroutineDispatchers() = CoroutineDispatchers(
|
||||
io = UnconfinedTestDispatcher(),
|
||||
computation = UnconfinedTestDispatcher(),
|
||||
main = UnconfinedTestDispatcher(),
|
||||
diffUpdateDispatcher = UnconfinedTestDispatcher(),
|
||||
)
|
||||
|
|
@ -14,6 +14,8 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
@file:OptIn(ExperimentalCoroutinesApi::class)
|
||||
|
||||
package io.element.android.features.messages.fixtures
|
||||
|
||||
import io.element.android.features.messages.impl.timeline.factories.TimelineItemsFactory
|
||||
|
|
@ -31,6 +33,8 @@ import io.element.android.features.messages.impl.timeline.factories.event.Timeli
|
|||
import io.element.android.features.messages.impl.timeline.factories.virtual.TimelineItemDaySeparatorFactory
|
||||
import io.element.android.features.messages.impl.timeline.factories.virtual.TimelineItemVirtualFactory
|
||||
import io.element.android.libraries.dateformatter.test.FakeDaySeparatorFormatter
|
||||
import io.element.android.tests.testutils.testCoroutineDispatchers
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
|
||||
internal fun aTimelineItemsFactory() = TimelineItemsFactory(
|
||||
dispatchers = testCoroutineDispatchers(),
|
||||
|
|
|
|||
|
|
@ -27,23 +27,37 @@ import io.element.android.features.messages.impl.textcomposer.MessageComposerEve
|
|||
import io.element.android.features.messages.impl.textcomposer.MessageComposerPresenter
|
||||
import io.element.android.features.messages.impl.textcomposer.MessageComposerState
|
||||
import io.element.android.libraries.core.data.StableCharSequence
|
||||
import io.element.android.libraries.featureflag.api.FeatureFlags
|
||||
import io.element.android.libraries.featureflag.test.FakeFeatureFlagService
|
||||
import io.element.android.libraries.matrix.test.ANOTHER_MESSAGE
|
||||
import io.element.android.libraries.matrix.test.AN_EVENT_ID
|
||||
import io.element.android.libraries.matrix.test.A_MESSAGE
|
||||
import io.element.android.libraries.matrix.test.A_REPLY
|
||||
import io.element.android.libraries.matrix.test.A_USER_NAME
|
||||
import io.element.android.libraries.matrix.test.room.FakeMatrixRoom
|
||||
import io.element.android.libraries.mediapickers.PickerProvider
|
||||
import io.element.android.libraries.textcomposer.MessageComposerMode
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Test
|
||||
|
||||
class MessageComposerPresenterTest {
|
||||
|
||||
private val pickerProvider = PickerProvider(isInTest = true)
|
||||
private val featureFlagService = FakeFeatureFlagService().apply {
|
||||
runBlocking {
|
||||
setFeatureEnabled(FeatureFlags.ShowMediaUploadingFlow, true)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - initial state`() = runTest {
|
||||
val presenter = MessageComposerPresenter(
|
||||
this,
|
||||
FakeMatrixRoom()
|
||||
FakeMatrixRoom(),
|
||||
pickerProvider,
|
||||
featureFlagService,
|
||||
)
|
||||
moleculeFlow(RecompositionClock.Immediate) {
|
||||
presenter.present()
|
||||
|
|
@ -60,7 +74,9 @@ class MessageComposerPresenterTest {
|
|||
fun `present - toggle fullscreen`() = runTest {
|
||||
val presenter = MessageComposerPresenter(
|
||||
this,
|
||||
FakeMatrixRoom()
|
||||
FakeMatrixRoom(),
|
||||
pickerProvider,
|
||||
featureFlagService,
|
||||
)
|
||||
moleculeFlow(RecompositionClock.Immediate) {
|
||||
presenter.present()
|
||||
|
|
@ -79,7 +95,9 @@ class MessageComposerPresenterTest {
|
|||
fun `present - change message`() = runTest {
|
||||
val presenter = MessageComposerPresenter(
|
||||
this,
|
||||
FakeMatrixRoom()
|
||||
FakeMatrixRoom(),
|
||||
pickerProvider,
|
||||
featureFlagService,
|
||||
)
|
||||
moleculeFlow(RecompositionClock.Immediate) {
|
||||
presenter.present()
|
||||
|
|
@ -100,7 +118,9 @@ class MessageComposerPresenterTest {
|
|||
fun `present - change mode to edit`() = runTest {
|
||||
val presenter = MessageComposerPresenter(
|
||||
this,
|
||||
FakeMatrixRoom()
|
||||
FakeMatrixRoom(),
|
||||
pickerProvider,
|
||||
featureFlagService,
|
||||
)
|
||||
moleculeFlow(RecompositionClock.Immediate) {
|
||||
presenter.present()
|
||||
|
|
@ -130,7 +150,9 @@ class MessageComposerPresenterTest {
|
|||
fun `present - change mode to reply`() = runTest {
|
||||
val presenter = MessageComposerPresenter(
|
||||
this,
|
||||
FakeMatrixRoom()
|
||||
FakeMatrixRoom(),
|
||||
pickerProvider,
|
||||
featureFlagService,
|
||||
)
|
||||
moleculeFlow(RecompositionClock.Immediate) {
|
||||
presenter.present()
|
||||
|
|
@ -150,7 +172,9 @@ class MessageComposerPresenterTest {
|
|||
fun `present - change mode to quote`() = runTest {
|
||||
val presenter = MessageComposerPresenter(
|
||||
this,
|
||||
FakeMatrixRoom()
|
||||
FakeMatrixRoom(),
|
||||
pickerProvider,
|
||||
featureFlagService,
|
||||
)
|
||||
moleculeFlow(RecompositionClock.Immediate) {
|
||||
presenter.present()
|
||||
|
|
@ -170,7 +194,9 @@ class MessageComposerPresenterTest {
|
|||
fun `present - send message`() = runTest {
|
||||
val presenter = MessageComposerPresenter(
|
||||
this,
|
||||
FakeMatrixRoom()
|
||||
FakeMatrixRoom(),
|
||||
pickerProvider,
|
||||
featureFlagService,
|
||||
)
|
||||
moleculeFlow(RecompositionClock.Immediate) {
|
||||
presenter.present()
|
||||
|
|
@ -192,7 +218,9 @@ class MessageComposerPresenterTest {
|
|||
val fakeMatrixRoom = FakeMatrixRoom()
|
||||
val presenter = MessageComposerPresenter(
|
||||
this,
|
||||
fakeMatrixRoom
|
||||
fakeMatrixRoom,
|
||||
pickerProvider,
|
||||
featureFlagService,
|
||||
)
|
||||
moleculeFlow(RecompositionClock.Immediate) {
|
||||
presenter.present()
|
||||
|
|
@ -223,7 +251,9 @@ class MessageComposerPresenterTest {
|
|||
val fakeMatrixRoom = FakeMatrixRoom()
|
||||
val presenter = MessageComposerPresenter(
|
||||
this,
|
||||
fakeMatrixRoom
|
||||
fakeMatrixRoom,
|
||||
pickerProvider,
|
||||
featureFlagService,
|
||||
)
|
||||
moleculeFlow(RecompositionClock.Immediate) {
|
||||
presenter.present()
|
||||
|
|
@ -248,6 +278,25 @@ class MessageComposerPresenterTest {
|
|||
assertThat(fakeMatrixRoom.replyMessageParameter).isEqualTo(A_REPLY)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - Take photo`() = runTest {
|
||||
val fakeMatrixRoom = FakeMatrixRoom()
|
||||
val presenter = MessageComposerPresenter(
|
||||
this,
|
||||
fakeMatrixRoom,
|
||||
pickerProvider,
|
||||
featureFlagService,
|
||||
)
|
||||
moleculeFlow(RecompositionClock.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
val initialState = awaitItem()
|
||||
initialState.eventSink(MessageComposerEvents.TakePhoto)
|
||||
|
||||
// TODO verify some post processing of the captured image is done
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun anEditMode() = MessageComposerMode.Edit(AN_EVENT_ID, A_MESSAGE)
|
||||
|
|
|
|||
|
|
@ -49,23 +49,6 @@ class TimelinePresenterTest {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - makes sure timeline is initialized and disposed`() = runTest {
|
||||
val fakeTimeline = FakeMatrixTimeline()
|
||||
val presenter = TimelinePresenter(
|
||||
timelineItemsFactory = aTimelineItemsFactory(),
|
||||
room = FakeMatrixRoom(matrixTimeline = fakeTimeline),
|
||||
)
|
||||
assertThat(fakeTimeline.isInitialized).isFalse()
|
||||
moleculeFlow(RecompositionClock.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
skipItems(2)
|
||||
assertThat(fakeTimeline.isInitialized).isTrue()
|
||||
}
|
||||
assertThat(fakeTimeline.isInitialized).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - load more`() = runTest {
|
||||
val presenter = TimelinePresenter(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue