Add Android PM and member invitation buttons with group picker
This commit is contained in:
1 parent
e5a87bd043
commit
d13663eb23
4 files changed
+91
-2
No files matched your search
@@ -201,6 +201,14 @@ class MainActivity : AppCompatActivity() {
|
||||
var screenBeforeCall by rememberSaveable { mutableStateOf<Screen?>(null) }
|
||||
val snackbarHostState = remember { SnackbarHostState() }
|
||||
val scope = rememberCoroutineScope()
|
||||
val pmInvite by vm.pmInvite.collectAsState()
|
||||
val linkJoin by vm.linkJoin.collectAsState()
|
||||
val joinedChannel by vm.joinedChannel.collectAsState()
|
||||
LaunchedEffect(joinedChannel) {
|
||||
joinedChannel?.let { channel ->
|
||||
vm.consumeJoinedChannel(); vm.selectChannel(channel); screen = Screen.Chat
|
||||
}
|
||||
}
|
||||
|
||||
val callState by vm.callState.collectAsState()
|
||||
|
||||
@@ -440,6 +448,34 @@ class MainActivity : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
pmInvite?.let { state ->
|
||||
PmInviteDialog(state, vm::selectPmInviteGroup, vm::sendPmInvite, vm::dismissPmInvite)
|
||||
}
|
||||
linkJoin?.let { state ->
|
||||
AlertDialog(
|
||||
onDismissRequest = vm::dismissLinkJoin,
|
||||
title = { Text(stringResource(R.string.join_channel)) },
|
||||
text = {
|
||||
Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||
Text(stringResource(R.string.invite_lifetime))
|
||||
if (state.pending) {
|
||||
LinearProgressIndicator(Modifier.fillMaxWidth())
|
||||
Text(stringResource(R.string.connecting_peer))
|
||||
} else {
|
||||
Text(if (state.channelId == 0L) stringResource(R.string.invalid_invite_link)
|
||||
else stringResource(R.string.invite_join_failed, state.result ?: -1),
|
||||
color = MaterialTheme.colorScheme.error)
|
||||
}
|
||||
}
|
||||
},
|
||||
confirmButton = {
|
||||
if (!state.pending && state.channelId != 0L) TextButton(onClick = { vm.openInviteLink(state.link) }) {
|
||||
Text(stringResource(R.string.retry))
|
||||
}
|
||||
},
|
||||
dismissButton = { TextButton(onClick = vm::dismissLinkJoin) { Text(stringResource(R.string.close)) } }
|
||||
)
|
||||
}
|
||||
if (showJoinDialog) {
|
||||
JoinChannelDialog(
|
||||
onConnect = { data: InviteData ->
|
||||
|
||||
@@ -9,6 +9,7 @@ import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Call
|
||||
import androidx.compose.material.icons.filled.Add
|
||||
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.*
|
||||
@@ -70,6 +71,9 @@ fun DmChatScreen(conv: DmConversation, messages: List<Message>, viewModel: ChatV
|
||||
}, navigationIcon = {
|
||||
IconButton(onClick = onBack) { Icon(Icons.AutoMirrored.Filled.ArrowBack, stringResource(R.string.back)) }
|
||||
}, actions = {
|
||||
IconButton(onClick = { viewModel.showPmInvite(conv.peerNodeId, conv.displayName) }) {
|
||||
Icon(Icons.Filled.Add, stringResource(R.string.invite_to_group))
|
||||
}
|
||||
IconButton(onClick = { viewModel.startDmCall() }, enabled = callAvailable && callState?.ongoing != true) {
|
||||
Icon(Icons.Filled.Call, stringResource(if (callAvailable) R.string.call else R.string.peer_unavailable))
|
||||
}
|
||||
|
||||
+5
-2
@@ -92,7 +92,8 @@ fun MemberListScreen(
|
||||
isSelected = selectedMember?.nodeId == m.nodeId,
|
||||
onClick = { viewModel.showMemberDetail(channel.id, m.nodeId) },
|
||||
onCall = { viewModel.startCall(channel.id, m.nodeId, m.name) },
|
||||
onMessage = { viewModel.startDm(channel.id, m.nodeId, m.name) }
|
||||
onMessage = { viewModel.startDm(channel.id, m.nodeId, m.name) },
|
||||
onInvite = { viewModel.showPmInvite(m.nodeId, m.name, channel.id) }
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -152,7 +153,8 @@ private fun MemberListItem(
|
||||
isSelected: Boolean = false,
|
||||
onClick: () -> Unit,
|
||||
onCall: () -> Unit,
|
||||
onMessage: () -> Unit
|
||||
onMessage: () -> Unit,
|
||||
onInvite: () -> Unit
|
||||
) {
|
||||
val onlineColor = when {
|
||||
member.connecting -> Color(0xFFFFEB3B) // yellow: connecting
|
||||
@@ -232,6 +234,7 @@ private fun MemberListItem(
|
||||
}
|
||||
|
||||
if (!member.isSelf) {
|
||||
IconButton(onClick = onInvite) { Icon(Icons.Filled.Add, stringResource(R.string.invite_to_group)) }
|
||||
IconButton(onClick = onCall, enabled = member.online) { Icon(Icons.Filled.Call, stringResource(R.string.call)) }
|
||||
IconButton(onClick = onMessage) { Icon(Icons.AutoMirrored.Filled.Message, stringResource(R.string.message)) }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.utun.chat.ui.screens
|
||||
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.utun.chat.R
|
||||
import com.utun.chat.viewmodel.ChatViewModel
|
||||
|
||||
/** Один диалог для строки участника и шапки PM; адресат и выбор переживают пересоздание Activity. */
|
||||
@Composable
|
||||
fun PmInviteDialog(state: ChatViewModel.PmInviteState, onChoose: (String) -> Unit, onSend: () -> Unit, onDismiss: () -> Unit) {
|
||||
AlertDialog(
|
||||
onDismissRequest = onDismiss,
|
||||
title = { Text(stringResource(R.string.invite_to_group)) },
|
||||
text = {
|
||||
Column(Modifier.verticalScroll(rememberScrollState()), verticalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||
Text(stringResource(R.string.invite_recipient, state.name))
|
||||
Text(stringResource(R.string.invite_lifetime), style = MaterialTheme.typography.bodySmall)
|
||||
Text(stringResource(if (state.groups.isEmpty()) R.string.invite_no_groups else R.string.invite_choose_group))
|
||||
state.groups.forEach { group ->
|
||||
Row(Modifier.fillMaxWidth().clickable(enabled = !state.pending) { onChoose(group.id) },
|
||||
verticalAlignment = Alignment.CenterVertically) {
|
||||
RadioButton(selected = state.groupId == group.id, onClick = { onChoose(group.id) }, enabled = !state.pending)
|
||||
Text(group.name, modifier = Modifier.weight(1f))
|
||||
}
|
||||
}
|
||||
if (state.pending) {
|
||||
LinearProgressIndicator(Modifier.fillMaxWidth())
|
||||
Text(stringResource(R.string.invite_sending))
|
||||
}
|
||||
if (state.errorRes != 0) Text(stringResource(state.errorRes), color = MaterialTheme.colorScheme.error)
|
||||
}
|
||||
},
|
||||
confirmButton = {
|
||||
TextButton(onClick = onSend, enabled = !state.pending && state.groupId.isNotEmpty()) { Text(stringResource(R.string.invite)) }
|
||||
},
|
||||
dismissButton = { TextButton(onClick = onDismiss) { Text(stringResource(R.string.cancel)) } }
|
||||
)
|
||||
}
|
||||
Reference in new issue
Block a user