Refine UI
This commit is contained in:
parent
c66b7a699c
commit
4551c9307e
8 changed files with 82 additions and 41 deletions
|
|
@ -1,3 +1,5 @@
|
||||||
|
@file:OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
|
||||||
package io.element.android.x.features.roomlist
|
package io.element.android.x.features.roomlist
|
||||||
|
|
||||||
import Avatar
|
import Avatar
|
||||||
|
|
@ -19,6 +21,7 @@ import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
|
@ -63,40 +66,48 @@ fun RoomListContent(
|
||||||
onRoomClicked: (RoomId) -> Unit,
|
onRoomClicked: (RoomId) -> Unit,
|
||||||
onLogoutClicked: () -> Unit,
|
onLogoutClicked: () -> Unit,
|
||||||
) {
|
) {
|
||||||
|
val appBarState = rememberTopAppBarState()
|
||||||
|
val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior(appBarState)
|
||||||
LogCompositions(tag = "RoomListScreen", msg = "Content")
|
LogCompositions(tag = "RoomListScreen", msg = "Content")
|
||||||
Surface(color = MaterialTheme.colorScheme.background) {
|
Scaffold(
|
||||||
Column(
|
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
|
||||||
modifier = Modifier.fillMaxSize()
|
topBar = {
|
||||||
) {
|
RoomListTopBar(matrixUser, onLogoutClicked, scrollBehavior)
|
||||||
RoomListTopBar(
|
},
|
||||||
matrixUser = matrixUser,
|
content = { padding ->
|
||||||
onLogoutClicked = onLogoutClicked
|
LazyColumn(modifier = Modifier.padding(padding)) {
|
||||||
)
|
items(roomSummaries) { room ->
|
||||||
LazyColumn {
|
|
||||||
items(roomSummaries, key = { it.id }) { room ->
|
|
||||||
RoomItem(room = room) {
|
RoomItem(room = room) {
|
||||||
onRoomClicked(it)
|
onRoomClicked(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun RoomListTopBar(matrixUser: MatrixUser?, onLogoutClicked: () -> Unit) {
|
fun RoomListTopBar(
|
||||||
|
matrixUser: MatrixUser?,
|
||||||
|
onLogoutClicked: () -> Unit,
|
||||||
|
scrollBehavior: TopAppBarScrollBehavior
|
||||||
|
) {
|
||||||
LogCompositions(tag = "RoomListScreen", msg = "TopBar")
|
LogCompositions(tag = "RoomListScreen", msg = "TopBar")
|
||||||
if (matrixUser == null) return
|
if (matrixUser == null) return
|
||||||
TopAppBar(
|
MediumTopAppBar(
|
||||||
|
modifier = Modifier
|
||||||
|
.nestedScroll(scrollBehavior.nestedScrollConnection),
|
||||||
title = {
|
title = {
|
||||||
Row(
|
Text(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
fontWeight = FontWeight.Bold,
|
||||||
verticalAlignment = Alignment.CenterVertically
|
text = "All Chats"
|
||||||
) {
|
)
|
||||||
|
},
|
||||||
|
navigationIcon = {
|
||||||
|
IconButton(onClick = {}) {
|
||||||
Avatar(matrixUser.avatarData)
|
Avatar(matrixUser.avatarData)
|
||||||
Spacer(modifier = Modifier.width(8.dp))
|
|
||||||
Text("${matrixUser.username}")
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
actions = {
|
actions = {
|
||||||
|
|
@ -105,7 +116,8 @@ fun RoomListTopBar(matrixUser: MatrixUser?, onLogoutClicked: () -> Unit) {
|
||||||
) {
|
) {
|
||||||
Icon(Icons.Default.ExitToApp, contentDescription = "logout")
|
Icon(Icons.Default.ExitToApp, contentDescription = "logout")
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
scrollBehavior = scrollBehavior,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -121,6 +133,7 @@ private fun RoomItem(
|
||||||
Column(
|
Column(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
|
.height(72.dp)
|
||||||
.clickable(
|
.clickable(
|
||||||
onClick = { onClick(room.roomId) },
|
onClick = { onClick(room.roomId) },
|
||||||
indication = rememberRipple(),
|
indication = rememberRipple(),
|
||||||
|
|
@ -141,7 +154,7 @@ private fun RoomItem(
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
fontSize = 16.sp,
|
fontSize = 16.sp,
|
||||||
fontWeight = FontWeight.Bold,
|
fontWeight = FontWeight.SemiBold,
|
||||||
text = room.name,
|
text = room.name,
|
||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
overflow = TextOverflow.Ellipsis
|
overflow = TextOverflow.Ellipsis
|
||||||
|
|
@ -149,6 +162,7 @@ private fun RoomItem(
|
||||||
Text(
|
Text(
|
||||||
text = room.lastMessage?.toString().orEmpty(),
|
text = room.lastMessage?.toString().orEmpty(),
|
||||||
color = MaterialTheme.colorScheme.secondary,
|
color = MaterialTheme.colorScheme.secondary,
|
||||||
|
fontSize = 15.sp,
|
||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
overflow = TextOverflow.Ellipsis
|
overflow = TextOverflow.Ellipsis
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package io.element.android.x.features.roomlist
|
package io.element.android.x.features.roomlist
|
||||||
|
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
import com.airbnb.mvrx.Fail
|
import com.airbnb.mvrx.Fail
|
||||||
import com.airbnb.mvrx.Loading
|
import com.airbnb.mvrx.Loading
|
||||||
import com.airbnb.mvrx.MavericksViewModel
|
import com.airbnb.mvrx.MavericksViewModel
|
||||||
|
|
@ -46,7 +47,7 @@ class RoomListViewModel(initialState: RoomListViewState) :
|
||||||
val userAvatarUrl = client.loadUserAvatarURLString().getOrNull()
|
val userAvatarUrl = client.loadUserAvatarURLString().getOrNull()
|
||||||
val userDisplayName = client.loadUserDisplayName().getOrNull()
|
val userDisplayName = client.loadUserDisplayName().getOrNull()
|
||||||
val avatarData =
|
val avatarData =
|
||||||
loadAvatarData(client, userDisplayName ?: client.userId().value, userAvatarUrl)
|
loadAvatarData(client, userDisplayName ?: client.userId().value, userAvatarUrl, 32)
|
||||||
MatrixUser(
|
MatrixUser(
|
||||||
username = userDisplayName ?: client.userId().value,
|
username = userDisplayName ?: client.userId().value,
|
||||||
avatarUrl = userAvatarUrl,
|
avatarUrl = userAvatarUrl,
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,12 @@ package io.element.android.x.features.roomlist.model
|
||||||
import com.airbnb.mvrx.Async
|
import com.airbnb.mvrx.Async
|
||||||
import com.airbnb.mvrx.MavericksState
|
import com.airbnb.mvrx.MavericksState
|
||||||
import com.airbnb.mvrx.Uninitialized
|
import com.airbnb.mvrx.Uninitialized
|
||||||
import io.element.android.x.features.roomlist.model.MatrixUser
|
import io.element.android.x.matrix.core.RoomId
|
||||||
import io.element.android.x.matrix.room.RoomSummary
|
|
||||||
|
|
||||||
data class RoomListViewState(
|
data class RoomListViewState(
|
||||||
val user: Async<MatrixUser> = Uninitialized,
|
val user: Async<MatrixUser> = Uninitialized,
|
||||||
val rooms: Async<List<RoomListRoomSummary>> = Uninitialized,
|
val rooms: Async<List<RoomListRoomSummary>> = Uninitialized,
|
||||||
val canLoadMore: Boolean = false,
|
val canLoadMore: Boolean = false,
|
||||||
val logoutAction: Async<Unit> = Uninitialized,
|
val logoutAction: Async<Unit> = Uninitialized,
|
||||||
|
val roomsById: Map<RoomId, RoomListRoomSummary> = emptyMap()
|
||||||
) : MavericksState
|
) : MavericksState
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,7 @@ coroutines_test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", ve
|
||||||
accompanist_animation = { module = "com.google.accompanist:accompanist-navigation-animation", version.ref = "accompanist" }
|
accompanist_animation = { module = "com.google.accompanist:accompanist-navigation-animation", version.ref = "accompanist" }
|
||||||
accompanist_permission = { module = "com.google.accompanist:accompanist-permissions", version.ref = "accompanist" }
|
accompanist_permission = { module = "com.google.accompanist:accompanist-permissions", version.ref = "accompanist" }
|
||||||
accompanist_material = { module = "com.google.accompanist:accompanist-navigation-material", version.ref = "accompanist" }
|
accompanist_material = { module = "com.google.accompanist:accompanist-navigation-material", version.ref = "accompanist" }
|
||||||
|
accompanist_systemui = { module = "com.google.accompanist:accompanist-systemuicontroller", version.ref = "accompanist" }
|
||||||
|
|
||||||
# Test
|
# Test
|
||||||
test_junit = { module = "junit:junit", version.ref = "test_junit" }
|
test_junit = { module = "junit:junit", version.ref = "test_junit" }
|
||||||
|
|
|
||||||
|
|
@ -8,5 +8,6 @@ android {
|
||||||
dependencies {
|
dependencies {
|
||||||
// Should not be there, but this is a POC
|
// Should not be there, but this is a POC
|
||||||
implementation("io.coil-kt:coil-compose:2.2.1")
|
implementation("io.coil-kt:coil-compose:2.2.1")
|
||||||
|
implementation(libs.accompanist.systemui)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -11,6 +11,7 @@ import androidx.compose.ui.graphics.toArgb
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.platform.LocalView
|
import androidx.compose.ui.platform.LocalView
|
||||||
import androidx.core.view.WindowCompat
|
import androidx.core.view.WindowCompat
|
||||||
|
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
||||||
|
|
||||||
private val DarkColorScheme = darkColorScheme(
|
private val DarkColorScheme = darkColorScheme(
|
||||||
primary = Color.White,
|
primary = Color.White,
|
||||||
|
|
@ -58,13 +59,11 @@ fun ElementXTheme(
|
||||||
darkTheme -> DarkColorScheme
|
darkTheme -> DarkColorScheme
|
||||||
else -> LightColorScheme
|
else -> LightColorScheme
|
||||||
}
|
}
|
||||||
val view = LocalView.current
|
val systemUiController = rememberSystemUiController()
|
||||||
if (!view.isInEditMode) {
|
SideEffect {
|
||||||
SideEffect {
|
systemUiController.setStatusBarColor(
|
||||||
val window = (view.context as Activity).window
|
color = colorScheme.background
|
||||||
window.statusBarColor = colorScheme.primary.toArgb()
|
)
|
||||||
WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars = darkTheme
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MaterialTheme(
|
MaterialTheme(
|
||||||
|
|
|
||||||
|
|
@ -8,13 +8,22 @@ import androidx.compose.ui.unit.sp
|
||||||
|
|
||||||
// Set of Material typography styles to start with
|
// Set of Material typography styles to start with
|
||||||
val Typography = Typography(
|
val Typography = Typography(
|
||||||
|
|
||||||
bodyLarge = TextStyle(
|
bodyLarge = TextStyle(
|
||||||
fontFamily = FontFamily.Default,
|
fontFamily = FontFamily.Default,
|
||||||
fontWeight = FontWeight.Normal,
|
fontWeight = FontWeight.Normal,
|
||||||
fontSize = 16.sp,
|
fontSize = 16.sp,
|
||||||
lineHeight = 24.sp,
|
lineHeight = 24.sp,
|
||||||
letterSpacing = 0.5.sp
|
letterSpacing = 0.5.sp
|
||||||
|
),
|
||||||
|
headlineSmall = TextStyle(
|
||||||
|
fontFamily = FontFamily.Default,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
fontSize = 32.sp,
|
||||||
|
lineHeight = 24.sp,
|
||||||
|
letterSpacing = 0.5.sp
|
||||||
)
|
)
|
||||||
|
|
||||||
/* Other default text styles to override
|
/* Other default text styles to override
|
||||||
titleLarge = TextStyle(
|
titleLarge = TextStyle(
|
||||||
fontFamily = FontFamily.Default,
|
fontFamily = FontFamily.Default,
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.graphics.Brush
|
import androidx.compose.ui.graphics.Brush
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.layout.ContentScale
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import coil.compose.AsyncImage
|
import coil.compose.AsyncImage
|
||||||
|
|
@ -18,28 +19,43 @@ import io.element.android.x.designsystem.AvatarGradientStart
|
||||||
import io.element.android.x.designsystem.components.avatar.AvatarData
|
import io.element.android.x.designsystem.components.avatar.AvatarData
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun Avatar(avatarData: AvatarData) {
|
fun Avatar(avatarData: AvatarData, modifier: Modifier = Modifier) {
|
||||||
if (avatarData.model == null) {
|
if (avatarData.model == null) {
|
||||||
InitialsAvatar(
|
InitialsAvatar(
|
||||||
modifier = Modifier
|
modifier = modifier
|
||||||
.size(avatarData.size.dp)
|
.size(avatarData.size.dp)
|
||||||
.clip(CircleShape),
|
.clip(CircleShape),
|
||||||
initials = avatarData.initials
|
initials = avatarData.initials
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
AsyncImage(
|
ImageAvatar(
|
||||||
model = avatarData.model,
|
modifier = modifier
|
||||||
onError = {
|
|
||||||
Log.e("TAG", "Error $it\n${it.result}", it.result.throwable)
|
|
||||||
},
|
|
||||||
contentDescription = null,
|
|
||||||
modifier = Modifier
|
|
||||||
.size(avatarData.size.dp)
|
.size(avatarData.size.dp)
|
||||||
.clip(CircleShape)
|
.clip(CircleShape),
|
||||||
|
avatarData = avatarData
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun ImageAvatar(
|
||||||
|
avatarData: AvatarData,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
) {
|
||||||
|
AsyncImage(
|
||||||
|
model = avatarData.model,
|
||||||
|
onError = {
|
||||||
|
Log.e("TAG", "Error $it\n${it.result}", it.result.throwable)
|
||||||
|
},
|
||||||
|
contentDescription = null,
|
||||||
|
contentScale = ContentScale.Crop,
|
||||||
|
modifier = modifier
|
||||||
|
.size(avatarData.size.dp)
|
||||||
|
.clip(CircleShape)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun InitialsAvatar(
|
private fun InitialsAvatar(
|
||||||
initials: String,
|
initials: String,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue