1
Fork 0
mirror of https://github.com/Steffo99/twom.git synced 2024-11-25 09:34:25 +00:00

Complete mockup of RoomActivity

This commit is contained in:
Steffo 2024-01-07 18:47:16 +01:00
parent 59702f1b15
commit 4b03307901
Signed by: steffo
GPG key ID: 2A24051445686895
23 changed files with 624 additions and 3 deletions

View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="deploymentTargetDropDown">
<runningDeviceTargetSelectedWithDropDown>
<Target>
<type value="RUNNING_DEVICE_TARGET" />
<deviceKey>
<Key>
<type value="SERIAL_NUMBER" />
<value value="adb-dedcc2dd-clt3EI._adb-tls-connect._tcp" />
</Key>
</deviceKey>
</Target>
</runningDeviceTargetSelectedWithDropDown>
<timeTargetWasSelectedWithDropDown value="2024-01-07T17:27:55.113026062Z" />
</component>
</project>

View file

@ -61,6 +61,7 @@ dependencies {
implementation("androidx.navigation:navigation-fragment-ktx:2.7.5") implementation("androidx.navigation:navigation-fragment-ktx:2.7.5")
implementation("androidx.navigation:navigation-ui-ktx:2.7.5") implementation("androidx.navigation:navigation-ui-ktx:2.7.5")
implementation("androidx.compose.material3:material3:1.1.2") implementation("androidx.compose.material3:material3:1.1.2")
implementation("androidx.compose.material:material-icons-extended") // TODO: Remove stuff with ProGuard?
implementation("org.matrix.android:matrix-android-sdk2:1.5.30") implementation("org.matrix.android:matrix-android-sdk2:1.5.30")
implementation("com.squareup.okhttp3:okhttp:4.12.0") implementation("com.squareup.okhttp3:okhttp:4.12.0")
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.2") implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.2")

View file

@ -0,0 +1,121 @@
package eu.steffo.twom.room
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material3.Icon
import androidx.compose.material3.ListItem
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.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import eu.steffo.twom.R
import eu.steffo.twom.matrix.LocalSession
import eu.steffo.twom.matrix.avatar.AvatarFromURL
import eu.steffo.twom.theme.colorRoleLater
import eu.steffo.twom.theme.colorRoleMaybe
import eu.steffo.twom.theme.colorRoleNoway
import eu.steffo.twom.theme.colorRoleSure
import eu.steffo.twom.theme.iconRoleLater
import eu.steffo.twom.theme.iconRoleMaybe
import eu.steffo.twom.theme.iconRoleNoway
import eu.steffo.twom.theme.iconRoleSure
import org.matrix.android.sdk.api.session.getUser
// TODO: Check this with brain on
@Composable
fun MemberListItem(
modifier: Modifier = Modifier,
memberId: String,
onClickMember: (memberId: String) -> Unit = {},
rsvpAnswer: RSVPAnswer? = null,
rsvpComment: String = "",
) {
val session = LocalSession.current
val user = session?.getUser(memberId)
// TODO: These are going to get cached many times...
val crSure = colorRoleSure()
val crLater = colorRoleLater()
val crMaybe = colorRoleMaybe()
val crNoway = colorRoleNoway()
ListItem(
modifier = Modifier.clickable {
onClickMember(memberId)
},
headlineContent = {
Text(user?.displayName ?: stringResource(R.string.user_unresolved_name))
},
leadingContent = {
Box(
Modifier
.padding(end = 10.dp)
.size(40.dp)
.clip(MaterialTheme.shapes.extraLarge)
) {
AvatarFromURL(
url = user?.avatarUrl,
)
}
},
trailingContent = {
when (rsvpAnswer) {
RSVPAnswer.SURE -> {
Icon(
imageVector = iconRoleSure,
contentDescription = stringResource(R.string.room_rsvp_sure_label),
tint = crSure.value,
)
}
RSVPAnswer.LATER -> {
Icon(
imageVector = iconRoleLater,
contentDescription = stringResource(R.string.room_rsvp_later_label),
tint = crLater.value,
)
}
RSVPAnswer.MAYBE -> {
Icon(
imageVector = iconRoleMaybe,
contentDescription = stringResource(R.string.room_rsvp_maybe_label),
tint = crMaybe.value,
)
}
RSVPAnswer.NOWAY -> {
Icon(
imageVector = iconRoleNoway,
contentDescription = stringResource(R.string.room_rsvp_later_label),
tint = crNoway.value,
)
}
null -> {}
}
},
supportingContent = {
if (rsvpComment != "") {
Text(
text = rsvpComment,
color = when (rsvpAnswer) {
RSVPAnswer.SURE -> crSure.value
RSVPAnswer.LATER -> crLater.value
RSVPAnswer.MAYBE -> crMaybe.value
RSVPAnswer.NOWAY -> crNoway.value
null -> Color.Unspecified
}
)
}
},
)
}

View file

@ -0,0 +1,8 @@
package eu.steffo.twom.room
enum class RSVPAnswer {
SURE,
LATER,
MAYBE,
NOWAY,
}

View file

@ -0,0 +1,49 @@
package eu.steffo.twom.room
import androidx.compose.material3.ElevatedFilterChip
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.FilterChipDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
import eu.steffo.twom.theme.StaticColorRole
import eu.steffo.twom.theme.TwoMPadding
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun RoomActivityChip(
modifier: Modifier = Modifier,
selected: Boolean = false,
onClick: () -> Unit = {},
text: String,
imageVector: ImageVector,
colorRole: StaticColorRole,
) {
ElevatedFilterChip(
modifier = TwoMPadding.chips,
selected = selected,
onClick = onClick,
leadingIcon = {
Icon(
imageVector = imageVector,
contentDescription = null,
)
},
label = {
Text(
text = text,
style = MaterialTheme.typography.labelLarge,
)
},
colors = FilterChipDefaults.elevatedFilterChipColors(
iconColor = colorRole.value,
labelColor = colorRole.value,
selectedContainerColor = colorRole.valueContainer,
selectedLeadingIconColor = colorRole.onValueContainer,
selectedLabelColor = colorRole.onValueContainer,
),
)
}

View file

@ -0,0 +1,25 @@
package eu.steffo.twom.room
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import eu.steffo.twom.R
import eu.steffo.twom.theme.colorRoleLater
import eu.steffo.twom.theme.iconRoleLater
@Composable
@Preview
fun RoomActivityChipLater(
modifier: Modifier = Modifier,
selected: Boolean = false,
onClick: () -> Unit = {},
) {
RoomActivityChip(
selected = selected,
onClick = onClick,
imageVector = iconRoleLater,
text = stringResource(R.string.room_rsvp_later_label),
colorRole = colorRoleLater(),
)
}

View file

@ -0,0 +1,26 @@
package eu.steffo.twom.room
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import eu.steffo.twom.R
import eu.steffo.twom.theme.colorRoleMaybe
import eu.steffo.twom.theme.iconRoleMaybe
@Composable
@Preview
fun RoomActivityChipMaybe(
modifier: Modifier = Modifier,
selected: Boolean = false,
onClick: () -> Unit = {},
) {
// TODO: Pick a better color
RoomActivityChip(
selected = selected,
onClick = onClick,
imageVector = iconRoleMaybe,
text = stringResource(R.string.room_rsvp_maybe_label),
colorRole = colorRoleMaybe(),
)
}

View file

@ -0,0 +1,25 @@
package eu.steffo.twom.room
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import eu.steffo.twom.R
import eu.steffo.twom.theme.colorRoleNoway
import eu.steffo.twom.theme.iconRoleNoway
@Composable
@Preview
fun RoomActivityChipNoway(
modifier: Modifier = Modifier,
selected: Boolean = false,
onClick: () -> Unit = {},
) {
RoomActivityChip(
selected = selected,
onClick = onClick,
imageVector = iconRoleNoway,
text = stringResource(R.string.room_rsvp_noway_label),
colorRole = colorRoleNoway(),
)
}

View file

@ -0,0 +1,79 @@
package eu.steffo.twom.room
import androidx.compose.foundation.horizontalScroll
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import eu.steffo.twom.theme.TwoMPadding
@Composable
@Preview
fun RoomActivityChipSelector(
modifier: Modifier = Modifier,
value: RSVPAnswer? = null,
onChange: (answer: RSVPAnswer?) -> Unit = {},
) {
Box(
modifier = modifier
.horizontalScroll(rememberScrollState())
) {
Row(
modifier = Modifier
.padding(start = 8.dp, end = 8.dp)
) {
RoomActivityChipSure(
modifier = TwoMPadding.chips,
selected = (value == RSVPAnswer.SURE),
onClick = {
onChange(
when (value) {
RSVPAnswer.SURE -> null
else -> RSVPAnswer.SURE
}
)
}
)
RoomActivityChipLater(
modifier = TwoMPadding.chips,
selected = (value == RSVPAnswer.LATER),
onClick = {
onChange(
when (value) {
RSVPAnswer.LATER -> null
else -> RSVPAnswer.LATER
}
)
}
)
RoomActivityChipMaybe(
modifier = TwoMPadding.chips,
selected = (value == RSVPAnswer.MAYBE),
onClick = {
onChange(
when (value) {
RSVPAnswer.MAYBE -> null
else -> RSVPAnswer.MAYBE
}
)
}
)
RoomActivityChipNoway(
modifier = TwoMPadding.chips,
selected = (value == RSVPAnswer.NOWAY),
onClick = {
onChange(
when (value) {
RSVPAnswer.NOWAY -> null
else -> RSVPAnswer.NOWAY
}
)
}
)
}
}
}

View file

@ -0,0 +1,26 @@
package eu.steffo.twom.room
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import eu.steffo.twom.R
import eu.steffo.twom.theme.colorRoleSure
import eu.steffo.twom.theme.iconRoleSure
@Composable
@Preview
fun RoomActivityChipSure(
modifier: Modifier = Modifier,
selected: Boolean = false,
onClick: () -> Unit = {},
) {
RoomActivityChip(
selected = selected,
onClick = onClick,
imageVector = iconRoleSure,
text = stringResource(R.string.room_rsvp_sure_label),
colorRole = colorRoleSure(),
)
}

View file

@ -2,11 +2,25 @@ package eu.steffo.twom.room
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import eu.steffo.twom.R
import eu.steffo.twom.matrix.LocalSession
import eu.steffo.twom.theme.TwoMPadding import eu.steffo.twom.theme.TwoMPadding
@Composable @Composable
fun RoomActivityContent( fun RoomActivityContent(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
@ -15,11 +29,74 @@ fun RoomActivityContent(
val roomSummary = LocalRoom.current?.getOrNull() val roomSummary = LocalRoom.current?.getOrNull()
val isError = (!isLoading && roomSummary == null) val isError = (!isLoading && roomSummary == null)
var rsvpAnswer by rememberSaveable { mutableStateOf<RSVPAnswer?>(null) }
var rsvpComment by rememberSaveable { mutableStateOf("") }
Column(modifier) { Column(modifier) {
Row(TwoMPadding.base) { if (roomSummary != null) {
if (roomSummary != null) { Row(TwoMPadding.base) {
Text(
text = stringResource(R.string.room_topic_title),
style = MaterialTheme.typography.titleMedium
)
}
Row(TwoMPadding.base) {
Text(roomSummary.topic) Text(roomSummary.topic)
} }
Row(TwoMPadding.base) {
Text(
text = stringResource(R.string.room_rsvp_title),
style = MaterialTheme.typography.titleMedium
)
}
RoomActivityChipSelector(
value = rsvpAnswer,
onChange = { rsvpAnswer = it }
)
if (rsvpAnswer != null) {
Row(Modifier.padding(start = 10.dp, end = 10.dp, bottom = 10.dp)) {
TextField(
modifier = Modifier.fillMaxWidth(),
singleLine = true,
value = rsvpComment,
onValueChange = { rsvpComment = it },
placeholder = {
Text(LocalContext.current.getString(R.string.room_rsvp_comment_placeholder))
},
)
}
}
Row(TwoMPadding.base) {
Text(
text = stringResource(R.string.room_invitees_title),
style = MaterialTheme.typography.titleMedium
)
}
// TODO: Risky assertion?
Column(TwoMPadding.base) {
MemberListItem(
memberId = LocalSession.current!!.myUserId,
rsvpAnswer = rsvpAnswer,
rsvpComment = if (rsvpAnswer != null) {
rsvpComment
} else {
""
},
)
roomSummary.otherMemberIds.forEach {
MemberListItem(
memberId = it,
rsvpAnswer = null,
rsvpComment = "",
)
}
}
} }
} }
} }

View file

@ -7,6 +7,7 @@ import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@ -38,7 +39,10 @@ fun RoomActivityTopBar(
}, },
title = { title = {
if (roomSummary != null) { if (roomSummary != null) {
Text(roomSummary.displayName) Text(
text = roomSummary.displayName,
style = MaterialTheme.typography.titleLarge,
)
} }
}, },
actions = { actions = {

View file

@ -0,0 +1,10 @@
package eu.steffo.twom.theme
import androidx.compose.ui.graphics.Color
data class StaticColorRole(
val value: Color,
val onValue: Color,
val valueContainer: Color,
val onValueContainer: Color,
)

View file

@ -7,4 +7,5 @@ import androidx.compose.ui.unit.dp
object TwoMPadding { object TwoMPadding {
val base = Modifier.padding(all = 10.dp) val base = Modifier.padding(all = 10.dp)
val chips = Modifier.padding(start = 2.5.dp, end = 2.5.dp)
} }

View file

@ -0,0 +1,29 @@
package eu.steffo.twom.theme
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import com.google.android.material.color.MaterialColors
@Composable
fun colorRoleLater(): StaticColorRole {
val ctx = LocalContext.current
return when (isSystemInDarkTheme()) {
false -> StaticColorRole(
value = Color(MaterialColors.harmonizeWithPrimary(ctx, 0x00658B)),
onValue = Color(MaterialColors.harmonizeWithPrimary(ctx, 0xFFFFFF)),
valueContainer = Color(MaterialColors.harmonizeWithPrimary(ctx, 0xC4E7FF)),
onValueContainer = Color(MaterialColors.harmonizeWithPrimary(ctx, 0x001E2C)),
)
true -> StaticColorRole(
value = Color(MaterialColors.harmonizeWithPrimary(ctx, 0x7DD0FF)),
onValue = Color(MaterialColors.harmonizeWithPrimary(ctx, 0x00344A)),
valueContainer = Color(MaterialColors.harmonizeWithPrimary(ctx, 0x004C69)),
onValueContainer = Color(MaterialColors.harmonizeWithPrimary(ctx, 0xC4E7FF)),
)
}
}

View file

@ -0,0 +1,29 @@
package eu.steffo.twom.theme
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import com.google.android.material.color.MaterialColors
@Composable
fun colorRoleMaybe(): StaticColorRole {
val ctx = LocalContext.current
return when (isSystemInDarkTheme()) {
false -> StaticColorRole(
value = Color(MaterialColors.harmonizeWithPrimary(ctx, 0x765B00)),
onValue = Color(MaterialColors.harmonizeWithPrimary(ctx, 0xFFFFFF)),
valueContainer = Color(MaterialColors.harmonizeWithPrimary(ctx, 0xFFDF94)),
onValueContainer = Color(MaterialColors.harmonizeWithPrimary(ctx, 0x241A00)),
)
true -> StaticColorRole(
value = Color(MaterialColors.harmonizeWithPrimary(ctx, 0xEDC148)),
onValue = Color(MaterialColors.harmonizeWithPrimary(ctx, 0x3E2E00)),
valueContainer = Color(MaterialColors.harmonizeWithPrimary(ctx, 0x594400)),
onValueContainer = Color(MaterialColors.harmonizeWithPrimary(ctx, 0xFFDF94)),
)
}
}

View file

@ -0,0 +1,29 @@
package eu.steffo.twom.theme
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import com.google.android.material.color.MaterialColors
@Composable
fun colorRoleNoway(): StaticColorRole {
val ctx = LocalContext.current
return when (isSystemInDarkTheme()) {
false -> StaticColorRole(
value = Color(MaterialColors.harmonizeWithPrimary(ctx, 0xAB3520)),
onValue = Color(MaterialColors.harmonizeWithPrimary(ctx, 0xFFFFFF)),
valueContainer = Color(MaterialColors.harmonizeWithPrimary(ctx, 0xFFDAD3)),
onValueContainer = Color(MaterialColors.harmonizeWithPrimary(ctx, 0x3F0400)),
)
true -> StaticColorRole(
value = Color(MaterialColors.harmonizeWithPrimary(ctx, 0xFFB4A5)),
onValue = Color(MaterialColors.harmonizeWithPrimary(ctx, 0x650A00)),
valueContainer = Color(MaterialColors.harmonizeWithPrimary(ctx, 0x891D0A)),
onValueContainer = Color(MaterialColors.harmonizeWithPrimary(ctx, 0xFFDAD3)),
)
}
}

View file

@ -0,0 +1,28 @@
package eu.steffo.twom.theme
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import com.google.android.material.color.MaterialColors
@Composable
fun colorRoleSure(): StaticColorRole {
val ctx = LocalContext.current
return when (isSystemInDarkTheme()) {
false -> StaticColorRole(
value = Color(MaterialColors.harmonizeWithPrimary(ctx, 0x006E2C)),
onValue = Color(MaterialColors.harmonizeWithPrimary(ctx, 0xFFFFFF)),
valueContainer = Color(MaterialColors.harmonizeWithPrimary(ctx, 0x7FFC95)),
onValueContainer = Color(MaterialColors.harmonizeWithPrimary(ctx, 0x002108)),
)
true -> StaticColorRole(
value = Color(MaterialColors.harmonizeWithPrimary(ctx, 0x62DF7C)),
onValue = Color(MaterialColors.harmonizeWithPrimary(ctx, 0x003913)),
valueContainer = Color(MaterialColors.harmonizeWithPrimary(ctx, 0x00531F)),
onValueContainer = Color(MaterialColors.harmonizeWithPrimary(ctx, 0x7FFC95)),
)
}
}

View file

@ -0,0 +1,6 @@
package eu.steffo.twom.theme
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Schedule
val iconRoleLater = Icons.Outlined.Schedule

View file

@ -0,0 +1,6 @@
package eu.steffo.twom.theme
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.PauseCircle
val iconRoleMaybe = Icons.Outlined.PauseCircle

View file

@ -0,0 +1,6 @@
package eu.steffo.twom.theme
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.RemoveCircleOutline
val iconRoleNoway = Icons.Outlined.RemoveCircleOutline

View file

@ -0,0 +1,6 @@
package eu.steffo.twom.theme
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.CheckCircle
val iconRoleSure = Icons.Outlined.CheckCircle

View file

@ -36,4 +36,17 @@
<string name="error">Error</string> <string name="error">Error</string>
<string name="login_error_username_invalid">The entered username is not a valid Matrix ID.</string> <string name="login_error_username_invalid">The entered username is not a valid Matrix ID.</string>
<string name="login_error_wellknown_missing">Failed to detect well-known data for the specified Matrix homeserver. The server might not exist, be offline, or not be supporting well-known lookups.</string> <string name="login_error_wellknown_missing">Failed to detect well-known data for the specified Matrix homeserver. The server might not exist, be offline, or not be supporting well-known lookups.</string>
<string name="room_invitees_title">Invitees</string>
<string name="room_rsvp_title">Your reply</string>
<string name="room_rsvp_sure_label">Sure!</string>
<string name="room_rsvp_later_label">I\'ll be late...</string>
<string name="room_rsvp_maybe_label">Maybe?</string>
<string name="room_rsvp_noway_label">Nope.</string>
<string name="room_topic_title">About this party</string>
<string name="user_unresolved_name">[unknown user]</string>
<string name="room_rsvp_sure_response">Will be there</string>
<string name="room_rsvp_later_response">Will arrive late</string>
<string name="room_rsvp_maybe_response">Will maybe partecipate</string>
<string name="room_rsvp_noway_response">Won\'t be there</string>
<string name="room_rsvp_comment_placeholder">Leave a comment...</string>
</resources> </resources>