Open channel radio from Android calls and move invitation into user details
This commit is contained in:
1 parent
62a976aef5
commit
25376197db
2 files changed
+29
-9
No files matched your search
@@ -18,6 +18,8 @@ import android.view.MotionEvent
|
||||
import android.view.WindowManager
|
||||
import com.utun.chat.data.CallController
|
||||
import com.utun.chat.data.CallPhase
|
||||
import com.utun.chat.data.RadioCallController
|
||||
import com.utun.chat.data.RadioCallPhase
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.activity.SystemBarStyle
|
||||
import androidx.activity.compose.BackHandler
|
||||
@@ -145,6 +147,7 @@ class MainActivity : AppCompatActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
RadioCallController.notificationIntent(intent)
|
||||
readFilesIntent(intent)
|
||||
lifecycleScope.launch {
|
||||
ChatApplication.instance.configProvider.radioVolumePttEnabled.collect { enabled ->
|
||||
@@ -206,6 +209,15 @@ class MainActivity : AppCompatActivity() {
|
||||
var screen by rememberSaveable { mutableStateOf(Screen.ChannelList) }
|
||||
var filesReturnScreen by rememberSaveable { mutableStateOf(Screen.Chat) }
|
||||
val fileChannels by vm.channels.collectAsState()
|
||||
val radioCall by RadioCallController.state.collectAsState()
|
||||
val radioActivation by RadioCallController.activation.collectAsState()
|
||||
LaunchedEffect(radioActivation, fileChannels) {
|
||||
val activation = radioActivation ?: return@LaunchedEffect
|
||||
if (fileChannels.none { it.id == activation.channelId }) return@LaunchedEffect
|
||||
screen = Screen.Chat
|
||||
vm.enableRadioForCall(activation.channelId) { success -> RadioCallController.activated(activation.id, success) }
|
||||
}
|
||||
BackHandler(radioCall != null && radioCall?.phase != RadioCallPhase.ENDED) { RadioCallController.end() }
|
||||
LaunchedEffect(requestedFiles, fileChannels) {
|
||||
requestedFiles?.let { target ->
|
||||
val channel = fileChannels.find { it.id == target.group.toULong().toString() }
|
||||
@@ -259,11 +271,11 @@ class MainActivity : AppCompatActivity() {
|
||||
|
||||
/* После звонка снимаем showWhenLocked входящего. Экран может гаснуть:
|
||||
аудио и CPU удерживает CallService независимо от Activity. */
|
||||
LaunchedEffect(callState) {
|
||||
LaunchedEffect(callState, radioCall) {
|
||||
val st = callState
|
||||
val inCall = st != null && st.phase != CallPhase.NONE &&
|
||||
st.phase != CallPhase.ENDED
|
||||
if (inCall) {
|
||||
if (inCall || radioCall != null && radioCall?.phase != RadioCallPhase.ENDED) {
|
||||
hadCall = true
|
||||
} else {
|
||||
if (hadCall) releaseLockScreen()
|
||||
@@ -516,6 +528,7 @@ class MainActivity : AppCompatActivity() {
|
||||
if (callState?.phase == CallPhase.INCOMING) {
|
||||
IncomingCallDialog(viewModel = vm)
|
||||
}
|
||||
radioCall?.let { RadioCallDialog(it) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -603,6 +616,7 @@ class MainActivity : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
CallController.setActivityVisible(true)
|
||||
RadioCallController.setVisible(true)
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
@@ -619,6 +633,7 @@ class MainActivity : AppCompatActivity() {
|
||||
override fun onNewIntent(intent: Intent) {
|
||||
super.onNewIntent(intent)
|
||||
setIntent(intent)
|
||||
RadioCallController.notificationIntent(intent)
|
||||
readFilesIntent(intent)
|
||||
if (intent.getBooleanExtra(MicrophonePermission.EXTRA_REQUEST, false)) {
|
||||
intent.removeExtra(MicrophonePermission.EXTRA_REQUEST)
|
||||
@@ -691,6 +706,7 @@ class MainActivity : AppCompatActivity() {
|
||||
if (MicrophonePermission.requester === microphoneRequester) MicrophonePermission.requester = null
|
||||
if (RadioOverlayService.overlayPermissionRequester === overlayPermissionRequester) RadioOverlayService.overlayPermissionRequester = null
|
||||
CallController.setActivityVisible(false)
|
||||
RadioCallController.setVisible(false)
|
||||
}
|
||||
|
||||
/** Volume-кнопки (удержание) → PTT рации, при активной рации и включённой опции. */
|
||||
|
||||
+11
-7
@@ -110,7 +110,6 @@ fun MemberListScreen(
|
||||
onCall = { viewModel.startCall(channel.id, m.nodeId, m.name) },
|
||||
onRadioCall = { com.utun.chat.data.RadioCallController.start(channel.id, m.nodeId) },
|
||||
onMessage = { viewModel.startDm(channel.id, m.nodeId, m.name) },
|
||||
onInvite = { viewModel.showPmInvite(m.nodeId, m.name, channel.id) },
|
||||
onRadioMute = { viewModel.toggleMemberRadioMute(channel.id, m.nodeId) }
|
||||
)
|
||||
}
|
||||
@@ -130,6 +129,7 @@ fun MemberListScreen(
|
||||
isSelf = member?.isSelf == true,
|
||||
canEdit = member != null,
|
||||
onFiles = { onFiles(detail.nodeId) },
|
||||
onInvite = { viewModel.showPmInvite(detail.nodeId, member?.name ?: detail.name, channel.id) },
|
||||
onConnect = {
|
||||
Log.i("utun-gui", "Member detail connect: channel=${channel.id} node=${detail.nodeId}")
|
||||
viewModel.connectMemberNode(channel.id, detail.nodeId)
|
||||
@@ -185,7 +185,6 @@ private fun MemberListItem(
|
||||
onCall: () -> Unit,
|
||||
onRadioCall: () -> Unit,
|
||||
onMessage: () -> Unit,
|
||||
onInvite: () -> Unit,
|
||||
onRadioMute: () -> Unit
|
||||
) {
|
||||
val onlineColor = when {
|
||||
@@ -278,15 +277,12 @@ private fun MemberListItem(
|
||||
RadioSpeakerIcon(speaking, member.radioMuted, radioStatus + ". " +
|
||||
stringResource(if (member.radioMuted) R.string.radio_member_listen else R.string.radio_member_mute))
|
||||
}
|
||||
IconButton(onClick = onInvite, modifier = actionModifier) {
|
||||
Icon(Icons.Filled.Add, stringResource(R.string.invite_to_group))
|
||||
IconButton(onClick = onRadioCall, enabled = member.online, modifier = actionModifier) {
|
||||
PortableRadioIcon(stringResource(R.string.radio_call_start))
|
||||
}
|
||||
IconButton(onClick = onCall, enabled = member.online, modifier = actionModifier) {
|
||||
Icon(Icons.Filled.Call, stringResource(R.string.call))
|
||||
}
|
||||
IconButton(onClick = onRadioCall, enabled = member.online, modifier = actionModifier) {
|
||||
PortableRadioIcon(stringResource(R.string.radio_call_start))
|
||||
}
|
||||
IconButton(onClick = onMessage, modifier = actionModifier) {
|
||||
Icon(Icons.AutoMirrored.Filled.Message, stringResource(R.string.message))
|
||||
}
|
||||
@@ -310,6 +306,7 @@ private fun MemberDetailCard(
|
||||
isSelf: Boolean = false,
|
||||
canEdit: Boolean,
|
||||
onFiles: () -> Unit,
|
||||
onInvite: () -> Unit,
|
||||
onConnect: () -> Unit,
|
||||
onEdit: () -> Unit
|
||||
) {
|
||||
@@ -403,6 +400,13 @@ private fun MemberDetailCard(
|
||||
}
|
||||
}
|
||||
|
||||
if (!isSelf) {
|
||||
TextButton(onClick = onInvite) {
|
||||
Icon(Icons.Filled.Add, stringResource(R.string.invite_to_group))
|
||||
Spacer(Modifier.width(4.dp))
|
||||
Text(stringResource(R.string.invite_to_group))
|
||||
}
|
||||
}
|
||||
Spacer(Modifier.height(4.dp))
|
||||
val headerParts = mutableListOf("0x${detail.nodeId.toString(16).padStart(16, '0')}")
|
||||
if (detail.lastSeen > 0) {
|
||||
|
||||
Reference in new issue
Block a user