First mapping of room. Still very dirty

This commit is contained in:
Benoit Marty 2022-10-12 15:38:11 +02:00
parent 58decf03d8
commit f906158f2b
11 changed files with 165 additions and 30 deletions

View file

@ -7,13 +7,13 @@ import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material3.*
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.unit.dp
import com.airbnb.mvrx.Fail
import com.airbnb.mvrx.Loading
@ -22,10 +22,10 @@ import com.airbnb.mvrx.compose.collectAsState
import com.airbnb.mvrx.compose.mavericksViewModel
import io.element.android.x.ui.theme.ElementXTheme
import io.element.android.x.ui.theme.components.VectorButton
import io.element.android.x.ui.theme.components.VectorTextField
class LoginActivity : ComponentActivity() {
@OptIn(ExperimentalMaterial3Api::class)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@ -44,21 +44,34 @@ class LoginActivity : ComponentActivity() {
val viewModel: LoginViewModel = mavericksViewModel()
val state by viewModel.collectAsState()
val isError = state.isLoggedIn is Fail
VectorTextField(value = state.homeserver,
OutlinedTextField(
value = state.homeserver,
onValueChange = {
viewModel.handle(LoginActions.SetHomeserver(it))
})
VectorTextField(
},
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Uri,
),
)
OutlinedTextField(
value = state.login,
onValueChange = {
viewModel.handle(LoginActions.SetLogin(it))
})
VectorTextField(
},
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Text,
),
)
OutlinedTextField(
value = state.password,
onValueChange = {
viewModel.handle(LoginActions.SetPassword(it))
},
isError = isError
isError = isError,
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Password,
imeAction = ImeAction.Send,
),
)
if (isError) {
Text(

View file

@ -58,4 +58,5 @@ dependencies {
implementation 'androidx.fragment:fragment-ktx:1.5.3'
implementation 'com.airbnb.android:mavericks-compose:2.7.0'
implementation 'io.coil-kt:coil-compose:2.2.1'
}

View file

@ -0,0 +1,6 @@
package io.element.android.x.ui.screen.roomlist
data class MatrixUser(
val username: String? = null,
val avatarUrl: String? = null,
)

View file

@ -1,6 +1,7 @@
package io.element.android.x.ui.screen.roomlist
sealed interface RoomListActions {
object Logout : RoomListActions
object Init : RoomListActions
object LoadMore : RoomListActions
object Logout : RoomListActions
}

View file

@ -3,13 +3,15 @@ package io.element.android.x.ui.screen.roomlist
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.*
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ExitToApp
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import coil.compose.rememberAsyncImagePainter
import com.airbnb.mvrx.Success
import com.airbnb.mvrx.compose.collectAsState
import com.airbnb.mvrx.compose.mavericksViewModel
@ -17,12 +19,18 @@ import io.element.android.x.ui.theme.ElementXTheme
class RoomListActivity : ComponentActivity() {
private var initDone = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
ElementXTheme {
val viewModel: RoomListViewModel = mavericksViewModel()
if (!initDone) {
initDone = true
viewModel.handle(RoomListActions.Init)
}
val state = viewModel.collectAsState()
// A surface container using the 'background' color from the theme
Surface(
@ -34,12 +42,13 @@ class RoomListActivity : ComponentActivity() {
Column(
modifier = Modifier.fillMaxSize()
) {
OptionMenu(viewModel)
/* TODO
val state = viewModel.state.collectAsState().value
RoomListHeader()
RoomList()
*/
OptionMenu(state.value.user, viewModel)
val rooms = state.value.rooms
if (rooms is Success) {
rooms().forEach {
Text(text = "Room: ${it.name() ?: it.id()}")
}
}
}
}
if (state.value.logoutAction is Success) {
@ -51,14 +60,25 @@ class RoomListActivity : ComponentActivity() {
@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun OptionMenu(viewModel: RoomListViewModel) {
private fun OptionMenu(matrixUser: MatrixUser, viewModel: RoomListViewModel) {
TopAppBar(
title = { Text("Room List") },
title = {
Row(
modifier = Modifier.fillMaxWidth()
) {
Image(
painter = rememberAsyncImagePainter(matrixUser.avatarUrl),
contentDescription = null,
modifier = Modifier.size(48.dp)
)
Text("${matrixUser.username}")
}
},
actions = {
Button(
IconButton(
onClick = { viewModel.handle(RoomListActions.Logout) }
) {
Text(text = "logout")
Icon(Icons.Default.ExitToApp, contentDescription = "logout")
}
}
)

View file

@ -4,22 +4,43 @@ import com.airbnb.mvrx.Fail
import com.airbnb.mvrx.Loading
import com.airbnb.mvrx.MavericksViewModel
import com.airbnb.mvrx.Success
import io.element.android.x.core.data.tryOrNull
import io.element.android.x.sdk.matrix.MatrixClient
import io.element.android.x.sdk.matrix.MatrixInstance
import kotlinx.coroutines.launch
import org.matrix.rustcomponents.sdk.Room
import org.matrix.rustcomponents.sdk.StoppableSpawn
import org.matrix.rustcomponents.sdk.UpdateSummary
class RoomListViewModel(initialState: RoomListViewState) :
MavericksViewModel<RoomListViewState>(initialState) {
MavericksViewModel<RoomListViewState>(initialState), MatrixClient.SlidingSyncListener {
private var sync: StoppableSpawn? = null
private val matrix = MatrixInstance.getInstance()
fun handle(action: RoomListActions) {
when (action) {
RoomListActions.Init -> handleInit()
RoomListActions.LoadMore -> TODO()
RoomListActions.Logout -> handleLogout()
}
}
private fun handleInit() {
viewModelScope.launch {
val client = getClient()
setState {
copy(
user = MatrixUser(
tryOrNull { client.username() } ?: "Room list",
tryOrNull { client.avatarUrl() } ?: "https://previews.123rf.com/images/lkeskinen/lkeskinen1802/lkeskinen180208322/95731150-exemple-de-tampon-%C3%A9tiquette-typographique-timbre-ou-ic%C3%B4ne.jpg",
)
)
}
sync = client.slidingSync(listener = this@RoomListViewModel)
}
}
private fun handleLogout() {
viewModelScope.launch {
setState { copy(logoutAction = Loading()) }
@ -35,4 +56,32 @@ class RoomListViewModel(initialState: RoomListViewState) :
private suspend fun getClient(): MatrixClient {
return matrix.restoreSession()!!
}
override fun onSyncUpdate(
summary: UpdateSummary,
rooms: List<Room>
) = withState { state ->
val list = state.rooms().orEmpty().toMutableList()
rooms.forEach { room ->
// Either replace or add the room
val idx = list.indexOfFirst { it.id() == room.id() }
if (idx == -1) {
list.add(room)
} else {
list[idx] = room
}
}
setState {
copy(
rooms = Success(list),
summary = Success(summary)
)
}
}
override fun onCleared() {
super.onCleared()
sync?.cancel()
}
}

View file

@ -3,9 +3,13 @@ package io.element.android.x.ui.screen.roomlist
import com.airbnb.mvrx.Async
import com.airbnb.mvrx.MavericksState
import com.airbnb.mvrx.Uninitialized
import org.matrix.rustcomponents.sdk.Room
import org.matrix.rustcomponents.sdk.UpdateSummary
data class RoomListViewState(
val list: List<String> = emptyList(),
val user: MatrixUser = MatrixUser(),
val rooms: Async<List<Room>> = Uninitialized,
val summary: Async<UpdateSummary> = Uninitialized,
val canLoadMore: Boolean = false,
val logoutAction: Async<Unit> = Uninitialized,
) : MavericksState