From c3013f44565c5e2446018bc2e611c5c5d4d580a9 Mon Sep 17 00:00:00 2001 From: Diogo Date: Wed, 20 Nov 2024 23:49:35 +0000 Subject: [PATCH] edit and view servers --- .../networkAndServers/OperatorView.kt | 71 ++++++++-- .../networkAndServers/ProtocolServerView.kt | 126 +++++++++++++----- .../networkAndServers/ProtocolServersView.kt | 53 ++++++++ .../commonMain/resources/MR/base/strings.xml | 5 + 4 files changed, 208 insertions(+), 47 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 a25c6d4708..b4058387dd 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 @@ -47,10 +47,56 @@ fun ModalData.OperatorView( val testing = remember { mutableStateOf(false) } val operator = remember { userServers.value[operatorIndex].operator_ } 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, currentUser, rhId) + 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 + ) if (testing.value) { DefaultProgressView(null) } @@ -63,6 +109,7 @@ fun OperatorViewLayout( userServers: MutableState>, serverErrors: MutableState>, operatorIndex: Int, + navigateToProtocolView: (Int, UserServer, ServerProtocol) -> Unit, currentUser: User?, rhId: Long? ) { @@ -163,8 +210,9 @@ fun OperatorViewLayout( if (userServers.value[operatorIndex].smpServers.any { it.preset }) { SectionDividerSpaced() SectionView(generalGetString(MR.strings.message_servers).uppercase()) { - userServers.value[operatorIndex].smpServers.forEach { server -> - SectionItemView { + userServers.value[operatorIndex].smpServers.forEachIndexed { i, server -> + if (!server.preset) return@forEachIndexed + SectionItemView({ navigateToProtocolView(i, server, ServerProtocol.SMP) }) { ProtocolServerView( srv = server, serverProtocol = ServerProtocol.SMP, @@ -196,9 +244,9 @@ fun OperatorViewLayout( if (userServers.value[operatorIndex].smpServers.any { !it.preset && !it.deleted }) { SectionDividerSpaced() SectionView(generalGetString(MR.strings.operator_added_message_servers).uppercase()) { - userServers.value[operatorIndex].smpServers.forEach { server -> - if (server.deleted || server.preset) return@forEach - SectionItemView { + userServers.value[operatorIndex].smpServers.forEachIndexed { i, server -> + if (server.deleted || server.preset) return@forEachIndexed + SectionItemView({ navigateToProtocolView(i, server, ServerProtocol.SMP) }) { ProtocolServerView( srv = server, serverProtocol = ServerProtocol.SMP, @@ -248,8 +296,9 @@ fun OperatorViewLayout( if (userServers.value[operatorIndex].xftpServers.any { it.preset }) { SectionDividerSpaced() SectionView(generalGetString(MR.strings.media_and_file_servers).uppercase()) { - userServers.value[operatorIndex].xftpServers.forEach { server -> - SectionItemView { + userServers.value[operatorIndex].xftpServers.forEachIndexed { i, server -> + if (!server.preset) return@forEachIndexed + SectionItemView({ navigateToProtocolView(i, server, ServerProtocol.XFTP) }) { ProtocolServerView( srv = server, serverProtocol = ServerProtocol.XFTP, @@ -281,9 +330,9 @@ fun OperatorViewLayout( if (userServers.value[operatorIndex].xftpServers.any { !it.preset && !it.deleted}) { SectionDividerSpaced() SectionView(generalGetString(MR.strings.operator_added_xftp_servers).uppercase()) { - userServers.value[operatorIndex].xftpServers.forEach { server -> - if (server.deleted || server.preset) return@forEach - SectionItemView { + userServers.value[operatorIndex].xftpServers.forEachIndexed { i, server -> + if (server.deleted || server.preset) return@forEachIndexed + SectionItemView({ navigateToProtocolView(i, server, ServerProtocol.XFTP) }) { ProtocolServerView( srv = server, serverProtocol = ServerProtocol.XFTP, diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/networkAndServers/ProtocolServerView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/networkAndServers/ProtocolServerView.kt index 7c8fb9fa40..bc5053442d 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/networkAndServers/ProtocolServerView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/networkAndServers/ProtocolServerView.kt @@ -31,37 +31,90 @@ import kotlinx.coroutines.* import kotlinx.coroutines.flow.distinctUntilChanged @Composable -fun ProtocolServerView(m: ChatModel, server: UserServer, serverProtocol: ServerProtocol, onUpdate: (UserServer) -> Unit, onDelete: () -> Unit) { +fun ProtocolServerView( + m: ChatModel, + server: UserServer, + serverProtocol: ServerProtocol, + userServers: MutableState>, + serverErrors: MutableState>, + onDelete: () -> Unit, + onUpdate: (UserServer) -> Unit, + close: () -> Unit, + rhId: Long? +) { var testing by remember { mutableStateOf(false) } - ProtocolServerLayout( - testing, - server, - serverProtocol, - testServer = { - testing = true - withLongRunningApi { - val res = testServerConnection(server, m) - if (isActive) { - onUpdate(res.first) - testing = false + val scope = rememberCoroutineScope() + val draftServer = remember { mutableStateOf(server) } + + ModalView( + close = { + scope.launch { + val draftResult = serverProtocolAndOperator(draftServer.value, userServers.value) + val savedResult = serverProtocolAndOperator(server, userServers.value) + + if (draftResult != null && savedResult != null) { + val (serverToEditProtocol, serverToEditOperator) = draftResult + val (svProtocol, serverOperator) = savedResult + + if (serverToEditProtocol != svProtocol) { + close() + AlertManager.shared.showAlertMsg( + title = generalGetString(MR.strings.error_updating_server_title), + text = generalGetString(MR.strings.error_server_protocol_changed) + ) + } else if (serverToEditOperator != serverOperator) { + close() + AlertManager.shared.showAlertMsg( + title = generalGetString(MR.strings.error_updating_server_title), + text = generalGetString(MR.strings.error_server_operator_changed) + ) + } else { + onUpdate(draftServer.value) + validateServers(rhId, userServers, serverErrors) + close() + } + } else { + close() + AlertManager.shared.showAlertMsg( + title = generalGetString(MR.strings.smp_servers_invalid_address), + text = generalGetString(MR.strings.smp_servers_check_address) + ) } } - }, - onUpdate, - onDelete - ) - if (testing) { - Box( - Modifier.fillMaxSize(), - contentAlignment = Alignment.Center - ) { - CircularProgressIndicator( - Modifier - .padding(horizontal = 2.dp) - .size(30.dp), - color = MaterialTheme.colors.secondary, - strokeWidth = 2.5.dp - ) + } + ) { + ProtocolServerLayout( + testing, + draftServer.value, + serverProtocol, + testServer = { + testing = true + withLongRunningApi { + val res = testServerConnection(draftServer.value, m) + if (isActive) { + draftServer.value = res.first + testing = false + } + } + }, + onUpdate = { + draftServer.value = it + }, + onDelete + ) + if (testing) { + Box( + Modifier.fillMaxSize(), + contentAlignment = Alignment.Center + ) { + CircularProgressIndicator( + Modifier + .padding(horizontal = 2.dp) + .size(30.dp), + color = MaterialTheme.colors.secondary, + strokeWidth = 2.5.dp + ) + } } } } @@ -76,10 +129,10 @@ private fun ProtocolServerLayout( onDelete: () -> Unit, ) { ColumnWithScrollBar { - AppBarTitle(stringResource(if (server.preset) MR.strings.smp_servers_preset_server else MR.strings.smp_servers_your_server)) + AppBarTitle(stringResource(if (serverProtocol == ServerProtocol.XFTP) MR.strings.xftp_server else MR.strings.smp_server)) if (server.preset) { - PresetServer(testing, server, testServer, onUpdate, onDelete) + PresetServer(testing, server, testServer, onUpdate) } else { CustomServer(testing, server, serverProtocol, testServer, onUpdate, onDelete) } @@ -93,7 +146,6 @@ private fun PresetServer( server: UserServer, testServer: () -> Unit, onUpdate: (UserServer) -> Unit, - onDelete: () -> Unit, ) { SectionView(stringResource(MR.strings.smp_servers_preset_address).uppercase()) { SelectionContainer { @@ -108,7 +160,7 @@ private fun PresetServer( } } SectionDividerSpaced() - UseServerSection(true, testing, server, testServer, onUpdate, onDelete) + UseServerSection(true, testing, server, testServer, onUpdate) } @Composable @@ -165,7 +217,7 @@ private fun UseServerSection( server: UserServer, testServer: () -> Unit, onUpdate: (UserServer) -> Unit, - onDelete: () -> Unit, + onDelete: (() -> Unit)? = null, ) { SectionView(stringResource(MR.strings.smp_servers_use_server).uppercase()) { SectionItemViewSpaceBetween(testServer, disabled = !valid || testing) { @@ -181,9 +233,11 @@ private fun UseServerSection( ) { onUpdate(server.copy(enabled = it)) } - - SectionItemView(onDelete, disabled = testing) { - Text(stringResource(MR.strings.smp_servers_delete_server), color = if (testing) MaterialTheme.colors.secondary else MaterialTheme.colors.error) + + if (onDelete != null) { + SectionItemView(onDelete, disabled = testing) { + Text(stringResource(MR.strings.smp_servers_delete_server), color = if (testing) MaterialTheme.colors.secondary else MaterialTheme.colors.error) + } } } } 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 3f5d60868e..0b5d9ae4ec 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 @@ -245,6 +245,59 @@ private suspend fun runServersTest(servers: List, m: ChatModel, onUp return fs } +fun deleteXFTPServer( + userServers: MutableState>, + operatorServersIndex: Int, + serverIndex: Int +) { + val serverIsSaved = userServers.value[operatorServersIndex].xftpServers[serverIndex].serverId != null + + if (serverIsSaved) { + userServers.value = userServers.value.toMutableList().apply { + this[operatorServersIndex] = this[operatorServersIndex].copy( + xftpServers = this[operatorServersIndex].xftpServers.toMutableList().apply { + this[serverIndex] = this[serverIndex].copy(deleted = true) + } + ) + } + } else { + userServers.value = userServers.value.toMutableList().apply { + this[operatorServersIndex] = this[operatorServersIndex].copy( + xftpServers = this[operatorServersIndex].xftpServers.toMutableList().apply { + this.removeAt(serverIndex) + } + ) + } + } +} + +fun deleteSMPServer( + userServers: MutableState>, + operatorServersIndex: Int, + serverIndex: Int +) { + val serverIsSaved = userServers.value[operatorServersIndex].smpServers[serverIndex].serverId != null + + if (serverIsSaved) { + userServers.value = userServers.value.toMutableList().apply { + this[operatorServersIndex] = this[operatorServersIndex].copy( + smpServers = this[operatorServersIndex].smpServers.toMutableList().apply { + this[serverIndex] = this[serverIndex].copy(deleted = true) + } + ) + } + } else { + userServers.value = userServers.value.toMutableList().apply { + this[operatorServersIndex] = this[operatorServersIndex].copy( + smpServers = this[operatorServersIndex].smpServers.toMutableList().apply { + this.removeAt(serverIndex) + } + ) + } + } +} + + private fun saveServers(rhId: Long?, protocol: ServerProtocol, currServers: MutableState>, servers: List, m: ChatModel, afterSave: () -> Unit = {}) { withBGApi { // if (m.controller.setUserServers(rhId, protocol, servers)) { diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml index 1549f1394f..f839b4bf8f 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml @@ -1712,6 +1712,11 @@ The servers for new files of your current chat profile Added media & file servers + + Error updating server + Server protocol changed. + Server operator changed. + TCP connection Reset to defaults