Room directory : add tests and cleanup
This commit is contained in:
parent
33c3dc07aa
commit
35b12f265f
27 changed files with 573 additions and 77 deletions
|
|
@ -28,12 +28,10 @@ import javax.inject.Inject
|
|||
|
||||
@ContributesBinding(AppScope::class)
|
||||
class DefaultRoomDirectoryEntryPoint @Inject constructor() : RoomDirectoryEntryPoint {
|
||||
|
||||
override fun nodeBuilder(parentNode: Node, buildContext: BuildContext): RoomDirectoryEntryPoint.NodeBuilder {
|
||||
val plugins = ArrayList<Plugin>()
|
||||
|
||||
return object : RoomDirectoryEntryPoint.NodeBuilder {
|
||||
|
||||
override fun callback(callback: RoomDirectoryEntryPoint.Callback): RoomDirectoryEntryPoint.NodeBuilder {
|
||||
plugins += callback
|
||||
return this
|
||||
|
|
|
|||
|
|
@ -35,7 +35,6 @@ class RoomDirectoryNode @AssistedInject constructor(
|
|||
@Assisted plugins: List<Plugin>,
|
||||
private val presenter: RoomDirectoryPresenter,
|
||||
) : Node(buildContext, plugins = plugins) {
|
||||
|
||||
private fun onRoomJoined(roomId: RoomId) {
|
||||
plugins<RoomDirectoryEntryPoint.Callback>().forEach {
|
||||
it.onOpenRoom(roomId)
|
||||
|
|
|
|||
|
|
@ -26,13 +26,13 @@ import androidx.compose.runtime.remember
|
|||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.runtime.setValue
|
||||
import io.element.android.features.roomdirectory.impl.root.di.JoinRoom
|
||||
import io.element.android.features.roomdirectory.impl.root.model.RoomDirectoryListState
|
||||
import io.element.android.features.roomdirectory.impl.root.model.toFeatureModel
|
||||
import io.element.android.libraries.architecture.AsyncAction
|
||||
import io.element.android.libraries.architecture.Presenter
|
||||
import io.element.android.libraries.architecture.runUpdatingState
|
||||
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
|
||||
import io.element.android.libraries.matrix.api.MatrixClient
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.roomdirectory.RoomDirectoryList
|
||||
import io.element.android.libraries.matrix.api.roomdirectory.RoomDirectoryService
|
||||
|
|
@ -46,10 +46,9 @@ import javax.inject.Inject
|
|||
|
||||
class RoomDirectoryPresenter @Inject constructor(
|
||||
private val dispatchers: CoroutineDispatchers,
|
||||
private val matrixClient: MatrixClient,
|
||||
private val joinRoom: JoinRoom,
|
||||
private val roomDirectoryService: RoomDirectoryService,
|
||||
) : Presenter<RoomDirectoryState> {
|
||||
|
||||
@Composable
|
||||
override fun present(): RoomDirectoryState {
|
||||
var loadingMore by remember {
|
||||
|
|
@ -68,9 +67,9 @@ class RoomDirectoryPresenter @Inject constructor(
|
|||
}
|
||||
LaunchedEffect(searchQuery) {
|
||||
if (searchQuery == null) return@LaunchedEffect
|
||||
//debounce search query
|
||||
// debounce search query
|
||||
delay(300)
|
||||
//cancel load more right away
|
||||
// cancel load more right away
|
||||
loadingMore = false
|
||||
roomDirectoryList.filter(searchQuery, 20)
|
||||
}
|
||||
|
|
@ -108,7 +107,7 @@ class RoomDirectoryPresenter @Inject constructor(
|
|||
|
||||
private fun CoroutineScope.joinRoom(state: MutableState<AsyncAction<RoomId>>, roomId: RoomId) = launch {
|
||||
state.runUpdatingState {
|
||||
matrixClient.joinRoom(roomId)
|
||||
joinRoom(roomId)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -25,39 +25,14 @@ import io.element.android.libraries.matrix.api.core.RoomId
|
|||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
||||
open class RoomDirectorySearchStateProvider : PreviewParameterProvider<RoomDirectoryState> {
|
||||
open class RoomDirectoryStateProvider : PreviewParameterProvider<RoomDirectoryState> {
|
||||
override val values: Sequence<RoomDirectoryState>
|
||||
get() = sequenceOf(
|
||||
aRoomDirectoryState(),
|
||||
aRoomDirectoryState(
|
||||
query = "Element",
|
||||
roomDescriptions = persistentListOf(
|
||||
RoomDescription(
|
||||
roomId = RoomId("@exa:matrix.org"),
|
||||
name = "Element X Android",
|
||||
description = "Element X is a secure, private and decentralized messenger.",
|
||||
avatarData = AvatarData(
|
||||
id = "@exa:matrix.org",
|
||||
name = "Element X Android",
|
||||
url = null,
|
||||
size = AvatarSize.RoomDirectoryItem
|
||||
),
|
||||
canBeJoined = true,
|
||||
),
|
||||
RoomDescription(
|
||||
roomId = RoomId("@exi:matrix.org"),
|
||||
name = "Element X iOS",
|
||||
description = "Element X is a secure, private and decentralized messenger.",
|
||||
avatarData = AvatarData(
|
||||
id = "@exi:matrix.org",
|
||||
name = "Element X iOS",
|
||||
url = null,
|
||||
size = AvatarSize.RoomDirectoryItem
|
||||
),
|
||||
canBeJoined = false,
|
||||
)
|
||||
)
|
||||
),
|
||||
roomDescriptions = aRoomDescriptionList(),
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -66,10 +41,40 @@ fun aRoomDirectoryState(
|
|||
displayLoadMoreIndicator: Boolean = false,
|
||||
roomDescriptions: ImmutableList<RoomDescription> = persistentListOf(),
|
||||
joinRoomAction: AsyncAction<RoomId> = AsyncAction.Uninitialized,
|
||||
eventSink: (RoomDirectoryEvents) -> Unit = {},
|
||||
) = RoomDirectoryState(
|
||||
query = query,
|
||||
roomDescriptions = roomDescriptions,
|
||||
displayLoadMoreIndicator = displayLoadMoreIndicator,
|
||||
joinRoomAction = joinRoomAction,
|
||||
eventSink = {},
|
||||
eventSink = eventSink,
|
||||
)
|
||||
|
||||
fun aRoomDescriptionList(): ImmutableList<RoomDescription> {
|
||||
return persistentListOf(
|
||||
RoomDescription(
|
||||
roomId = RoomId("!exa:matrix.org"),
|
||||
name = "Element X Android",
|
||||
description = "Element X is a secure, private and decentralized messenger.",
|
||||
avatarData = AvatarData(
|
||||
id = "!exa:matrix.org",
|
||||
name = "Element X Android",
|
||||
url = null,
|
||||
size = AvatarSize.RoomDirectoryItem
|
||||
),
|
||||
canBeJoined = true,
|
||||
),
|
||||
RoomDescription(
|
||||
roomId = RoomId("!exi:matrix.org"),
|
||||
name = "Element X iOS",
|
||||
description = "Element X is a secure, private and decentralized messenger.",
|
||||
avatarData = AvatarData(
|
||||
id = "!exi:matrix.org",
|
||||
name = "Element X iOS",
|
||||
url = null,
|
||||
size = AvatarSize.RoomDirectoryItem
|
||||
),
|
||||
canBeJoined = false,
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ import androidx.compose.ui.Alignment
|
|||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalFocusManager
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
|
|
@ -61,6 +62,7 @@ import io.element.android.libraries.designsystem.theme.components.Text
|
|||
import io.element.android.libraries.designsystem.theme.components.TextField
|
||||
import io.element.android.libraries.designsystem.theme.components.TopAppBar
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.testtags.TestTags
|
||||
import io.element.android.libraries.ui.strings.CommonStrings
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
||||
|
|
@ -71,7 +73,6 @@ fun RoomDirectoryView(
|
|||
onBackPressed: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
|
||||
fun joinRoom(roomId: RoomId) {
|
||||
state.eventSink(RoomDirectoryEvents.JoinRoom(roomId))
|
||||
}
|
||||
|
|
@ -86,8 +87,8 @@ fun RoomDirectoryView(
|
|||
state = state,
|
||||
onResultClicked = ::joinRoom,
|
||||
modifier = Modifier
|
||||
.padding(padding)
|
||||
.consumeWindowInsets(padding)
|
||||
.padding(padding)
|
||||
.consumeWindowInsets(padding)
|
||||
)
|
||||
}
|
||||
)
|
||||
|
|
@ -96,7 +97,8 @@ fun RoomDirectoryView(
|
|||
onSuccess = onRoomJoined,
|
||||
onErrorDismiss = {
|
||||
state.eventSink(RoomDirectoryEvents.JoinRoomDismissError)
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
|
|
@ -171,7 +173,7 @@ private fun RoomDirectoryRoomList(
|
|||
if (displayLoadMoreIndicator) {
|
||||
item {
|
||||
LoadMoreIndicator(modifier = Modifier.fillMaxWidth())
|
||||
LaunchedEffect(Unit) {
|
||||
LaunchedEffect(onReachedLoadMore) {
|
||||
onReachedLoadMore()
|
||||
}
|
||||
}
|
||||
|
|
@ -182,10 +184,10 @@ private fun RoomDirectoryRoomList(
|
|||
@Composable
|
||||
private fun LoadMoreIndicator(modifier: Modifier = Modifier) {
|
||||
Box(
|
||||
modifier
|
||||
.fillMaxWidth()
|
||||
.wrapContentHeight()
|
||||
.padding(24.dp),
|
||||
modifier
|
||||
.fillMaxWidth()
|
||||
.wrapContentHeight()
|
||||
.padding(24.dp),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
CircularProgressIndicator(
|
||||
|
|
@ -213,7 +215,7 @@ private fun SearchTextField(
|
|||
) {
|
||||
val focusManager = LocalFocusManager.current
|
||||
TextField(
|
||||
modifier = modifier,
|
||||
modifier = modifier.testTag(TestTags.searchTextField.value),
|
||||
textStyle = ElementTheme.typography.fontBodyLgRegular,
|
||||
singleLine = true,
|
||||
value = query,
|
||||
|
|
@ -255,14 +257,14 @@ private fun RoomDirectoryRoomRow(
|
|||
) {
|
||||
Row(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.clickable { onClick(roomDescription.roomId) }
|
||||
.padding(
|
||||
top = 12.dp,
|
||||
bottom = 12.dp,
|
||||
start = 16.dp,
|
||||
)
|
||||
.height(IntrinsicSize.Min),
|
||||
.fillMaxWidth()
|
||||
.clickable { onClick(roomDescription.roomId) }
|
||||
.padding(
|
||||
top = 12.dp,
|
||||
bottom = 12.dp,
|
||||
start = 16.dp,
|
||||
)
|
||||
.height(IntrinsicSize.Min),
|
||||
) {
|
||||
Avatar(
|
||||
avatarData = roomDescription.avatarData,
|
||||
|
|
@ -270,8 +272,8 @@ private fun RoomDirectoryRoomRow(
|
|||
)
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.padding(start = 16.dp)
|
||||
.weight(1f)
|
||||
.padding(start = 16.dp)
|
||||
) {
|
||||
Text(
|
||||
text = roomDescription.name,
|
||||
|
|
@ -293,8 +295,8 @@ private fun RoomDirectoryRoomRow(
|
|||
text = stringResource(id = CommonStrings.action_join),
|
||||
color = ElementTheme.colors.textSuccessPrimary,
|
||||
modifier = Modifier
|
||||
.align(Alignment.CenterVertically)
|
||||
.padding(start = 4.dp, end = 12.dp)
|
||||
.align(Alignment.CenterVertically)
|
||||
.padding(start = 4.dp, end = 12.dp)
|
||||
)
|
||||
} else {
|
||||
Spacer(modifier = Modifier.width(24.dp))
|
||||
|
|
@ -304,7 +306,7 @@ private fun RoomDirectoryRoomRow(
|
|||
|
||||
@PreviewsDayNight
|
||||
@Composable
|
||||
fun RoomDirectorySearchViewLightPreview(@PreviewParameter(RoomDirectorySearchStateProvider::class) state: RoomDirectoryState) = ElementPreview {
|
||||
internal fun RoomDirectoryViewPreview(@PreviewParameter(RoomDirectoryStateProvider::class) state: RoomDirectoryState) = ElementPreview {
|
||||
RoomDirectoryView(
|
||||
state = state,
|
||||
onRoomJoined = {},
|
||||
|
|
|
|||
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Copyright (c) 2024 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.roomdirectory.impl.root.di
|
||||
|
||||
import com.squareup.anvil.annotations.ContributesBinding
|
||||
import io.element.android.libraries.di.SessionScope
|
||||
import io.element.android.libraries.matrix.api.MatrixClient
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import javax.inject.Inject
|
||||
|
||||
interface JoinRoom {
|
||||
suspend operator fun invoke(roomId: RoomId): Result<RoomId>
|
||||
}
|
||||
|
||||
@ContributesBinding(SessionScope::class)
|
||||
class DefaultJoinRoom @Inject constructor(private val client: MatrixClient) : JoinRoom {
|
||||
override suspend fun invoke(roomId: RoomId) = client.joinRoom(roomId)
|
||||
}
|
||||
|
|
@ -24,7 +24,6 @@ internal data class RoomDirectoryListState(
|
|||
val hasMoreToLoad: Boolean,
|
||||
val items: ImmutableList<RoomDescription>,
|
||||
) {
|
||||
|
||||
companion object {
|
||||
val Default = RoomDirectoryListState(
|
||||
hasMoreToLoad = true,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue