feat: m3 list style
This commit is contained in:
parent
8c197165b3
commit
3a07d78da3
|
|
@ -1,22 +1,28 @@
|
|||
package chat.stoat.composables.chat
|
||||
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.combinedClickable
|
||||
import androidx.compose.material3.ListItem
|
||||
import androidx.compose.material3.ListItemDefaults
|
||||
import androidx.compose.material3.LocalContentColor
|
||||
import androidx.compose.material3.LocalTextStyle
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Brush
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import chat.stoat.api.internals.BrushCompat
|
||||
import chat.stoat.api.internals.Roles
|
||||
import chat.stoat.api.internals.solidColor
|
||||
import chat.stoat.core.model.schemas.Member
|
||||
import chat.stoat.core.model.schemas.User
|
||||
import chat.stoat.composables.generic.UserAvatar
|
||||
import chat.stoat.composables.generic.presenceFromStatus
|
||||
import chat.stoat.core.model.data.STOAT_FILES
|
||||
import chat.stoat.internals.extensions.TransparentListItemColours
|
||||
import chat.stoat.core.model.schemas.Member
|
||||
import chat.stoat.core.model.schemas.User
|
||||
|
||||
private val NoneLambda = { }
|
||||
|
||||
@Composable
|
||||
fun MemberListItem(
|
||||
|
|
@ -25,6 +31,10 @@ fun MemberListItem(
|
|||
serverId: String?,
|
||||
userId: String,
|
||||
modifier: Modifier = Modifier,
|
||||
first: Boolean = false,
|
||||
last: Boolean = false,
|
||||
onClick: () -> Unit = {},
|
||||
onLongClick: () -> Unit = NoneLambda,
|
||||
trailingContent: @Composable (() -> Unit)? = null,
|
||||
) {
|
||||
val highestColourRole = serverId?.let {
|
||||
|
|
@ -41,8 +51,43 @@ fun MemberListItem(
|
|||
?: Brush.solidColor(LocalContentColor.current)
|
||||
|
||||
ListItem(
|
||||
colors = TransparentListItemColours,
|
||||
modifier = modifier,
|
||||
colors = ListItemDefaults.colors(
|
||||
containerColor = MaterialTheme.colorScheme.surfaceContainer
|
||||
),
|
||||
modifier = modifier
|
||||
.then(
|
||||
when {
|
||||
first && last -> Modifier.clip(MaterialTheme.shapes.large)
|
||||
|
||||
first -> Modifier.clip(
|
||||
MaterialTheme.shapes.extraSmall.copy(
|
||||
topStart = MaterialTheme.shapes.large.topStart,
|
||||
topEnd = MaterialTheme.shapes.large.topEnd
|
||||
)
|
||||
)
|
||||
|
||||
last -> Modifier.clip(
|
||||
MaterialTheme.shapes.extraSmall.copy(
|
||||
bottomStart = MaterialTheme.shapes.large.bottomStart,
|
||||
bottomEnd = MaterialTheme.shapes.large.bottomEnd
|
||||
)
|
||||
)
|
||||
|
||||
else -> Modifier.clip(MaterialTheme.shapes.extraSmall)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
if (onLongClick != NoneLambda) {
|
||||
Modifier.combinedClickable(
|
||||
onClick = onClick,
|
||||
onLongClick = onLongClick
|
||||
)
|
||||
} else {
|
||||
Modifier.clickable(
|
||||
onClick = onClick
|
||||
)
|
||||
}
|
||||
),
|
||||
headlineContent = {
|
||||
Text(
|
||||
text = member?.nickname
|
||||
|
|
|
|||
|
|
@ -7,6 +7,6 @@ import androidx.compose.ui.graphics.Color
|
|||
|
||||
val TransparentListItemColours: ListItemColors
|
||||
@Composable
|
||||
get() = ListItemDefaults.colors().copy(
|
||||
get() = ListItemDefaults.colors(
|
||||
containerColor = Color.Transparent
|
||||
)
|
||||
|
|
@ -7,7 +7,6 @@ import androidx.activity.compose.rememberLauncherForActivityResult
|
|||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
|
|
@ -179,8 +178,24 @@ fun FriendsScreen(topNav: NavController, useDrawer: Boolean, onDrawerClicked: ()
|
|||
text = AnnotatedString.fromHtml(
|
||||
stringResource(
|
||||
R.string.friends_add_by_tag_sheet_description,
|
||||
"<font color=\"${Color(HL_USERNAME).toArgb().let { "#%02x%02x%02x".format(it shr 16 and 0xff, it shr 8 and 0xff, it and 0xff) }}\">",
|
||||
"<font color=\"${Color(HL_TAG).toArgb().let { "#%02x%02x%02x".format(it shr 16 and 0xff, it shr 8 and 0xff, it and 0xff) }}\">",
|
||||
"<font color=\"${
|
||||
Color(HL_USERNAME).toArgb().let {
|
||||
"#%02x%02x%02x".format(
|
||||
it shr 16 and 0xff,
|
||||
it shr 8 and 0xff,
|
||||
it and 0xff
|
||||
)
|
||||
}
|
||||
}\">",
|
||||
"<font color=\"${
|
||||
Color(HL_TAG).toArgb().let {
|
||||
"#%02x%02x%02x".format(
|
||||
it shr 16 and 0xff,
|
||||
it shr 8 and 0xff,
|
||||
it and 0xff
|
||||
)
|
||||
}
|
||||
}\">",
|
||||
"</font>",
|
||||
)
|
||||
),
|
||||
|
|
@ -601,19 +616,28 @@ fun FriendsScreen(topNav: NavController, useDrawer: Boolean, onDrawerClicked: ()
|
|||
val item = FriendRequests.getIncoming().getOrNull(it)
|
||||
if (item == null) return@items
|
||||
|
||||
val isLast = it == FriendRequests.getIncoming().size - 1
|
||||
|
||||
MemberListItem(
|
||||
member = null,
|
||||
user = item,
|
||||
serverId = null,
|
||||
userId = item.id ?: "",
|
||||
modifier = Modifier.clickable {
|
||||
first = it == 0,
|
||||
last = isLast,
|
||||
onClick = {
|
||||
scope.launch {
|
||||
item.id?.let { userId ->
|
||||
ActionChannel.send(Action.OpenUserSheet(userId, null))
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
modifier = Modifier.padding(horizontal = 16.dp)
|
||||
)
|
||||
|
||||
if (!isLast) {
|
||||
Spacer(modifier = Modifier.height(2.dp))
|
||||
}
|
||||
}
|
||||
|
||||
stickyHeader(key = "outgoing") {
|
||||
|
|
@ -627,19 +651,28 @@ fun FriendsScreen(topNav: NavController, useDrawer: Boolean, onDrawerClicked: ()
|
|||
val item = FriendRequests.getOutgoing().getOrNull(it)
|
||||
if (item == null) return@items
|
||||
|
||||
val isLast = it == FriendRequests.getOutgoing().size - 1
|
||||
|
||||
MemberListItem(
|
||||
member = null,
|
||||
user = item,
|
||||
serverId = null,
|
||||
userId = item.id ?: "",
|
||||
modifier = Modifier.clickable {
|
||||
first = it == 0,
|
||||
last = isLast,
|
||||
onClick = {
|
||||
scope.launch {
|
||||
item.id?.let { userId ->
|
||||
ActionChannel.send(Action.OpenUserSheet(userId, null))
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
modifier = Modifier.padding(horizontal = 16.dp)
|
||||
)
|
||||
|
||||
if (!isLast) {
|
||||
Spacer(modifier = Modifier.height(2.dp))
|
||||
}
|
||||
}
|
||||
|
||||
stickyHeader(key = "online") {
|
||||
|
|
@ -653,19 +686,28 @@ fun FriendsScreen(topNav: NavController, useDrawer: Boolean, onDrawerClicked: ()
|
|||
val item = FriendRequests.getOnlineFriends().getOrNull(it)
|
||||
if (item == null) return@items
|
||||
|
||||
val isLast = it == FriendRequests.getOnlineFriends().size - 1
|
||||
|
||||
MemberListItem(
|
||||
member = null,
|
||||
user = item,
|
||||
serverId = null,
|
||||
userId = item.id ?: "",
|
||||
modifier = Modifier.clickable {
|
||||
first = it == 0,
|
||||
last = isLast,
|
||||
onClick = {
|
||||
scope.launch {
|
||||
item.id?.let { userId ->
|
||||
ActionChannel.send(Action.OpenUserSheet(userId, null))
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
modifier = Modifier.padding(horizontal = 16.dp)
|
||||
)
|
||||
|
||||
if (!isLast) {
|
||||
Spacer(modifier = Modifier.height(2.dp))
|
||||
}
|
||||
}
|
||||
|
||||
stickyHeader(key = "not_online") {
|
||||
|
|
@ -679,19 +721,28 @@ fun FriendsScreen(topNav: NavController, useDrawer: Boolean, onDrawerClicked: ()
|
|||
val item = FriendRequests.getFriends(true).getOrNull(it)
|
||||
if (item == null) return@items
|
||||
|
||||
val isLast = it == FriendRequests.getFriends(true).size - 1
|
||||
|
||||
MemberListItem(
|
||||
member = null,
|
||||
user = item,
|
||||
serverId = null,
|
||||
userId = item.id ?: "",
|
||||
modifier = Modifier.clickable {
|
||||
first = it == 0,
|
||||
last = isLast,
|
||||
onClick = {
|
||||
scope.launch {
|
||||
item.id?.let { userId ->
|
||||
ActionChannel.send(Action.OpenUserSheet(userId, null))
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
modifier = Modifier.padding(horizontal = 16.dp)
|
||||
)
|
||||
|
||||
if (!isLast) {
|
||||
Spacer(modifier = Modifier.height(2.dp))
|
||||
}
|
||||
}
|
||||
|
||||
stickyHeader(key = "blocked") {
|
||||
|
|
@ -706,19 +757,28 @@ fun FriendsScreen(topNav: NavController, useDrawer: Boolean, onDrawerClicked: ()
|
|||
val item = FriendRequests.getBlocked().getOrNull(it)
|
||||
if (item == null) return@items
|
||||
|
||||
val isLast = it == FriendRequests.getBlocked().size - 1
|
||||
|
||||
MemberListItem(
|
||||
member = null,
|
||||
user = item,
|
||||
serverId = null,
|
||||
userId = item.id ?: "",
|
||||
modifier = Modifier.clickable {
|
||||
first = it == 0,
|
||||
last = isLast,
|
||||
onClick = {
|
||||
scope.launch {
|
||||
item.id?.let { userId ->
|
||||
ActionChannel.send(Action.OpenUserSheet(userId, null))
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
modifier = Modifier.padding(horizontal = 16.dp)
|
||||
)
|
||||
|
||||
if (!isLast) {
|
||||
Spacer(modifier = Modifier.height(2.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,10 +3,11 @@ package chat.stoat.screens.create
|
|||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.scaleIn
|
||||
import androidx.compose.animation.scaleOut
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.imePadding
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
|
|
@ -192,13 +193,16 @@ fun CreateGroupScreen(
|
|||
val friend = StoatAPI.userCache[viewModel.friendsFilteredBySearch[index]]
|
||||
?: return@items
|
||||
val isMember = viewModel.groupMembers.contains(friend.id)
|
||||
val isLast = index == viewModel.friendsFilteredBySearch.size - 1
|
||||
|
||||
MemberListItem(
|
||||
member = null,
|
||||
user = friend,
|
||||
serverId = null,
|
||||
userId = friend.id!!,
|
||||
modifier = Modifier.clickable {
|
||||
first = index == 0,
|
||||
last = isLast,
|
||||
onClick = {
|
||||
if (isMember) {
|
||||
viewModel.groupMembers.remove(friend.id)
|
||||
} else {
|
||||
|
|
@ -207,6 +211,7 @@ fun CreateGroupScreen(
|
|||
}
|
||||
}
|
||||
},
|
||||
modifier = Modifier.padding(horizontal = 16.dp),
|
||||
trailingContent = {
|
||||
Checkbox(
|
||||
checked = isMember,
|
||||
|
|
@ -215,6 +220,9 @@ fun CreateGroupScreen(
|
|||
)
|
||||
}
|
||||
)
|
||||
if (!isLast) {
|
||||
Spacer(modifier = Modifier.height(2.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,9 @@ import android.content.Intent
|
|||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
|
|
@ -13,6 +15,7 @@ import androidx.compose.material3.Icon
|
|||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.LargeTopAppBar
|
||||
import androidx.compose.material3.ListItem
|
||||
import androidx.compose.material3.ListItemDefaults
|
||||
import androidx.compose.material3.LocalContentColor
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Scaffold
|
||||
|
|
@ -21,6 +24,7 @@ import androidx.compose.material3.TopAppBarDefaults
|
|||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.testTag
|
||||
|
|
@ -100,18 +104,15 @@ fun SettingsScreen(
|
|||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(vertical = 10.dp)
|
||||
.padding(bottom = 10.dp)
|
||||
) {
|
||||
ListHeader {
|
||||
Text(stringResource(R.string.settings_category_account))
|
||||
}
|
||||
|
||||
ListItem(
|
||||
headlineContent = {
|
||||
Text(
|
||||
text = stringResource(id = R.string.settings_account)
|
||||
)
|
||||
},
|
||||
SettingsListItem(
|
||||
first = true,
|
||||
headlineContent = { Text(text = stringResource(id = R.string.settings_account)) },
|
||||
leadingContent = {
|
||||
SettingsIcon {
|
||||
Icon(
|
||||
|
|
@ -122,17 +123,11 @@ fun SettingsScreen(
|
|||
},
|
||||
modifier = Modifier
|
||||
.testTag("settings_view_account")
|
||||
.clickable {
|
||||
navController.navigate("settings/account")
|
||||
}
|
||||
.clickable { navController.navigate("settings/account") }
|
||||
)
|
||||
|
||||
ListItem(
|
||||
headlineContent = {
|
||||
Text(
|
||||
text = stringResource(id = R.string.settings_profile)
|
||||
)
|
||||
},
|
||||
Spacer(Modifier.height(2.dp))
|
||||
SettingsListItem(
|
||||
headlineContent = { Text(text = stringResource(id = R.string.settings_profile)) },
|
||||
leadingContent = {
|
||||
SettingsIcon {
|
||||
Icon(
|
||||
|
|
@ -143,17 +138,12 @@ fun SettingsScreen(
|
|||
},
|
||||
modifier = Modifier
|
||||
.testTag("settings_view_profile")
|
||||
.clickable {
|
||||
navController.navigate("settings/profile")
|
||||
}
|
||||
.clickable { navController.navigate("settings/profile") }
|
||||
)
|
||||
|
||||
ListItem(
|
||||
headlineContent = {
|
||||
Text(
|
||||
text = stringResource(id = R.string.settings_sessions)
|
||||
)
|
||||
},
|
||||
Spacer(Modifier.height(2.dp))
|
||||
SettingsListItem(
|
||||
last = true,
|
||||
headlineContent = { Text(text = stringResource(id = R.string.settings_sessions)) },
|
||||
leadingContent = {
|
||||
SettingsIcon {
|
||||
Icon(
|
||||
|
|
@ -164,21 +154,16 @@ fun SettingsScreen(
|
|||
},
|
||||
modifier = Modifier
|
||||
.testTag("settings_view_sessions")
|
||||
.clickable {
|
||||
navController.navigate("settings/sessions")
|
||||
}
|
||||
.clickable { navController.navigate("settings/sessions") }
|
||||
)
|
||||
|
||||
ListHeader {
|
||||
Text(stringResource(R.string.settings_category_general))
|
||||
}
|
||||
|
||||
ListItem(
|
||||
headlineContent = {
|
||||
Text(
|
||||
text = stringResource(id = R.string.settings_appearance)
|
||||
)
|
||||
},
|
||||
SettingsListItem(
|
||||
first = true,
|
||||
headlineContent = { Text(text = stringResource(id = R.string.settings_appearance)) },
|
||||
leadingContent = {
|
||||
SettingsIcon {
|
||||
Icon(
|
||||
|
|
@ -189,17 +174,11 @@ fun SettingsScreen(
|
|||
},
|
||||
modifier = Modifier
|
||||
.testTag("settings_view_appearance")
|
||||
.clickable {
|
||||
navController.navigate("settings/appearance")
|
||||
}
|
||||
.clickable { navController.navigate("settings/appearance") }
|
||||
)
|
||||
|
||||
ListItem(
|
||||
headlineContent = {
|
||||
Text(
|
||||
text = stringResource(id = R.string.settings_language)
|
||||
)
|
||||
},
|
||||
Spacer(Modifier.height(2.dp))
|
||||
SettingsListItem(
|
||||
headlineContent = { Text(text = stringResource(id = R.string.settings_language)) },
|
||||
leadingContent = {
|
||||
SettingsIcon {
|
||||
Icon(
|
||||
|
|
@ -210,17 +189,11 @@ fun SettingsScreen(
|
|||
},
|
||||
modifier = Modifier
|
||||
.testTag("settings_view_language")
|
||||
.clickable {
|
||||
navController.navigate("settings/language")
|
||||
}
|
||||
.clickable { navController.navigate("settings/language") }
|
||||
)
|
||||
|
||||
ListItem(
|
||||
headlineContent = {
|
||||
Text(
|
||||
text = stringResource(id = R.string.settings_chat)
|
||||
)
|
||||
},
|
||||
Spacer(Modifier.height(2.dp))
|
||||
SettingsListItem(
|
||||
headlineContent = { Text(text = stringResource(id = R.string.settings_chat)) },
|
||||
leadingContent = {
|
||||
SettingsIcon {
|
||||
Icon(
|
||||
|
|
@ -231,16 +204,12 @@ fun SettingsScreen(
|
|||
},
|
||||
modifier = Modifier
|
||||
.testTag("settings_view_chat")
|
||||
.clickable {
|
||||
navController.navigate("settings/chat")
|
||||
}
|
||||
.clickable { navController.navigate("settings/chat") }
|
||||
)
|
||||
ListItem(
|
||||
headlineContent = {
|
||||
Text(
|
||||
text = stringResource(id = R.string.settings_notifications)
|
||||
)
|
||||
},
|
||||
Spacer(Modifier.height(2.dp))
|
||||
SettingsListItem(
|
||||
last = true,
|
||||
headlineContent = { Text(text = stringResource(id = R.string.settings_notifications)) },
|
||||
leadingContent = {
|
||||
SettingsIcon {
|
||||
Icon(
|
||||
|
|
@ -251,21 +220,25 @@ fun SettingsScreen(
|
|||
},
|
||||
modifier = Modifier
|
||||
.testTag("settings_view_notifications")
|
||||
.clickable {
|
||||
navController.navigate("settings/notifications")
|
||||
}
|
||||
.clickable { navController.navigate("settings/notifications") }
|
||||
)
|
||||
|
||||
ListHeader {
|
||||
Text(stringResource(R.string.settings_category_miscellaneous))
|
||||
}
|
||||
|
||||
ListItem(
|
||||
headlineContent = {
|
||||
Text(
|
||||
text = stringResource(id = R.string.about)
|
||||
)
|
||||
},
|
||||
val miscLastIsExperiments = LoadedSettings.experimentsEnabled
|
||||
val miscLastIsLabs =
|
||||
!miscLastIsExperiments && FeatureFlags.labsAccessControlGranted
|
||||
val miscLastIsDebug =
|
||||
!miscLastIsExperiments && !miscLastIsLabs && BuildConfig.DEBUG
|
||||
val miscLastIsAbout =
|
||||
!miscLastIsExperiments && !miscLastIsLabs && !miscLastIsDebug
|
||||
|
||||
SettingsListItem(
|
||||
first = true,
|
||||
last = miscLastIsAbout,
|
||||
headlineContent = { Text(text = stringResource(id = R.string.about)) },
|
||||
leadingContent = {
|
||||
SettingsIcon {
|
||||
Icon(
|
||||
|
|
@ -276,18 +249,14 @@ fun SettingsScreen(
|
|||
},
|
||||
modifier = Modifier
|
||||
.testTag("settings_view_about")
|
||||
.clickable {
|
||||
navController.navigate("about")
|
||||
}
|
||||
.clickable { navController.navigate("about") }
|
||||
)
|
||||
|
||||
if (BuildConfig.DEBUG) {
|
||||
ListItem(
|
||||
headlineContent = {
|
||||
Text(
|
||||
text = "Debug"
|
||||
)
|
||||
},
|
||||
Spacer(Modifier.height(2.dp))
|
||||
SettingsListItem(
|
||||
last = miscLastIsDebug,
|
||||
headlineContent = { Text(text = "Debug") },
|
||||
leadingContent = {
|
||||
SettingsIcon {
|
||||
Icon(
|
||||
|
|
@ -298,19 +267,15 @@ fun SettingsScreen(
|
|||
},
|
||||
modifier = Modifier
|
||||
.testTag("settings_view_debug")
|
||||
.clickable {
|
||||
navController.navigate("settings/debug")
|
||||
}
|
||||
.clickable { navController.navigate("settings/debug") }
|
||||
)
|
||||
}
|
||||
|
||||
if (FeatureFlags.labsAccessControlGranted) {
|
||||
ListItem(
|
||||
headlineContent = {
|
||||
Text(
|
||||
text = "Labs"
|
||||
)
|
||||
},
|
||||
Spacer(Modifier.height(2.dp))
|
||||
SettingsListItem(
|
||||
last = miscLastIsLabs,
|
||||
headlineContent = { Text(text = "Labs") },
|
||||
leadingContent = {
|
||||
SettingsIcon {
|
||||
Icon(
|
||||
|
|
@ -321,19 +286,15 @@ fun SettingsScreen(
|
|||
},
|
||||
modifier = Modifier
|
||||
.testTag("settings_view_labs")
|
||||
.clickable {
|
||||
navController.navigate("labs")
|
||||
}
|
||||
.clickable { navController.navigate("labs") }
|
||||
)
|
||||
}
|
||||
|
||||
if (LoadedSettings.experimentsEnabled) {
|
||||
ListItem(
|
||||
headlineContent = {
|
||||
Text(
|
||||
text = "Experiments"
|
||||
)
|
||||
},
|
||||
Spacer(Modifier.height(2.dp))
|
||||
SettingsListItem(
|
||||
last = true,
|
||||
headlineContent = { Text(text = "Experiments") },
|
||||
leadingContent = {
|
||||
SettingsIcon {
|
||||
Icon(
|
||||
|
|
@ -344,9 +305,7 @@ fun SettingsScreen(
|
|||
},
|
||||
modifier = Modifier
|
||||
.testTag("settings_view_experiments")
|
||||
.clickable {
|
||||
navController.navigate("settings/experiments")
|
||||
}
|
||||
.clickable { navController.navigate("settings/experiments") }
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -359,12 +318,9 @@ fun SettingsScreen(
|
|||
)
|
||||
}
|
||||
|
||||
ListItem(
|
||||
headlineContent = {
|
||||
Text(
|
||||
text = stringResource(id = R.string.settings_changelog)
|
||||
)
|
||||
},
|
||||
SettingsListItem(
|
||||
first = true,
|
||||
headlineContent = { Text(text = stringResource(id = R.string.settings_changelog)) },
|
||||
leadingContent = {
|
||||
SettingsIcon {
|
||||
Icon(
|
||||
|
|
@ -375,22 +331,12 @@ fun SettingsScreen(
|
|||
},
|
||||
modifier = Modifier
|
||||
.testTag("settings_view_changelog")
|
||||
.clickable {
|
||||
navController.navigate("changelog/latest")
|
||||
}
|
||||
.clickable { navController.navigate("changelog/latest") }
|
||||
)
|
||||
|
||||
ListItem(
|
||||
headlineContent = {
|
||||
Text(
|
||||
text = stringResource(id = R.string.settings_feedback)
|
||||
)
|
||||
},
|
||||
supportingContent = {
|
||||
Text(
|
||||
text = stringResource(id = R.string.settings_feedback_description)
|
||||
)
|
||||
},
|
||||
Spacer(Modifier.height(2.dp))
|
||||
SettingsListItem(
|
||||
headlineContent = { Text(text = stringResource(id = R.string.settings_feedback)) },
|
||||
supportingContent = { Text(text = stringResource(id = R.string.settings_feedback_description)) },
|
||||
leadingContent = {
|
||||
SettingsIcon {
|
||||
Icon(
|
||||
|
|
@ -406,18 +352,16 @@ fun SettingsScreen(
|
|||
context,
|
||||
InviteActivity::class.java
|
||||
).setAction(Intent.ACTION_VIEW)
|
||||
|
||||
intent.data = "https://stt.gg/Testers".toUri()
|
||||
context.startActivity(intent)
|
||||
}
|
||||
)
|
||||
|
||||
ListItem(
|
||||
Spacer(Modifier.height(2.dp))
|
||||
SettingsListItem(
|
||||
last = true,
|
||||
headlineContent = {
|
||||
CompositionLocalProvider(LocalContentColor provides MaterialTheme.colorScheme.error) {
|
||||
Text(
|
||||
text = stringResource(id = R.string.logout)
|
||||
)
|
||||
Text(text = stringResource(id = R.string.logout))
|
||||
}
|
||||
},
|
||||
leadingContent = {
|
||||
|
|
@ -445,6 +389,42 @@ fun SettingsScreen(
|
|||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun SettingsListItem(
|
||||
first: Boolean = false,
|
||||
last: Boolean = false,
|
||||
headlineContent: @Composable () -> Unit,
|
||||
supportingContent: (@Composable () -> Unit)? = null,
|
||||
leadingContent: (@Composable () -> Unit)? = null,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
ListItem(
|
||||
colors = ListItemDefaults.colors(containerColor = MaterialTheme.colorScheme.surfaceContainer),
|
||||
headlineContent = headlineContent,
|
||||
supportingContent = supportingContent,
|
||||
leadingContent = leadingContent,
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 16.dp)
|
||||
.clip(
|
||||
when {
|
||||
first && last -> MaterialTheme.shapes.large
|
||||
first -> MaterialTheme.shapes.extraSmall.copy(
|
||||
topStart = MaterialTheme.shapes.large.topStart,
|
||||
topEnd = MaterialTheme.shapes.large.topEnd
|
||||
)
|
||||
|
||||
last -> MaterialTheme.shapes.extraSmall.copy(
|
||||
bottomStart = MaterialTheme.shapes.large.bottomStart,
|
||||
bottomEnd = MaterialTheme.shapes.large.bottomEnd
|
||||
)
|
||||
|
||||
else -> MaterialTheme.shapes.extraSmall
|
||||
}
|
||||
)
|
||||
.then(modifier)
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SettingsIcon(danger: Boolean = false, content: @Composable () -> Unit) {
|
||||
CompositionLocalProvider(
|
||||
|
|
@ -454,4 +434,4 @@ fun SettingsIcon(danger: Boolean = false, content: @Composable () -> Unit) {
|
|||
) {
|
||||
content()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,11 +4,12 @@ import android.app.Application
|
|||
import android.util.Log
|
||||
import androidx.compose.animation.animateContentSize
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.combinedClickable
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
|
|
@ -311,47 +312,58 @@ fun MemberListSheet(
|
|||
)
|
||||
}
|
||||
|
||||
is MemberListSheetItem.MemberItem -> item(key = item.member.id!!.user) {
|
||||
MemberListItem(
|
||||
user = StoatAPI.userCache[item.member.id!!.user],
|
||||
member = item.member,
|
||||
serverId = serverId,
|
||||
userId = item.member.id!!.user,
|
||||
modifier = Modifier
|
||||
.combinedClickable(
|
||||
onClick = {
|
||||
userInfoSheetTarget = item.member.id!!.user
|
||||
showUserInfoSheet = true
|
||||
},
|
||||
onClickLabel = stringResource(R.string.user_info_sheet_open),
|
||||
onLongClick = {
|
||||
memberContextSheetTarget = item.member.id!!.user
|
||||
showMemberContextSheet = true
|
||||
},
|
||||
onLongClickLabel = stringResource(R.string.member_context_sheet_open)
|
||||
)
|
||||
)
|
||||
is MemberListSheetItem.MemberItem -> {
|
||||
val isFirst = index == 0 || viewModel.fullItemList[index - 1] is MemberListSheetItem.CategoryItem
|
||||
val isLast = index == viewModel.fullItemList.size - 1 || viewModel.fullItemList[index + 1] is MemberListSheetItem.CategoryItem
|
||||
item(key = item.member.id!!.user) {
|
||||
MemberListItem(
|
||||
user = StoatAPI.userCache[item.member.id!!.user],
|
||||
member = item.member,
|
||||
serverId = serverId,
|
||||
userId = item.member.id!!.user,
|
||||
first = isFirst,
|
||||
last = isLast,
|
||||
onClick = {
|
||||
userInfoSheetTarget = item.member.id!!.user
|
||||
showUserInfoSheet = true
|
||||
},
|
||||
onLongClick = {
|
||||
memberContextSheetTarget = item.member.id!!.user
|
||||
showMemberContextSheet = true
|
||||
},
|
||||
modifier = Modifier.padding(horizontal = 16.dp)
|
||||
)
|
||||
if (!isLast) {
|
||||
Spacer(modifier = Modifier.height(2.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
is MemberListSheetItem.UserItem -> item(key = item.user.id!!) {
|
||||
MemberListItem(
|
||||
user = item.user,
|
||||
member = null,
|
||||
serverId = serverId,
|
||||
userId = item.user.id!!,
|
||||
modifier = Modifier.combinedClickable(
|
||||
is MemberListSheetItem.UserItem -> {
|
||||
val isFirst = index == 0 || viewModel.fullItemList[index - 1] is MemberListSheetItem.CategoryItem
|
||||
val isLast = index == viewModel.fullItemList.size - 1 || viewModel.fullItemList[index + 1] is MemberListSheetItem.CategoryItem
|
||||
item(key = item.user.id!!) {
|
||||
MemberListItem(
|
||||
user = item.user,
|
||||
member = null,
|
||||
serverId = serverId,
|
||||
userId = item.user.id!!,
|
||||
first = isFirst,
|
||||
last = isLast,
|
||||
onClick = {
|
||||
userInfoSheetTarget = item.user.id!!
|
||||
showUserInfoSheet = true
|
||||
},
|
||||
onClickLabel = stringResource(R.string.user_info_sheet_open),
|
||||
onLongClick = {
|
||||
memberContextSheetTarget = item.user.id!!
|
||||
showMemberContextSheet = true
|
||||
},
|
||||
onLongClickLabel = stringResource(R.string.member_context_sheet_open)
|
||||
modifier = Modifier.padding(horizontal = 16.dp)
|
||||
)
|
||||
)
|
||||
if (!isLast) {
|
||||
Spacer(modifier = Modifier.height(2.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ import androidx.compose.foundation.layout.padding
|
|||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
|
|
@ -218,9 +218,9 @@ fun ReactionInfoSheet(messageId: String, emoji: String, onDismiss: () -> Unit) {
|
|||
verticalArrangement = Arrangement.spacedBy(16.dp),
|
||||
modifier = Modifier.padding(
|
||||
top = 16.dp,
|
||||
start = 16.dp,
|
||||
end = 16.dp,
|
||||
bottom = 4.dp
|
||||
start = 24.dp,
|
||||
end = 24.dp,
|
||||
bottom = 16.dp
|
||||
),
|
||||
) {
|
||||
Row(
|
||||
|
|
@ -308,15 +308,14 @@ fun ReactionInfoSheet(messageId: String, emoji: String, onDismiss: () -> Unit) {
|
|||
)
|
||||
}
|
||||
}
|
||||
|
||||
HorizontalDivider()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val reactionsForEmoji =
|
||||
reactions?.get(reactionEmoji[selectedReactionIndex]) ?: emptyList()
|
||||
items(items = reactionsForEmoji) { reaction ->
|
||||
itemsIndexed(items = reactionsForEmoji) { index, reaction ->
|
||||
val isLast = index == reactionsForEmoji.size - 1
|
||||
val userOrNull = StoatAPI.userCache[reaction]
|
||||
val user = userOrNull ?: User.getPlaceholder(reaction)
|
||||
val member = if (channel.server != null && user.id != null) {
|
||||
|
|
@ -340,7 +339,13 @@ fun ReactionInfoSheet(messageId: String, emoji: String, onDismiss: () -> Unit) {
|
|||
user = user,
|
||||
serverId = channel.server,
|
||||
userId = reaction,
|
||||
first = index == 0,
|
||||
last = isLast,
|
||||
modifier = Modifier.padding(horizontal = 16.dp)
|
||||
)
|
||||
if (!isLast) {
|
||||
Spacer(modifier = Modifier.height(2.dp))
|
||||
}
|
||||
}
|
||||
|
||||
item("bottom") {
|
||||
|
|
|
|||
Loading…
Reference in New Issue