diff --git a/android/app/src/main/java/com/ts3client/android/ui/App.kt b/android/app/src/main/java/com/ts3client/android/ui/App.kt index 37771f7..87ea2c0 100644 --- a/android/app/src/main/java/com/ts3client/android/ui/App.kt +++ b/android/app/src/main/java/com/ts3client/android/ui/App.kt @@ -73,12 +73,12 @@ fun App(vm: SessionController) { CompositionLocalProvider(LocalIconTheme provides vm.icons, LocalWebPictures provides vm.pictures) { val server = current when { - settingsOpen -> SettingsScreen(vm, onBack = { settingsOpen = false }) contactsOpen -> ContactsScreen(vm, editingContact, onEdit = { uniqueId -> if (uniqueId == null && contactDirect) contactsOpen = false contactDirect = false editingContact = uniqueId }, onBack = { contactsOpen = false }) + settingsOpen -> SettingsScreen(vm, onContacts = { openContacts(null) }, onBack = { settingsOpen = false }) server != null && !connectOpen -> { serverStates.SaveableStateProvider(server.id) { CompositionLocalProvider(LocalServerImages provides server.images) { @@ -89,7 +89,7 @@ fun App(vm: SessionController) { } } } - else -> ConnectScreen(vm, snackbar, { settingsOpen = true }, { openContacts(null) }, connectAsking, + else -> ConnectScreen(vm, snackbar, { settingsOpen = true }, connectAsking, onBack = if (current != null) ({ connectOpen = false }) else null) } } diff --git a/android/app/src/main/java/com/ts3client/android/ui/ConnectScreen.kt b/android/app/src/main/java/com/ts3client/android/ui/ConnectScreen.kt index bd290f0..479253e 100644 --- a/android/app/src/main/java/com/ts3client/android/ui/ConnectScreen.kt +++ b/android/app/src/main/java/com/ts3client/android/ui/ConnectScreen.kt @@ -64,7 +64,6 @@ fun ConnectScreen( vm: SessionController, snackbar: SnackbarHostState, onSettings: () -> Unit, - onContacts: () -> Unit, onConnect: (() -> Unit) -> Unit, /** Back to the servers already connected; null when there are none. */ onBack: (() -> Unit)?, @@ -89,7 +88,6 @@ fun ConnectScreen( if (onBack != null) IconButton(onClick = onBack) { Icon(Icons.AutoMirrored.Filled.ArrowBack, "Back") } }, actions = { - IconButton(onClick = onContacts) { PackIcon("CONTACT", "Contacts") } IconButton(onClick = onSettings) { PackIcon("SETTINGS", "Settings") } }, ) diff --git a/android/app/src/main/java/com/ts3client/android/ui/ServerScreen.kt b/android/app/src/main/java/com/ts3client/android/ui/ServerScreen.kt index a1aefaf..b7c5be7 100644 --- a/android/app/src/main/java/com/ts3client/android/ui/ServerScreen.kt +++ b/android/app/src/main/java/com/ts3client/android/ui/ServerScreen.kt @@ -2,6 +2,7 @@ package com.ts3client.android.ui import android.widget.Toast import androidx.activity.compose.BackHandler +import androidx.compose.foundation.Image import androidx.compose.foundation.clickable import androidx.compose.foundation.combinedClickable import androidx.compose.foundation.gestures.detectTapGestures @@ -108,8 +109,8 @@ fun ServerScreen( server: ServerController, snackbar: SnackbarHostState, onSettings: () -> Unit, - /** Opens the contacts, on the given client's page when one is named. */ - onContacts: (String?) -> Unit, + /** Opens the given client's contact page. */ + onEditContact: (String) -> Unit, onEnableMicrophone: () -> Unit, onConnectOther: () -> Unit, ) { @@ -233,7 +234,6 @@ fun ServerScreen( actions = { state.hostButton?.let { HostButtonAction(it) { url -> runCatching { uriHandler.openUri(url) } } } IconButton(onClick = find::show) { PackIcon("FIND", "Find") } - IconButton(onClick = { onContacts(null) }) { PackIcon("CONTACT", "Contacts") } IconButton(onClick = onSettings) { PackIcon("SETTINGS", "Settings") } }, ) @@ -333,7 +333,7 @@ fun ServerScreen( onVolume = { server.setClientVolume(id, it) }, onAway = { server.setAway(it); clientSheet = null }, onAddContact = { server.addContact(id, it) }, - onEditContact = { clientSheet = null; onContacts(client.uniqueId) }, + onEditContact = { clientSheet = null; onEditContact(client.uniqueId) }, onMove = if (server.canMoveClients) ({ clientSheet = null; moving = id }) else null, onMoveToOwnChannel = if (server.canMoveClients && tree.channel(state.channelId)?.clients?.none { it.id == id } == true) { { server.moveClient(id, state.channelId); clientSheet = null } @@ -523,6 +523,16 @@ private fun PushToTalk(talking: Boolean, onPressed: (Boolean) -> Unit, modifier: } } +/** The server's own icon, else the pack's server icon. */ +@Composable +private fun ServerLogo(server: ServerController, modifier: Modifier = Modifier) { + val tree by server.tree.collectAsStateWithLifecycle() + val version by server.images.version.collectAsStateWithLifecycle() + val icon = remember(tree.serverIconId, version) { server.images.icon(tree.serverIconId) } + if (icon != null) Image(icon, null, modifier.size(24.dp)) + else PackIcon("SERVER_GREEN", null, modifier) +} + /** The server on screen, opening onto the others and connecting to another. */ @Composable private fun ServerSwitcher(vm: SessionController, server: ServerController, state: SessionState, onConnectOther: () -> Unit) { @@ -531,6 +541,7 @@ private fun ServerSwitcher(vm: SessionController, server: ServerController, stat Box(Modifier.fillMaxWidth()) { Row(Modifier.fillMaxWidth().heightIn(min = 48.dp).clickable { open = true }, verticalAlignment = Alignment.CenterVertically) { + ServerLogo(server, Modifier.padding(end = 12.dp)) Column(Modifier.weight(1f)) { Text(state.title, maxLines = 1, overflow = TextOverflow.Ellipsis) if (!state.connected) { @@ -548,7 +559,7 @@ private fun ServerSwitcher(vm: SessionController, server: ServerController, stat text = { Text(otherState.title, maxLines = 1, overflow = TextOverflow.Ellipsis) }, onClick = { open = false; vm.select(other) }, leadingIcon = { - PackIcon("SERVER_GREEN", null, Modifier.alpha(if (otherState.connected) 1f else 0.5f)) + ServerLogo(other, Modifier.alpha(if (otherState.connected) 1f else 0.5f)) }, trailingIcon = if (otherState.micActive) ({ PackIcon("ACTIVATE_MICROPHONE", "Microphone") }) else null, colors = if (other == server) MenuDefaults.itemColors(textColor = MaterialTheme.colorScheme.primary) diff --git a/android/app/src/main/java/com/ts3client/android/ui/SettingsScreen.kt b/android/app/src/main/java/com/ts3client/android/ui/SettingsScreen.kt index 6bac6fa..d44295f 100644 --- a/android/app/src/main/java/com/ts3client/android/ui/SettingsScreen.kt +++ b/android/app/src/main/java/com/ts3client/android/ui/SettingsScreen.kt @@ -21,17 +21,18 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext -private enum class SettingsPage { SOUND, IDENTITIES, MY_TEAMSPEAK } +private enum class SettingsPage { SOUND, DESIGN, IDENTITIES, MY_TEAMSPEAK } /** * The settings, by category. Every change is saved and put into effect at once, * as there is no dialog to confirm. */ @Composable -fun SettingsScreen(vm: SessionController, onBack: () -> Unit) { +fun SettingsScreen(vm: SessionController, onContacts: () -> Unit, onBack: () -> Unit) { var page by rememberSaveable { mutableStateOf(null) } when (page) { SettingsPage.SOUND -> return SoundSettingsScreen(vm, onBack = { page = null }) + SettingsPage.DESIGN -> return DesignScreen(vm, onBack = { page = null }) SettingsPage.IDENTITIES -> return IdentitiesScreen(vm.identities, onBack = { page = null }) SettingsPage.MY_TEAMSPEAK -> return MyTeamSpeakScreen(vm, onBack = { page = null }) null -> {} @@ -39,16 +40,27 @@ fun SettingsScreen(vm: SessionController, onBack: () -> Unit) { SubScreen("Settings", onBack) { padding -> Column(Modifier.padding(padding).verticalScroll(rememberScrollState())) { + LinkRow("Contacts", "Friends and blocked users", "CONTACT", onContacts) LinkRow("Sound Settings", "Devices, transmission, voice activation, processing, volume", "PLAYBACK") { page = SettingsPage.SOUND } + LinkRow("Design", "Icon pack, country flags, description pictures", "GUISETUP") { + page = SettingsPage.DESIGN + } LinkRow("Identities", "Create, import, export, security level", "IDENTITY_MANAGER") { page = SettingsPage.IDENTITIES } LinkRow("myTeamSpeak", if (vm.myTeamSpeak.isSignedIn) "Signed in as ${vm.myTeamSpeak.username()}" else "Sign in to bring over your synchronised bookmarks and identities", "MYTS_ACCOUNT") { page = SettingsPage.MY_TEAMSPEAK } - Section("Appearance") + } + } +} + +@Composable +private fun DesignScreen(vm: SessionController, onBack: () -> Unit) { + SubScreen("Design", onBack) { padding -> + Column(Modifier.padding(padding).verticalScroll(rememberScrollState())) { IconPackPicker(vm.icons) var flags by remember { mutableStateOf(vm.settings.countryFlags) } Toggle("Show country flags in the channel tree", flags) {