1
Fork 0
mirror of https://github.com/Steffo99/twom.git synced 2024-11-22 08:04:26 +00:00

It works!

This commit is contained in:
Steffo 2024-01-09 04:27:50 +01:00
parent a6e562c14b
commit acf9f34f59
Signed by: steffo
GPG key ID: 2A24051445686895
10 changed files with 284 additions and 115 deletions

View file

@ -19,6 +19,7 @@ import kotlinx.coroutines.launch
import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams
import org.matrix.android.sdk.api.session.room.model.create.CreateRoomPreset import org.matrix.android.sdk.api.session.room.model.create.CreateRoomPreset
import org.matrix.android.sdk.api.session.room.model.create.CreateRoomStateEvent
class MainActivity : ComponentActivity() { class MainActivity : ComponentActivity() {
@ -176,6 +177,52 @@ class MainActivity : ComponentActivity() {
createRoomParams.topic = description createRoomParams.topic = description
createRoomParams.preset = CreateRoomPreset.PRESET_PRIVATE_CHAT createRoomParams.preset = CreateRoomPreset.PRESET_PRIVATE_CHAT
createRoomParams.roomType = TwoMMatrix.ROOM_TYPE createRoomParams.roomType = TwoMMatrix.ROOM_TYPE
createRoomParams.initialStates = mutableListOf(
CreateRoomStateEvent(
type = "m.room.power_levels",
content = mapOf(
// Users start with a power level of 0
"users_default" to 0,
// Allow only the party creator to send arbitrary events
"events_default" to 100,
// Allow only the party creator to send arbitrary states
"state_default" to 100,
// Allow only party officers to send invites
"invite" to 50,
// Allow only party officers to kick invitees
"kick" to 50,
// Allow only party officers to ban invitees
"ban" to 50,
// Allow only party officers to redact other people's events
"redact" to 50,
"notifications" to mapOf(
// Allow only party officers to ping the room
"room" to 50,
),
"events" to mapOf(
// Allow party officers to rename the room
"m.room.name" to 50,
// Allow party officers to change the room avatar
"m.room.avatar" to 50,
// Allow party officers to change the room topic
"m.room.topic" to 50,
// Allow everyone to redact their own states
"m.room.redaction" to 0,
// Allow everyone to set RSVPs
// FIXME: Do we really want everyone to set RSVPs? Maybe we should use m.room.member instead?
"eu.steffo.twom.rsvp" to 0,
),
"users" to mapOf(
// Give ourselves admin permissions
session!!.myUserId to 100,
)
)
)
)
when (avatarUri?.toFile()?.isFile) { when (avatarUri?.toFile()?.isFile) {
false -> { false -> {

View file

@ -25,8 +25,8 @@ fun MemberListItem(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
memberId: String, memberId: String,
onClickMember: (memberId: String) -> Unit = {}, onClickMember: (memberId: String) -> Unit = {},
rsvpAnswer: RSVPAnswer? = null, rsvpAnswer: RSVPAnswer,
rsvpComment: String = "", rsvpComment: String,
) { ) {
val session = LocalSession.current val session = LocalSession.current

View file

@ -1,6 +1,8 @@
package eu.steffo.twom.room package eu.steffo.twom.room
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.graphics.vector.ImageVector
import eu.steffo.twom.R import eu.steffo.twom.R
import eu.steffo.twom.theme.StaticColorRole import eu.steffo.twom.theme.StaticColorRole
@ -14,33 +16,37 @@ import eu.steffo.twom.theme.iconMaybe
import eu.steffo.twom.theme.iconNoway import eu.steffo.twom.theme.iconNoway
import eu.steffo.twom.theme.iconSure import eu.steffo.twom.theme.iconSure
import eu.steffo.twom.theme.iconUnknown import eu.steffo.twom.theme.iconUnknown
import org.matrix.android.sdk.api.util.JsonDict import org.matrix.android.sdk.api.query.QueryStringValue
import org.matrix.android.sdk.api.session.events.model.Event
import org.matrix.android.sdk.api.session.room.Room
import org.matrix.android.sdk.api.util.Optional
enum class RSVPAnswer : JsonDict { enum class RSVPAnswer {
SURE, SURE,
LATER, LATER,
MAYBE, MAYBE,
NOWAY, NOWAY,
UNKNOWN,
} }
@Composable @Composable
fun RSVPAnswer?.toStaticColorRole(): StaticColorRole { fun RSVPAnswer.toStaticColorRole(): StaticColorRole {
return when (this) { return when (this) {
RSVPAnswer.SURE -> colorRoleSure() RSVPAnswer.SURE -> colorRoleSure()
RSVPAnswer.LATER -> colorRoleLater() RSVPAnswer.LATER -> colorRoleLater()
RSVPAnswer.MAYBE -> colorRoleMaybe() RSVPAnswer.MAYBE -> colorRoleMaybe()
RSVPAnswer.NOWAY -> colorRoleNoway() RSVPAnswer.NOWAY -> colorRoleNoway()
null -> colorRoleUnknown() RSVPAnswer.UNKNOWN -> colorRoleUnknown()
} }
} }
fun RSVPAnswer?.toIcon(): ImageVector { fun RSVPAnswer.toIcon(): ImageVector {
return when (this) { return when (this) {
RSVPAnswer.SURE -> iconSure RSVPAnswer.SURE -> iconSure
RSVPAnswer.LATER -> iconLater RSVPAnswer.LATER -> iconLater
RSVPAnswer.MAYBE -> iconMaybe RSVPAnswer.MAYBE -> iconMaybe
RSVPAnswer.NOWAY -> iconNoway RSVPAnswer.NOWAY -> iconNoway
null -> iconUnknown RSVPAnswer.UNKNOWN -> iconUnknown
} }
} }
@ -50,25 +56,72 @@ fun RSVPAnswer.toLabelResourceId(): Int {
RSVPAnswer.LATER -> R.string.room_rsvp_later_label RSVPAnswer.LATER -> R.string.room_rsvp_later_label
RSVPAnswer.MAYBE -> R.string.room_rsvp_maybe_label RSVPAnswer.MAYBE -> R.string.room_rsvp_maybe_label
RSVPAnswer.NOWAY -> R.string.room_rsvp_noway_label RSVPAnswer.NOWAY -> R.string.room_rsvp_noway_label
RSVPAnswer.UNKNOWN -> R.string.room_rsvp_unknown_label
} }
} }
fun RSVPAnswer?.toResponseResourceId(): Int { fun RSVPAnswer.toResponseResourceId(): Int {
return when (this) { return when (this) {
RSVPAnswer.SURE -> R.string.room_rsvp_sure_response RSVPAnswer.SURE -> R.string.room_rsvp_sure_response
RSVPAnswer.LATER -> R.string.room_rsvp_later_response RSVPAnswer.LATER -> R.string.room_rsvp_later_response
RSVPAnswer.MAYBE -> R.string.room_rsvp_maybe_response RSVPAnswer.MAYBE -> R.string.room_rsvp_maybe_response
RSVPAnswer.NOWAY -> R.string.room_rsvp_noway_response RSVPAnswer.NOWAY -> R.string.room_rsvp_noway_response
null -> R.string.room_rsvp_unknown_response RSVPAnswer.UNKNOWN -> R.string.room_rsvp_unknown_response
} }
} }
fun RSVPAnswer?.toPlaceholderResourceId(): Int { fun RSVPAnswer.toPlaceholderResourceId(): Int {
return when (this) { return when (this) {
RSVPAnswer.SURE -> R.string.room_rsvp_sure_placeholder RSVPAnswer.SURE -> R.string.room_rsvp_sure_placeholder
RSVPAnswer.LATER -> R.string.room_rsvp_later_placeholder RSVPAnswer.LATER -> R.string.room_rsvp_later_placeholder
RSVPAnswer.MAYBE -> R.string.room_rsvp_maybe_placeholder RSVPAnswer.MAYBE -> R.string.room_rsvp_maybe_placeholder
RSVPAnswer.NOWAY -> R.string.room_rsvp_noway_placeholder RSVPAnswer.NOWAY -> R.string.room_rsvp_noway_placeholder
null -> R.string.room_rsvp_unknown_placeholder RSVPAnswer.UNKNOWN -> R.string.room_rsvp_unknown_placeholder
} }
} }
fun RSVPAnswer.toEmoji(): String {
return when (this) {
RSVPAnswer.SURE -> ""
RSVPAnswer.LATER -> "\uD83D\uDD52"
RSVPAnswer.MAYBE -> ""
RSVPAnswer.NOWAY -> "⛔️"
RSVPAnswer.UNKNOWN -> ""
}
}
fun makeRSVP(request: State<Optional<Event>?>?): Triple<Event, RSVPAnswer, String>? {
val event = request?.value?.getOrNull() ?: return null
val content = event.content ?: return null
val answerAny = content["answer"]
val commentAny = content["comment"]
val answer = if (answerAny is String) {
try {
RSVPAnswer.valueOf(answerAny)
} catch (_: IllegalArgumentException) {
RSVPAnswer.UNKNOWN
}
} else {
RSVPAnswer.UNKNOWN
}
val comment = if (commentAny is String) {
commentAny
} else {
""
}
return Triple(event, answer, comment)
}
@Composable
fun observeRsvpAsLiveState(room: Room, userId: String): Triple<Event, RSVPAnswer, String>? {
val request = room.stateService().getStateEventLive(
eventType = "eu.steffo.twom.rsvp",
stateKey = QueryStringValue.Equals(userId),
).observeAsState()
return makeRSVP(request)
}

View file

@ -15,14 +15,14 @@ import eu.steffo.twom.theme.TwoMPadding
@Preview @Preview
fun RSVPAnswerSelectRow( fun RSVPAnswerSelectRow(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
value: RSVPAnswer? = null, value: RSVPAnswer = RSVPAnswer.UNKNOWN,
onChange: (answer: RSVPAnswer?) -> Unit = {}, onChange: (answer: RSVPAnswer) -> Unit = {},
) { ) {
fun toggleSwitch(representing: RSVPAnswer): () -> Unit { fun toggleSwitch(representing: RSVPAnswer): () -> Unit {
return { return {
onChange( onChange(
when (value) { when (value) {
representing -> null representing -> RSVPAnswer.UNKNOWN
else -> representing else -> representing
} }
) )
@ -35,7 +35,7 @@ fun RSVPAnswerSelectRow(
) { ) {
Row( Row(
modifier = Modifier modifier = Modifier
.padding(start = 10.dp, end = 10.dp) .padding(start = 8.dp, end = 8.dp)
) { ) {
RSVPAnswerFilterChip( RSVPAnswerFilterChip(
modifier = TwoMPadding.chips, modifier = TwoMPadding.chips,

View file

@ -1,6 +1,5 @@
package eu.steffo.twom.room package eu.steffo.twom.room
import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.OutlinedTextFieldDefaults import androidx.compose.material3.OutlinedTextFieldDefaults
@ -16,9 +15,9 @@ fun RSVPCommentField(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
value: String = "", value: String = "",
onChange: (value: String) -> Unit = {}, onChange: (value: String) -> Unit = {},
currentRsvpAnswer: RSVPAnswer? = null, rsvpAnswer: RSVPAnswer = RSVPAnswer.UNKNOWN,
) { ) {
val colorRole = currentRsvpAnswer.toStaticColorRole() val colorRole = rsvpAnswer.toStaticColorRole()
OutlinedTextField( OutlinedTextField(
modifier = modifier, modifier = modifier,
@ -28,24 +27,17 @@ fun RSVPCommentField(
shape = MaterialTheme.shapes.small, shape = MaterialTheme.shapes.small,
placeholder = { placeholder = {
Text( Text(
text = stringResource(currentRsvpAnswer.toPlaceholderResourceId()) text = stringResource(rsvpAnswer.toPlaceholderResourceId())
)
},
colors = if (currentRsvpAnswer != null) {
OutlinedTextFieldDefaults.colors(
focusedContainerColor = colorRole.valueContainer,
unfocusedContainerColor = colorRole.valueContainer,
focusedTextColor = colorRole.onValueContainer,
unfocusedTextColor = colorRole.onValueContainer,
focusedBorderColor = colorRole.onValueContainer,
unfocusedBorderColor = colorRole.onValueContainer.copy(alpha = 0.3f),
cursorColor = colorRole.onValueContainer,
)
} else {
OutlinedTextFieldDefaults.colors(
focusedBorderColor = LocalContentColor.current,
unfocusedBorderColor = MaterialTheme.colorScheme.surfaceVariant,
) )
}, },
colors = OutlinedTextFieldDefaults.colors(
focusedContainerColor = colorRole.valueContainer,
unfocusedContainerColor = colorRole.valueContainer,
focusedTextColor = colorRole.onValueContainer,
unfocusedTextColor = colorRole.onValueContainer,
focusedBorderColor = colorRole.onValueContainer,
unfocusedBorderColor = colorRole.onValueContainer.copy(alpha = 0.3f),
cursorColor = colorRole.onValueContainer,
)
) )
} }

View file

@ -16,9 +16,9 @@ fun RSVPUpdateButton(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
enabled: Boolean = true, enabled: Boolean = true,
onClick: () -> Unit = {}, onClick: () -> Unit = {},
currentRsvpAnswer: RSVPAnswer? = null, rsvpAnswer: RSVPAnswer = RSVPAnswer.UNKNOWN,
) { ) {
val colorRole = currentRsvpAnswer.toStaticColorRole() val colorRole = rsvpAnswer.toStaticColorRole()
Button( Button(
modifier = modifier, modifier = modifier,

View file

@ -14,9 +14,10 @@ import androidx.compose.ui.unit.dp
@Composable @Composable
@Preview @Preview
fun RoomActivityAnswerForm( fun RoomActivityAnswerForm(
currentRsvpAnswer: RSVPAnswer? = null, currentRsvpAnswer: RSVPAnswer = RSVPAnswer.UNKNOWN,
currentRsvpComment: String = "", currentRsvpComment: String = "",
onUpdate: (rsvpAnswer: RSVPAnswer?, rsvpComment: String) -> Unit = { _, _ -> }, onUpdate: (rsvpAnswer: RSVPAnswer, rsvpComment: String) -> Unit = { _, _ -> },
isUpdating: Boolean = false,
) { ) {
var rsvpAnswer by rememberSaveable { mutableStateOf(currentRsvpAnswer) } var rsvpAnswer by rememberSaveable { mutableStateOf(currentRsvpAnswer) }
var rsvpComment by rememberSaveable { mutableStateOf(currentRsvpComment) } var rsvpComment by rememberSaveable { mutableStateOf(currentRsvpComment) }
@ -33,14 +34,14 @@ fun RoomActivityAnswerForm(
.fillMaxWidth(), .fillMaxWidth(),
value = rsvpComment, value = rsvpComment,
onChange = { rsvpComment = it }, onChange = { rsvpComment = it },
currentRsvpAnswer = rsvpAnswer, rsvpAnswer = rsvpAnswer,
) )
RSVPUpdateButton( RSVPUpdateButton(
modifier = Modifier modifier = Modifier
.padding(start = 10.dp, end = 10.dp, top = 4.dp, bottom = 4.dp) .padding(start = 10.dp, end = 10.dp, top = 4.dp, bottom = 4.dp)
.fillMaxWidth(), .fillMaxWidth(),
onClick = { onUpdate(rsvpAnswer, rsvpComment) }, onClick = { onUpdate(rsvpAnswer, rsvpComment) },
enabled = hasChanged, enabled = hasChanged && !isUpdating,
currentRsvpAnswer = rsvpAnswer, rsvpAnswer = rsvpAnswer,
) )
} }

View file

@ -1,12 +1,17 @@
package eu.steffo.twom.room package eu.steffo.twom.room
import android.util.Log
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.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.livedata.observeAsState import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberCoroutineScope
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.res.stringResource import androidx.compose.ui.res.stringResource
import eu.steffo.twom.R import eu.steffo.twom.R
@ -14,7 +19,7 @@ import eu.steffo.twom.matrix.LocalSession
import eu.steffo.twom.theme.ErrorText import eu.steffo.twom.theme.ErrorText
import eu.steffo.twom.theme.TwoMPadding import eu.steffo.twom.theme.TwoMPadding
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.matrix.android.sdk.api.query.QueryStringValue import org.matrix.android.sdk.api.failure.Failure
import kotlin.jvm.optionals.getOrNull import kotlin.jvm.optionals.getOrNull
@ -25,52 +30,88 @@ fun RoomActivityContent(
val scope = rememberCoroutineScope() val scope = rememberCoroutineScope()
val session = LocalSession.current val session = LocalSession.current
val roomRequest = LocalRoom.current if (session == null) {
val room = roomRequest?.getOrNull() ErrorText(stringResource(R.string.room_error_session_missing))
val roomSummaryRequest = LocalRoomSummary.current return
val roomSummary = roomSummaryRequest?.getOrNull() }
val myRsvp = room?.stateService()?.getStateEventLive( val roomRequest = LocalRoom.current
eventType = "eu.steffo.twom.rsvp", if (roomRequest == null) {
stateKey = QueryStringValue.Equals(session!!.myUserId), ErrorText(stringResource(R.string.room_error_room_missing))
)?.observeAsState() return
// TODO: I stopped here; how to retrieve the RSVP from this? }
val room = roomRequest.getOrNull()
if (room == null) {
ErrorText(stringResource(R.string.room_error_room_notfound))
return
}
val roomSummaryRequest = LocalRoomSummary.current
if (roomSummaryRequest == null) {
ErrorText(stringResource(R.string.room_error_roomsummary_missing))
return
}
val roomSummary = roomSummaryRequest.getOrNull()
if (roomSummary == null) {
ErrorText(stringResource(R.string.room_error_roomsummary_notfound))
return
}
LaunchedEffect(roomSummary.otherMemberIds) ResolveUnknownUsers@{
// Resolve unknown users, one at a time
roomSummary.otherMemberIds.map {
if (session.userService().getUser(it) == null) {
Log.i("Room", "Resolving unknown user: $it")
session.userService().resolveUser(it)
Log.d("Room", "Successfully resolved unknown user: $it")
} else {
Log.v("Room", "Not resolving known user: $it")
}
}
}
val myRsvpRequest = observeRsvpAsLiveState(room = room, userId = session.myUserId)
val otherRsvpRequests =
roomSummary.otherMemberIds.map { it to observeRsvpAsLiveState(room = room, userId = it) }
var isUpdatingMyRsvp by rememberSaveable { mutableStateOf(false) }
var errorMyRsvp by rememberSaveable { mutableStateOf<Failure.ServerError?>(null) }
Column(modifier) { Column(modifier) {
if (session == null) { Row(TwoMPadding.base) {
ErrorText(stringResource(R.string.room_error_session_missing)) Text(
} else if (roomRequest == null) { text = stringResource(R.string.room_topic_title),
ErrorText(stringResource(R.string.room_error_room_missing)) style = MaterialTheme.typography.labelLarge,
} else if (!roomRequest.isPresent) { )
ErrorText(stringResource(R.string.room_error_room_notfound)) }
} else if (roomSummaryRequest == null) { Row(TwoMPadding.base) {
// Loading Text(roomSummary.topic)
} else if (!roomSummaryRequest.hasValue()) { }
ErrorText(stringResource(R.string.room_error_room_notfound))
} else if (roomSummary != null) {
Row(TwoMPadding.base) {
Text(
text = stringResource(R.string.room_topic_title),
style = MaterialTheme.typography.labelLarge,
)
}
Row(TwoMPadding.base) {
Text(roomSummary.topic)
}
Row(TwoMPadding.base) { Row(TwoMPadding.base) {
Text( Text(
text = stringResource(R.string.room_rsvp_title), text = stringResource(R.string.room_rsvp_title),
style = MaterialTheme.typography.labelLarge, style = MaterialTheme.typography.labelLarge,
) )
} }
RoomActivityAnswerForm( RoomActivityAnswerForm(
currentRsvpAnswer = myRsvp, // FIXME: This always set the request to UNKNOWN
currentRsvpComment = myRsvp, currentRsvpAnswer = myRsvpRequest?.second ?: RSVPAnswer.UNKNOWN,
onUpdate = { answer, comment -> currentRsvpComment = myRsvpRequest?.third ?: "",
scope.launch SendStateEvent@{ onUpdate = { answer, comment ->
room!!.stateService().sendStateEvent( isUpdatingMyRsvp = true
errorMyRsvp = null
scope.launch SendRSVP@{
Log.d(
"Room",
"Updating eu.steffo.twom.rsvp with answer `$answer` and comment `$comment`..."
)
try {
room.stateService().sendStateEvent(
eventType = "eu.steffo.twom.rsvp", eventType = "eu.steffo.twom.rsvp",
stateKey = session.myUserId, stateKey = session.myUserId,
body = mapOf( body = mapOf(
@ -80,38 +121,70 @@ fun RoomActivityContent(
) )
), ),
) )
} catch (error: Failure.ServerError) {
Log.e("Room", "Failed to update eu.steffo.twom.rsvp: $error")
errorMyRsvp = error
isUpdatingMyRsvp = false
return@SendRSVP
} }
Log.d(
"Room",
"Updated eu.steffo.twom.rsvp with answer `$answer` and comment `$comment`!"
)
if (myRsvpRequest != null) {
val myRsvpRequestEventId = myRsvpRequest.first.eventId
Log.d(
"Room",
"Attempting to redact old eu.steffo.twom.rsvp event `${myRsvpRequestEventId}`..."
)
try {
room.sendService()
.redactEvent(myRsvpRequest.first, "Replaced with new information")
} catch (error: Failure.ServerError) {
Log.e("Room", "Failed to redact the old eu.steffo.twom.rsvp: $error")
errorMyRsvp = error
isUpdatingMyRsvp = false
return@SendRSVP
}
} else {
Log.d("Room", "Not doing anything else; there isn't anything to redact.")
}
isUpdatingMyRsvp = false
} }
},
isUpdating = isUpdatingMyRsvp,
)
if (errorMyRsvp != null) {
// TODO: Maybe add an human-friendly error message?
Row(TwoMPadding.base) {
ErrorText(
errorMyRsvp.toString()
)
}
}
Row(TwoMPadding.base) {
Text(
text = stringResource(R.string.room_invitees_title),
style = MaterialTheme.typography.labelLarge,
)
}
Column(TwoMPadding.base) {
MemberListItem(
memberId = LocalSession.current!!.myUserId,
rsvpAnswer = myRsvpRequest?.second ?: RSVPAnswer.UNKNOWN,
rsvpComment = myRsvpRequest?.third ?: "",
) )
Row(TwoMPadding.base) { otherRsvpRequests.forEach {
Text(
text = stringResource(R.string.room_invitees_title),
style = MaterialTheme.typography.labelLarge,
)
}
Column(TwoMPadding.base) {
MemberListItem( MemberListItem(
memberId = LocalSession.current!!.myUserId, memberId = it.first,
rsvpAnswer = rsvpAnswer, rsvpAnswer = it.second?.second ?: RSVPAnswer.UNKNOWN,
rsvpComment = rsvpComment, rsvpComment = it.second?.third ?: "",
)
roomSummary.otherMemberIds.forEach {
MemberListItem(
memberId = it,
rsvpAnswer = null,
rsvpComment = "",
)
}
}
} else if (isError) {
Row(TwoMPadding.base) {
Text(
// TODO: Maybe add a better error string
text = stringResource(R.string.error),
color = MaterialTheme.colorScheme.error,
) )
} }
} }

View file

@ -8,7 +8,7 @@ fun colorRoleUnknown(): StaticColorRole {
return StaticColorRole( return StaticColorRole(
value = MaterialTheme.colorScheme.inverseSurface, value = MaterialTheme.colorScheme.inverseSurface,
onValue = MaterialTheme.colorScheme.inverseOnSurface, onValue = MaterialTheme.colorScheme.inverseOnSurface,
valueContainer = MaterialTheme.colorScheme.surfaceVariant, valueContainer = MaterialTheme.colorScheme.surface,
onValueContainer = MaterialTheme.colorScheme.onSurfaceVariant, onValueContainer = MaterialTheme.colorScheme.onSurface,
) )
} }

View file

@ -58,4 +58,7 @@
<string name="room_error_session_missing">The Matrix session context has not been initialized.</string> <string name="room_error_session_missing">The Matrix session context has not been initialized.</string>
<string name="room_error_room_notfound">Could not find the requested Matrix room.</string> <string name="room_error_room_notfound">Could not find the requested Matrix room.</string>
<string name="room_error_room_missing">The Matrix room context has not been initialized.</string> <string name="room_error_room_missing">The Matrix room context has not been initialized.</string>
<string name="room_rsvp_unknown_label">No answer</string>
<string name="room_error_roomsummary_missing">The Matrix room summary context has not been initialized.</string>
<string name="room_error_roomsummary_notfound">Could not find the requested Matrix room summary.</string>
</resources> </resources>