From 3817a1609a07c03b02b4f4ab6a2ff232e2243f55 Mon Sep 17 00:00:00 2001 From: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com> Date: Thu, 21 Nov 2024 12:27:27 +0400 Subject: [PATCH] android: custom servers view (#5224) --- .../networkAndServers/OperatorView.kt | 155 ++++++++++-------- .../networkAndServers/ProtocolServersView.kt | 117 +++++++++++-- 2 files changed, 188 insertions(+), 84 deletions(-) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/networkAndServers/OperatorView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/networkAndServers/OperatorView.kt index b4058387dd..b7f97574ce 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/networkAndServers/OperatorView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/networkAndServers/OperatorView.kt @@ -1,5 +1,6 @@ package chat.simplex.common.views.usersettings.networkAndServers +import SectionBottomSpacer import SectionCustomFooter import SectionDividerSpaced import SectionItemView @@ -33,8 +34,8 @@ import chat.simplex.common.views.helpers.* import chat.simplex.res.MR import dev.icerock.moko.resources.compose.painterResource import dev.icerock.moko.resources.compose.stringResource +import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch -import kotlin.random.Random @Composable fun ModalData.OperatorView( @@ -49,60 +50,77 @@ fun ModalData.OperatorView( val currentUser = remember { chatModel.currentUser }.value val scope = rememberCoroutineScope() - ColumnWithScrollBar(Modifier.alpha(if (testing.value) 0.6f else 1f)) { - AppBarTitle(String.format(stringResource(MR.strings.operator_servers_title), operator.tradeName)) - OperatorViewLayout( - currUserServers, - userServers, - serverErrors, - operatorIndex, - { serverIndex, server, protocol -> - ModalManager.start.showCustomModal { close -> - ProtocolServerView( - m = chatModel, - server = server, - serverProtocol = protocol, - userServers = userServers, - serverErrors = serverErrors, - onDelete = { - if (protocol == ServerProtocol.SMP) { - deleteSMPServer(userServers, operatorIndex, serverIndex) - } else { - deleteXFTPServer(userServers, operatorIndex, serverIndex) - } - close() - scope.launch { validateServers(rhId, userServers, serverErrors) } - }, - onUpdate = { updatedServer -> - userServers.value = userServers.value.toMutableList().apply { - this[operatorIndex] = this[operatorIndex].copy( - smpServers = if (protocol == ServerProtocol.SMP) { - this[operatorIndex].smpServers.toMutableList().apply { - this[serverIndex] = updatedServer - } - } else this[operatorIndex].smpServers, - xftpServers = if (protocol == ServerProtocol.XFTP) { - this[operatorIndex].xftpServers.toMutableList().apply { - this[serverIndex] = updatedServer - } - } else this[operatorIndex].xftpServers - ) - } - }, - close = close, - rhId = rhId - ) - } - }, - currentUser, - rhId - ) + Box { + ColumnWithScrollBar(Modifier.alpha(if (testing.value) 0.6f else 1f)) { + AppBarTitle(String.format(stringResource(MR.strings.operator_servers_title), operator.tradeName)) + OperatorViewLayout( + currUserServers, + userServers, + serverErrors, + operatorIndex, + navigateToProtocolView = { serverIndex, server, protocol -> + navigateToProtocolView(scope, userServers, serverErrors, operatorIndex, rhId, serverIndex, server, protocol) + }, + currentUser, + rhId, + testing + ) + } + if (testing.value) { DefaultProgressView(null) } } } +fun navigateToProtocolView( + scope: CoroutineScope, + userServers: MutableState>, + serverErrors: MutableState>, + operatorIndex: Int, + rhId: Long?, + serverIndex: Int, + server: UserServer, + protocol: ServerProtocol +) { + ModalManager.start.showCustomModal { close -> + ProtocolServerView( + m = chatModel, + server = server, + serverProtocol = protocol, + userServers = userServers, + serverErrors = serverErrors, + onDelete = { + if (protocol == ServerProtocol.SMP) { + deleteSMPServer(userServers, operatorIndex, serverIndex) + } else { + deleteXFTPServer(userServers, operatorIndex, serverIndex) + } + close() + scope.launch { validateServers(rhId, userServers, serverErrors) } + }, + onUpdate = { updatedServer -> + userServers.value = userServers.value.toMutableList().apply { + this[operatorIndex] = this[operatorIndex].copy( + smpServers = if (protocol == ServerProtocol.SMP) { + this[operatorIndex].smpServers.toMutableList().apply { + this[serverIndex] = updatedServer + } + } else this[operatorIndex].smpServers, + xftpServers = if (protocol == ServerProtocol.XFTP) { + this[operatorIndex].xftpServers.toMutableList().apply { + this[serverIndex] = updatedServer + } + } else this[operatorIndex].xftpServers + ) + } + }, + close = close, + rhId = rhId + ) + } +} + @Composable fun OperatorViewLayout( currUserServers: MutableState>, @@ -111,12 +129,12 @@ fun OperatorViewLayout( operatorIndex: Int, navigateToProtocolView: (Int, UserServer, ServerProtocol) -> Unit, currentUser: User?, - rhId: Long? + rhId: Long?, + testing: MutableState ) { val operator by remember { derivedStateOf { userServers.value[operatorIndex].operator_ } } val scope = rememberCoroutineScope() val duplicateHosts = findDuplicateHosts(serverErrors.value) - val testing = remember { mutableStateOf(false) } Column { SectionView(generalGetString(MR.strings.operator).uppercase()) { @@ -362,24 +380,29 @@ fun OperatorViewLayout( } SectionDividerSpaced() - TestServersButton( - testing = testing, - smpServers = userServers.value[operatorIndex].smpServers, - xftpServers = userServers.value[operatorIndex].xftpServers, - ) { p, l -> - when (p) { - ServerProtocol.XFTP -> userServers.value = userServers.value.toMutableList().apply { - this[operatorIndex] = this[operatorIndex].copy( - xftpServers = l - ) - } - ServerProtocol.SMP -> userServers.value = userServers.value.toMutableList().apply { - this[operatorIndex] = this[operatorIndex].copy( - smpServers = l - ) + SectionView { + TestServersButton( + testing = testing, + smpServers = userServers.value[operatorIndex].smpServers, + xftpServers = userServers.value[operatorIndex].xftpServers, + ) { p, l -> + when (p) { + ServerProtocol.XFTP -> userServers.value = userServers.value.toMutableList().apply { + this[operatorIndex] = this[operatorIndex].copy( + xftpServers = l + ) + } + + ServerProtocol.SMP -> userServers.value = userServers.value.toMutableList().apply { + this[operatorIndex] = this[operatorIndex].copy( + smpServers = l + ) + } } } } + + SectionBottomSpacer() } } } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/networkAndServers/ProtocolServersView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/networkAndServers/ProtocolServersView.kt index 79c27912ff..0ba40fe60f 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/networkAndServers/ProtocolServersView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/networkAndServers/ProtocolServersView.kt @@ -9,8 +9,6 @@ import SectionView import androidx.compose.foundation.layout.* import androidx.compose.material.* import androidx.compose.runtime.* -import androidx.compose.runtime.saveable.rememberSaveable -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalUriHandler import dev.icerock.moko.resources.compose.painterResource @@ -36,10 +34,26 @@ fun ModalData.YourServersView( rhId: Long? ) { val testing = remember { mutableStateOf(false) } + val currentUser = remember { chatModel.currentUser }.value + val scope = rememberCoroutineScope() + + Box { + ColumnWithScrollBar { + AppBarTitle(stringResource(MR.strings.your_servers)) + YourServersViewLayout( + currUserServers, + userServers, + serverErrors, + operatorIndex, + navigateToProtocolView = { serverIndex, server, protocol -> + navigateToProtocolView(scope, userServers, serverErrors, operatorIndex, rhId, serverIndex, server, protocol) + }, + currentUser, + rhId, + testing + ) + } - ColumnWithScrollBar { - AppBarTitle(stringResource(MR.strings.your_servers)) - YourServersViewLayout(currUserServers, userServers, serverErrors, operatorIndex, rhId, testing.value) if (testing.value) { DefaultProgressView(null) } @@ -52,17 +66,19 @@ fun YourServersViewLayout( userServers: MutableState>, serverErrors: MutableState>, operatorIndex: Int, + navigateToProtocolView: (Int, UserServer, ServerProtocol) -> Unit, + currentUser: User?, rhId: Long?, - testing: Boolean + testing: MutableState ) { - val scope = rememberCoroutineScope() val duplicateHosts = findDuplicateHosts(serverErrors.value) Column { if (userServers.value[operatorIndex].smpServers.any { !it.deleted }) { SectionView(generalGetString(MR.strings.message_servers).uppercase()) { - userServers.value[operatorIndex].smpServers.forEach { server -> - SectionItemView { + userServers.value[operatorIndex].smpServers.forEachIndexed { i, server -> + if (server.deleted) return@forEachIndexed + SectionItemView({ navigateToProtocolView(i, server, ServerProtocol.SMP) }) { ProtocolServerView( srv = server, serverProtocol = ServerProtocol.SMP, @@ -76,30 +92,95 @@ fun YourServersViewLayout( SectionCustomFooter { ServerErrorsView(smpErrors) } + } else { + SectionTextFooter( + remember(currentUser?.displayName) { + buildAnnotatedString { + append(generalGetString(MR.strings.smp_servers_per_user) + " ") + withStyle(SpanStyle(fontWeight = FontWeight.Bold)) { + append(currentUser?.displayName ?: "") + } + append(".") + } + } + ) } } - SectionDividerSpaced() + if (userServers.value[operatorIndex].xftpServers.any { !it.deleted }) { + SectionDividerSpaced() + SectionView(generalGetString(MR.strings.media_and_file_servers).uppercase()) { + userServers.value[operatorIndex].xftpServers.forEachIndexed { i, server -> + if (server.deleted) return@forEachIndexed + SectionItemView({ navigateToProtocolView(i, server, ServerProtocol.XFTP) }) { + ProtocolServerView( + srv = server, + serverProtocol = ServerProtocol.XFTP, + duplicateHosts = duplicateHosts + ) + } + } + } + val xftpErrors = globalXFTPServersError(serverErrors.value) + if (xftpErrors != null) { + SectionCustomFooter { + ServerErrorsView(xftpErrors) + } + } else { + SectionTextFooter( + remember(currentUser?.displayName) { + buildAnnotatedString { + append(generalGetString(MR.strings.xftp_servers_per_user) + " ") + withStyle(SpanStyle(fontWeight = FontWeight.Bold)) { + append(currentUser?.displayName ?: "") + } + append(".") + } + } + ) + } + } + + if ( + userServers.value[operatorIndex].smpServers.any { !it.deleted } || + userServers.value[operatorIndex].xftpServers.any { !it.deleted } + ) { + SectionDividerSpaced(maxTopPadding = false, maxBottomPadding = false) + } SectionView { SettingsActionItem( painterResource(MR.images.ic_add), stringResource(MR.strings.smp_servers_add), click = { showAddServerDialog(userServers, serverErrors, operatorIndex, rhId) }, - disabled = testing, - textColor = if (testing) MaterialTheme.colors.secondary else MaterialTheme.colors.primary, - iconColor = if (testing) MaterialTheme.colors.secondary else MaterialTheme.colors.primary + disabled = testing.value, + textColor = if (testing.value) MaterialTheme.colors.secondary else MaterialTheme.colors.primary, + iconColor = if (testing.value) MaterialTheme.colors.secondary else MaterialTheme.colors.primary ) } SectionDividerSpaced(maxTopPadding = false, maxBottomPadding = false) SectionView { - // TODO Test servers button - SectionItemView { Text("Test servers") } - } - SectionDividerSpaced(maxBottomPadding = false) + TestServersButton( + testing = testing, + smpServers = userServers.value[operatorIndex].smpServers, + xftpServers = userServers.value[operatorIndex].xftpServers, + ) { p, l -> + when (p) { + ServerProtocol.XFTP -> userServers.value = userServers.value.toMutableList().apply { + this[operatorIndex] = this[operatorIndex].copy( + xftpServers = l + ) + } + + ServerProtocol.SMP -> userServers.value = userServers.value.toMutableList().apply { + this[operatorIndex] = this[operatorIndex].copy( + smpServers = l + ) + } + } + } - SectionView { HowToButton() } SectionBottomSpacer()