mirror of
https://github.com/Steffo99/twom.git
synced 2024-11-25 01:24:24 +00:00
Add support for sending invites
This commit is contained in:
parent
822a2e5770
commit
23de2ed278
21 changed files with 271 additions and 178 deletions
|
@ -7,7 +7,7 @@ import android.os.Bundle
|
|||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.activity.result.contract.ActivityResultContract
|
||||
import eu.steffo.twom.composables.configureroom.CreateRoomScaffold
|
||||
import eu.steffo.twom.composables.configureroom.ConfigureRoomScaffold
|
||||
|
||||
|
||||
class ConfigureRoomActivity : ComponentActivity() {
|
||||
|
@ -51,6 +51,6 @@ class ConfigureRoomActivity : ComponentActivity() {
|
|||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
setContent { CreateRoomScaffold() }
|
||||
setContent { ConfigureRoomScaffold() }
|
||||
}
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
package eu.steffo.twom.activities
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.activity.result.contract.ActivityResultContract
|
||||
import androidx.compose.material3.Text
|
||||
|
||||
|
||||
class InviteUserActivity : ComponentActivity() {
|
||||
companion object {
|
||||
const val USER_EXTRA = "user"
|
||||
}
|
||||
|
||||
class Contract : ActivityResultContract<Unit, String?>() {
|
||||
override fun createIntent(context: Context, input: Unit): Intent {
|
||||
return Intent(context, ConfigureRoomActivity::class.java)
|
||||
}
|
||||
|
||||
override fun parseResult(resultCode: Int, intent: Intent?): String? {
|
||||
return when (resultCode) {
|
||||
RESULT_OK -> intent!!.getStringExtra(USER_EXTRA)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
setContent { Text("Garasauto Prime") }
|
||||
}
|
||||
}
|
|
@ -17,16 +17,17 @@ import androidx.compose.ui.tooling.preview.Preview
|
|||
fun AvatarEmpty(
|
||||
modifier: Modifier = Modifier,
|
||||
text: String? = null,
|
||||
alpha: Float = 1.0f,
|
||||
) {
|
||||
Box(
|
||||
modifier = modifier
|
||||
.fillMaxSize()
|
||||
.background(MaterialTheme.colorScheme.tertiary),
|
||||
.background(MaterialTheme.colorScheme.tertiary.copy(alpha = alpha)),
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.align(Alignment.Center),
|
||||
color = MaterialTheme.colorScheme.onTertiary,
|
||||
color = MaterialTheme.colorScheme.onTertiary.copy(alpha = alpha),
|
||||
text = text ?: "?",
|
||||
)
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ fun AvatarImage(
|
|||
bitmap: ImageBitmap? = null,
|
||||
fallbackText: String? = null,
|
||||
contentDescription: String = "",
|
||||
alpha: Float = 1.0f,
|
||||
) {
|
||||
if (bitmap == null) {
|
||||
AvatarEmpty(
|
||||
|
@ -25,6 +26,7 @@ fun AvatarImage(
|
|||
this.contentDescription = contentDescription
|
||||
},
|
||||
text = fallbackText,
|
||||
alpha = alpha,
|
||||
)
|
||||
} else {
|
||||
Image(
|
||||
|
@ -33,6 +35,7 @@ fun AvatarImage(
|
|||
contentDescription = contentDescription,
|
||||
contentScale = ContentScale.Crop,
|
||||
alignment = Alignment.Center,
|
||||
alpha = alpha,
|
||||
)
|
||||
}
|
||||
}
|
|
@ -23,6 +23,7 @@ fun AvatarPicker(
|
|||
modifier: Modifier = Modifier,
|
||||
fallbackText: String = "?",
|
||||
onPick: (bitmap: Bitmap) -> Unit = {},
|
||||
alpha: Float = 1.0f,
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
val resolver = context.contentResolver
|
||||
|
@ -51,6 +52,7 @@ fun AvatarPicker(
|
|||
AvatarImage(
|
||||
bitmap = selection?.asImageBitmap(),
|
||||
fallbackText = fallbackText,
|
||||
alpha = alpha,
|
||||
)
|
||||
}
|
||||
}
|
|
@ -22,6 +22,7 @@ fun AvatarURL(
|
|||
url: String? = "",
|
||||
fallbackText: String? = null,
|
||||
contentDescription: String = "",
|
||||
alpha: Float = 1.0f,
|
||||
) {
|
||||
val session = LocalSession.current
|
||||
var bitmap by remember { mutableStateOf<Bitmap?>(null) }
|
||||
|
@ -67,5 +68,6 @@ fun AvatarURL(
|
|||
bitmap = bitmap?.asImageBitmap(),
|
||||
fallbackText = fallbackText,
|
||||
contentDescription = contentDescription,
|
||||
alpha = alpha,
|
||||
)
|
||||
}
|
|
@ -13,11 +13,13 @@ fun AvatarUser(
|
|||
user: User? = null,
|
||||
fallbackText: String? = null,
|
||||
contentDescription: String = "",
|
||||
alpha: Float = 1.0f,
|
||||
) {
|
||||
AvatarURL(
|
||||
modifier = modifier,
|
||||
url = user?.avatarUrl,
|
||||
fallbackText = user?.toMatrixItem()?.firstLetterOfDisplayName(),
|
||||
contentDescription = contentDescription,
|
||||
alpha = alpha,
|
||||
)
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ fun AvatarUserId(
|
|||
userId: String = "",
|
||||
fallbackText: String = "?",
|
||||
contentDescription: String = "",
|
||||
alpha: Float = 1.0f,
|
||||
) {
|
||||
val session = LocalSession.current
|
||||
var avatarUrl by rememberSaveable { mutableStateOf<String?>(null) }
|
||||
|
@ -43,5 +44,6 @@ fun AvatarUserId(
|
|||
url = avatarUrl,
|
||||
fallbackText = fallbackText,
|
||||
contentDescription = contentDescription,
|
||||
alpha = alpha,
|
||||
)
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ import eu.steffo.twom.utils.BitmapUtilities
|
|||
@Preview(showBackground = true)
|
||||
fun ConfigureRoomForm(
|
||||
modifier: Modifier = Modifier,
|
||||
onSubmit: (name: String, description: String, avatarUri: Uri?) -> Unit = { _, _, _ -> },
|
||||
onSubmit: (name: String, description: String, avatarUri: String?) -> Unit = { _, _, _ -> },
|
||||
) {
|
||||
var name by rememberSaveable { mutableStateOf("") }
|
||||
var description by rememberSaveable { mutableStateOf("") }
|
||||
|
@ -85,7 +85,7 @@ fun ConfigureRoomForm(
|
|||
modifier = Modifier
|
||||
.fillMaxWidth(),
|
||||
onClick = {
|
||||
onSubmit(name, description, avatarUri)
|
||||
onSubmit(name, description, avatarUri.toString())
|
||||
},
|
||||
) {
|
||||
Text(stringResource(R.string.create_complete_text))
|
||||
|
|
|
@ -2,7 +2,6 @@ package eu.steffo.twom.composables.configureroom
|
|||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.Scaffold
|
||||
|
@ -15,11 +14,11 @@ import eu.steffo.twom.composables.theme.TwoMTheme
|
|||
|
||||
@Composable
|
||||
@Preview
|
||||
fun CreateRoomScaffold() {
|
||||
fun ConfigureRoomScaffold() {
|
||||
val context = LocalContext.current
|
||||
val activity = context as Activity
|
||||
|
||||
fun submitActivity(name: String, description: String, avatarUri: Uri?) {
|
||||
fun submitActivity(name: String, description: String, avatarUri: String?) {
|
||||
val resultIntent = Intent()
|
||||
resultIntent.putExtra(ConfigureRoomActivity.NAME_EXTRA, name)
|
||||
resultIntent.putExtra(ConfigureRoomActivity.DESCRIPTION_EXTRA, description)
|
||||
|
@ -34,12 +33,12 @@ fun CreateRoomScaffold() {
|
|||
TwoMTheme {
|
||||
Scaffold(
|
||||
topBar = {
|
||||
CreateActivityTopBar()
|
||||
ConfigureActivityTopBar()
|
||||
},
|
||||
content = {
|
||||
ConfigureRoomForm(
|
||||
modifier = Modifier.padding(it),
|
||||
onSubmit = { name: String, description: String, avatarUri: Uri? ->
|
||||
onSubmit = { name: String, description: String, avatarUri: String? ->
|
||||
submitActivity(name, description, avatarUri)
|
||||
}
|
||||
)
|
||||
|
|
|
@ -13,7 +13,7 @@ import eu.steffo.twom.composables.navigation.BackIconButton
|
|||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
@Preview
|
||||
fun CreateActivityTopBar(
|
||||
fun ConfigureActivityTopBar(
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
TopAppBar(
|
||||
|
|
|
@ -1,47 +0,0 @@
|
|||
package eu.steffo.twom.composables.inviteuser
|
||||
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import eu.steffo.twom.R
|
||||
import eu.steffo.twom.composables.theme.basePadding
|
||||
|
||||
@Composable
|
||||
fun InviteUserContent() {
|
||||
Row(Modifier.basePadding()) {
|
||||
Text(
|
||||
text = stringResource(R.string.room_invite_title),
|
||||
style = MaterialTheme.typography.labelLarge,
|
||||
)
|
||||
}
|
||||
|
||||
Row(Modifier.basePadding()) {
|
||||
InviteUserForm(
|
||||
/*
|
||||
onConfirm = {
|
||||
scope.launch SendInvite@{
|
||||
isSendingInvite = true
|
||||
errorInvite = null
|
||||
|
||||
Log.d("Room", "Sending invite to `$it`...")
|
||||
|
||||
try {
|
||||
room.membershipService().invite(it)
|
||||
} catch (error: Throwable) {
|
||||
Log.e("Room", "Failed to send invite to `$it`: $error")
|
||||
errorInvite = error
|
||||
isSendingInvite = false
|
||||
return@SendInvite
|
||||
}
|
||||
|
||||
Log.d("Room", "Successfully sent invite to `$it`!")
|
||||
isSendingInvite = false
|
||||
}
|
||||
}
|
||||
*/
|
||||
)
|
||||
}
|
||||
}
|
|
@ -1,54 +0,0 @@
|
|||
package eu.steffo.twom.composables.inviteuser
|
||||
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.Text
|
||||
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.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import eu.steffo.twom.R
|
||||
|
||||
@Composable
|
||||
@Preview
|
||||
fun InviteUserForm(
|
||||
onConfirm: (userId: String) -> Unit = {},
|
||||
) {
|
||||
var value by rememberSaveable { mutableStateOf("") }
|
||||
|
||||
OutlinedTextField(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth(),
|
||||
value = value,
|
||||
onValueChange = { value = it },
|
||||
singleLine = true,
|
||||
shape = MaterialTheme.shapes.small,
|
||||
placeholder = {
|
||||
Text(
|
||||
text = stringResource(R.string.room_invite_username_placeholder)
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
Button(
|
||||
modifier = Modifier
|
||||
.padding(top = 4.dp)
|
||||
.fillMaxWidth(),
|
||||
onClick = { onConfirm(value) },
|
||||
shape = MaterialTheme.shapes.small,
|
||||
// FIXME: Maybe I should validate usernames with a regex
|
||||
enabled = (value.contains("@") && value.contains(":")),
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(R.string.room_invite_button_label)
|
||||
)
|
||||
}
|
||||
}
|
|
@ -1,9 +1,7 @@
|
|||
package eu.steffo.twom.composables.viewroom
|
||||
|
||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||
import androidx.activity.result.launch
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Add
|
||||
import androidx.compose.material.icons.filled.Email
|
||||
import androidx.compose.material3.ExtendedFloatingActionButton
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Text
|
||||
|
@ -12,27 +10,20 @@ 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.activities.InviteUserActivity
|
||||
|
||||
@Composable
|
||||
@Preview
|
||||
fun InviteFAB(
|
||||
modifier: Modifier = Modifier,
|
||||
onClick: () -> Unit = {},
|
||||
onUserSelected: (userId: String) -> Unit = {},
|
||||
) {
|
||||
val launcher =
|
||||
rememberLauncherForActivityResult(InviteUserActivity.Contract()) {
|
||||
if (it != null) {
|
||||
onUserSelected(it)
|
||||
}
|
||||
}
|
||||
|
||||
ExtendedFloatingActionButton(
|
||||
modifier = modifier,
|
||||
onClick = { launcher.launch() },
|
||||
onClick = { onClick() },
|
||||
icon = {
|
||||
Icon(
|
||||
Icons.Filled.Add,
|
||||
Icons.Filled.Email,
|
||||
contentDescription = null
|
||||
)
|
||||
},
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
package eu.steffo.twom.composables.viewroom
|
||||
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.ModalBottomSheet
|
||||
import androidx.compose.material3.SheetState
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import eu.steffo.twom.R
|
||||
import eu.steffo.twom.composables.theme.basePadding
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun InviteSheet(
|
||||
sheetState: SheetState,
|
||||
modifier: Modifier = Modifier,
|
||||
onDismissed: () -> Unit = {},
|
||||
onCompleted: () -> Unit = {},
|
||||
) {
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
ModalBottomSheet(
|
||||
modifier = modifier,
|
||||
sheetState = sheetState,
|
||||
onDismissRequest = {
|
||||
// Not super sure what this is for
|
||||
// https://developer.android.com/jetpack/compose/components/bottom-sheets
|
||||
scope.launch {
|
||||
sheetState.hide()
|
||||
}.invokeOnCompletion {
|
||||
if (!sheetState.isVisible) {
|
||||
onDismissed()
|
||||
}
|
||||
}
|
||||
},
|
||||
) {
|
||||
// Hack required as it seems that ModalBottomSheet does not take in account screen insets yet
|
||||
Column(Modifier.padding(bottom = 80.dp)) {
|
||||
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.basePadding()
|
||||
.fillMaxWidth(),
|
||||
text = stringResource(R.string.room_invite_title),
|
||||
style = MaterialTheme.typography.headlineSmall,
|
||||
textAlign = TextAlign.Center,
|
||||
)
|
||||
|
||||
InviteUserForm(
|
||||
onDone = {
|
||||
scope.launch {
|
||||
sheetState.hide()
|
||||
}.invokeOnCompletion {
|
||||
if (!sheetState.isVisible) {
|
||||
onCompleted()
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,114 @@
|
|||
package eu.steffo.twom.composables.viewroom
|
||||
|
||||
import android.util.Log
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextField
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
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.res.stringResource
|
||||
import eu.steffo.twom.R
|
||||
import eu.steffo.twom.composables.errorhandling.ErrorText
|
||||
import eu.steffo.twom.composables.errorhandling.LoadingText
|
||||
import eu.steffo.twom.composables.errorhandling.LocalizableError
|
||||
import eu.steffo.twom.composables.theme.basePadding
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlin.jvm.optionals.getOrNull
|
||||
|
||||
@Composable
|
||||
fun InviteUserForm(
|
||||
onDone: () -> Unit = {},
|
||||
) {
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
var userId by rememberSaveable { mutableStateOf("") }
|
||||
|
||||
val roomRequest = LocalRoom.current
|
||||
if (roomRequest == null) {
|
||||
LoadingText(
|
||||
modifier = Modifier.basePadding(),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
val room = roomRequest.getOrNull()
|
||||
if (room == null) {
|
||||
ErrorText(
|
||||
modifier = Modifier.basePadding(),
|
||||
text = stringResource(R.string.room_error_room_notfound)
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
TextField(
|
||||
modifier = Modifier
|
||||
.basePadding()
|
||||
.fillMaxWidth(),
|
||||
value = userId,
|
||||
onValueChange = { userId = it },
|
||||
singleLine = true,
|
||||
label = {
|
||||
Text(
|
||||
text = stringResource(R.string.room_invite_username_label)
|
||||
)
|
||||
},
|
||||
placeholder = {
|
||||
Text(
|
||||
text = stringResource(R.string.room_invite_username_placeholder)
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
var busy by rememberSaveable { mutableStateOf(false) }
|
||||
val error by remember { mutableStateOf(LocalizableError()) }
|
||||
|
||||
Button(
|
||||
modifier = Modifier
|
||||
.basePadding()
|
||||
.fillMaxWidth(),
|
||||
// FIXME: Maybe I should validate usernames with a regex
|
||||
enabled = (!busy && userId.contains("@") && userId.contains(":")),
|
||||
onClick = {
|
||||
scope.launch SendInvite@{
|
||||
busy = true
|
||||
error.clear()
|
||||
|
||||
Log.d("Room", "Sending invite to `$userId`...")
|
||||
|
||||
try {
|
||||
room.membershipService().invite(userId)
|
||||
} catch (e: Throwable) {
|
||||
Log.e("Room", "Failed to send invite to `$userId`: $error")
|
||||
error.set(R.string.room_error_invite_generic, e)
|
||||
busy = false
|
||||
return@SendInvite
|
||||
}
|
||||
|
||||
Log.d("Room", "Successfully sent invite to `$userId`!")
|
||||
onDone()
|
||||
|
||||
busy = false
|
||||
}
|
||||
},
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(R.string.room_invite_button_label)
|
||||
)
|
||||
}
|
||||
|
||||
error.Show {
|
||||
ErrorText(
|
||||
modifier = Modifier
|
||||
.basePadding()
|
||||
.fillMaxWidth(),
|
||||
text = it,
|
||||
)
|
||||
}
|
||||
}
|
|
@ -27,6 +27,7 @@ import eu.steffo.twom.R
|
|||
import eu.steffo.twom.composables.avatar.AvatarUser
|
||||
import eu.steffo.twom.composables.errorhandling.ErrorText
|
||||
import eu.steffo.twom.composables.matrix.LocalSession
|
||||
import eu.steffo.twom.utils.RSVPAnswer
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomMemberSummary
|
||||
import org.matrix.android.sdk.api.session.user.model.User
|
||||
import kotlin.jvm.optionals.getOrNull
|
||||
|
@ -72,18 +73,24 @@ fun MemberListItem(
|
|||
Log.d("UserListItem", "Resolved user: $memberId")
|
||||
}
|
||||
|
||||
val rsvp = observeRSVP(room = room, member = member)
|
||||
val rsvp = observeRSVP(room = room, member = member) ?: return
|
||||
|
||||
var expanded by rememberSaveable { mutableStateOf(false) }
|
||||
|
||||
val alpha = if (rsvp.answer == RSVPAnswer.PENDING) 0.4f else 1.0f
|
||||
val color = rsvp.answer.staticColorRole.color().copy(alpha)
|
||||
|
||||
ListItem(
|
||||
modifier = modifier.combinedClickable(
|
||||
modifier = modifier
|
||||
.combinedClickable(
|
||||
onClick = {},
|
||||
onLongClick = { expanded = true },
|
||||
),
|
||||
headlineContent = {
|
||||
Text(
|
||||
text = user?.displayName ?: stringResource(R.string.user_unresolved_name),
|
||||
color = color,
|
||||
style = MaterialTheme.typography.titleMedium,
|
||||
)
|
||||
},
|
||||
leadingContent = {
|
||||
|
@ -95,6 +102,7 @@ fun MemberListItem(
|
|||
) {
|
||||
AvatarUser(
|
||||
user = user,
|
||||
alpha = alpha,
|
||||
)
|
||||
}
|
||||
},
|
||||
|
@ -102,14 +110,14 @@ fun MemberListItem(
|
|||
Icon(
|
||||
imageVector = rsvp.answer.icon,
|
||||
contentDescription = rsvp.answer.toResponse(),
|
||||
tint = rsvp.answer.staticColorRole.color(),
|
||||
tint = color,
|
||||
)
|
||||
},
|
||||
supportingContent = {
|
||||
if (rsvp.comment != "") {
|
||||
Text(
|
||||
text = rsvp.comment,
|
||||
color = rsvp.answer.staticColorRole.color(),
|
||||
color = color,
|
||||
)
|
||||
}
|
||||
},
|
||||
|
@ -119,11 +127,13 @@ fun MemberListItem(
|
|||
expanded = expanded,
|
||||
onDismissRequest = { expanded = false }
|
||||
) {
|
||||
if (member.userId != session.myUserId) {
|
||||
DropdownMenuItem(
|
||||
text = {
|
||||
Text(stringResource(R.string.room_uninvite_label))
|
||||
},
|
||||
onClick = { expanded = false }
|
||||
onClick = { expanded = false },
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ import eu.steffo.twom.composables.errorhandling.LocalizableError
|
|||
import eu.steffo.twom.composables.matrix.LocalSession
|
||||
import eu.steffo.twom.composables.theme.basePadding
|
||||
import kotlinx.coroutines.launch
|
||||
import org.matrix.android.sdk.api.session.room.model.Membership
|
||||
import kotlin.jvm.optionals.getOrNull
|
||||
|
||||
@Composable
|
||||
|
@ -62,7 +63,7 @@ fun ViewRoomForm() {
|
|||
}
|
||||
|
||||
val member = room.membershipService().getRoomMember(session.myUserId)
|
||||
if (member == null) {
|
||||
if (member == null || member.membership != Membership.JOIN) {
|
||||
Row(Modifier.basePadding()) {
|
||||
ErrorText(
|
||||
text = stringResource(R.string.room_error_self_notfound)
|
||||
|
@ -71,7 +72,8 @@ fun ViewRoomForm() {
|
|||
return
|
||||
}
|
||||
|
||||
val published = observeRSVP(room = room, member = member)
|
||||
// JOIN status is checked above
|
||||
val published = observeRSVP(room = room, member = member)!!
|
||||
|
||||
var isPublishRunning by rememberSaveable { mutableStateOf(false) }
|
||||
val publishError by remember { mutableStateOf(LocalizableError()) }
|
||||
|
|
|
@ -1,17 +1,25 @@
|
|||
package eu.steffo.twom.composables.viewroom
|
||||
|
||||
import androidx.compose.foundation.layout.ExperimentalLayoutApi
|
||||
import androidx.compose.foundation.layout.consumeWindowInsets
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.rememberModalBottomSheetState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.livedata.observeAsState
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import eu.steffo.twom.composables.matrix.LocalSession
|
||||
import eu.steffo.twom.composables.theme.TwoMTheme
|
||||
import org.matrix.android.sdk.api.session.Session
|
||||
import java.util.Optional
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class, ExperimentalLayoutApi::class)
|
||||
@Composable
|
||||
fun ViewRoomScaffold(
|
||||
session: Session,
|
||||
|
@ -20,6 +28,9 @@ fun ViewRoomScaffold(
|
|||
val room = Optional.ofNullable(session.roomService().getRoom(roomId))
|
||||
val roomSummary by session.roomService().getRoomSummaryLive(roomId).observeAsState()
|
||||
|
||||
val inviteDialogState = rememberModalBottomSheetState()
|
||||
var inviteDialogExpanded by rememberSaveable { mutableStateOf(false) }
|
||||
|
||||
TwoMTheme {
|
||||
CompositionLocalProvider(LocalSession provides session) {
|
||||
CompositionLocalProvider(LocalRoom provides room) {
|
||||
|
@ -32,7 +43,19 @@ fun ViewRoomScaffold(
|
|||
ViewRoomContent(
|
||||
modifier = Modifier.padding(it),
|
||||
)
|
||||
if (inviteDialogExpanded) {
|
||||
InviteSheet(
|
||||
// FIXME: Does this work?
|
||||
modifier = Modifier.consumeWindowInsets(it),
|
||||
sheetState = inviteDialogState,
|
||||
onDismissed = { inviteDialogExpanded = false },
|
||||
onCompleted = { inviteDialogExpanded = false },
|
||||
)
|
||||
}
|
||||
},
|
||||
floatingActionButton = {
|
||||
InviteFAB(onClick = { inviteDialogExpanded = true })
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ import org.matrix.android.sdk.api.session.room.model.Membership
|
|||
import org.matrix.android.sdk.api.session.room.model.RoomMemberSummary
|
||||
|
||||
@Composable
|
||||
fun observeRSVP(room: Room, member: RoomMemberSummary): RSVP {
|
||||
fun observeRSVP(room: Room, member: RoomMemberSummary): RSVP? {
|
||||
if (member.membership == Membership.INVITE) {
|
||||
return RSVP(
|
||||
event = null,
|
||||
|
@ -21,6 +21,11 @@ fun observeRSVP(room: Room, member: RoomMemberSummary): RSVP {
|
|||
)
|
||||
}
|
||||
|
||||
// TODO: Add a DECLINED variant?
|
||||
if (member.membership == Membership.LEAVE || member.membership == Membership.BAN) {
|
||||
return null
|
||||
}
|
||||
|
||||
val request by room.stateService().getStateEventLive(
|
||||
eventType = TwoMGlobals.RSVP_STATE_TYPE,
|
||||
stateKey = QueryStringValue.Equals(member.userId),
|
||||
|
|
|
@ -59,7 +59,7 @@
|
|||
<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>
|
||||
<string name="room_invite_username_placeholder">\@steffotwo:candy.steffo.eu</string>
|
||||
<string name="room_invite_username_label">Username</string>
|
||||
<string name="room_invite_username_label">User you want to invite</string>
|
||||
<string name="room_rsvp_comment_label">Reason</string>
|
||||
<string name="room_invite_button_label">Invite</string>
|
||||
<string name="room_invite_title">Send an invite</string>
|
||||
|
@ -83,4 +83,5 @@
|
|||
<string name="room_error_publish_generic">Something went wrong while updating your RSVP: %1$s</string>
|
||||
<string name="room_error_redact_generic">Your response has been updated, but something went wrong while attempting to remove your previous one: %1$s</string>
|
||||
<string name="room_error_self_notfound">You have been removed from the room.</string>
|
||||
<string name="room_error_invite_generic">Something went wrong while sending the invite: %1$s</string>
|
||||
</resources>
|
Loading…
Reference in a new issue