mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-05-11 15:24:58 +00:00
Merge branch 'master' into ios-one-hand-ui
This commit is contained in:
@@ -137,8 +137,8 @@ func apiGetActiveUser(ctrl: chat_ctrl? = nil) throws -> User? {
|
||||
}
|
||||
}
|
||||
|
||||
func apiCreateActiveUser(_ p: Profile?, sameServers: Bool = false, pastTimestamp: Bool = false, ctrl: chat_ctrl? = nil) throws -> User {
|
||||
let r = chatSendCmdSync(.createActiveUser(profile: p, sameServers: sameServers, pastTimestamp: pastTimestamp), ctrl)
|
||||
func apiCreateActiveUser(_ p: Profile?, pastTimestamp: Bool = false, ctrl: chat_ctrl? = nil) throws -> User {
|
||||
let r = chatSendCmdSync(.createActiveUser(profile: p, pastTimestamp: pastTimestamp), ctrl)
|
||||
if case let .activeUser(user) = r { return user }
|
||||
throw r
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ public let jsonEncoder = getJSONEncoder()
|
||||
|
||||
public enum ChatCommand {
|
||||
case showActiveUser
|
||||
case createActiveUser(profile: Profile?, sameServers: Bool, pastTimestamp: Bool)
|
||||
case createActiveUser(profile: Profile?, pastTimestamp: Bool)
|
||||
case listUsers
|
||||
case apiSetActiveUser(userId: Int64, viewPwd: String?)
|
||||
case setAllContactReceipts(enable: Bool)
|
||||
@@ -156,8 +156,8 @@ public enum ChatCommand {
|
||||
get {
|
||||
switch self {
|
||||
case .showActiveUser: return "/u"
|
||||
case let .createActiveUser(profile, sameServers, pastTimestamp):
|
||||
let user = NewUser(profile: profile, sameServers: sameServers, pastTimestamp: pastTimestamp)
|
||||
case let .createActiveUser(profile, pastTimestamp):
|
||||
let user = NewUser(profile: profile, pastTimestamp: pastTimestamp)
|
||||
return "/_create user \(encodeJSON(user))"
|
||||
case .listUsers: return "/users"
|
||||
case let .apiSetActiveUser(userId, viewPwd): return "/_user \(userId)\(maybePwd(viewPwd))"
|
||||
@@ -1097,7 +1097,6 @@ public enum GroupLinkPlan: Decodable, Hashable {
|
||||
|
||||
struct NewUser: Encodable, Hashable {
|
||||
var profile: Profile?
|
||||
var sameServers: Bool
|
||||
var pastTimestamp: Bool
|
||||
}
|
||||
|
||||
|
||||
@@ -276,7 +276,9 @@ fun AndroidScreen(settingsState: SettingsViewState) {
|
||||
snapshotFlow { ModalManager.center.modalCount.value > 0 }
|
||||
.filter { chatModel.chatId.value == null }
|
||||
.collect { modalBackground ->
|
||||
if (modalBackground && !chatModel.newChatSheetVisible.value) {
|
||||
if (chatModel.newChatSheetVisible.value) {
|
||||
platform.androidSetStatusAndNavBarColors(CurrentColors.value.colors.isLight, CurrentColors.value.colors.background, false, appPrefs.oneHandUI.get())
|
||||
} else if (modalBackground) {
|
||||
platform.androidSetStatusAndNavBarColors(CurrentColors.value.colors.isLight, CurrentColors.value.colors.background, false, false)
|
||||
} else {
|
||||
platform.androidSetStatusAndNavBarColors(CurrentColors.value.colors.isLight, CurrentColors.value.colors.background, !appPrefs.oneHandUI.get(), appPrefs.oneHandUI.get())
|
||||
|
||||
+6
-15
@@ -142,8 +142,8 @@ class AppPreferences {
|
||||
},
|
||||
set = fun(mode: TransportSessionMode) { _networkSessionMode.set(mode.name) }
|
||||
)
|
||||
val networkSMPProxyMode = mkStrPreference(SHARED_PREFS_NETWORK_SMP_PROXY_MODE, SMPProxyMode.Never.name)
|
||||
val networkSMPProxyFallback = mkStrPreference(SHARED_PREFS_NETWORK_SMP_PROXY_FALLBACK, SMPProxyFallback.Allow.name)
|
||||
val networkSMPProxyMode = mkStrPreference(SHARED_PREFS_NETWORK_SMP_PROXY_MODE, NetCfg.defaults.smpProxyMode.name)
|
||||
val networkSMPProxyFallback = mkStrPreference(SHARED_PREFS_NETWORK_SMP_PROXY_FALLBACK, NetCfg.defaults.smpProxyFallback.name)
|
||||
val networkHostMode = mkStrPreference(SHARED_PREFS_NETWORK_HOST_MODE, HostMode.OnionViaSocks.name)
|
||||
val networkRequiredHostMode = mkBoolPreference(SHARED_PREFS_NETWORK_REQUIRED_HOST_MODE, false)
|
||||
val networkTCPConnectTimeout = mkTimeoutPreference(SHARED_PREFS_NETWORK_TCP_CONNECT_TIMEOUT, NetCfg.defaults.tcpConnectTimeout, NetCfg.proxyDefaults.tcpConnectTimeout)
|
||||
@@ -657,8 +657,8 @@ object ChatController {
|
||||
return null
|
||||
}
|
||||
|
||||
suspend fun apiCreateActiveUser(rh: Long?, p: Profile?, sameServers: Boolean = false, pastTimestamp: Boolean = false, ctrl: ChatCtrl? = null): User? {
|
||||
val r = sendCmd(rh, CC.CreateActiveUser(p, sameServers = sameServers, pastTimestamp = pastTimestamp), ctrl)
|
||||
suspend fun apiCreateActiveUser(rh: Long?, p: Profile?, pastTimestamp: Boolean = false, ctrl: ChatCtrl? = null): User? {
|
||||
val r = sendCmd(rh, CC.CreateActiveUser(p, pastTimestamp = pastTimestamp), ctrl)
|
||||
if (r is CR.ActiveUser) return r.user.updateRemoteHostId(rh)
|
||||
else if (
|
||||
r is CR.ChatCmdError && r.chatError is ChatError.ChatErrorStore && r.chatError.storeError is StoreError.DuplicateName ||
|
||||
@@ -2824,7 +2824,7 @@ class SharedPreference<T>(val get: () -> T, set: (T) -> Unit) {
|
||||
sealed class CC {
|
||||
class Console(val cmd: String): CC()
|
||||
class ShowActiveUser: CC()
|
||||
class CreateActiveUser(val profile: Profile?, val sameServers: Boolean, val pastTimestamp: Boolean): CC()
|
||||
class CreateActiveUser(val profile: Profile?, val pastTimestamp: Boolean): CC()
|
||||
class ListUsers: CC()
|
||||
class ApiSetActiveUser(val userId: Long, val viewPwd: String?): CC()
|
||||
class SetAllContactReceipts(val enable: Boolean): CC()
|
||||
@@ -2962,7 +2962,7 @@ sealed class CC {
|
||||
is Console -> cmd
|
||||
is ShowActiveUser -> "/u"
|
||||
is CreateActiveUser -> {
|
||||
val user = NewUser(profile, sameServers = sameServers, pastTimestamp = pastTimestamp)
|
||||
val user = NewUser(profile, pastTimestamp = pastTimestamp)
|
||||
"/_create user ${json.encodeToString(user)}"
|
||||
}
|
||||
is ListUsers -> "/users"
|
||||
@@ -3293,7 +3293,6 @@ fun onOff(b: Boolean): String = if (b) "on" else "off"
|
||||
@Serializable
|
||||
data class NewUser(
|
||||
val profile: Profile?,
|
||||
val sameServers: Boolean,
|
||||
val pastTimestamp: Boolean
|
||||
)
|
||||
|
||||
@@ -3589,10 +3588,6 @@ enum class SMPProxyMode {
|
||||
@SerialName("unknown") Unknown,
|
||||
@SerialName("unprotected") Unprotected,
|
||||
@SerialName("never") Never;
|
||||
|
||||
companion object {
|
||||
val default = Never
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
@@ -3600,10 +3595,6 @@ enum class SMPProxyFallback {
|
||||
@SerialName("allow") Allow,
|
||||
@SerialName("allowProtected") AllowProtected,
|
||||
@SerialName("prohibit") Prohibit;
|
||||
|
||||
companion object {
|
||||
val default = Allow
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
|
||||
+18
-7
@@ -47,13 +47,24 @@ private fun showNewChatSheet(oneHandUI: State<Boolean>) {
|
||||
ModalManager.start.closeModals()
|
||||
ModalManager.end.closeModals()
|
||||
chatModel.newChatSheetVisible.value = true
|
||||
ModalManager.start.showModalCloseable(
|
||||
closeOnTop = !oneHandUI.value,
|
||||
) { close ->
|
||||
NewChatSheet(rh = chatModel.currentRemoteHost.value, close)
|
||||
DisposableEffect(Unit) {
|
||||
onDispose {
|
||||
chatModel.newChatSheetVisible.value = false
|
||||
ModalManager.start.showCustomModal { close ->
|
||||
val close = {
|
||||
// It will set it faster than in onDispose. It's important to catch the actual state before
|
||||
// closing modal for reacting with status bar changes in [App]
|
||||
chatModel.newChatSheetVisible.value = false
|
||||
close()
|
||||
}
|
||||
ModalView(close, closeOnTop = !oneHandUI.value) {
|
||||
if (appPlatform.isAndroid) {
|
||||
BackHandler {
|
||||
close()
|
||||
}
|
||||
}
|
||||
NewChatSheet(rh = chatModel.currentRemoteHost.value, close)
|
||||
DisposableEffect(Unit) {
|
||||
onDispose {
|
||||
chatModel.newChatSheetVisible.value = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+36
-6
@@ -522,9 +522,17 @@ private fun exportArchive(
|
||||
progressIndicator.value = true
|
||||
withLongRunningApi {
|
||||
try {
|
||||
val archiveFile = exportChatArchive(m, null, chatArchiveName, chatArchiveTime, chatArchiveFile)
|
||||
val (archiveFile, archiveErrors) = exportChatArchive(m, null, chatArchiveName, chatArchiveTime, chatArchiveFile)
|
||||
chatArchiveFile.value = archiveFile
|
||||
saveArchiveLauncher.launch(archiveFile.substringAfterLast(File.separator))
|
||||
if (archiveErrors.isEmpty()) {
|
||||
saveArchiveLauncher.launch(archiveFile.substringAfterLast(File.separator))
|
||||
} else {
|
||||
showArchiveExportedWithErrorsAlert(generalGetString(MR.strings.chat_database_exported_save), archiveErrors) {
|
||||
withLongRunningApi {
|
||||
saveArchiveLauncher.launch(archiveFile.substringAfterLast(File.separator))
|
||||
}
|
||||
}
|
||||
}
|
||||
progressIndicator.value = false
|
||||
} catch (e: Error) {
|
||||
AlertManager.shared.showAlertMsg(generalGetString(MR.strings.error_exporting_chat_database), e.toString())
|
||||
@@ -539,7 +547,7 @@ suspend fun exportChatArchive(
|
||||
chatArchiveName: MutableState<String?>,
|
||||
chatArchiveTime: MutableState<Instant?>,
|
||||
chatArchiveFile: MutableState<String?>
|
||||
): String {
|
||||
): Pair<String, List<ArchiveError>> {
|
||||
val archiveTime = Clock.System.now()
|
||||
val ts = SimpleDateFormat("yyyy-MM-dd'T'HHmmss", Locale.US).format(Date.from(archiveTime.toJavaInstant()))
|
||||
val archiveName = "simplex-chat.$ts.zip"
|
||||
@@ -550,7 +558,7 @@ suspend fun exportChatArchive(
|
||||
controller.apiSaveAppSettings(AppSettings.current.prepareForExport())
|
||||
}
|
||||
wallpapersDir.mkdirs()
|
||||
m.controller.apiExportArchive(config)
|
||||
val archiveErrors = m.controller.apiExportArchive(config)
|
||||
if (storagePath == null) {
|
||||
deleteOldArchive(m)
|
||||
m.controller.appPrefs.chatArchiveName.set(archiveName)
|
||||
@@ -559,7 +567,7 @@ suspend fun exportChatArchive(
|
||||
chatArchiveName.value = archiveName
|
||||
chatArchiveTime.value = archiveTime
|
||||
chatArchiveFile.value = archivePath
|
||||
return archivePath
|
||||
return archivePath to archiveErrors
|
||||
}
|
||||
|
||||
private fun deleteOldArchive(m: ChatModel) {
|
||||
@@ -592,6 +600,28 @@ private fun importArchiveAlert(
|
||||
)
|
||||
}
|
||||
|
||||
fun showArchiveImportedWithErrorsAlert(archiveErrors: List<ArchiveError>) {
|
||||
AlertManager.shared.showAlertMsg(
|
||||
title = generalGetString(MR.strings.chat_database_imported),
|
||||
text = generalGetString(MR.strings.restart_the_app_to_use_imported_chat_database) + "\n\n" + generalGetString(MR.strings.non_fatal_errors_occured_during_import) + archiveErrorsText(archiveErrors))
|
||||
}
|
||||
|
||||
fun showArchiveExportedWithErrorsAlert(description: String, archiveErrors: List<ArchiveError>, onConfirm: () -> Unit) {
|
||||
AlertManager.shared.showAlertMsg(
|
||||
title = generalGetString(MR.strings.chat_database_exported_title),
|
||||
text = description + "\n\n" + generalGetString(MR.strings.chat_database_exported_not_all_files) + archiveErrorsText(archiveErrors),
|
||||
confirmText = generalGetString(MR.strings.chat_database_exported_continue),
|
||||
onConfirm = onConfirm
|
||||
)
|
||||
}
|
||||
|
||||
private fun archiveErrorsText(errs: List<ArchiveError>): String = "\n" + errs.map {
|
||||
when (it) {
|
||||
is ArchiveError.ArchiveErrorImport -> it.importError
|
||||
is ArchiveError.ArchiveErrorFile -> "${it.file}: ${it.fileError}"
|
||||
}
|
||||
}.joinToString(separator = "\n")
|
||||
|
||||
private fun importArchive(
|
||||
m: ChatModel,
|
||||
importedArchiveURI: URI,
|
||||
@@ -621,7 +651,7 @@ private fun importArchive(
|
||||
}
|
||||
} else {
|
||||
operationEnded(m, progressIndicator) {
|
||||
AlertManager.shared.showAlertMsg(generalGetString(MR.strings.chat_database_imported), text = generalGetString(MR.strings.restart_the_app_to_use_imported_chat_database) + "\n" + generalGetString(MR.strings.non_fatal_errors_occured_during_import))
|
||||
showArchiveImportedWithErrorsAlert(archiveErrors)
|
||||
}
|
||||
}
|
||||
} catch (e: Error) {
|
||||
|
||||
+1
-1
@@ -70,7 +70,7 @@ fun CloseSheetBar(close: (() -> Unit)?, showClose: Boolean = true, tintColor: Co
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun AppBarTitle(title: String, hostDevice: Pair<Long?, String>? = null, withPadding: Boolean = true, bottomPadding: Dp = DEFAULT_PADDING * 1.5f) {
|
||||
fun AppBarTitle(title: String, hostDevice: Pair<Long?, String>? = null, withPadding: Boolean = true, bottomPadding: Dp = DEFAULT_PADDING * 1.5f + 8.dp) {
|
||||
val theme = CurrentColors.collectAsState()
|
||||
val titleColor = MaterialTheme.appColors.title
|
||||
val brush = if (theme.value.base == DefaultTheme.SIMPLEX)
|
||||
|
||||
+17
-5
@@ -480,12 +480,13 @@ private fun MutableState<MigrationFromState>.exportArchive() {
|
||||
withLongRunningApi {
|
||||
try {
|
||||
getMigrationTempFilesDirectory().mkdir()
|
||||
val archivePath = exportChatArchive(chatModel, getMigrationTempFilesDirectory(), mutableStateOf(""), mutableStateOf(Instant.DISTANT_PAST), mutableStateOf(""))
|
||||
val totalBytes = File(archivePath).length()
|
||||
if (totalBytes > 0L) {
|
||||
state = MigrationFromState.DatabaseInit(totalBytes, archivePath)
|
||||
val (archivePath, archiveErrors) = exportChatArchive(chatModel, getMigrationTempFilesDirectory(), mutableStateOf(""), mutableStateOf(Instant.DISTANT_PAST), mutableStateOf(""))
|
||||
if (archiveErrors.isEmpty()) {
|
||||
uploadArchive(archivePath)
|
||||
} else {
|
||||
AlertManager.shared.showAlertMsg(generalGetString(MR.strings.migrate_from_device_exported_file_doesnt_exist))
|
||||
showArchiveExportedWithErrorsAlert(generalGetString(MR.strings.chat_database_exported_migrate), archiveErrors) {
|
||||
uploadArchive(archivePath)
|
||||
}
|
||||
state = MigrationFromState.UploadConfirmation
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
@@ -498,6 +499,17 @@ private fun MutableState<MigrationFromState>.exportArchive() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun MutableState<MigrationFromState>.uploadArchive(archivePath: String) {
|
||||
val totalBytes = File(archivePath).length()
|
||||
if (totalBytes > 0L) {
|
||||
state = MigrationFromState.DatabaseInit(totalBytes, archivePath)
|
||||
} else {
|
||||
AlertManager.shared.showAlertMsg(generalGetString(MR.strings.migrate_from_device_exported_file_doesnt_exist))
|
||||
state = MigrationFromState.UploadConfirmation
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
suspend fun initTemporaryDatabase(tempDatabaseFile: File, netCfg: NetCfg): Pair<ChatCtrl, User>? {
|
||||
val (status, ctrl) = chatInitTemporaryDatabase(tempDatabaseFile.absolutePath)
|
||||
showErrorOnMigrationIfNeeded(status)
|
||||
|
||||
+1
-6
@@ -237,7 +237,6 @@ private fun ModalData.OnionView(link: String, socksProxy: String?, hostMode: Hos
|
||||
proxy
|
||||
}
|
||||
}
|
||||
val proxyPort = remember { derivedStateOf { networkProxyHostPort.value?.split(":")?.lastOrNull()?.toIntOrNull() ?: 9050 } }
|
||||
|
||||
val netCfg = rememberSaveable(stateSaver = serializableSaver()) {
|
||||
mutableStateOf(getNetCfg().withOnionHosts(onionHosts.value).copy(socksProxy = socksProxy, sessionMode = sessionMode.value))
|
||||
@@ -275,7 +274,6 @@ private fun ModalData.OnionView(link: String, socksProxy: String?, hostMode: Hos
|
||||
onionHosts,
|
||||
sessionMode,
|
||||
networkProxyHostPortPref,
|
||||
proxyPort,
|
||||
toggleSocksProxy = { enable ->
|
||||
networkUseSocksProxy.value = enable
|
||||
},
|
||||
@@ -599,10 +597,7 @@ private fun MutableState<MigrationToState?>.importArchive(archivePath: String, n
|
||||
val config = ArchiveConfig(archivePath, parentTempDirectory = databaseExportDir.toString())
|
||||
val archiveErrors = controller.apiImportArchive(config)
|
||||
if (archiveErrors.isNotEmpty()) {
|
||||
AlertManager.shared.showAlertMsg(
|
||||
generalGetString(MR.strings.chat_database_imported),
|
||||
generalGetString(MR.strings.non_fatal_errors_occured_during_import)
|
||||
)
|
||||
showArchiveImportedWithErrorsAlert(archiveErrors)
|
||||
}
|
||||
state = MigrationToState.Passphrase("", netCfg)
|
||||
MigrationToDeviceState.save(MigrationToDeviceState.Passphrase(netCfg))
|
||||
|
||||
+3
-9
@@ -89,10 +89,7 @@ fun ConnectMobileLayout(
|
||||
connectDesktop: () -> Unit,
|
||||
deleteHost: (RemoteHostInfo) -> Unit,
|
||||
) {
|
||||
ColumnWithScrollBar(
|
||||
Modifier.fillMaxWidth(),
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
ColumnWithScrollBar(Modifier.fillMaxWidth()) {
|
||||
AppBarTitle(stringResource(if (remember { chatModel.remoteHosts }.isEmpty()) MR.strings.link_a_mobile else MR.strings.linked_mobiles))
|
||||
SectionView(generalGetString(MR.strings.this_device_name).uppercase()) {
|
||||
DeviceNameField(deviceName.value ?: "") { updateDeviceName(it) }
|
||||
@@ -100,7 +97,7 @@ fun ConnectMobileLayout(
|
||||
PreferenceToggle(stringResource(MR.strings.multicast_discoverable_via_local_network), checked = remember { controller.appPrefs.offerRemoteMulticast.state }.value) {
|
||||
controller.appPrefs.offerRemoteMulticast.set(it)
|
||||
}
|
||||
SectionDividerSpaced(maxBottomPadding = false)
|
||||
SectionDividerSpaced()
|
||||
}
|
||||
SectionView(stringResource(MR.strings.devices).uppercase()) {
|
||||
if (chatModel.localUserCreated.value == true) {
|
||||
@@ -179,10 +176,7 @@ private fun ConnectMobileViewLayout(
|
||||
refreshQrCode: () -> Unit = {},
|
||||
UnderQrLayout: @Composable () -> Unit = {},
|
||||
) {
|
||||
ColumnWithScrollBar(
|
||||
Modifier.fillMaxWidth(),
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
ColumnWithScrollBar(Modifier.fillMaxWidth()) {
|
||||
if (title != null) {
|
||||
AppBarTitle(title)
|
||||
}
|
||||
|
||||
+234
-90
@@ -2,39 +2,54 @@ package chat.simplex.common.views.usersettings
|
||||
|
||||
import SectionBottomSpacer
|
||||
import SectionCustomFooter
|
||||
import SectionDividerSpaced
|
||||
import SectionItemView
|
||||
import SectionItemWithValue
|
||||
import SectionView
|
||||
import SectionViewSelectableCards
|
||||
import androidx.compose.desktop.ui.tooling.preview.Preview
|
||||
import androidx.compose.foundation.*
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
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.graphics.Color
|
||||
import androidx.compose.ui.graphics.painter.Painter
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import dev.icerock.moko.resources.compose.painterResource
|
||||
import dev.icerock.moko.resources.compose.stringResource
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import chat.simplex.common.model.*
|
||||
import chat.simplex.common.model.ChatController.appPrefs
|
||||
import chat.simplex.common.ui.theme.*
|
||||
import chat.simplex.common.views.helpers.*
|
||||
import chat.simplex.common.model.ChatModel
|
||||
import chat.simplex.common.model.ChatModel.controller
|
||||
import chat.simplex.common.platform.ColumnWithScrollBar
|
||||
import chat.simplex.common.platform.chatModel
|
||||
import chat.simplex.res.MR
|
||||
import java.text.DecimalFormat
|
||||
|
||||
@Composable
|
||||
fun AdvancedNetworkSettingsView(chatModel: ChatModel) {
|
||||
val currentCfg = remember { mutableStateOf(chatModel.controller.getNetCfg()) }
|
||||
fun ModalData.AdvancedNetworkSettingsView(showModal: (ModalData.() -> Unit) -> Unit, close: () -> Unit) {
|
||||
val currentRemoteHost by remember { chatModel.currentRemoteHost }
|
||||
val developerTools = remember { appPrefs.developerTools.get() }
|
||||
|
||||
// Will be actual once the screen is re-opened
|
||||
val savedCfg = remember { mutableStateOf(controller.getNetCfg()) }
|
||||
// Will have an edited state when the screen is re-opened
|
||||
val currentCfg = remember { stateGetOrPut("currentCfg") { controller.getNetCfg() } }
|
||||
val currentCfgVal = currentCfg.value // used only on initialization
|
||||
|
||||
val onionHosts = remember { mutableStateOf(currentCfgVal.onionHosts) }
|
||||
val sessionMode = remember { mutableStateOf(currentCfgVal.sessionMode) }
|
||||
val smpProxyMode = remember { mutableStateOf(currentCfgVal.smpProxyMode) }
|
||||
val smpProxyFallback = remember { mutableStateOf(currentCfgVal.smpProxyFallback) }
|
||||
|
||||
val networkUseSocksProxy: MutableState<Boolean> = remember { mutableStateOf(currentCfgVal.useSocksProxy) }
|
||||
val networkTCPConnectTimeout = remember { mutableStateOf(currentCfgVal.tcpConnectTimeout) }
|
||||
val networkTCPTimeout = remember { mutableStateOf(currentCfgVal.tcpTimeout) }
|
||||
val networkTCPTimeoutPerKb = remember { mutableStateOf(currentCfgVal.tcpTimeoutPerKb) }
|
||||
var networkRcvConcurrency = remember { mutableStateOf(currentCfgVal.rcvConcurrency) }
|
||||
val networkRcvConcurrency = remember { mutableStateOf(currentCfgVal.rcvConcurrency) }
|
||||
val networkSMPPingInterval = remember { mutableStateOf(currentCfgVal.smpPingInterval) }
|
||||
val networkSMPPingCount = remember { mutableStateOf(currentCfgVal.smpPingCount) }
|
||||
val networkEnableKeepAlive = remember { mutableStateOf(currentCfgVal.enableKeepAlive) }
|
||||
@@ -63,11 +78,11 @@ fun AdvancedNetworkSettingsView(chatModel: ChatModel) {
|
||||
}
|
||||
return NetCfg(
|
||||
socksProxy = currentCfg.value.socksProxy,
|
||||
hostMode = currentCfg.value.hostMode,
|
||||
requiredHostMode = currentCfg.value.requiredHostMode,
|
||||
sessionMode = currentCfg.value.sessionMode,
|
||||
smpProxyMode = currentCfg.value.smpProxyMode,
|
||||
smpProxyFallback = currentCfg.value.smpProxyFallback,
|
||||
// hostMode = currentCfg.value.hostMode,
|
||||
// requiredHostMode = currentCfg.value.requiredHostMode,
|
||||
sessionMode = sessionMode.value,
|
||||
smpProxyMode = smpProxyMode.value,
|
||||
smpProxyFallback = smpProxyFallback.value,
|
||||
tcpConnectTimeout = networkTCPConnectTimeout.value,
|
||||
tcpTimeout = networkTCPTimeout.value,
|
||||
tcpTimeoutPerKb = networkTCPTimeoutPerKb.value,
|
||||
@@ -75,10 +90,14 @@ fun AdvancedNetworkSettingsView(chatModel: ChatModel) {
|
||||
tcpKeepAlive = tcpKeepAlive,
|
||||
smpPingInterval = networkSMPPingInterval.value,
|
||||
smpPingCount = networkSMPPingCount.value
|
||||
)
|
||||
).withOnionHosts(onionHosts.value)
|
||||
}
|
||||
|
||||
fun updateView(cfg: NetCfg) {
|
||||
onionHosts.value = cfg.onionHosts
|
||||
sessionMode.value = cfg.sessionMode
|
||||
smpProxyMode.value = cfg.smpProxyMode
|
||||
smpProxyFallback.value = cfg.smpProxyFallback
|
||||
networkTCPConnectTimeout.value = cfg.tcpConnectTimeout
|
||||
networkTCPTimeout.value = cfg.tcpTimeout
|
||||
networkTCPTimeoutPerKb.value = cfg.tcpTimeoutPerKb
|
||||
@@ -97,40 +116,80 @@ fun AdvancedNetworkSettingsView(chatModel: ChatModel) {
|
||||
}
|
||||
}
|
||||
|
||||
fun saveCfg(cfg: NetCfg) {
|
||||
fun saveCfg(cfg: NetCfg, close: (() -> Unit)? = null) {
|
||||
withBGApi {
|
||||
chatModel.controller.apiSetNetworkConfig(cfg)
|
||||
currentCfg.value = cfg
|
||||
chatModel.controller.setNetCfg(cfg)
|
||||
if (chatModel.controller.apiSetNetworkConfig(cfg)) {
|
||||
currentCfg.value = cfg
|
||||
savedCfg.value = cfg
|
||||
chatModel.controller.setNetCfg(cfg)
|
||||
close?.invoke()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun reset() {
|
||||
val newCfg = if (currentCfg.value.useSocksProxy) NetCfg.proxyDefaults else NetCfg.defaults
|
||||
updateView(newCfg)
|
||||
saveCfg(newCfg)
|
||||
currentCfg.value = newCfg
|
||||
}
|
||||
|
||||
AdvancedNetworkSettingsLayout(
|
||||
networkTCPConnectTimeout,
|
||||
networkTCPTimeout,
|
||||
networkTCPTimeoutPerKb,
|
||||
networkRcvConcurrency,
|
||||
networkSMPPingInterval,
|
||||
networkSMPPingCount,
|
||||
networkEnableKeepAlive,
|
||||
networkTCPKeepIdle,
|
||||
networkTCPKeepIntvl,
|
||||
networkTCPKeepCnt,
|
||||
resetDisabled = if (currentCfg.value.useSocksProxy) currentCfg.value == NetCfg.proxyDefaults else currentCfg.value == NetCfg.defaults,
|
||||
reset = { showUpdateNetworkSettingsDialog(::reset) },
|
||||
footerDisabled = buildCfg() == currentCfg.value,
|
||||
revert = { updateView(currentCfg.value) },
|
||||
save = { showUpdateNetworkSettingsDialog { saveCfg(buildCfg()) } }
|
||||
)
|
||||
val saveDisabled = buildCfg() == savedCfg.value
|
||||
|
||||
ModalView(
|
||||
close = {
|
||||
if (saveDisabled) {
|
||||
close()
|
||||
} else {
|
||||
showUnsavedChangesAlert({
|
||||
saveCfg(buildCfg(), close)
|
||||
}, close)
|
||||
}
|
||||
},
|
||||
) {
|
||||
AdvancedNetworkSettingsLayout(
|
||||
currentRemoteHost = currentRemoteHost,
|
||||
networkUseSocksProxy = networkUseSocksProxy,
|
||||
developerTools = developerTools,
|
||||
onionHosts = onionHosts,
|
||||
useOnion = { onionHosts.value = it; currentCfg.value = currentCfg.value.withOnionHosts(it) },
|
||||
sessionMode = sessionMode,
|
||||
smpProxyMode = smpProxyMode,
|
||||
smpProxyFallback = smpProxyFallback,
|
||||
networkTCPConnectTimeout,
|
||||
networkTCPTimeout,
|
||||
networkTCPTimeoutPerKb,
|
||||
networkRcvConcurrency,
|
||||
networkSMPPingInterval,
|
||||
networkSMPPingCount,
|
||||
networkEnableKeepAlive,
|
||||
networkTCPKeepIdle,
|
||||
networkTCPKeepIntvl,
|
||||
networkTCPKeepCnt,
|
||||
updateSessionMode = { sessionMode.value = it; currentCfg.value = currentCfg.value.copy(sessionMode = it) },
|
||||
updateSMPProxyMode = { smpProxyMode.value = it; currentCfg.value = currentCfg.value.copy(smpProxyMode = it) },
|
||||
updateSMPProxyFallback = { smpProxyFallback.value = it; currentCfg.value = currentCfg.value.copy(smpProxyFallback = it) },
|
||||
showModal = showModal,
|
||||
resetDisabled = if (currentCfg.value.useSocksProxy) buildCfg() == NetCfg.proxyDefaults else buildCfg() == NetCfg.defaults,
|
||||
reset = ::reset,
|
||||
saveDisabled = saveDisabled,
|
||||
save = {
|
||||
showUpdateNetworkSettingsDialog {
|
||||
saveCfg(buildCfg())
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable fun AdvancedNetworkSettingsLayout(
|
||||
currentRemoteHost: RemoteHostInfo?,
|
||||
networkUseSocksProxy: State<Boolean>,
|
||||
developerTools: Boolean,
|
||||
onionHosts: MutableState<OnionHosts>,
|
||||
useOnion: (OnionHosts) -> Unit,
|
||||
sessionMode: MutableState<TransportSessionMode>,
|
||||
smpProxyMode: MutableState<SMPProxyMode>,
|
||||
smpProxyFallback: MutableState<SMPProxyFallback>,
|
||||
networkTCPConnectTimeout: MutableState<Long>,
|
||||
networkTCPTimeout: MutableState<Long>,
|
||||
networkTCPTimeoutPerKb: MutableState<Long>,
|
||||
@@ -141,10 +200,13 @@ fun AdvancedNetworkSettingsView(chatModel: ChatModel) {
|
||||
networkTCPKeepIdle: MutableState<Int>,
|
||||
networkTCPKeepIntvl: MutableState<Int>,
|
||||
networkTCPKeepCnt: MutableState<Int>,
|
||||
updateSessionMode: (TransportSessionMode) -> Unit,
|
||||
updateSMPProxyMode: (SMPProxyMode) -> Unit,
|
||||
updateSMPProxyFallback: (SMPProxyFallback) -> Unit,
|
||||
showModal: (ModalData.() -> Unit) -> Unit,
|
||||
resetDisabled: Boolean,
|
||||
reset: () -> Unit,
|
||||
footerDisabled: Boolean,
|
||||
revert: () -> Unit,
|
||||
saveDisabled: Boolean,
|
||||
save: () -> Unit
|
||||
) {
|
||||
val secondsLabel = stringResource(MR.strings.network_option_seconds_label)
|
||||
@@ -154,10 +216,39 @@ fun AdvancedNetworkSettingsView(chatModel: ChatModel) {
|
||||
.fillMaxWidth(),
|
||||
) {
|
||||
AppBarTitle(stringResource(MR.strings.network_settings_title))
|
||||
SectionView {
|
||||
SectionItemView {
|
||||
ResetToDefaultsButton(reset, disabled = resetDisabled)
|
||||
|
||||
if (currentRemoteHost == null) {
|
||||
SectionView(generalGetString(MR.strings.settings_section_title_private_message_routing)) {
|
||||
SMPProxyModePicker(smpProxyMode, showModal, updateSMPProxyMode)
|
||||
SMPProxyFallbackPicker(smpProxyFallback, showModal, updateSMPProxyFallback, enabled = remember { derivedStateOf { smpProxyMode.value != SMPProxyMode.Never } })
|
||||
SettingsPreferenceItem(painterResource(MR.images.ic_arrow_forward), stringResource(MR.strings.private_routing_show_message_status), chatModel.controller.appPrefs.showSentViaProxy)
|
||||
}
|
||||
SectionCustomFooter {
|
||||
Text(stringResource(MR.strings.private_routing_explanation))
|
||||
}
|
||||
SectionDividerSpaced(maxTopPadding = true)
|
||||
}
|
||||
|
||||
if (currentRemoteHost == null && networkUseSocksProxy.value) {
|
||||
SectionView(stringResource(MR.strings.network_socks_proxy).uppercase()) {
|
||||
UseOnionHosts(onionHosts, networkUseSocksProxy, showModal, useOnion)
|
||||
SectionCustomFooter {
|
||||
Column {
|
||||
Text(annotatedStringResource(MR.strings.disable_onion_hosts_when_not_supported))
|
||||
}
|
||||
}
|
||||
}
|
||||
SectionDividerSpaced(maxTopPadding = true)
|
||||
}
|
||||
|
||||
if (currentRemoteHost == null && developerTools) {
|
||||
SectionView(stringResource(MR.strings.network_session_mode_transport_isolation).uppercase()) {
|
||||
SessionModePicker(sessionMode, showModal, updateSessionMode)
|
||||
}
|
||||
SectionDividerSpaced()
|
||||
}
|
||||
|
||||
SectionView(stringResource(MR.strings.network_option_tcp_connection).uppercase()) {
|
||||
SectionItemView {
|
||||
TimeoutSettingRow(
|
||||
stringResource(MR.strings.network_option_tcp_connection_timeout), networkTCPConnectTimeout,
|
||||
@@ -220,23 +311,92 @@ fun AdvancedNetworkSettingsView(chatModel: ChatModel) {
|
||||
}
|
||||
}
|
||||
}
|
||||
SectionCustomFooter {
|
||||
SettingsSectionFooter(revert, save, footerDisabled)
|
||||
|
||||
SectionDividerSpaced(maxBottomPadding = false)
|
||||
|
||||
SectionView {
|
||||
SectionItemView(reset, disabled = resetDisabled) {
|
||||
Text(stringResource(MR.strings.network_options_reset_to_defaults), color = if (resetDisabled) MaterialTheme.colors.secondary else MaterialTheme.colors.primary)
|
||||
}
|
||||
SectionItemView(save, disabled = saveDisabled) {
|
||||
Text(stringResource(MR.strings.network_options_save_and_reconnect), color = if (saveDisabled) MaterialTheme.colors.secondary else MaterialTheme.colors.primary)
|
||||
}
|
||||
}
|
||||
SectionBottomSpacer()
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ResetToDefaultsButton(reset: () -> Unit, disabled: Boolean) {
|
||||
val modifier = if (disabled) Modifier else Modifier.clickable { reset() }
|
||||
Row(
|
||||
modifier.fillMaxSize(),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
val color = if (disabled) MaterialTheme.colors.secondary else MaterialTheme.colors.primary
|
||||
Text(stringResource(MR.strings.network_options_reset_to_defaults), color = color)
|
||||
private fun SMPProxyModePicker(
|
||||
smpProxyMode: MutableState<SMPProxyMode>,
|
||||
showModal: (@Composable ModalData.() -> Unit) -> Unit,
|
||||
updateSMPProxyMode: (SMPProxyMode) -> Unit,
|
||||
) {
|
||||
val density = LocalDensity.current
|
||||
val values = remember {
|
||||
SMPProxyMode.values().map {
|
||||
when (it) {
|
||||
SMPProxyMode.Always -> ValueTitleDesc(SMPProxyMode.Always, generalGetString(MR.strings.network_smp_proxy_mode_always), escapedHtmlToAnnotatedString(generalGetString(MR.strings.network_smp_proxy_mode_always_description), density))
|
||||
SMPProxyMode.Unknown -> ValueTitleDesc(SMPProxyMode.Unknown, generalGetString(MR.strings.network_smp_proxy_mode_unknown), escapedHtmlToAnnotatedString(generalGetString(MR.strings.network_smp_proxy_mode_unknown_description), density))
|
||||
SMPProxyMode.Unprotected -> ValueTitleDesc(SMPProxyMode.Unprotected, generalGetString(MR.strings.network_smp_proxy_mode_unprotected), escapedHtmlToAnnotatedString(generalGetString(MR.strings.network_smp_proxy_mode_unprotected_description), density))
|
||||
SMPProxyMode.Never -> ValueTitleDesc(SMPProxyMode.Never, generalGetString(MR.strings.network_smp_proxy_mode_never), escapedHtmlToAnnotatedString(generalGetString(MR.strings.network_smp_proxy_mode_never_description), density))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SectionItemWithValue(
|
||||
generalGetString(MR.strings.network_smp_proxy_mode_private_routing),
|
||||
smpProxyMode,
|
||||
values,
|
||||
icon = painterResource(MR.images.ic_settings_ethernet),
|
||||
onSelected = {
|
||||
showModal {
|
||||
ColumnWithScrollBar(
|
||||
Modifier.fillMaxWidth(),
|
||||
) {
|
||||
AppBarTitle(stringResource(MR.strings.network_smp_proxy_mode_private_routing))
|
||||
SectionViewSelectableCards(null, smpProxyMode, values, updateSMPProxyMode)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun SMPProxyFallbackPicker(
|
||||
smpProxyFallback: MutableState<SMPProxyFallback>,
|
||||
showModal: (@Composable ModalData.() -> Unit) -> Unit,
|
||||
updateSMPProxyFallback: (SMPProxyFallback) -> Unit,
|
||||
enabled: State<Boolean>,
|
||||
) {
|
||||
val density = LocalDensity.current
|
||||
val values = remember {
|
||||
SMPProxyFallback.values().map {
|
||||
when (it) {
|
||||
SMPProxyFallback.Allow -> ValueTitleDesc(SMPProxyFallback.Allow, generalGetString(MR.strings.network_smp_proxy_fallback_allow), escapedHtmlToAnnotatedString(generalGetString(MR.strings.network_smp_proxy_fallback_allow_description), density))
|
||||
SMPProxyFallback.AllowProtected -> ValueTitleDesc(SMPProxyFallback.AllowProtected, generalGetString(MR.strings.network_smp_proxy_fallback_allow_protected), escapedHtmlToAnnotatedString(generalGetString(MR.strings.network_smp_proxy_fallback_allow_protected_description), density))
|
||||
SMPProxyFallback.Prohibit -> ValueTitleDesc(SMPProxyFallback.Prohibit, generalGetString(MR.strings.network_smp_proxy_fallback_prohibit), escapedHtmlToAnnotatedString(generalGetString(MR.strings.network_smp_proxy_fallback_prohibit_description), density))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SectionItemWithValue(
|
||||
generalGetString(MR.strings.network_smp_proxy_fallback_allow_downgrade),
|
||||
smpProxyFallback,
|
||||
values,
|
||||
icon = painterResource(MR.images.ic_arrows_left_right),
|
||||
enabled = enabled,
|
||||
onSelected = {
|
||||
showModal {
|
||||
ColumnWithScrollBar(
|
||||
Modifier.fillMaxWidth(),
|
||||
) {
|
||||
AppBarTitle(stringResource(MR.strings.network_smp_proxy_fallback_allow_downgrade))
|
||||
SectionViewSelectableCards(null, smpProxyFallback, values, updateSMPProxyFallback)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
@@ -377,43 +537,6 @@ fun TimeoutSettingRow(title: String, selection: MutableState<Long>, values: List
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SettingsSectionFooter(revert: () -> Unit, save: () -> Unit, disabled: Boolean) {
|
||||
Row(
|
||||
Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
FooterButton(painterResource(MR.images.ic_replay), stringResource(MR.strings.network_options_revert), revert, disabled)
|
||||
FooterButton(painterResource(MR.images.ic_check), stringResource(MR.strings.network_options_save), save, disabled)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun FooterButton(icon: Painter, title: String, action: () -> Unit, disabled: Boolean) {
|
||||
Surface(
|
||||
shape = RoundedCornerShape(20.dp),
|
||||
color = Color.Black.copy(alpha = 0f),
|
||||
contentColor = LocalContentColor.current
|
||||
) {
|
||||
val modifier = if (disabled) Modifier else Modifier.clickable { action() }
|
||||
Row(
|
||||
modifier.padding(8.dp),
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
Icon(
|
||||
icon,
|
||||
title,
|
||||
tint = if (disabled) MaterialTheme.colors.secondary else MaterialTheme.colors.primary
|
||||
)
|
||||
Text(
|
||||
title,
|
||||
color = if (disabled) MaterialTheme.colors.secondary else MaterialTheme.colors.primary
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun showUpdateNetworkSettingsDialog(action: () -> Unit) {
|
||||
AlertManager.shared.showAlertDialog(
|
||||
title = generalGetString(MR.strings.update_network_settings_question),
|
||||
@@ -423,11 +546,27 @@ fun showUpdateNetworkSettingsDialog(action: () -> Unit) {
|
||||
)
|
||||
}
|
||||
|
||||
private fun showUnsavedChangesAlert(save: () -> Unit, revert: () -> Unit) {
|
||||
AlertManager.shared.showAlertDialogStacked(
|
||||
title = generalGetString(MR.strings.update_network_settings_question),
|
||||
confirmText = generalGetString(MR.strings.network_options_save_and_reconnect),
|
||||
dismissText = generalGetString(MR.strings.exit_without_saving),
|
||||
onConfirm = save,
|
||||
onDismiss = revert,
|
||||
)
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun PreviewAdvancedNetworkSettingsLayout() {
|
||||
SimpleXTheme {
|
||||
AdvancedNetworkSettingsLayout(
|
||||
currentRemoteHost = null,
|
||||
networkUseSocksProxy = remember { mutableStateOf(false) },
|
||||
developerTools = false,
|
||||
sessionMode = remember { mutableStateOf(TransportSessionMode.User) },
|
||||
smpProxyMode = remember { mutableStateOf(SMPProxyMode.Never) },
|
||||
smpProxyFallback = remember { mutableStateOf(SMPProxyFallback.Allow) },
|
||||
networkTCPConnectTimeout = remember { mutableStateOf(10_000000) },
|
||||
networkTCPTimeout = remember { mutableStateOf(10_000000) },
|
||||
networkTCPTimeoutPerKb = remember { mutableStateOf(10_000) },
|
||||
@@ -438,10 +577,15 @@ fun PreviewAdvancedNetworkSettingsLayout() {
|
||||
networkTCPKeepIdle = remember { mutableStateOf(10) },
|
||||
networkTCPKeepIntvl = remember { mutableStateOf(10) },
|
||||
networkTCPKeepCnt = remember { mutableStateOf(10) },
|
||||
onionHosts = remember { mutableStateOf(OnionHosts.PREFER) },
|
||||
useOnion = {},
|
||||
updateSessionMode = {},
|
||||
updateSMPProxyMode = {},
|
||||
updateSMPProxyFallback = {},
|
||||
showModal = {},
|
||||
resetDisabled = false,
|
||||
reset = {},
|
||||
footerDisabled = false,
|
||||
revert = {},
|
||||
saveDisabled = false,
|
||||
save = {}
|
||||
)
|
||||
}
|
||||
|
||||
+1
-4
@@ -36,10 +36,7 @@ fun CallSettingsLayout(
|
||||
callOnLockScreen: SharedPreference<CallOnLockScreen>,
|
||||
editIceServers: () -> Unit,
|
||||
) {
|
||||
ColumnWithScrollBar(
|
||||
Modifier.fillMaxWidth(),
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
ColumnWithScrollBar(Modifier.fillMaxWidth()) {
|
||||
AppBarTitle(stringResource(MR.strings.your_calls))
|
||||
val lockCallState = remember { mutableStateOf(callOnLockScreen.get()) }
|
||||
SectionView(stringResource(MR.strings.settings_section_title_settings)) {
|
||||
|
||||
+128
-374
@@ -7,9 +7,7 @@ import SectionItemView
|
||||
import SectionItemWithValue
|
||||
import SectionView
|
||||
import SectionViewSelectable
|
||||
import SectionViewSelectableCards
|
||||
import TextIconSpaced
|
||||
import androidx.compose.foundation.*
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.text.KeyboardActions
|
||||
import androidx.compose.material.*
|
||||
@@ -20,20 +18,17 @@ import androidx.compose.ui.Modifier
|
||||
import dev.icerock.moko.resources.compose.painterResource
|
||||
import dev.icerock.moko.resources.compose.stringResource
|
||||
import androidx.compose.ui.text.*
|
||||
import androidx.compose.ui.text.font.*
|
||||
import androidx.compose.ui.text.input.*
|
||||
import androidx.compose.desktop.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import chat.simplex.common.model.*
|
||||
import chat.simplex.common.model.ChatController.appPrefs
|
||||
import chat.simplex.common.model.ChatModel.controller
|
||||
import chat.simplex.common.platform.*
|
||||
import chat.simplex.common.ui.theme.*
|
||||
import chat.simplex.common.views.chat.item.ClickableText
|
||||
import chat.simplex.common.views.helpers.*
|
||||
import chat.simplex.common.views.helpers.annotatedStringResource
|
||||
import chat.simplex.res.MR
|
||||
|
||||
@Composable
|
||||
@@ -42,22 +37,11 @@ fun NetworkAndServersView() {
|
||||
// It's not a state, just a one-time value. Shouldn't be used in any state-related situations
|
||||
val netCfg = remember { chatModel.controller.getNetCfg() }
|
||||
val networkUseSocksProxy: MutableState<Boolean> = remember { mutableStateOf(netCfg.useSocksProxy) }
|
||||
val developerTools = chatModel.controller.appPrefs.developerTools.get()
|
||||
val onionHosts = remember { mutableStateOf(netCfg.onionHosts) }
|
||||
val sessionMode = remember { mutableStateOf(netCfg.sessionMode) }
|
||||
val smpProxyMode = remember { mutableStateOf(netCfg.smpProxyMode) }
|
||||
val smpProxyFallback = remember { mutableStateOf(netCfg.smpProxyFallback) }
|
||||
|
||||
val proxyPort = remember { derivedStateOf { chatModel.controller.appPrefs.networkProxyHostPort.state.value?.split(":")?.lastOrNull()?.toIntOrNull() ?: 9050 } }
|
||||
NetworkAndServersLayout(
|
||||
currentRemoteHost = currentRemoteHost,
|
||||
developerTools = developerTools,
|
||||
networkUseSocksProxy = networkUseSocksProxy,
|
||||
onionHosts = onionHosts,
|
||||
sessionMode = sessionMode,
|
||||
smpProxyMode = smpProxyMode,
|
||||
smpProxyFallback = smpProxyFallback,
|
||||
proxyPort = proxyPort,
|
||||
toggleSocksProxy = { enable ->
|
||||
val def = NetCfg.defaults
|
||||
val proxyDef = NetCfg.proxyDefaults
|
||||
@@ -84,7 +68,6 @@ fun NetworkAndServersView() {
|
||||
chatModel.controller.apiSetNetworkConfig(conf)
|
||||
chatModel.controller.setNetCfg(conf)
|
||||
networkUseSocksProxy.value = true
|
||||
onionHosts.value = conf.onionHosts
|
||||
}
|
||||
}
|
||||
)
|
||||
@@ -111,184 +94,48 @@ fun NetworkAndServersView() {
|
||||
chatModel.controller.apiSetNetworkConfig(conf)
|
||||
chatModel.controller.setNetCfg(conf)
|
||||
networkUseSocksProxy.value = false
|
||||
onionHosts.value = conf.onionHosts
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
},
|
||||
useOnion = {
|
||||
if (onionHosts.value == it) return@NetworkAndServersLayout
|
||||
val prevValue = onionHosts.value
|
||||
onionHosts.value = it
|
||||
val startsWith = when (it) {
|
||||
OnionHosts.NEVER -> generalGetString(MR.strings.network_use_onion_hosts_no_desc_in_alert)
|
||||
OnionHosts.PREFER -> generalGetString(MR.strings.network_use_onion_hosts_prefer_desc_in_alert)
|
||||
OnionHosts.REQUIRED -> generalGetString(MR.strings.network_use_onion_hosts_required_desc_in_alert)
|
||||
}
|
||||
showUpdateNetworkSettingsDialog(
|
||||
title = generalGetString(MR.strings.update_onion_hosts_settings_question),
|
||||
startsWith,
|
||||
onDismiss = {
|
||||
onionHosts.value = prevValue
|
||||
}
|
||||
) {
|
||||
withBGApi {
|
||||
val newCfg = chatModel.controller.getNetCfg().withOnionHosts(it)
|
||||
val res = chatModel.controller.apiSetNetworkConfig(newCfg)
|
||||
if (res) {
|
||||
chatModel.controller.setNetCfg(newCfg)
|
||||
onionHosts.value = it
|
||||
} else {
|
||||
onionHosts.value = prevValue
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
updateSessionMode = {
|
||||
if (sessionMode.value == it) return@NetworkAndServersLayout
|
||||
val prevValue = sessionMode.value
|
||||
sessionMode.value = it
|
||||
val startsWith = when (it) {
|
||||
TransportSessionMode.User -> generalGetString(MR.strings.network_session_mode_user_description)
|
||||
TransportSessionMode.Entity -> generalGetString(MR.strings.network_session_mode_entity_description)
|
||||
}
|
||||
showUpdateNetworkSettingsDialog(
|
||||
title = generalGetString(MR.strings.update_network_session_mode_question),
|
||||
startsWith,
|
||||
onDismiss = { sessionMode.value = prevValue }
|
||||
) {
|
||||
withBGApi {
|
||||
val newCfg = chatModel.controller.getNetCfg().copy(sessionMode = it)
|
||||
val res = chatModel.controller.apiSetNetworkConfig(newCfg)
|
||||
if (res) {
|
||||
chatModel.controller.setNetCfg(newCfg)
|
||||
sessionMode.value = it
|
||||
} else {
|
||||
sessionMode.value = prevValue
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
updateSMPProxyMode = {
|
||||
if (smpProxyMode.value == it) return@NetworkAndServersLayout
|
||||
val prevValue = smpProxyMode.value
|
||||
smpProxyMode.value = it
|
||||
val startsWith = when (it) {
|
||||
SMPProxyMode.Always -> generalGetString(MR.strings.network_smp_proxy_mode_always_description)
|
||||
SMPProxyMode.Unknown -> generalGetString(MR.strings.network_smp_proxy_mode_unknown_description)
|
||||
SMPProxyMode.Unprotected -> generalGetString(MR.strings.network_smp_proxy_mode_unprotected_description)
|
||||
SMPProxyMode.Never -> generalGetString(MR.strings.network_smp_proxy_mode_never_description)
|
||||
}
|
||||
showUpdateNetworkSettingsDialog(
|
||||
title = generalGetString(MR.strings.update_network_smp_proxy_mode_question),
|
||||
startsWith,
|
||||
onDismiss = { smpProxyMode.value = prevValue }
|
||||
) {
|
||||
withBGApi {
|
||||
val newCfg = chatModel.controller.getNetCfg().copy(smpProxyMode = it)
|
||||
val res = chatModel.controller.apiSetNetworkConfig(newCfg)
|
||||
if (res) {
|
||||
chatModel.controller.setNetCfg(newCfg)
|
||||
smpProxyMode.value = it
|
||||
} else {
|
||||
smpProxyMode.value = prevValue
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
updateSMPProxyFallback = {
|
||||
if (smpProxyFallback.value == it) return@NetworkAndServersLayout
|
||||
val prevValue = smpProxyFallback.value
|
||||
smpProxyFallback.value = it
|
||||
val startsWith = when (it) {
|
||||
SMPProxyFallback.Allow -> generalGetString(MR.strings.network_smp_proxy_fallback_allow_description)
|
||||
SMPProxyFallback.AllowProtected -> generalGetString(MR.strings.network_smp_proxy_fallback_allow_protected_description)
|
||||
SMPProxyFallback.Prohibit -> generalGetString(MR.strings.network_smp_proxy_fallback_prohibit_description)
|
||||
}
|
||||
showUpdateNetworkSettingsDialog(
|
||||
title = generalGetString(MR.strings.update_network_smp_proxy_fallback_question),
|
||||
startsWith,
|
||||
onDismiss = { smpProxyFallback.value = prevValue }
|
||||
) {
|
||||
withBGApi {
|
||||
val newCfg = chatModel.controller.getNetCfg().copy(smpProxyFallback = it)
|
||||
val res = chatModel.controller.apiSetNetworkConfig(newCfg)
|
||||
if (res) {
|
||||
chatModel.controller.setNetCfg(newCfg)
|
||||
smpProxyFallback.value = it
|
||||
} else {
|
||||
smpProxyFallback.value = prevValue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@Composable fun NetworkAndServersLayout(
|
||||
currentRemoteHost: RemoteHostInfo?,
|
||||
developerTools: Boolean,
|
||||
networkUseSocksProxy: MutableState<Boolean>,
|
||||
onionHosts: MutableState<OnionHosts>,
|
||||
sessionMode: MutableState<TransportSessionMode>,
|
||||
smpProxyMode: MutableState<SMPProxyMode>,
|
||||
smpProxyFallback: MutableState<SMPProxyFallback>,
|
||||
proxyPort: State<Int>,
|
||||
toggleSocksProxy: (Boolean) -> Unit,
|
||||
useOnion: (OnionHosts) -> Unit,
|
||||
updateSessionMode: (TransportSessionMode) -> Unit,
|
||||
updateSMPProxyMode: (SMPProxyMode) -> Unit,
|
||||
updateSMPProxyFallback: (SMPProxyFallback) -> Unit,
|
||||
) {
|
||||
val m = chatModel
|
||||
ColumnWithScrollBar(
|
||||
Modifier.fillMaxWidth(),
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
ColumnWithScrollBar(Modifier.fillMaxWidth()) {
|
||||
val showModal = { it: @Composable ModalData.() -> Unit -> ModalManager.start.showModal(content = it) }
|
||||
val showCustomModal = { it: @Composable (close: () -> Unit) -> Unit -> ModalManager.start.showCustomModal { close -> it(close) }}
|
||||
|
||||
AppBarTitle(stringResource(MR.strings.network_and_servers))
|
||||
if (!chatModel.desktopNoUserNoRemote) {
|
||||
SectionView(generalGetString(MR.strings.settings_section_title_messages)) {
|
||||
SettingsActionItem(painterResource(MR.images.ic_dns), stringResource(MR.strings.smp_servers), { ModalManager.start.showCustomModal { close -> ProtocolServersView(m, m.remoteHostId, ServerProtocol.SMP, close) } })
|
||||
SettingsActionItem(painterResource(MR.images.ic_dns), stringResource(MR.strings.message_servers), { ModalManager.start.showCustomModal { close -> ProtocolServersView(m, m.remoteHostId, ServerProtocol.SMP, close) } })
|
||||
|
||||
SettingsActionItem(painterResource(MR.images.ic_dns), stringResource(MR.strings.xftp_servers), { ModalManager.start.showCustomModal { close -> ProtocolServersView(m, m.remoteHostId, ServerProtocol.XFTP, close) } })
|
||||
SettingsActionItem(painterResource(MR.images.ic_dns), stringResource(MR.strings.media_and_file_servers), { ModalManager.start.showCustomModal { close -> ProtocolServersView(m, m.remoteHostId, ServerProtocol.XFTP, close) } })
|
||||
|
||||
if (currentRemoteHost == null) {
|
||||
UseSocksProxySwitch(networkUseSocksProxy, proxyPort, toggleSocksProxy, showModal, chatModel.controller.appPrefs.networkProxyHostPort, false)
|
||||
UseOnionHosts(onionHosts, networkUseSocksProxy, showModal, useOnion)
|
||||
if (developerTools) {
|
||||
SessionModePicker(sessionMode, showModal, updateSessionMode)
|
||||
UseSocksProxySwitch(networkUseSocksProxy, toggleSocksProxy)
|
||||
SettingsActionItem(painterResource(MR.images.ic_settings_ethernet), stringResource(MR.strings.network_socks_proxy_settings), { showCustomModal { SocksProxySettings(networkUseSocksProxy.value, appPrefs.networkProxyHostPort, false, it) }})
|
||||
SettingsActionItem(painterResource(MR.images.ic_cable), stringResource(MR.strings.network_settings), { ModalManager.start.showCustomModal { AdvancedNetworkSettingsView(showModal, it) } })
|
||||
if (networkUseSocksProxy.value) {
|
||||
SectionCustomFooter {
|
||||
Column {
|
||||
Text(annotatedStringResource(MR.strings.socks_proxy_setting_limitations))
|
||||
}
|
||||
}
|
||||
SectionDividerSpaced(maxTopPadding = true)
|
||||
} else {
|
||||
SectionDividerSpaced()
|
||||
}
|
||||
SettingsActionItem(painterResource(MR.images.ic_cable), stringResource(MR.strings.network_settings), { ModalManager.start.showModal { AdvancedNetworkSettingsView(m) } })
|
||||
}
|
||||
}
|
||||
}
|
||||
if (currentRemoteHost == null && networkUseSocksProxy.value) {
|
||||
SectionCustomFooter {
|
||||
Column {
|
||||
Text(annotatedStringResource(MR.strings.disable_onion_hosts_when_not_supported))
|
||||
Spacer(Modifier.height(DEFAULT_PADDING_HALF))
|
||||
Text(annotatedStringResource(MR.strings.socks_proxy_setting_limitations))
|
||||
}
|
||||
}
|
||||
Divider(Modifier.padding(start = DEFAULT_PADDING_HALF, top = 32.dp, end = DEFAULT_PADDING_HALF, bottom = 30.dp))
|
||||
} else if (!chatModel.desktopNoUserNoRemote) {
|
||||
Divider(Modifier.padding(start = DEFAULT_PADDING_HALF, top = 24.dp, end = DEFAULT_PADDING_HALF, bottom = 30.dp))
|
||||
}
|
||||
|
||||
if (currentRemoteHost == null) {
|
||||
SectionView(generalGetString(MR.strings.settings_section_title_private_message_routing)) {
|
||||
SMPProxyModePicker(smpProxyMode, showModal, updateSMPProxyMode)
|
||||
SMPProxyFallbackPicker(smpProxyFallback, showModal, updateSMPProxyFallback, enabled = remember { mutableStateOf(smpProxyMode.value != SMPProxyMode.Never) })
|
||||
SettingsPreferenceItem(painterResource(MR.images.ic_arrow_forward), stringResource(MR.strings.private_routing_show_message_status), chatModel.controller.appPrefs.showSentViaProxy)
|
||||
}
|
||||
SectionCustomFooter {
|
||||
Text(stringResource(MR.strings.private_routing_explanation))
|
||||
}
|
||||
Divider(Modifier.padding(start = DEFAULT_PADDING_HALF, top = 32.dp, end = DEFAULT_PADDING_HALF, bottom = 30.dp))
|
||||
}
|
||||
|
||||
SectionView(generalGetString(MR.strings.settings_section_title_calls)) {
|
||||
SettingsActionItem(painterResource(MR.images.ic_electrical_services), stringResource(MR.strings.webrtc_ice_servers), { ModalManager.start.showModal { RTCServersView(m) } })
|
||||
@@ -313,13 +160,14 @@ fun NetworkAndServersView() {
|
||||
onionHosts: MutableState<OnionHosts>,
|
||||
sessionMode: MutableState<TransportSessionMode>,
|
||||
networkProxyHostPort: SharedPreference<String?>,
|
||||
proxyPort: State<Int>,
|
||||
toggleSocksProxy: (Boolean) -> Unit,
|
||||
useOnion: (OnionHosts) -> Unit,
|
||||
updateSessionMode: (TransportSessionMode) -> Unit,
|
||||
) {
|
||||
val showModal = { it: @Composable ModalData.() -> Unit -> ModalManager.fullscreen.showModal(content = it) }
|
||||
UseSocksProxySwitch(networkUseSocksProxy, proxyPort, toggleSocksProxy, showModal, networkProxyHostPort, true)
|
||||
val showCustomModal = { it: @Composable (close: () -> Unit) -> Unit -> ModalManager.fullscreen.showCustomModal { close -> it(close) }}
|
||||
UseSocksProxySwitch(networkUseSocksProxy, toggleSocksProxy)
|
||||
SettingsActionItem(painterResource(MR.images.ic_settings_ethernet), stringResource(MR.strings.network_socks_proxy_settings), { showCustomModal { SocksProxySettings(networkUseSocksProxy.value, networkProxyHostPort, true, it) } })
|
||||
UseOnionHosts(onionHosts, networkUseSocksProxy, showModal, useOnion)
|
||||
if (developerTools) {
|
||||
SessionModePicker(sessionMode, showModal, updateSessionMode)
|
||||
@@ -329,11 +177,7 @@ fun NetworkAndServersView() {
|
||||
@Composable
|
||||
fun UseSocksProxySwitch(
|
||||
networkUseSocksProxy: MutableState<Boolean>,
|
||||
proxyPort: State<Int>,
|
||||
toggleSocksProxy: (Boolean) -> Unit,
|
||||
showModal: (@Composable ModalData.() -> Unit) -> Unit,
|
||||
networkProxyHostPort: SharedPreference<String?> = chatModel.controller.appPrefs.networkProxyHostPort,
|
||||
migration: Boolean = false,
|
||||
) {
|
||||
Row(
|
||||
Modifier.fillMaxWidth().padding(end = DEFAULT_PADDING),
|
||||
@@ -350,32 +194,7 @@ fun UseSocksProxySwitch(
|
||||
tint = MaterialTheme.colors.secondary
|
||||
)
|
||||
TextIconSpaced(false)
|
||||
val text = buildAnnotatedString {
|
||||
append(generalGetString(MR.strings.network_socks_toggle_use_socks_proxy) + " (")
|
||||
val style = SpanStyle(color = MaterialTheme.colors.primary)
|
||||
val disabledStyle = SpanStyle(color = MaterialTheme.colors.onBackground)
|
||||
withAnnotation(tag = "PORT", annotation = generalGetString(MR.strings.network_proxy_port).format(proxyPort.value)) {
|
||||
withStyle(if (networkUseSocksProxy.value || !migration) style else disabledStyle) {
|
||||
append(generalGetString(MR.strings.network_proxy_port).format(proxyPort.value))
|
||||
}
|
||||
}
|
||||
append(")")
|
||||
}
|
||||
ClickableText(
|
||||
text,
|
||||
style = TextStyle(color = MaterialTheme.colors.onBackground, fontSize = 16.sp, fontFamily = Inter, fontWeight = FontWeight.Normal),
|
||||
onClick = { offset ->
|
||||
text.getStringAnnotations(tag = "PORT", start = offset, end = offset)
|
||||
.firstOrNull()?.let { _ ->
|
||||
if (networkUseSocksProxy.value || !migration) {
|
||||
showModal { SockProxySettings(chatModel, networkProxyHostPort, migration) }
|
||||
}
|
||||
}
|
||||
},
|
||||
shouldConsumeEvent = { offset ->
|
||||
text.getStringAnnotations(tag = "PORT", start = offset, end = offset).any()
|
||||
}
|
||||
)
|
||||
Text(generalGetString(MR.strings.network_socks_toggle_use_socks_proxy))
|
||||
}
|
||||
DefaultSwitch(
|
||||
checked = networkUseSocksProxy.value,
|
||||
@@ -385,94 +204,124 @@ fun UseSocksProxySwitch(
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SockProxySettings(
|
||||
m: ChatModel,
|
||||
networkProxyHostPort: SharedPreference<String?> = m.controller.appPrefs.networkProxyHostPort,
|
||||
fun SocksProxySettings(
|
||||
networkUseSocksProxy: Boolean,
|
||||
networkProxyHostPort: SharedPreference<String?> = appPrefs.networkProxyHostPort,
|
||||
migration: Boolean,
|
||||
close: () -> Unit
|
||||
) {
|
||||
ColumnWithScrollBar(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
) {
|
||||
val defaultHostPort = remember { "localhost:9050" }
|
||||
AppBarTitle(generalGetString(MR.strings.network_socks_proxy_settings))
|
||||
val hostPortSaved by remember { networkProxyHostPort.state }
|
||||
val hostUnsaved = rememberSaveable(stateSaver = TextFieldValue.Saver) {
|
||||
mutableStateOf(TextFieldValue(hostPortSaved?.split(":")?.firstOrNull() ?: "localhost"))
|
||||
}
|
||||
val portUnsaved = rememberSaveable(stateSaver = TextFieldValue.Saver) {
|
||||
mutableStateOf(TextFieldValue(hostPortSaved?.split(":")?.lastOrNull() ?: "9050"))
|
||||
}
|
||||
val save = {
|
||||
val defaultHostPort = remember { "localhost:9050" }
|
||||
val hostPortSaved by remember { networkProxyHostPort.state }
|
||||
val hostUnsaved = rememberSaveable(stateSaver = TextFieldValue.Saver) {
|
||||
mutableStateOf(TextFieldValue(hostPortSaved?.split(":")?.firstOrNull() ?: "localhost"))
|
||||
}
|
||||
val portUnsaved = rememberSaveable(stateSaver = TextFieldValue.Saver) {
|
||||
mutableStateOf(TextFieldValue(hostPortSaved?.split(":")?.lastOrNull() ?: "9050"))
|
||||
}
|
||||
val save = {
|
||||
val oldValue = networkProxyHostPort.get()
|
||||
networkProxyHostPort.set(hostUnsaved.value.text + ":" + portUnsaved.value.text)
|
||||
if (networkUseSocksProxy && !migration) {
|
||||
withBGApi {
|
||||
networkProxyHostPort.set(hostUnsaved.value.text + ":" + portUnsaved.value.text)
|
||||
if (m.controller.appPrefs.networkUseSocksProxy.get() && !migration) {
|
||||
m.controller.apiSetNetworkConfig(m.controller.getNetCfg())
|
||||
if (!controller.apiSetNetworkConfig(controller.getNetCfg())) {
|
||||
networkProxyHostPort.set(oldValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
SectionView {
|
||||
SectionItemView {
|
||||
ResetToDefaultsButton({
|
||||
val reset = {
|
||||
networkProxyHostPort.set(defaultHostPort)
|
||||
val newHost = defaultHostPort.split(":").first()
|
||||
val newPort = defaultHostPort.split(":").last()
|
||||
hostUnsaved.value = hostUnsaved.value.copy(newHost, TextRange(newHost.length))
|
||||
portUnsaved.value = portUnsaved.value.copy(newPort, TextRange(newPort.length))
|
||||
save()
|
||||
}
|
||||
if (m.controller.appPrefs.networkUseSocksProxy.get() && !migration) {
|
||||
showUpdateNetworkSettingsDialog {
|
||||
reset()
|
||||
}
|
||||
} else {
|
||||
reset()
|
||||
}
|
||||
}, disabled = hostPortSaved == defaultHostPort)
|
||||
}
|
||||
SectionItemView {
|
||||
DefaultConfigurableTextField(
|
||||
hostUnsaved,
|
||||
stringResource(MR.strings.host_verb),
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
isValid = ::validHost,
|
||||
keyboardActions = KeyboardActions(onNext = { defaultKeyboardAction(ImeAction.Next) }),
|
||||
keyboardType = KeyboardType.Text,
|
||||
)
|
||||
}
|
||||
SectionItemView {
|
||||
DefaultConfigurableTextField(
|
||||
portUnsaved,
|
||||
stringResource(MR.strings.port_verb),
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
isValid = ::validPort,
|
||||
keyboardActions = KeyboardActions(onDone = { defaultKeyboardAction(ImeAction.Done); save() }),
|
||||
keyboardType = KeyboardType.Number,
|
||||
)
|
||||
}
|
||||
val saveAndClose = {
|
||||
val oldValue = networkProxyHostPort.get()
|
||||
networkProxyHostPort.set(hostUnsaved.value.text + ":" + portUnsaved.value.text)
|
||||
if (networkUseSocksProxy && !migration) {
|
||||
withBGApi {
|
||||
if (controller.apiSetNetworkConfig(controller.getNetCfg())) {
|
||||
close()
|
||||
} else {
|
||||
networkProxyHostPort.set(oldValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
SectionCustomFooter {
|
||||
NetworkSectionFooter(
|
||||
revert = {
|
||||
val prevHost = hostPortSaved?.split(":")?.firstOrNull() ?: "localhost"
|
||||
val prevPort = hostPortSaved?.split(":")?.lastOrNull() ?: "9050"
|
||||
hostUnsaved.value = hostUnsaved.value.copy(prevHost, TextRange(prevHost.length))
|
||||
portUnsaved.value = portUnsaved.value.copy(prevPort, TextRange(prevPort.length))
|
||||
},
|
||||
save = { if (m.controller.appPrefs.networkUseSocksProxy.get() && !migration) showUpdateNetworkSettingsDialog { save() } else save() },
|
||||
revertDisabled = hostPortSaved == (hostUnsaved.value.text + ":" + portUnsaved.value.text),
|
||||
saveDisabled = hostPortSaved == (hostUnsaved.value.text + ":" + portUnsaved.value.text) ||
|
||||
remember { derivedStateOf { !validHost(hostUnsaved.value.text) } }.value ||
|
||||
remember { derivedStateOf { !validPort(portUnsaved.value.text) } }.value
|
||||
)
|
||||
}
|
||||
val saveDisabled = hostPortSaved == (hostUnsaved.value.text + ":" + portUnsaved.value.text) ||
|
||||
remember { derivedStateOf { !validHost(hostUnsaved.value.text) } }.value ||
|
||||
remember { derivedStateOf { !validPort(portUnsaved.value.text) } }.value
|
||||
val resetDisabled = hostUnsaved.value.text + ":" + portUnsaved.value.text == defaultHostPort
|
||||
ModalView(
|
||||
close = {
|
||||
if (saveDisabled) {
|
||||
close()
|
||||
} else {
|
||||
showUnsavedSocksHostPortAlert(
|
||||
confirmText = generalGetString(if (networkUseSocksProxy && !migration) MR.strings.network_options_save_and_reconnect else MR.strings.network_options_save),
|
||||
save = saveAndClose,
|
||||
close = close
|
||||
)
|
||||
}
|
||||
},
|
||||
) {
|
||||
ColumnWithScrollBar(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
) {
|
||||
AppBarTitle(generalGetString(MR.strings.network_socks_proxy_settings))
|
||||
SectionView {
|
||||
SectionItemView {
|
||||
DefaultConfigurableTextField(
|
||||
hostUnsaved,
|
||||
stringResource(MR.strings.host_verb),
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
isValid = ::validHost,
|
||||
keyboardActions = KeyboardActions(onNext = { defaultKeyboardAction(ImeAction.Next) }),
|
||||
keyboardType = KeyboardType.Text,
|
||||
)
|
||||
}
|
||||
SectionItemView {
|
||||
DefaultConfigurableTextField(
|
||||
portUnsaved,
|
||||
stringResource(MR.strings.port_verb),
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
isValid = ::validPort,
|
||||
keyboardActions = KeyboardActions(onDone = { defaultKeyboardAction(ImeAction.Done); save() }),
|
||||
keyboardType = KeyboardType.Number,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Divider(Modifier.padding(start = DEFAULT_PADDING_HALF, top = 27.dp, end = DEFAULT_PADDING_HALF, bottom = 30.dp))
|
||||
|
||||
SectionView {
|
||||
SectionItemView({
|
||||
val newHost = defaultHostPort.split(":").first()
|
||||
val newPort = defaultHostPort.split(":").last()
|
||||
hostUnsaved.value = hostUnsaved.value.copy(newHost, TextRange(newHost.length))
|
||||
portUnsaved.value = portUnsaved.value.copy(newPort, TextRange(newPort.length))
|
||||
}, disabled = resetDisabled) {
|
||||
Text(stringResource(MR.strings.network_options_reset_to_defaults), color = if (resetDisabled) MaterialTheme.colors.secondary else MaterialTheme.colors.primary)
|
||||
}
|
||||
SectionItemView(
|
||||
click = { if (networkUseSocksProxy && !migration) showUpdateNetworkSettingsDialog { save() } else save() },
|
||||
disabled = saveDisabled
|
||||
) {
|
||||
Text(stringResource(if (networkUseSocksProxy && !migration) MR.strings.network_options_save_and_reconnect else MR.strings.network_options_save), color = if (saveDisabled) MaterialTheme.colors.secondary else MaterialTheme.colors.primary)
|
||||
}
|
||||
}
|
||||
SectionBottomSpacer()
|
||||
}
|
||||
SectionBottomSpacer()
|
||||
}
|
||||
}
|
||||
|
||||
private fun showUnsavedSocksHostPortAlert(confirmText: String, save: () -> Unit, close: () -> Unit) {
|
||||
AlertManager.shared.showAlertDialogStacked(
|
||||
title = generalGetString(MR.strings.update_network_settings_question),
|
||||
confirmText = confirmText,
|
||||
dismissText = generalGetString(MR.strings.exit_without_saving),
|
||||
onConfirm = save,
|
||||
onDismiss = close,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun UseOnionHosts(
|
||||
fun UseOnionHosts(
|
||||
onionHosts: MutableState<OnionHosts>,
|
||||
enabled: State<Boolean>,
|
||||
showModal: (@Composable ModalData.() -> Unit) -> Unit,
|
||||
@@ -521,7 +370,7 @@ private fun UseOnionHosts(
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun SessionModePicker(
|
||||
fun SessionModePicker(
|
||||
sessionMode: MutableState<TransportSessionMode>,
|
||||
showModal: (@Composable ModalData.() -> Unit) -> Unit,
|
||||
updateSessionMode: (TransportSessionMode) -> Unit,
|
||||
@@ -554,91 +403,6 @@ private fun SessionModePicker(
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun SMPProxyModePicker(
|
||||
smpProxyMode: MutableState<SMPProxyMode>,
|
||||
showModal: (@Composable ModalData.() -> Unit) -> Unit,
|
||||
updateSMPProxyMode: (SMPProxyMode) -> Unit,
|
||||
) {
|
||||
val density = LocalDensity.current
|
||||
val values = remember {
|
||||
SMPProxyMode.values().map {
|
||||
when (it) {
|
||||
SMPProxyMode.Always -> ValueTitleDesc(SMPProxyMode.Always, generalGetString(MR.strings.network_smp_proxy_mode_always), escapedHtmlToAnnotatedString(generalGetString(MR.strings.network_smp_proxy_mode_always_description), density))
|
||||
SMPProxyMode.Unknown -> ValueTitleDesc(SMPProxyMode.Unknown, generalGetString(MR.strings.network_smp_proxy_mode_unknown), escapedHtmlToAnnotatedString(generalGetString(MR.strings.network_smp_proxy_mode_unknown_description), density))
|
||||
SMPProxyMode.Unprotected -> ValueTitleDesc(SMPProxyMode.Unprotected, generalGetString(MR.strings.network_smp_proxy_mode_unprotected), escapedHtmlToAnnotatedString(generalGetString(MR.strings.network_smp_proxy_mode_unprotected_description), density))
|
||||
SMPProxyMode.Never -> ValueTitleDesc(SMPProxyMode.Never, generalGetString(MR.strings.network_smp_proxy_mode_never), escapedHtmlToAnnotatedString(generalGetString(MR.strings.network_smp_proxy_mode_never_description), density))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SectionItemWithValue(
|
||||
generalGetString(MR.strings.network_smp_proxy_mode_private_routing),
|
||||
smpProxyMode,
|
||||
values,
|
||||
icon = painterResource(MR.images.ic_settings_ethernet),
|
||||
onSelected = {
|
||||
showModal {
|
||||
ColumnWithScrollBar(
|
||||
Modifier.fillMaxWidth(),
|
||||
) {
|
||||
AppBarTitle(stringResource(MR.strings.network_smp_proxy_mode_private_routing))
|
||||
SectionViewSelectableCards(null, smpProxyMode, values, updateSMPProxyMode)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun SMPProxyFallbackPicker(
|
||||
smpProxyFallback: MutableState<SMPProxyFallback>,
|
||||
showModal: (@Composable ModalData.() -> Unit) -> Unit,
|
||||
updateSMPProxyFallback: (SMPProxyFallback) -> Unit,
|
||||
enabled: State<Boolean>,
|
||||
) {
|
||||
val density = LocalDensity.current
|
||||
val values = remember {
|
||||
SMPProxyFallback.values().map {
|
||||
when (it) {
|
||||
SMPProxyFallback.Allow -> ValueTitleDesc(SMPProxyFallback.Allow, generalGetString(MR.strings.network_smp_proxy_fallback_allow), escapedHtmlToAnnotatedString(generalGetString(MR.strings.network_smp_proxy_fallback_allow_description), density))
|
||||
SMPProxyFallback.AllowProtected -> ValueTitleDesc(SMPProxyFallback.AllowProtected, generalGetString(MR.strings.network_smp_proxy_fallback_allow_protected), escapedHtmlToAnnotatedString(generalGetString(MR.strings.network_smp_proxy_fallback_allow_protected_description), density))
|
||||
SMPProxyFallback.Prohibit -> ValueTitleDesc(SMPProxyFallback.Prohibit, generalGetString(MR.strings.network_smp_proxy_fallback_prohibit), escapedHtmlToAnnotatedString(generalGetString(MR.strings.network_smp_proxy_fallback_prohibit_description), density))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SectionItemWithValue(
|
||||
generalGetString(MR.strings.network_smp_proxy_fallback_allow_downgrade),
|
||||
smpProxyFallback,
|
||||
values,
|
||||
icon = painterResource(MR.images.ic_arrows_left_right),
|
||||
enabled = enabled,
|
||||
onSelected = {
|
||||
showModal {
|
||||
ColumnWithScrollBar(
|
||||
Modifier.fillMaxWidth(),
|
||||
) {
|
||||
AppBarTitle(stringResource(MR.strings.network_smp_proxy_fallback_allow_downgrade))
|
||||
SectionViewSelectableCards(null, smpProxyFallback, values, updateSMPProxyFallback)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun NetworkSectionFooter(revert: () -> Unit, save: () -> Unit, revertDisabled: Boolean, saveDisabled: Boolean) {
|
||||
Row(
|
||||
Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
FooterButton(painterResource(MR.images.ic_replay), stringResource(MR.strings.network_options_revert), revert, revertDisabled)
|
||||
FooterButton(painterResource(MR.images.ic_check), stringResource(MR.strings.network_options_save), save, saveDisabled)
|
||||
}
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/a/106223
|
||||
private fun validHost(s: String): Boolean {
|
||||
val validIp = Regex("^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])[.]){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$")
|
||||
@@ -652,7 +416,7 @@ fun validPort(s: String): Boolean {
|
||||
return s.isNotBlank() && s.matches(validPort)
|
||||
}
|
||||
|
||||
private fun showUpdateNetworkSettingsDialog(
|
||||
fun showUpdateNetworkSettingsDialog(
|
||||
title: String,
|
||||
startsWith: String = "",
|
||||
message: String = generalGetString(MR.strings.updating_settings_will_reconnect_client_to_all_servers),
|
||||
@@ -675,18 +439,8 @@ fun PreviewNetworkAndServersLayout() {
|
||||
SimpleXTheme {
|
||||
NetworkAndServersLayout(
|
||||
currentRemoteHost = null,
|
||||
developerTools = true,
|
||||
networkUseSocksProxy = remember { mutableStateOf(true) },
|
||||
proxyPort = remember { mutableStateOf(9050) },
|
||||
toggleSocksProxy = {},
|
||||
onionHosts = remember { mutableStateOf(OnionHosts.PREFER) },
|
||||
sessionMode = remember { mutableStateOf(TransportSessionMode.User) },
|
||||
smpProxyMode = remember { mutableStateOf(SMPProxyMode.Never) },
|
||||
smpProxyFallback = remember { mutableStateOf(SMPProxyFallback.Allow) },
|
||||
useOnion = {},
|
||||
updateSessionMode = {},
|
||||
updateSMPProxyMode = {},
|
||||
updateSMPProxyFallback = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -112,7 +112,7 @@ fun SettingsLayout(
|
||||
Modifier
|
||||
.fillMaxSize()
|
||||
.themedBackground(theme.value.base)
|
||||
.padding(top = if (appPlatform.isAndroid) DEFAULT_PADDING else DEFAULT_PADDING * 3)
|
||||
.padding(top = if (appPlatform.isAndroid) DEFAULT_PADDING else DEFAULT_PADDING * 2.8f)
|
||||
) {
|
||||
AppBarTitle(stringResource(MR.strings.your_settings))
|
||||
|
||||
|
||||
@@ -773,7 +773,6 @@
|
||||
<string name="old_database_archive">أرشيف قاعدة البيانات القديمة</string>
|
||||
<string name="feature_off">غير مفعّل</string>
|
||||
<string name="one_time_link">رابط دعوة لمرة واحدة</string>
|
||||
<string name="network_use_onion_hosts_required_desc_in_alert">سوف تكون مضيفات البصل مطلوبة للاتصال.</string>
|
||||
<string name="group_member_role_observer">المراقب</string>
|
||||
<string name="item_info_no_text">لا يوجد نص</string>
|
||||
<string name="new_member_role">دور عضو جديد</string>
|
||||
@@ -789,8 +788,6 @@
|
||||
<string name="network_use_onion_hosts_no">لا</string>
|
||||
<string name="network_use_onion_hosts_required_desc">سوف تكون مضيفات البصل مطلوبة للاتصال.
|
||||
\nيُرجى ملاحظة: أنك لن تتمكن من الاتصال بالخوادم بدون عنوان onion.</string>
|
||||
<string name="network_use_onion_hosts_prefer_desc_in_alert">سيتم استخدام مضيفات البصل عند توفرها.</string>
|
||||
<string name="network_use_onion_hosts_no_desc_in_alert">لن يتم استخدام مضيفات البصل.</string>
|
||||
<string name="self_destruct_new_display_name">اسم عرض جديد:</string>
|
||||
<string name="new_passphrase">عبارة مرور جديدة…</string>
|
||||
<string name="icon_descr_server_status_pending">قيد الانتظار</string>
|
||||
@@ -892,7 +889,6 @@
|
||||
<string name="info_row_updated_at">حٌديثت السجل في</string>
|
||||
<string name="share_text_updated_at">حٌديثت السجل في: %s</string>
|
||||
<string name="restore_database_alert_confirm">استعادة</string>
|
||||
<string name="network_options_revert">إرجاع</string>
|
||||
<string name="v4_4_live_messages_desc">يرى المستلمون التحديثات أثناء كتابتها.</string>
|
||||
<string name="feature_received_prohibited">استلمت، ممنوع</string>
|
||||
<string name="save_servers_button">حفظ</string>
|
||||
@@ -1165,7 +1161,6 @@
|
||||
<string name="your_chat_profiles">ملفات تعريف الدردشة الخاصة بك</string>
|
||||
<string name="your_simplex_contact_address">عنوان SimpleX الخاص بك</string>
|
||||
<string name="your_SMP_servers">خوادم SMP الخاصة بك</string>
|
||||
<string name="update_onion_hosts_settings_question">هل تريد تحديث إعداد مضيفي onion.؟</string>
|
||||
<string name="onboarding_notifications_mode_off">عندما يكون التطبيق قيد التشغيل</string>
|
||||
<string name="call_connection_via_relay">عبر المُرحل</string>
|
||||
<string name="you_joined_this_group">لقد انضممت إلى هذه المجموعة</string>
|
||||
|
||||
@@ -707,6 +707,7 @@
|
||||
<string name="send_us_an_email">Send us email</string>
|
||||
<string name="chat_lock">SimpleX Lock</string>
|
||||
<string name="chat_console">Chat console</string>
|
||||
<string name="message_servers">Message servers</string>
|
||||
<string name="smp_servers">SMP servers</string>
|
||||
<string name="smp_servers_configured">Configured SMP servers</string>
|
||||
<string name="smp_servers_other">Other SMP servers</string>
|
||||
@@ -731,6 +732,8 @@
|
||||
<string name="smp_servers_delete_server">Delete server</string>
|
||||
<string name="smp_servers_per_user">The servers for new connections of your current chat profile</string>
|
||||
<string name="smp_save_servers_question">Save servers?</string>
|
||||
<string name="update_network_settings_question">Update network settings?</string>
|
||||
<string name="media_and_file_servers">Media & file servers</string>
|
||||
<string name="xftp_servers">XFTP servers</string>
|
||||
<string name="xftp_servers_configured">Configured XFTP servers</string>
|
||||
<string name="xftp_servers_other">Other XFTP servers</string>
|
||||
@@ -754,7 +757,8 @@
|
||||
<string name="save_servers_button">Save</string>
|
||||
<string name="network_and_servers">Network & servers</string>
|
||||
<string name="network_settings">Advanced network settings</string>
|
||||
<string name="network_settings_title">Network settings</string>
|
||||
<string name="network_settings_title">Advanced settings</string>
|
||||
<string name="network_socks_proxy">SOCKS proxy</string>
|
||||
<string name="network_socks_proxy_settings">SOCKS proxy settings</string>
|
||||
<string name="network_socks_toggle_use_socks_proxy">Use SOCKS proxy</string>
|
||||
<string name="network_proxy_port">port %d</string>
|
||||
@@ -764,7 +768,6 @@
|
||||
<string name="network_enable_socks_info">Access the servers via SOCKS proxy on port %d? Proxy must be started before enabling this option.</string>
|
||||
<string name="network_disable_socks">Use direct Internet connection?</string>
|
||||
<string name="network_disable_socks_info">If you confirm, the messaging servers will be able to see your IP address, and your provider - which servers you are connecting to.</string>
|
||||
<string name="update_onion_hosts_settings_question">Update .onion hosts setting?</string>
|
||||
<string name="network_use_onion_hosts">Use .onion hosts</string>
|
||||
<string name="network_use_onion_hosts_prefer">When available</string>
|
||||
<string name="network_use_onion_hosts_no">No</string>
|
||||
@@ -772,9 +775,6 @@
|
||||
<string name="network_use_onion_hosts_prefer_desc">Onion hosts will be used when available.</string>
|
||||
<string name="network_use_onion_hosts_no_desc">Onion hosts will not be used.</string>
|
||||
<string name="network_use_onion_hosts_required_desc">Onion hosts will be required for connection.\nPlease note: you will not be able to connect to the servers without .onion address.</string>
|
||||
<string name="network_use_onion_hosts_prefer_desc_in_alert">Onion hosts will be used when available.</string>
|
||||
<string name="network_use_onion_hosts_no_desc_in_alert">Onion hosts will not be used.</string>
|
||||
<string name="network_use_onion_hosts_required_desc_in_alert">Onion hosts will be required for connection.</string>
|
||||
<string name="network_session_mode_transport_isolation">Transport isolation</string>
|
||||
<string name="network_session_mode_user">Chat profile</string>
|
||||
<string name="network_session_mode_entity">Connection</string>
|
||||
@@ -785,7 +785,7 @@
|
||||
<string name="socks_proxy_setting_limitations"><![CDATA[<b>Please note</b>: message and file relays are connected via SOCKS proxy. Calls and sending link previews use direct connection.]]></string>
|
||||
<string name="network_smp_proxy_mode_private_routing">Private routing</string>
|
||||
<string name="network_smp_proxy_mode_always">Always</string>
|
||||
<string name="network_smp_proxy_mode_unknown">Unknown relays</string>
|
||||
<string name="network_smp_proxy_mode_unknown">Unknown servers</string>
|
||||
<string name="network_smp_proxy_mode_unprotected">Unprotected</string>
|
||||
<string name="network_smp_proxy_mode_never">Never</string>
|
||||
<string name="network_smp_proxy_mode_always_description">Always use private routing.</string>
|
||||
@@ -1196,7 +1196,7 @@
|
||||
<string name="error_importing_database">Error importing chat database</string>
|
||||
<string name="chat_database_imported">Chat database imported</string>
|
||||
<string name="restart_the_app_to_use_imported_chat_database">Restart the app to use imported chat database.</string>
|
||||
<string name="non_fatal_errors_occured_during_import">Some non-fatal errors occurred during import - you may see Chat console for more details.</string>
|
||||
<string name="non_fatal_errors_occured_during_import">Some non-fatal errors occurred during import:</string>
|
||||
<string name="delete_chat_profile_question">Delete chat profile?</string>
|
||||
<string name="delete_chat_profile_action_cannot_be_undone_warning">This action cannot be undone - your profile, contacts, messages and files will be irreversibly lost.</string>
|
||||
<string name="chat_database_deleted">Chat database deleted</string>
|
||||
@@ -1222,6 +1222,11 @@
|
||||
<string name="enable_automatic_deletion_message">This action cannot be undone - the messages sent and received earlier than selected will be deleted. It may take several minutes.</string>
|
||||
<string name="delete_messages">Delete messages</string>
|
||||
<string name="error_changing_message_deletion">Error changing setting</string>
|
||||
<string name="chat_database_exported_title">Chat database exported</string>
|
||||
<string name="chat_database_exported_save">You may save the exported archive.</string>
|
||||
<string name="chat_database_exported_migrate">You may migrate the exported database.</string>
|
||||
<string name="chat_database_exported_not_all_files">Some file(s) were not exported</string>
|
||||
<string name="chat_database_exported_continue">Continue</string>
|
||||
|
||||
<!-- DatabaseEncryptionView.kt -->
|
||||
<string name="save_passphrase_in_keychain">Save passphrase in Keystore</string>
|
||||
@@ -1607,6 +1612,7 @@
|
||||
<string name="error_saving_group_profile">Error saving group profile</string>
|
||||
|
||||
<!-- AdvancedNetworkSettings.kt -->
|
||||
<string name="network_option_tcp_connection">TCP connection</string>
|
||||
<string name="network_options_reset_to_defaults">Reset to defaults</string>
|
||||
<string name="network_option_seconds_label">sec</string>
|
||||
<string name="network_option_tcp_connection_timeout">TCP connection timeout</string>
|
||||
@@ -1616,8 +1622,8 @@
|
||||
<string name="network_option_ping_interval">PING interval</string>
|
||||
<string name="network_option_ping_count">PING count</string>
|
||||
<string name="network_option_enable_tcp_keep_alive">Enable TCP keep-alive</string>
|
||||
<string name="network_options_revert">Revert</string>
|
||||
<string name="network_options_save">Save</string>
|
||||
<string name="network_options_save_and_reconnect">Save and reconnect</string>
|
||||
<string name="update_network_settings_question">Update network settings?</string>
|
||||
<string name="updating_settings_will_reconnect_client_to_all_servers">Updating settings will re-connect the client to all servers.</string>
|
||||
<string name="update_network_settings_confirmation">Update</string>
|
||||
|
||||
@@ -800,13 +800,11 @@
|
||||
<string name="network_settings_title">Мрежови настройки</string>
|
||||
<string name="port_verb">Порт</string>
|
||||
<string name="network_proxy_port">порт %d</string>
|
||||
<string name="network_use_onion_hosts_no_desc_in_alert">Няма се използват Onion хостове.</string>
|
||||
<string name="network_use_onion_hosts_required">Задължително</string>
|
||||
<string name="network_use_onion_hosts_no">Не</string>
|
||||
<string name="network_use_onion_hosts_required_desc">За свързване ще са необходими Onion хостове.
|
||||
\nМоля, обърнете внимание: няма да можете да се свържете със сървърите без .onion адрес.</string>
|
||||
<string name="network_use_onion_hosts_prefer_desc">Ще се използват Onion хостове, когато са налични.</string>
|
||||
<string name="network_use_onion_hosts_prefer_desc_in_alert">Ще се използват Onion хостове, когато са налични.</string>
|
||||
<string name="network_use_onion_hosts_no_desc">Няма се използват Onion хостове.</string>
|
||||
<string name="email_invite_subject">Нека да поговорим в SimpleX Chat</string>
|
||||
<string name="password_to_show">Парола за показване</string>
|
||||
@@ -878,7 +876,6 @@
|
||||
<string name="no_selected_chat">Няма избран чат</string>
|
||||
<string name="notifications">Известия</string>
|
||||
<string name="shutdown_alert_desc">Известията ще спрат да работят, докато не стартирате отново приложението</string>
|
||||
<string name="network_use_onion_hosts_required_desc_in_alert">За свързване ще са необходими Onion хостове.</string>
|
||||
<string name="images_limit_desc">Само 10 изображения могат да бъдат изпратени едновременно</string>
|
||||
<string name="only_owners_can_enable_files_and_media">Само собствениците на групата могат да активират файлове и медията.</string>
|
||||
<string name="only_group_owners_can_enable_voice">Само собствениците на групата могат да активират гласови съобщения.</string>
|
||||
@@ -1147,7 +1144,6 @@
|
||||
<string name="icon_descr_speaker_off">Високоговорителят е изключен</string>
|
||||
<string name="stop_chat_to_enable_database_actions">Спрете чата, за да активирате действията с базата данни.</string>
|
||||
<string name="role_in_group">Роля</string>
|
||||
<string name="network_options_revert">Отмени промените</string>
|
||||
<string name="network_options_save">Запази</string>
|
||||
<string name="reset_color">Нулирай цветовете</string>
|
||||
<string name="color_secondary">Вторичен</string>
|
||||
@@ -1225,7 +1221,6 @@
|
||||
<string name="your_SMP_servers">Вашите SMP сървъри</string>
|
||||
<string name="network_socks_toggle_use_socks_proxy">Използвай SOCKS прокси</string>
|
||||
<string name="network_enable_socks">Използвай SOCKS прокси\?</string>
|
||||
<string name="update_onion_hosts_settings_question">Актуализиране на настройката за .onion хостове\?</string>
|
||||
<string name="network_disable_socks">Използване на директна интернет връзка\?</string>
|
||||
<string name="network_use_onion_hosts">Използвай .onion хостове</string>
|
||||
<string name="network_use_onion_hosts_prefer">Когато са налични</string>
|
||||
|
||||
@@ -228,7 +228,6 @@
|
||||
<string name="network_enable_socks">Použít proxy server SOCKS\?</string>
|
||||
<string name="network_disable_socks">Použít přímé připojení k internetu\?</string>
|
||||
<string name="network_use_onion_hosts_no">Ne</string>
|
||||
<string name="network_use_onion_hosts_no_desc_in_alert">Onion hostitelé nebudou použiti.</string>
|
||||
<string name="network_session_mode_user">Chat profil</string>
|
||||
<string name="network_session_mode_entity">Připojení</string>
|
||||
<string name="core_simplexmq_version">simplexmq: v%s (%2s)</string>
|
||||
@@ -357,7 +356,6 @@
|
||||
<string name="no_contacts_selected">Nebyl vybrán žádný kontakt</string>
|
||||
<string name="invite_prohibited_description">Snažíte se pozvat kontakt, se kterým jste sdíleli inkognito profil, do skupiny, ve které používáte svůj hlavní profil</string>
|
||||
<string name="info_row_group">Skupina</string>
|
||||
<string name="network_options_revert">Vrátit</string>
|
||||
<string name="updating_settings_will_reconnect_client_to_all_servers">Aktualizací nastavení se klient znovu připojí ke všem serverům.</string>
|
||||
<string name="accept_feature_set_1_day">Nastavit 1 den</string>
|
||||
<string name="connection_error_auth">Chyba spojení (AUTH)</string>
|
||||
@@ -629,14 +627,11 @@
|
||||
<string name="ensure_ICE_server_address_are_correct_format_and_unique">Ujistěte se, že adresy serverů WebRTC ICE jsou ve správném formátu, oddělené na řádcích a nejsou duplicitní.</string>
|
||||
<string name="save_servers_button">Uložit</string>
|
||||
<string name="network_and_servers">Síť a servery</string>
|
||||
<string name="update_onion_hosts_settings_question">Aktualizovat nastavení hostitelů .onion\?</string>
|
||||
<string name="network_use_onion_hosts">Použít hostitele .onion</string>
|
||||
<string name="network_use_onion_hosts_prefer">Když bude dostupný</string>
|
||||
<string name="network_use_onion_hosts_required">Povinné</string>
|
||||
<string name="network_use_onion_hosts_prefer_desc">Onion hostitelé budou použiti, pokud jsou k dispozici.</string>
|
||||
<string name="network_use_onion_hosts_no_desc">Onion hostitelé nebudou použiti.</string>
|
||||
<string name="network_use_onion_hosts_prefer_desc_in_alert">Onion hostitelé budou použiti, pokud jsou k dispozici.</string>
|
||||
<string name="network_use_onion_hosts_required_desc_in_alert">Pro připojení budou vyžadováni Onion hostitelé.</string>
|
||||
<string name="network_session_mode_transport_isolation">Izolace přenosu</string>
|
||||
<string name="network_session_mode_user_description"><![CDATA[A separate TCP connection (and SOCKS credential) will be used <b>for each chat profile you have in the app</b>.]]></string>
|
||||
<string name="network_session_mode_entity_description">Oddělit TCP připojení (a SOCKS pověření) bude použito <b>pro všechny kontakty a členy skupin</b>.
|
||||
|
||||
@@ -396,7 +396,6 @@
|
||||
<string name="network_enable_socks_info">Zugriff auf die Server über SOCKS-Proxy auf Port %d? Der Proxy muss gestartet werden, bevor diese Option aktiviert wird.</string>
|
||||
<string name="network_disable_socks">Direkte Internetverbindung verwenden?</string>
|
||||
<string name="network_disable_socks_info">Wenn Sie dies bestätigen, können die Messaging-Server Ihre IP-Adresse sowie Ihren Provider sehen und mit welchen Servern Sie sich verbinden.</string>
|
||||
<string name="update_onion_hosts_settings_question">Einstellung für .onion-Hosts aktualisieren?</string>
|
||||
<string name="network_use_onion_hosts">Verwende .onion-Hosts</string>
|
||||
<string name="network_use_onion_hosts_prefer">Wenn verfügbar</string>
|
||||
<string name="network_use_onion_hosts_no">Nein</string>
|
||||
@@ -405,9 +404,6 @@
|
||||
<string name="network_use_onion_hosts_no_desc">Onion-Hosts werden nicht verwendet.</string>
|
||||
<string name="network_use_onion_hosts_required_desc">Für die Verbindung werden Onion-Hosts benötigt.
|
||||
\nBitte beachten Sie: Ohne .onion-Adresse können Sie keine Verbindung mit den Servern herstellen.</string>
|
||||
<string name="network_use_onion_hosts_prefer_desc_in_alert">Wenn Onion-Hosts verfügbar sind, werden sie verwendet.</string>
|
||||
<string name="network_use_onion_hosts_no_desc_in_alert">Onion-Hosts werden nicht verwendet.</string>
|
||||
<string name="network_use_onion_hosts_required_desc_in_alert">Für die Verbindung werden Onion-Hosts benötigt.</string>
|
||||
<string name="appearance_settings">Erscheinungsbild</string>
|
||||
<!-- Address Items - UserAddressView.kt -->
|
||||
<string name="create_address">Adresse erstellen</string>
|
||||
@@ -826,7 +822,6 @@
|
||||
<string name="network_option_protocol_timeout">Protokollzeitüberschreitung</string>
|
||||
<string name="network_option_ping_interval">PING-Intervall</string>
|
||||
<string name="network_option_enable_tcp_keep_alive">TCP-Keep-Alive aktivieren</string>
|
||||
<string name="network_options_revert">Zurücksetzen</string>
|
||||
<string name="network_options_save">Speichern</string>
|
||||
<string name="update_network_settings_question">Netzwerkeinstellungen aktualisieren?</string>
|
||||
<string name="updating_settings_will_reconnect_client_to_all_servers">Die Aktualisierung der Einstellungen wird den Client wieder mit allen Servern verbinden.</string>
|
||||
|
||||
@@ -447,7 +447,6 @@
|
||||
<string name="ensure_smp_server_address_are_correct_format_and_unique">Asegúrate de que las direcciones del servidor SMP tienen el formato correcto, están separadas por líneas y no están duplicadas.</string>
|
||||
<string name="icon_descr_instant_notifications">Notificación instantánea</string>
|
||||
<string name="network_settings_title">Configuración de red</string>
|
||||
<string name="network_use_onion_hosts_no_desc_in_alert">No se usarán hosts .onion</string>
|
||||
<string name="only_client_devices_store_contacts_groups_e2e_encrypted_messages"><![CDATA[Sólo los dispositivos cliente almacenan perfiles de usuario, contactos, grupos y mensajes enviados con <b>cifrado de extremo a extremo de 2 capas</b> .]]></string>
|
||||
<string name="onboarding_notifications_mode_subtitle">Puedes cambiar estos ajustes más tarde en Configuración.</string>
|
||||
<string name="onboarding_notifications_mode_service">Instantánea</string>
|
||||
@@ -466,7 +465,6 @@
|
||||
<string name="notification_preview_mode_message">Contacto y texto</string>
|
||||
<string name="member_info_section_title_member">MIEMBRO</string>
|
||||
<string name="chat_item_ttl_none">nunca</string>
|
||||
<string name="network_use_onion_hosts_required_desc_in_alert">Se requieren hosts .onion para la conexión</string>
|
||||
<string name="network_use_onion_hosts_no_desc">No se usarán hosts .onion</string>
|
||||
<string name="settings_notification_preview_title">Vista previa de notificaciones</string>
|
||||
<string name="alert_title_group_invitation_expired">¡Invitación caducada!</string>
|
||||
@@ -511,7 +509,6 @@
|
||||
<string name="ensure_ICE_server_address_are_correct_format_and_unique">Asegúrate de que las direcciones del servidor WebRTC ICE tienen el formato correcto, están separadas por líneas y no duplicadas.</string>
|
||||
<string name="network_use_onion_hosts_required_desc">Se requieren hosts .onion para la conexión
|
||||
\nRecuerda: no podrás conectarte a servidores que no tengan dirección .onion.</string>
|
||||
<string name="network_use_onion_hosts_prefer_desc_in_alert">Se usarán hosts .onion si están disponibles.</string>
|
||||
<string name="immune_to_spam_and_abuse">Inmune a spam y abuso</string>
|
||||
<string name="many_people_asked_how_can_it_deliver"><![CDATA[Muchos se preguntarán: <i>si SimpleX no tiene identificadores de usuario, ¿cómo puede entregar los mensajes\?</i>]]></string>
|
||||
<string name="incoming_video_call">Videollamada entrante</string>
|
||||
@@ -636,7 +633,6 @@
|
||||
<string name="save_and_notify_contacts">Guardar y notificar contactos</string>
|
||||
<string name="opensource_protocol_and_code_anybody_can_run_servers">Protocolo y código abiertos: cualquiera puede usar los servidores.</string>
|
||||
<string name="role_in_group">Rol</string>
|
||||
<string name="network_options_revert">Revertir</string>
|
||||
<string name="network_option_ping_interval">Intervalo PING</string>
|
||||
<string name="network_option_ping_count">Contador PING</string>
|
||||
<string name="only_your_contact_can_delete">Sólo tu contacto puede eliminar mensajes de forma irreversible (tu puedes marcarlos para eliminar). (24 horas)</string>
|
||||
@@ -800,7 +796,6 @@
|
||||
<string name="star_on_github">Estrella en GitHub</string>
|
||||
<string name="smp_servers_per_user">Lista de servidores para las conexiones nuevas de tu perfil actual</string>
|
||||
<string name="network_disable_socks">¿Usar conexión directa a Internet\?</string>
|
||||
<string name="update_onion_hosts_settings_question">¿Actualizar la configuración de los hosts .onion\?</string>
|
||||
<string name="profile_is_only_shared_with_your_contacts">El perfil sólo se comparte con tus contactos.</string>
|
||||
<string name="callstate_starting">inicializando…</string>
|
||||
<string name="alert_title_skipped_messages">Mensajes omitidos</string>
|
||||
|
||||
@@ -588,7 +588,6 @@
|
||||
<string name="network_use_onion_hosts_required_desc">میزبانهای Onion برای اتصال الزامی خواهد بود.
|
||||
\nلطفا توجه داشته باشید: شما بدون نشانی onion. قادر نخواهید بود به سرورها متصل شوید.</string>
|
||||
<string name="save_servers_button">ذخیره</string>
|
||||
<string name="update_onion_hosts_settings_question">تنظیمات میزبانهای onion. به روز شود؟</string>
|
||||
<string name="port_verb">پورت</string>
|
||||
<string name="network_enable_socks">از پروکسی SOCKS استفاده شود؟</string>
|
||||
<string name="network_disable_socks">از اتصال مستقیم اینترنت استفاده شود؟</string>
|
||||
@@ -597,7 +596,6 @@
|
||||
<string name="host_verb">هاست</string>
|
||||
<string name="network_use_onion_hosts_required">الزامی</string>
|
||||
<string name="network_use_onion_hosts_prefer_desc">از میزبانهای Onion وقتی موجود باشند استفاده خواهد شد.</string>
|
||||
<string name="network_use_onion_hosts_prefer_desc_in_alert">از میزبانهای Onion وقتی موجود باشند استفاده خواهد شد.</string>
|
||||
<string name="appearance_settings">ظاهر</string>
|
||||
<string name="app_version_name">نسخه برنامه: v%s</string>
|
||||
<string name="show_developer_options">نمایش گزینههای توسعهدهنده</string>
|
||||
@@ -608,7 +606,6 @@
|
||||
<string name="network_session_mode_user_description"><![CDATA[یک اتصال جدای TCP (و اطلاعات ورود SOCKS) <b>برای هر نمایه گپی که در برنامه دارید</b> استفاده خواهد شد.]]></string>
|
||||
<string name="show_internal_errors">نمایش خطاهای داخلی</string>
|
||||
<string name="show_slow_api_calls">نمایش تماسهای کند API</string>
|
||||
<string name="network_use_onion_hosts_no_desc_in_alert">از میزبانهای Onion استفاده نخواهد شد.</string>
|
||||
<string name="network_use_onion_hosts_no">خیر</string>
|
||||
<string name="disable_onion_hosts_when_not_supported"><![CDATA[<i>استفاده از میزبانهای onion.</i> را روی «خیر» تنظیم کنید اگر پروکسی SOCKS از آنها پشتیبانی نمیکند.]]></string>
|
||||
<string name="customize_theme_title">سفارشی کردن تم</string>
|
||||
@@ -630,7 +627,6 @@
|
||||
<string name="network_session_mode_entity">اتصال</string>
|
||||
<string name="app_version_code">ساختار برنامه: %s</string>
|
||||
<string name="network_settings_title">تنظیمات شبکه</string>
|
||||
<string name="network_use_onion_hosts_required_desc_in_alert">میزبانهای Onion برای اتصال الزامی خواهد بود.</string>
|
||||
<string name="show_dev_options">نمایش:</string>
|
||||
<string name="socks_proxy_setting_limitations"><![CDATA[<b>لطفا توجه داشته باشید</b>: واسطههای پیام و پرونده از طریق پروکسی SOCKS متصل میشوند. تماسها و ارسال پیشنمایشهای لینک از اتصال مستقیم استفاده میکنند.]]></string>
|
||||
<string name="developer_options_section">گزینههای توسعهدهنده</string>
|
||||
@@ -1313,7 +1309,6 @@
|
||||
<string name="network_option_ping_interval">وقفه پینگ</string>
|
||||
<string name="network_option_ping_count">شمار پینگ</string>
|
||||
<string name="network_option_enable_tcp_keep_alive">فعال کردن زنده نگهداشتن TCP</string>
|
||||
<string name="network_options_revert">برگشت</string>
|
||||
<string name="network_options_save">ذخیره</string>
|
||||
<string name="update_network_settings_question">تنظیمات شبکه بهروزرسانی شود؟</string>
|
||||
<string name="users_add">افزودن نمایه</string>
|
||||
|
||||
@@ -623,7 +623,6 @@
|
||||
<string name="text_field_set_contact_placeholder">Aseta kontaktin nimi…</string>
|
||||
<string name="save_passphrase_in_keychain">Tallenna salasana Keystoreen</string>
|
||||
<string name="only_your_contact_can_send_disappearing">Vain kontaktisi voi lähettää katoavia viestejä.</string>
|
||||
<string name="network_use_onion_hosts_prefer_desc_in_alert">Onion-isäntiä käytetään, kun niitä on saatavilla.</string>
|
||||
<string name="port_verb">Portti</string>
|
||||
<string name="network_proxy_port">portti %d</string>
|
||||
<string name="disable_onion_hosts_when_not_supported"><![CDATA[Aseta <i>Use .onion hosts</i> arvoon Ei, jos SOCKS-välityspalvelin ei tue niitä.]]></string>
|
||||
@@ -661,7 +660,6 @@
|
||||
<string name="network_option_tcp_connection_timeout">TCP-yhteyden aikakatkaisu</string>
|
||||
<string name="network_option_ping_count">PING-määrä</string>
|
||||
<string name="network_option_ping_interval">PING-väli</string>
|
||||
<string name="network_options_revert">Palauta</string>
|
||||
<string name="users_delete_with_connections">Profiili- ja palvelinyhteydet</string>
|
||||
<string name="set_group_preferences">Aseta ryhmän asetukset</string>
|
||||
<string name="many_people_asked_how_can_it_deliver"><![CDATA[Monet ovat kysyneet: <i>jos SimpleX ei sisällä käyttäjätunnuksia, kuinka se voi toimittaa viestejä\?</i>]]></string>
|
||||
@@ -916,8 +914,6 @@
|
||||
<string name="thank_you_for_installing_simplex">Kiitos SimpleX Chatin asentamisesta!</string>
|
||||
<string name="icon_descr_settings">Asetukset</string>
|
||||
<string name="icon_descr_more_button">Lisää</string>
|
||||
<string name="network_use_onion_hosts_no_desc_in_alert">Onion-isäntiä ei käytetä.</string>
|
||||
<string name="network_use_onion_hosts_required_desc_in_alert">Yhteyden muodostamiseen tarvitaan Onion-isäntiä.</string>
|
||||
<string name="onboarding_notifications_mode_title">Yksityiset ilmoitukset</string>
|
||||
<string name="icon_descr_speaker_off">Kaiutin pois päältä</string>
|
||||
<string name="icon_descr_speaker_on">Kaiutin päällä</string>
|
||||
@@ -1156,7 +1152,6 @@
|
||||
\nkontakteillesi</string>
|
||||
<string name="your_ICE_servers">ICE-palvelimesi</string>
|
||||
<string name="network_use_onion_hosts_prefer">Kun saatavilla</string>
|
||||
<string name="update_onion_hosts_settings_question">Päivitä .onion-isäntien asetus\?</string>
|
||||
<string name="network_use_onion_hosts">Käytä .onion-isäntiä</string>
|
||||
<string name="your_calls">Puhelusi</string>
|
||||
<string name="alert_message_no_group">Tätä ryhmää ei enää ole olemassa.</string>
|
||||
|
||||
@@ -321,8 +321,6 @@
|
||||
<string name="ensure_ICE_server_address_are_correct_format_and_unique">Assurez-vous que les adresses des serveurs WebRTC ICE sont au bon format et ne sont pas dupliquées, un par ligne.</string>
|
||||
<string name="network_enable_socks_info">Accéder aux serveurs via un proxy SOCKS sur le port %d \? Le proxy doit être démarré avant d\'activer cette option.</string>
|
||||
<string name="network_use_onion_hosts">Utiliser les hôtes .onions</string>
|
||||
<string name="network_use_onion_hosts_prefer_desc_in_alert">Les hôtes .onion seront utilisés lorsqu\'ils sont disponibles.</string>
|
||||
<string name="network_use_onion_hosts_required_desc_in_alert">Les hôtes .onion seront nécessaires pour la connexion.</string>
|
||||
<string name="you_control_servers_to_receive_your_contacts_to_send"><![CDATA[Vous contrôlez par quel·s serveur·s vous pouvez <b>transmettre</b> ainsi que par quel·s serveur·s vous pouvez <b>recevoir</b> les messages de vos contacts.]]></string>
|
||||
<string name="your_settings">Vos paramètres</string>
|
||||
<string name="chat_lock">SimpleX Lock</string>
|
||||
@@ -414,12 +412,10 @@
|
||||
<string name="how_to">Comment faire</string>
|
||||
<string name="enter_one_ICE_server_per_line">Serveurs ICE (un par ligne)</string>
|
||||
<string name="error_saving_ICE_servers">Erreur lors de la sauvegarde des serveurs ICE</string>
|
||||
<string name="update_onion_hosts_settings_question">Mettre à jour le paramètre des hôtes .onion \?</string>
|
||||
<string name="network_use_onion_hosts_prefer">Quand disponible</string>
|
||||
<string name="network_use_onion_hosts_no_desc">Les hôtes .onion ne seront pas utilisés.</string>
|
||||
<string name="network_use_onion_hosts_required_desc">Les hôtes .onion seront nécessaires pour la connexion.
|
||||
\nAttention : vous ne pourrez pas vous connecter aux serveurs sans adresse .onion.</string>
|
||||
<string name="network_use_onion_hosts_no_desc_in_alert">Les hôtes .onion ne seront pas utilisés.</string>
|
||||
<string name="delete_address__question">Supprimer l\'adresse \?</string>
|
||||
<string name="all_your_contacts_will_remain_connected">Tous vos contacts resteront connectés.</string>
|
||||
<string name="share_link">Partager le lien</string>
|
||||
@@ -833,7 +829,6 @@
|
||||
<string name="conn_level_desc_direct">directe</string>
|
||||
<string name="group_is_decentralized">Entièrement décentralisé – visible que par ses membres.</string>
|
||||
<string name="group_members_can_send_disappearing">Les membres du groupes peuvent envoyer des messages éphémères.</string>
|
||||
<string name="network_options_revert">Revenir en arrière</string>
|
||||
<string name="prohibit_sending_disappearing_messages">Interdire l’envoi de messages éphémères.</string>
|
||||
<string name="incognito_info_protects">Le mode incognito protège votre vie privée en utilisant un nouveau profil aléatoire pour chaque contact.</string>
|
||||
<string name="updating_settings_will_reconnect_client_to_all_servers">La mise à jour des ces paramètres reconnectera le client à tous les serveurs.</string>
|
||||
|
||||
@@ -740,9 +740,7 @@
|
||||
<string name="new_member_role">Új tag szerepköre</string>
|
||||
<string name="la_mode_off">Kikapcsolva</string>
|
||||
<string name="invalid_contact_link">Érvénytelen hivatkozás!</string>
|
||||
<string name="network_use_onion_hosts_required_desc_in_alert">A kapcsolódáshoz Onion kiszolgálókra lesz szükség.</string>
|
||||
<string name="new_in_version">Változások a %s verzióban</string>
|
||||
<string name="network_use_onion_hosts_prefer_desc_in_alert">Onion kiszolgálók használata, ha azok rendelkezésre állnak.</string>
|
||||
<string name="smp_servers_invalid_address">Érvénytelen kiszolgálócím!</string>
|
||||
<string name="thousand_abbreviation">k</string>
|
||||
<string name="chat_item_ttl_none">soha</string>
|
||||
@@ -765,7 +763,6 @@
|
||||
<string name="chat_preferences_on">bekapcsolva</string>
|
||||
<string name="v5_1_japanese_portuguese_interface">Japán és portugál kezelőfelület</string>
|
||||
<string name="message_deletion_prohibited_in_chat">Az üzenetek végleges törlése le van tiltva ebben a csoportban.</string>
|
||||
<string name="network_use_onion_hosts_no_desc_in_alert">Onion kiszolgálók nem lesznek használva.</string>
|
||||
<string name="remote_host_was_disconnected_toast"><![CDATA[A(z) <b>%s</b> eszközzel megszakadt a kapcsolat]]></string>
|
||||
<string name="custom_time_unit_months">hónap</string>
|
||||
<string name="privacy_message_draft">Üzenetvázlat</string>
|
||||
@@ -1098,7 +1095,6 @@
|
||||
<string name="your_calls">Hívások</string>
|
||||
<string name="icon_descr_sent_msg_status_send_failed">nem sikerült elküldeni</string>
|
||||
<string name="theme_colors_section_title">KEZELŐFELÜLET SZÍNEI</string>
|
||||
<string name="network_options_revert">Visszaállítás</string>
|
||||
<string name="restore_database_alert_desc">Előző jelszó megadása az adatbázis biztonsági mentésének visszaállítása után. Ez a művelet nem vonható vissza.</string>
|
||||
<string name="color_secondary">Másodlagos</string>
|
||||
<string name="settings_section_title_socks">SOCKS PROXY</string>
|
||||
@@ -1432,7 +1428,6 @@
|
||||
<string name="unknown_database_error_with_info">Ismeretlen adatbázis hiba: %s</string>
|
||||
<string name="you_can_hide_or_mute_user_profile">Elrejtheti vagy lenémíthatja a felhasználó profiljait - koppintson (vagy asztali alkalmazásban kattintson) hosszan a profilra a felugró menühöz.</string>
|
||||
<string name="v5_3_simpler_incognito_mode_descr">Inkognító mód kapcsolódáskor.</string>
|
||||
<string name="update_onion_hosts_settings_question">Tor .onion kiszolgálók beállításainak frissítése?</string>
|
||||
<string name="you_can_share_group_link_anybody_will_be_able_to_connect">Megoszthat egy hivatkozást vagy QR-kódot - így bárki csatlakozhat a csoporthoz. Ha a csoport később törlésre kerül, akkor nem fogja elveszíteni annak tagjait.</string>
|
||||
<string name="you_joined_this_group">Csatlakozott ehhez a csoporthoz</string>
|
||||
<string name="connect_plan_this_is_your_link_for_group_vName"><![CDATA[Ez a hivatkozása a(z) <b>%1$s</b> csoporthoz!]]></string>
|
||||
|
||||
@@ -610,18 +610,14 @@
|
||||
<string name="network_use_onion_hosts_no">No</string>
|
||||
<string name="network_use_onion_hosts_required_desc">Gli host Onion saranno necessari per la connessione.
|
||||
\nNota bene: non potrai connetterti ai server senza indirizzo .onion .</string>
|
||||
<string name="network_use_onion_hosts_required_desc_in_alert">Gli host Onion saranno necessari per la connessione.</string>
|
||||
<string name="network_use_onion_hosts_prefer_desc">Gli host Onion verranno usati quando disponibili.</string>
|
||||
<string name="network_use_onion_hosts_prefer_desc_in_alert">Gli host Onion verranno usati quando disponibili.</string>
|
||||
<string name="network_use_onion_hosts_no_desc">Gli host Onion non verranno usati.</string>
|
||||
<string name="network_use_onion_hosts_no_desc_in_alert">Gli host Onion non verranno usati.</string>
|
||||
<string name="rate_the_app">Valuta l\'app</string>
|
||||
<string name="network_use_onion_hosts_required">Obbligatorio</string>
|
||||
<string name="save_servers_button">Salva</string>
|
||||
<string name="saved_ICE_servers_will_be_removed">I server WebRTC ICE salvati verranno rimossi.</string>
|
||||
<string name="share_link">Condividi link</string>
|
||||
<string name="star_on_github">Dai una stella su GitHub</string>
|
||||
<string name="update_onion_hosts_settings_question">Aggiornare l\'impostazione degli host .onion\?</string>
|
||||
<string name="network_disable_socks">Usare una connessione internet diretta\?</string>
|
||||
<string name="network_use_onion_hosts">Usa gli host .onion</string>
|
||||
<string name="network_enable_socks">Usare il proxy SOCKS\?</string>
|
||||
@@ -816,7 +812,6 @@
|
||||
<string name="network_option_protocol_timeout">Scadenza del protocollo</string>
|
||||
<string name="receiving_via">Ricezione via</string>
|
||||
<string name="network_options_reset_to_defaults">Ripristina i predefiniti</string>
|
||||
<string name="network_options_revert">Ripristina</string>
|
||||
<string name="network_options_save">Salva</string>
|
||||
<string name="save_group_profile">Salva il profilo del gruppo</string>
|
||||
<string name="network_option_seconds_label">sec</string>
|
||||
|
||||
@@ -604,8 +604,6 @@
|
||||
<string name="theme_light">בהיר</string>
|
||||
<string name="import_theme_error_desc">ודאו שלקובץ יש תחביר YAML תקין. ייצאו ערכת נושא כדי לקבל דוגמה למבנה תקין של קובץ ערכת נושא.</string>
|
||||
<string name="message_delivery_error_desc">ככל הנראה איש קשר זה מחק את החיבור איתך.</string>
|
||||
<string name="network_use_onion_hosts_prefer_desc_in_alert">ייעשה שימוש במארחי Onion כאשר יהיו זמינים.</string>
|
||||
<string name="network_use_onion_hosts_required_desc_in_alert">מארחי Onion יידרשו לחיבור.</string>
|
||||
<string name="moderated_item_description">נחסם על ידי %s</string>
|
||||
<string name="la_no_app_password">אין קוד גישה לאפליקציה</string>
|
||||
<string name="videos_limit_desc">ניתן לשלוח רק 10 סרטונים בו־זמנית</string>
|
||||
@@ -674,7 +672,6 @@
|
||||
<string name="network_use_onion_hosts_required_desc">יידרשו מארחי onion לחיבור.
|
||||
\nשימו לב: לא תוכלו להתחבר לשרתים ללא כתובת .onion.</string>
|
||||
<string name="network_use_onion_hosts_no_desc">לא ייעשה שימוש במארחי Onion.</string>
|
||||
<string name="network_use_onion_hosts_no_desc_in_alert">לא ייעשה שימוש במארחי Onion.</string>
|
||||
<string name="callstatus_missed">שיחה שלא נענתה</string>
|
||||
<string name="only_client_devices_store_contacts_groups_e2e_encrypted_messages"><![CDATA[רק מכשירי לקוח מאחסנים פרופילי משתמש, אנשי קשר, קבוצות, והודעות שנשלחו עם <b>הצפנה מקצה־לקצה דו־שכבתית</b>.]]></string>
|
||||
<string name="status_no_e2e_encryption">ללא הצפנה מקצה־לקצה</string>
|
||||
@@ -902,7 +899,6 @@
|
||||
<string name="custom_time_unit_seconds">שניות</string>
|
||||
<string name="custom_time_picker_select">אישור</string>
|
||||
<string name="role_in_group">תפקיד</string>
|
||||
<string name="network_options_revert">ביטול</string>
|
||||
<string name="save_and_update_group_profile">שמור ועדכן את פרופיל הקבוצה</string>
|
||||
<string name="save_welcome_message_question">לשמור הודעת פתיחה\?</string>
|
||||
<string name="current_version_timestamp">%s (נוכחי)</string>
|
||||
@@ -1077,7 +1073,6 @@
|
||||
<string name="to_share_with_your_contact">(כדי לשתף עם איש הקשר שלך)</string>
|
||||
<string name="to_start_a_new_chat_help_header">כדי להתחיל צ׳אט חדש</string>
|
||||
<string name="smp_servers_use_server_for_new_conn">השתמש עבור חיבורים חדשים</string>
|
||||
<string name="update_onion_hosts_settings_question">לעדכן הגדרות מארחי .onion\?</string>
|
||||
<string name="to_verify_compare">כדי לאמת הצפנה מקצה־לקצה עם איש הקשר שלכם, יש להשוות (או לסרוק) את הקוד במכשירים שלכם.</string>
|
||||
<string name="your_chat_profiles">פרופילי צ׳אט</string>
|
||||
<string name="update_network_session_mode_question">לעדכן מצב בידוד תעבורה\?</string>
|
||||
|
||||
@@ -204,7 +204,6 @@
|
||||
<string name="display_name_connection_established">接続済み</string>
|
||||
<string name="connect_via_link">リンク経由で繋がる。</string>
|
||||
<string name="connection_error">接続エラー</string>
|
||||
<string name="network_use_onion_hosts_required_desc_in_alert">接続にオニオンのホストが必要となります。</string>
|
||||
<string name="group_member_status_introduced">接続待ち (紹介済み)</string>
|
||||
<string name="connection_error_auth">接続エラー (AUTH)</string>
|
||||
<string name="connection_timeout">接続タイムアウト</string>
|
||||
@@ -222,7 +221,6 @@
|
||||
<string name="icon_descr_context">追加情報アイコン</string>
|
||||
<string name="network_use_onion_hosts_prefer_desc">オニオンのホストが利用可能時に使われます。</string>
|
||||
<string name="network_use_onion_hosts_no_desc">オニオンのホストが使われません。</string>
|
||||
<string name="network_use_onion_hosts_prefer_desc_in_alert">オニオンのホストが利用可能時に使われます。</string>
|
||||
<string name="images_limit_desc">画像を1回で最大10枚を送信できます。</string>
|
||||
<string name="only_client_devices_store_contacts_groups_e2e_encrypted_messages"><![CDATA[<b>2層エンドツーエンド暗号化</b>で送信されたプロフィール、連絡先、グループ、メッセージは、クライント端末にしか保存されません。]]></string>
|
||||
<string name="only_group_owners_can_change_prefs">グループ設定を変えられるのはグループのオーナーだけです。</string>
|
||||
@@ -315,7 +313,6 @@
|
||||
<string name="enter_one_ICE_server_per_line">ICEサーバ (1行に1サーバ)</string>
|
||||
<string name="network_and_servers">ネットワークとサーバ</string>
|
||||
<string name="network_settings_title">ネットワーク設定</string>
|
||||
<string name="network_use_onion_hosts_no_desc_in_alert">オニオンのホストが使われません。</string>
|
||||
<string name="delete_address">アドレスを削除</string>
|
||||
<string name="exit_without_saving">保存せずに閉じる</string>
|
||||
<string name="display_name_cannot_contain_whitespace">表示の名前には空白が使用できません。</string>
|
||||
@@ -735,7 +732,6 @@
|
||||
<string name="your_ICE_servers">あなたのICEサーバ</string>
|
||||
<string name="network_disable_socks">直接にインタネットに繋がりますか?</string>
|
||||
<string name="network_enable_socks">SOCKSプロキシを使いますか?</string>
|
||||
<string name="update_onion_hosts_settings_question">.onionのホスト設定を更新しますか?</string>
|
||||
<string name="network_use_onion_hosts">.onionホストを使う</string>
|
||||
<string name="network_use_onion_hosts_prefer">利用可能時に</string>
|
||||
<string name="network_session_mode_transport_isolation">トランスポート隔離</string>
|
||||
@@ -883,7 +879,6 @@
|
||||
<string name="you_have_to_enter_passphrase_every_time">アプリ起動時にパスフレーズを入力しなければなりません。端末に保存されてません。</string>
|
||||
<string name="database_backup_can_be_restored">データベースのパスフレーズ変更が完了してません。</string>
|
||||
<string name="you_can_share_group_link_anybody_will_be_able_to_connect">リンク、またはQRコードを共有できます。誰でもグループに参加できます。後で削除しても、グループのメンバーがそのままのこります。</string>
|
||||
<string name="network_options_revert">元に戻す</string>
|
||||
<string name="update_network_settings_confirmation">更新</string>
|
||||
<string name="accept_feature_set_1_day">1日に設定</string>
|
||||
<string name="v4_4_disappearing_messages_desc">一定時間が経ったら送信されたメッセージが削除されます。</string>
|
||||
|
||||
@@ -635,7 +635,6 @@
|
||||
<string name="messages_section_description">이 설정은 현재 내 프로필의 메시지에 적용되어요.</string>
|
||||
<string name="member_info_section_title_member">멤버</string>
|
||||
<string name="member_role_will_be_changed_with_invitation">역할이 \"%s\"(으)로 변경되고, 회원은 새로운 초대를 받게 될 거예요.</string>
|
||||
<string name="network_options_revert">되돌리기</string>
|
||||
<string name="message_deletion_prohibited">이 채팅에서는 메시지 영구 삭제가 허용되지 않았어요.</string>
|
||||
<string name="leave_group_button">나가기</string>
|
||||
<string name="large_file">큰 파일!</string>
|
||||
@@ -667,9 +666,6 @@
|
||||
<string name="network_use_onion_hosts_prefer_desc">사용 가능한 경우 Onion 호스트가 사용될 거예요.</string>
|
||||
<string name="network_use_onion_hosts_no_desc">Onion 호스트가 사용되지 않을 거예요.</string>
|
||||
<string name="network_session_mode_transport_isolation">전송 격리</string>
|
||||
<string name="network_use_onion_hosts_no_desc_in_alert">Onion 호스트가 사용되지 않을 거예요.</string>
|
||||
<string name="network_use_onion_hosts_prefer_desc_in_alert">사용 가능한 경우 Onion 호스트가 사용될 거예요.</string>
|
||||
<string name="network_use_onion_hosts_required_desc_in_alert">연결하려면 Onion 호스트가 필요해요.</string>
|
||||
<string name="next_generation_of_private_messaging">차세대 사생활 보호 메시징</string>
|
||||
<string name="new_passphrase">새 비밀번호…</string>
|
||||
<string name="network_option_enable_tcp_keep_alive">TCP 연결 유지 활성화</string>
|
||||
|
||||
@@ -130,7 +130,6 @@
|
||||
<string name="snd_group_event_group_profile_updated">grupės profilis atnaujintas</string>
|
||||
<string name="info_row_group">Grupė</string>
|
||||
<string name="users_delete_question">Ištrinti pokalbio profilį\?</string>
|
||||
<string name="network_options_revert">Sugrąžinti</string>
|
||||
<string name="network_options_save">Įrašyti</string>
|
||||
<string name="feature_enabled">įjungta</string>
|
||||
<string name="delete_after">Ištrinti po</string>
|
||||
@@ -1373,7 +1372,6 @@
|
||||
<string name="connect_via_link_or_qr_from_clipboard_or_in_person">(nuskanuokite ar įklijuokite iš iškarpinės)</string>
|
||||
<string name="you_accepted_connection">Priėmėte prisijungimą</string>
|
||||
<string name="you_invited_a_contact">Jūs pakvietėte kontaktą</string>
|
||||
<string name="network_use_onion_hosts_required_desc_in_alert">Onion serveriai bus reikalingi ryšiui.</string>
|
||||
<string name="network_use_onion_hosts_prefer_desc">Onion serveriai bus naudojami, kai tik bus.</string>
|
||||
<string name="exit_without_saving">Išeiti neišsaugant</string>
|
||||
<string name="you_control_your_chat">Jūs kontroliuojate savo pokalbį!</string>
|
||||
@@ -1565,7 +1563,6 @@
|
||||
<string name="your_simplex_contact_address">Jūsų SimpleX adresas</string>
|
||||
<string name="smp_servers_scan_qr">Nuskanuoti serverio QR kodą</string>
|
||||
<string name="network_use_onion_hosts_required">Reikalingi</string>
|
||||
<string name="network_use_onion_hosts_prefer_desc_in_alert">Onion serveriai bus naudojami, kai tik bus.</string>
|
||||
<string name="network_use_onion_hosts_no_desc">Onion serveriai nebus naudojami.</string>
|
||||
<string name="self_destruct">Savaiminis susinaikinimas</string>
|
||||
<string name="old_database_archive">Senas duomenų bazės archyvas</string>
|
||||
@@ -1628,8 +1625,6 @@
|
||||
<string name="moderate_verb">Moderuoti</string>
|
||||
<string name="contact_wants_to_connect_with_you">nori prisijungti prie jūsų!</string>
|
||||
<string name="image_descr_link_preview">nuorodos peržiūros nuotrauka</string>
|
||||
<string name="network_use_onion_hosts_no_desc_in_alert">Onion serveriai nebus naudojami.</string>
|
||||
<string name="update_onion_hosts_settings_question">Atnaujinti .onion serverių nustatymą?</string>
|
||||
<string name="onboarding_notifications_mode_off">Kai programėlė yra paleista</string>
|
||||
<string name="lock_mode">Užrakto režimas</string>
|
||||
<string name="you_can_start_chat_via_setting_or_by_restarting_the_app">Galite paleisti pokalbius per programėlės nustatymus/ duomenų bazę arba paleisdami programėlę iš naujo.</string>
|
||||
|
||||
@@ -320,7 +320,6 @@
|
||||
<string name="switch_receiving_address">സ്വീകരിക്കുന്ന വിലാസം മാറുക</string>
|
||||
<string name="conn_stats_section_title_servers">സെർവറുകൾ</string>
|
||||
<string name="network_options_save">സംരക്ഷിക്കുക</string>
|
||||
<string name="network_options_revert">പഴയപടിയാക്കുക</string>
|
||||
<string name="theme_system">സംവിധാനം</string>
|
||||
<string name="language_system">സംവിധാനം</string>
|
||||
<string name="color_title">ശീർഷകം</string>
|
||||
|
||||
@@ -546,7 +546,6 @@
|
||||
<string name="one_time_link">Eenmalige uitnodiging link</string>
|
||||
<string name="paste_button">Plakken</string>
|
||||
<string name="smp_servers_preset_address">Vooraf ingesteld server adres</string>
|
||||
<string name="network_use_onion_hosts_no_desc_in_alert">Onion hosts worden niet gebruikt.</string>
|
||||
<string name="onboarding_notifications_mode_title">Privé meldingen</string>
|
||||
<string name="paste_the_link_you_received">Plak de link die je hebt ontvangen</string>
|
||||
<string name="onboarding_notifications_mode_periodic">Periodiek</string>
|
||||
@@ -573,7 +572,6 @@
|
||||
<string name="enter_passphrase_notification_title">Wachtwoord is nodig</string>
|
||||
<string name="feature_off">uit</string>
|
||||
<string name="add_contact">Eenmalige uitnodiging link</string>
|
||||
<string name="network_use_onion_hosts_required_desc_in_alert">Onion hosts zijn vereist voor verbinding.</string>
|
||||
<string name="only_group_owners_can_change_prefs">Alleen groep eigenaren kunnen groep voorkeuren wijzigen.</string>
|
||||
<string name="only_stored_on_members_devices">(alleen opgeslagen door groepsleden)</string>
|
||||
<string name="smp_servers_preset_server">Vooraf ingestelde server</string>
|
||||
@@ -584,7 +582,6 @@
|
||||
<string name="ok">OK</string>
|
||||
<string name="network_use_onion_hosts_required_desc">Onion hosts zijn vereist voor verbinding.</string>
|
||||
<string name="network_use_onion_hosts_prefer_desc">Onion hosts worden gebruikt indien beschikbaar.</string>
|
||||
<string name="network_use_onion_hosts_prefer_desc_in_alert">Onion hosts worden gebruikt indien beschikbaar.</string>
|
||||
<string name="network_use_onion_hosts_no_desc">Onion hosts worden niet gebruikt.</string>
|
||||
<string name="opensource_protocol_and_code_anybody_can_run_servers">Open-source protocol en code. Iedereen kan de servers draaien.</string>
|
||||
<string name="people_can_connect_only_via_links_you_share">Mensen kunnen alleen verbinding met u maken via de links die u deelt.</string>
|
||||
@@ -808,7 +805,6 @@
|
||||
<string name="network_options_reset_to_defaults">Resetten naar standaardwaarden</string>
|
||||
<string name="switch_receiving_address">Ontvangst adres wijzigen</string>
|
||||
<string name="network_option_protocol_timeout">Protocol timeout</string>
|
||||
<string name="network_options_revert">Terugdraaien</string>
|
||||
<string name="network_options_save">Opslaan</string>
|
||||
<string name="network_option_seconds_label">sec</string>
|
||||
<string name="incognito_info_share">Wanneer je een incognito profiel met iemand deelt, wordt dit profiel gebruikt voor de groepen waarvoor ze je uitnodigen.</string>
|
||||
@@ -904,7 +900,6 @@
|
||||
<string name="you_can_connect_to_simplex_chat_founder"><![CDATA[U kunt <font color="#0088ff">verbinding maken met SimpleX Chat ontwikkelaars om vragen te stellen en updates te ontvangen</font>.]]></string>
|
||||
<string name="connection_error_auth_desc">Tenzij uw contact de verbinding heeft verwijderd of deze link al is gebruikt, kan het een bug zijn. Meld het alstublieft.
|
||||
\nOm verbinding te maken, vraagt u uw contact om een andere verbinding link te maken en te controleren of u een stabiele netwerkverbinding heeft.</string>
|
||||
<string name="update_onion_hosts_settings_question">.onion hosts-instelling updaten\?</string>
|
||||
<string name="use_simplex_chat_servers__question">SimpleX Chat servers gebruiken\?</string>
|
||||
<string name="voice_messages_are_prohibited">Spraak berichten zijn verboden in deze groep.</string>
|
||||
<string name="personal_welcome">Welkom %1$s!</string>
|
||||
|
||||
@@ -348,14 +348,11 @@
|
||||
<string name="network_use_onion_hosts_no">Nie</string>
|
||||
<string name="network_use_onion_hosts_required_desc">Hosty onion będą wymagane do połączenia.
|
||||
\nUwaga: nie będziesz mógł połączyć się z serwerami bez adresu .onion.</string>
|
||||
<string name="network_use_onion_hosts_required_desc_in_alert">Hosty onion będą wymagane do połączenia.</string>
|
||||
<string name="network_use_onion_hosts_prefer_desc">Hosty onion będą używane, gdy będą dostępne.</string>
|
||||
<string name="network_use_onion_hosts_prefer_desc_in_alert">Hosty onion będą używane, gdy będą dostępne.</string>
|
||||
<string name="network_use_onion_hosts_no_desc">Hosty onion nie będą używane.</string>
|
||||
<string name="network_use_onion_hosts_required">Wymagane</string>
|
||||
<string name="save_servers_button">Zapisz</string>
|
||||
<string name="network_session_mode_transport_isolation">Izolacja transportu</string>
|
||||
<string name="update_onion_hosts_settings_question">Zaktualizować ustawienie hostów .onion\?</string>
|
||||
<string name="update_network_session_mode_question">Zaktualizować tryb izolacji transportu\?</string>
|
||||
<string name="network_disable_socks">Użyć bezpośredniego połączenia z Internetem\?</string>
|
||||
<string name="network_use_onion_hosts">Użyj hostów .onion</string>
|
||||
@@ -758,7 +755,6 @@
|
||||
<string name="users_delete_with_connections">Profil i połączenia z serwerem</string>
|
||||
<string name="network_option_protocol_timeout">Limit czasu protokołu</string>
|
||||
<string name="network_options_reset_to_defaults">Przywróć wartości domyślne</string>
|
||||
<string name="network_options_revert">Przywrócić</string>
|
||||
<string name="network_options_save">Zapisz</string>
|
||||
<string name="network_option_seconds_label">sek</string>
|
||||
<string name="tap_to_activate_profile">Dotknij, aby aktywować profil.</string>
|
||||
@@ -953,7 +949,6 @@
|
||||
<string name="gallery_video_button">Wideo</string>
|
||||
<string name="feature_offered_item_with_param">zaproponował %s: %2s</string>
|
||||
<string name="only_group_owners_can_enable_voice">Tylko właściciele grup mogą włączyć wiadomości głosowe.</string>
|
||||
<string name="network_use_onion_hosts_no_desc_in_alert">Hosty onion nie będą używane.</string>
|
||||
<string name="only_your_contact_can_delete">Tylko Twój kontakt może nieodwracalnie usunąć wiadomości (możesz oznaczyć je do usunięcia). (24 godziny)</string>
|
||||
<string name="restore_passphrase_not_found_desc">Hasło nie zostało znalezione w Keystore, wprowadź je ręcznie. Może się tak zdarzyć, gdy przywrócisz dane aplikacji za pomocą narzędzia do kopii zapasowych. Jeśli tak nie jest, skontaktuj się z programistami.</string>
|
||||
<string name="group_members_can_send_disappearing">Członkowie grupy mogą wysyłać znikające wiadomości.</string>
|
||||
|
||||
@@ -482,7 +482,6 @@
|
||||
<string name="old_database_archive">Arquivo de banco de dados antigo</string>
|
||||
<string name="button_add_members">Convidar membros</string>
|
||||
<string name="no_contacts_selected">Nenhum contato selecionado</string>
|
||||
<string name="network_options_revert">Reverter</string>
|
||||
<string name="network_options_save">Salvar</string>
|
||||
<string name="reset_color">Redefinir cores</string>
|
||||
<string name="v4_5_italian_interface">interface italiana</string>
|
||||
@@ -647,7 +646,6 @@
|
||||
<string name="network_use_onion_hosts_no_desc">Onion hosts não serão usados.</string>
|
||||
<string name="network_use_onion_hosts_required_desc">Os hosts Onion serão necessários para a conexão.
|
||||
\nAtenção: você não será capaz de se conectar aos servidores sem um endereço .onion</string>
|
||||
<string name="network_use_onion_hosts_required_desc_in_alert">Os hosts Onion serão necessários para a conexão.</string>
|
||||
<string name="core_version">Versão principal: v%s</string>
|
||||
<string name="read_more_in_github_with_link"><![CDATA[Leia mais no nosso <font color="#0088ff">repositório do GitHub</font>.]]></string>
|
||||
<string name="onboarding_notifications_mode_subtitle">Pode ser mudado mais tarde via configurações.</string>
|
||||
@@ -761,9 +759,7 @@
|
||||
<string name="v4_6_hidden_chat_profiles_descr">Proteja seus perfis de bate-papo com uma senha!</string>
|
||||
<string name="this_text_is_available_in_settings">Este texto está disponível nas configurações</string>
|
||||
<string name="scan_code">Escanear código</string>
|
||||
<string name="network_use_onion_hosts_no_desc_in_alert">Hosts Onion não serão usados.</string>
|
||||
<string name="network_use_onion_hosts_prefer_desc">Os hosts Onion serão usados quando disponíveis.</string>
|
||||
<string name="network_use_onion_hosts_prefer_desc_in_alert">Os hosts Onion serão usados quando disponíveis.</string>
|
||||
<string name="your_current_profile">Seu perfil atual</string>
|
||||
<string name="privacy_redefined">Privacidade redefinida</string>
|
||||
<string name="onboarding_notifications_mode_title">Notificações privadas</string>
|
||||
@@ -963,7 +959,6 @@
|
||||
<string name="share_message">Compartilhar mensagem…</string>
|
||||
<string name="personal_welcome">Bem-vindo(a) %1$s!</string>
|
||||
<string name="group_preview_you_are_invited">você está convidado para o grupo</string>
|
||||
<string name="update_onion_hosts_settings_question">Atualizar configuração de hosts .onion\?</string>
|
||||
<string name="use_chat">Usar bate-papo</string>
|
||||
<string name="voice_prohibited_in_this_chat">Mensagens de voz são proibidas neste chat.</string>
|
||||
<string name="video_descr">Vídeo</string>
|
||||
|
||||
@@ -578,7 +578,6 @@
|
||||
<string name="settings_notification_preview_title">Pré-visualização de notificação</string>
|
||||
<string name="message_delivery_error_desc">Muito provavelmente este contato eliminou a conexão consigo.</string>
|
||||
<string name="this_text_is_available_in_settings">Este texto está disponível nas definições</string>
|
||||
<string name="update_onion_hosts_settings_question">Atualizar definições de servidores .onion\?</string>
|
||||
<string name="onboarding_notifications_mode_subtitle">Pode ser alterado mais tarde através das definições.</string>
|
||||
<string name="settings_section_title_help">AJUDA</string>
|
||||
<string name="settings_section_title_support">SUPORTE SIMPLEX CHAT</string>
|
||||
@@ -613,7 +612,6 @@
|
||||
<string name="enter_passphrase_notification_desc">Para receber notificações, por favor, digite a senha da base de dados</string>
|
||||
<string name="network_use_onion_hosts_no_desc">Hosts Onion não serão usados.</string>
|
||||
<string name="network_use_onion_hosts_prefer_desc">Hosts Onion serão usados quando disponíveis.</string>
|
||||
<string name="network_use_onion_hosts_required_desc_in_alert">Hosts Onion serão necessários para a conexão.</string>
|
||||
<string name="video_call_no_encryption">chamada de vídeo (sem encriptação ponta a ponta)</string>
|
||||
<string name="audio_call_no_encryption">chamada de áudio (não encriptada ponta a ponta)</string>
|
||||
<string name="encrypted_audio_call">chamada de áudio encriptada ponta a ponta</string>
|
||||
@@ -623,7 +621,6 @@
|
||||
<string name="feature_offered_item">oferecido %s</string>
|
||||
<string name="old_database_archive">Arquivo de base de dados antigo</string>
|
||||
<string name="network_use_onion_hosts_required_desc">Hosts Onion serão necessários para a conexão.</string>
|
||||
<string name="network_use_onion_hosts_prefer_desc_in_alert">Hosts Onion serão usados quando disponíveis.</string>
|
||||
<string name="alert_text_fragment_encryption_out_of_sync_old_database">Pode acontecer quando você ou sua conexão usaram o backup de base de dados antigo.</string>
|
||||
<string name="status_e2e_encrypted">encriptado ponta a ponta</string>
|
||||
<string name="feature_off">desligado</string>
|
||||
@@ -644,7 +641,6 @@
|
||||
<string name="to_verify_compare">Para verificar a encriptação de ponta a ponta com o seu contato, compare (ou leia) o código nos seus dispositivos.</string>
|
||||
<string name="scan_code_from_contacts_app">Ler o código de segurança a partir da aplicação do seu contacto.</string>
|
||||
<string name="smp_servers_scan_qr">Ler o código QR do servidor</string>
|
||||
<string name="network_use_onion_hosts_no_desc_in_alert">Hosts Onion não serão usados.</string>
|
||||
<string name="only_client_devices_store_contacts_groups_e2e_encrypted_messages"><![CDATA[Apenas dispositivos cliente armazenam perfis de utilizador, contatos, grupos e mensagens enviadas com <b>encriptação de ponta a ponta de 2 camadas</b>.]]></string>
|
||||
<string name="status_contact_has_e2e_encryption">o contacto tem encriptação ponta a ponta</string>
|
||||
<string name="status_no_e2e_encryption">sem encriptação ponta a ponta</string>
|
||||
|
||||
@@ -193,7 +193,6 @@
|
||||
<string name="reject">Respinge</string>
|
||||
<string name="save_passphrase_in_settings">Salvează fraza de acces în setări</string>
|
||||
<string name="save_and_update_group_profile">Salvează și actualizează profilul grupului</string>
|
||||
<string name="network_options_revert">Revenire</string>
|
||||
<string name="connect_plan_repeat_join_request">Repetă cererea de alăturare?</string>
|
||||
<string name="restart_chat_button">Repornește conversația</string>
|
||||
<string name="saved_description">salvat</string>
|
||||
|
||||
@@ -394,7 +394,6 @@
|
||||
<string name="network_enable_socks_info">Соединяться с серверами через SOCKS прокси через порт %d? Прокси должен быть запущен до включения этой опции.</string>
|
||||
<string name="network_disable_socks">Использовать прямое соединение с Интернет?</string>
|
||||
<string name="network_disable_socks_info">Если Вы подтвердите, серверы смогут видеть Ваш IP адрес, а провайдер - с какими серверами Вы соединяетесь.</string>
|
||||
<string name="update_onion_hosts_settings_question">Обновить настройки .onion хостов?</string>
|
||||
<string name="network_use_onion_hosts">Использовать .onion хосты</string>
|
||||
<string name="network_use_onion_hosts_prefer">Когда возможно</string>
|
||||
<string name="network_use_onion_hosts_no">Нет</string>
|
||||
@@ -403,9 +402,6 @@
|
||||
<string name="network_use_onion_hosts_no_desc">Onion хосты не используются.</string>
|
||||
<string name="network_use_onion_hosts_required_desc">Подключаться только к onion хостам.
|
||||
\nОбратите внимание: Вы не сможете соединиться с серверами, у которых нет .onion адреса.</string>
|
||||
<string name="network_use_onion_hosts_prefer_desc_in_alert">Onion хосты используются, если возможно.</string>
|
||||
<string name="network_use_onion_hosts_no_desc_in_alert">Onion хосты не используются.</string>
|
||||
<string name="network_use_onion_hosts_required_desc_in_alert">Подключаться только к onion хостам.</string>
|
||||
<string name="appearance_settings">Интерфейс</string>
|
||||
<!-- Address Items - UserAddressView.kt -->
|
||||
<string name="create_address">Создать адрес</string>
|
||||
@@ -831,7 +827,6 @@
|
||||
<string name="network_option_protocol_timeout">Таймаут протокола</string>
|
||||
<string name="network_option_ping_interval">Интервал PING</string>
|
||||
<string name="network_option_enable_tcp_keep_alive">Включить TCP keep-alive</string>
|
||||
<string name="network_options_revert">Отменить изменения</string>
|
||||
<string name="network_options_save">Сохранить</string>
|
||||
<string name="update_network_settings_question">Обновить настройки сети?</string>
|
||||
<string name="updating_settings_will_reconnect_client_to_all_servers">Обновление настроек приведет к переподключению клиента ко всем серверам.</string>
|
||||
|
||||
@@ -665,10 +665,7 @@
|
||||
<string name="network_settings_title">การตั้งค่าเครือข่าย</string>
|
||||
<string name="network_use_onion_hosts_required_desc">จำเป็นต้องมีโฮสต์หัวหอมสำหรับการเชื่อมต่อ</string>
|
||||
<string name="network_use_onion_hosts_no">ไม่</string>
|
||||
<string name="network_use_onion_hosts_required_desc_in_alert">จำเป็นต้องมีโฮสต์หัวหอมสำหรับการเชื่อมต่อ</string>
|
||||
<string name="network_use_onion_hosts_prefer_desc_in_alert">โฮสต์หัวหอมจะถูกใช้เมื่อมี</string>
|
||||
<string name="network_use_onion_hosts_no_desc">โฮสต์หัวหอมจะไม่ถูกใช้</string>
|
||||
<string name="network_use_onion_hosts_no_desc_in_alert">โฮสต์หัวหอมจะไม่ถูกใช้</string>
|
||||
<string name="password_to_show">รหัสผ่านที่จะแสดง</string>
|
||||
<string name="callstatus_missed">สายที่ไม่ได้รับ</string>
|
||||
<string name="people_can_connect_only_via_links_you_share">ผู้คนสามารถเชื่อมต่อกับคุณผ่านลิงก์ที่คุณแบ่งปันเท่านั้น</string>
|
||||
@@ -852,7 +849,6 @@
|
||||
<string name="save_and_update_group_profile">บันทึกและอัปเดตโปรไฟล์กลุ่ม</string>
|
||||
<string name="receiving_via">กำลังรับผ่าน</string>
|
||||
<string name="network_options_reset_to_defaults">รีเซ็ตเป็นค่าเริ่มต้น</string>
|
||||
<string name="network_options_revert">เปลี่ยนกลับ</string>
|
||||
<string name="network_options_save">บันทึก</string>
|
||||
<string name="reset_color">รีเซ็ตสี</string>
|
||||
<string name="feature_received_prohibited">ได้รับ, ห้าม</string>
|
||||
@@ -1147,7 +1143,6 @@
|
||||
<string name="network_socks_toggle_use_socks_proxy">ใช้พร็อกซี SOCKS</string>
|
||||
<string name="network_disable_socks">ใช้การเชื่อมต่ออินเทอร์เน็ตโดยตรงหรือไม่\?</string>
|
||||
<string name="network_enable_socks">ใช้พร็อกซี SOCKS หรือไม่\?</string>
|
||||
<string name="update_onion_hosts_settings_question">อัปเดตการตั้งค่าโฮสต์ .onion ไหม\?</string>
|
||||
<string name="network_use_onion_hosts">ใช้โฮสต์ .onion</string>
|
||||
<string name="network_use_onion_hosts_prefer">เมื่อพร้อมใช้งาน</string>
|
||||
<string name="update_network_session_mode_question">อัปเดตโหมดการแยกการขนส่งไหม\?</string>
|
||||
|
||||
@@ -1145,7 +1145,6 @@
|
||||
<string name="share_link">Bağlantı paylaş</string>
|
||||
<string name="icon_descr_simplex_team">SimpleX Ekibi</string>
|
||||
<string name="rcv_group_event_3_members_connected">%s, %s ve %s bağlandı</string>
|
||||
<string name="network_options_revert">Geri al</string>
|
||||
<string name="settings_section_title_socks">SOCKS VEKİLİ</string>
|
||||
<string name="desktop_devices">Masaüstür cihazlar</string>
|
||||
<string name="smp_servers">SMP sunucuları</string>
|
||||
@@ -1318,14 +1317,12 @@
|
||||
<string name="share_text_updated_at">Kayıt %s te güncellendi</string>
|
||||
<string name="v5_3_encrypt_local_files_descr">Uygulama yeni yerel dosyaları şifreler (videolar dışında).</string>
|
||||
<string name="sender_at_ts">%s , %s de</string>
|
||||
<string name="network_use_onion_hosts_required_desc_in_alert">Bağlantı için Onion ana bilgisayarları gerekli olacaktır.</string>
|
||||
<string name="receipts_contacts_title_disable">Alıcılar devre dışı bırakılsın mı?</string>
|
||||
<string name="sync_connection_force_question">Bağlantı yeniden senkronizasyonunu şifrele?</string>
|
||||
<string name="receipts_section_description_1">Grup ayarlarından ve kişilerden geçersiz kılınmış olabilirler</string>
|
||||
<string name="recent_history_is_not_sent_to_new_members">Yeni üyelere geçmiş gönderilmedi.</string>
|
||||
<string name="v4_2_security_assessment">Güvenlik değerlendirmesi</string>
|
||||
<string name="retry_verb">Yeniden dene</string>
|
||||
<string name="network_use_onion_hosts_prefer_desc_in_alert">Onion ana bilgisayarları mümkün olduğunda kullanılacaktır.</string>
|
||||
<string name="network_enable_socks_info">Sunuculara %d bağlantı noktasındaki vekil SOCKS aracılığıyla erişilsin mi? Vekil bu seçeneği etkinleştirmeden önce başlatılmak zorundadır.</string>
|
||||
<string name="v5_4_block_group_members_descr">İstenmeyen mesajları gizlemek için.</string>
|
||||
<string name="error_smp_test_failed_at_step">Test %s adımında hata yaşandı.</string>
|
||||
@@ -1362,7 +1359,6 @@
|
||||
<string name="remove_passphrase_from_settings">Ayarlardaki parola silinsin mi?</string>
|
||||
<string name="receipts_contacts_title_enable">Alıcılar etkinleştirilsin mi?</string>
|
||||
<string name="tap_to_start_new_chat">Yeni bir sohbet başlatmak için tıkla</string>
|
||||
<string name="network_use_onion_hosts_no_desc_in_alert">Onion ana bilgisayarları kullanılmayacaktır.</string>
|
||||
<string name="unblock_member_button">Kişinin engelini kaldır</string>
|
||||
<string name="relay_server_if_necessary">Yönlendirici sunucusu sadece lazım ise kullanılacak. Diğer taraf IP adresini görebilir.</string>
|
||||
<string name="remote_host_was_disconnected_toast"><![CDATA[Telefon bağlantılı <b>%s</b> ın bağlantısı kesildi]]></string>
|
||||
@@ -1510,7 +1506,6 @@
|
||||
<string name="connected_to_mobile">Telefona bağlandı</string>
|
||||
<string name="v5_3_simpler_incognito_mode_descr">Bağlanırken takma ada geçiş yap.</string>
|
||||
<string name="v5_2_message_delivery_receipts">Mesaj gönderildi!</string>
|
||||
<string name="update_onion_hosts_settings_question">.onion ana bilgisayarları ayarı güncellensin mi?</string>
|
||||
<string name="smp_servers_use_server_for_new_conn">Yeni bağlantılar için kullan</string>
|
||||
<string name="rcv_conn_event_switch_queue_phase_completed">senin için adres değiştirildi</string>
|
||||
<string name="network_enable_socks">SOCKS vekilini kullan?</string>
|
||||
|
||||
@@ -251,7 +251,6 @@
|
||||
<string name="network_settings_title">Налаштування мережі</string>
|
||||
<string name="network_enable_socks">Використовувати SOCKS-проксі?</string>
|
||||
<string name="network_disable_socks">Використовувати прямий підключення до Інтернету?</string>
|
||||
<string name="update_onion_hosts_settings_question">Оновити налаштування .onion-хостів?</string>
|
||||
<string name="network_use_onion_hosts">Використовувати .onion-хости</string>
|
||||
<string name="network_use_onion_hosts_prefer">Якщо доступно</string>
|
||||
<string name="network_use_onion_hosts_no">Ні</string>
|
||||
@@ -640,8 +639,6 @@
|
||||
<string name="error_saving_ICE_servers">Помилка збереження серверів ICE</string>
|
||||
<string name="network_use_onion_hosts_required_desc">.Onion-хости будуть обов\'язковими для підключення.
|
||||
\nЗверніть увагу: ви не зможете підключитися до серверів без адреси .onion.</string>
|
||||
<string name="network_use_onion_hosts_prefer_desc_in_alert">Хости .onion будуть використовуватися, якщо доступні.</string>
|
||||
<string name="network_use_onion_hosts_required_desc_in_alert">Хости .onion будуть обов\'язковими для підключення.</string>
|
||||
<string name="show_developer_options">Показати параметри розробника</string>
|
||||
<string name="developer_options">Ідентифікатори бази даних та опція ізоляції транспорту.</string>
|
||||
<string name="shutdown_alert_desc">Сповіщення перестануть працювати, поки ви не перезапустите додаток</string>
|
||||
@@ -953,7 +950,6 @@
|
||||
<string name="image_descr_link_preview">зображення попереднього перегляду посилання</string>
|
||||
<string name="icon_descr_cancel_link_preview">скасувати попередній перегляд посилання</string>
|
||||
<string name="icon_descr_settings">Налаштування</string>
|
||||
<string name="network_use_onion_hosts_no_desc_in_alert">Хости .onion не будуть використовуватися.</string>
|
||||
<string name="icon_descr_call_progress">Виклик у процесі</string>
|
||||
<string name="database_error">Помилка бази даних</string>
|
||||
<string name="restore_database_alert_confirm">Відновити</string>
|
||||
@@ -997,7 +993,6 @@
|
||||
<string name="section_title_for_console">ДЛЯ КОНСОЛІ</string>
|
||||
<string name="member_will_be_removed_from_group_cannot_be_undone">Учасника буде вилучено з групи - цю дію неможливо скасувати!</string>
|
||||
<string name="change_role">Змінити роль</string>
|
||||
<string name="network_options_revert">Відновити</string>
|
||||
<string name="you_will_still_receive_calls_and_ntfs">Ви все ще отримуватимете дзвінки та сповіщення від приглушених профілів, коли вони активні.</string>
|
||||
<string name="ttl_months">%d місяці</string>
|
||||
<string name="ttl_mth">%dmth</string>
|
||||
|
||||
@@ -667,7 +667,6 @@
|
||||
<string name="feature_off">关闭</string>
|
||||
<string name="network_use_onion_hosts_required_desc">连接需要 Onion 主机。
|
||||
\n请注意:如果没有 .onion 地址,您将无法连接到服务器。</string>
|
||||
<string name="network_use_onion_hosts_prefer_desc_in_alert">Onion 主机将在可用时使用。</string>
|
||||
<string name="chat_item_ttl_none">从不</string>
|
||||
<string name="feature_offered_item">已提供 %s</string>
|
||||
<string name="feature_offered_item_with_param">已提供 %s:%2s</string>
|
||||
@@ -686,8 +685,6 @@
|
||||
<string name="no_contacts_to_add">没有联系人可添加</string>
|
||||
<string name="network_status">网络状态</string>
|
||||
<string name="chat_preferences_off">关闭</string>
|
||||
<string name="network_use_onion_hosts_no_desc_in_alert">将不会使用 Onion 主机。</string>
|
||||
<string name="network_use_onion_hosts_required_desc_in_alert">连接需要 Onion 主机。</string>
|
||||
<string name="no_received_app_files">没有收到或发送的文件</string>
|
||||
<string name="sender_cancelled_file_transfer">发送人已取消文件传输。</string>
|
||||
<string name="share_verb">分享</string>
|
||||
@@ -744,7 +741,6 @@
|
||||
<string name="to_start_a_new_chat_help_header">开始新的聊天</string>
|
||||
<string name="to_verify_compare">要与您的联系人验证端到端加密,请比较(或扫描)您设备上的代码。</string>
|
||||
<string name="unmute_chat">取消静音</string>
|
||||
<string name="update_onion_hosts_settings_question">更新 .onion 主机设置?</string>
|
||||
<string name="update_network_session_mode_question">更新传输隔离模式?</string>
|
||||
<string name="connect_via_link_or_qr_from_clipboard_or_in_person">(从剪贴板扫描或粘贴)</string>
|
||||
<string name="smp_server_test_secure_queue">保护队列</string>
|
||||
@@ -829,7 +825,6 @@
|
||||
<string name="group_member_status_removed">已删除</string>
|
||||
<string name="role_in_group">角色</string>
|
||||
<string name="network_option_seconds_label">秒</string>
|
||||
<string name="network_options_revert">恢复</string>
|
||||
<string name="reset_color">重置颜色</string>
|
||||
<string name="v4_5_reduced_battery_usage">减少电池使用量</string>
|
||||
<string name="v4_5_private_filenames_descr">为了保护时区,图像/语音文件使用 UTC。</string>
|
||||
|
||||
@@ -412,8 +412,6 @@
|
||||
<string name="enter_one_ICE_server_per_line">ICE 伺服器(每行一個)</string>
|
||||
<string name="network_use_onion_hosts">使用 .onion 主機</string>
|
||||
<string name="network_use_onion_hosts_no_desc">Onion 主機不會啟用。</string>
|
||||
<string name="network_use_onion_hosts_prefer_desc_in_alert">Onion 主機會在可用時啟用。</string>
|
||||
<string name="network_use_onion_hosts_no_desc_in_alert">Onion 主機不會啟用。</string>
|
||||
<string name="network_session_mode_entity">連接</string>
|
||||
<string name="delete_address">刪除聯絡地址</string>
|
||||
<string name="colored_text">顏色</string>
|
||||
@@ -437,7 +435,6 @@
|
||||
<string name="ensure_ICE_server_address_are_correct_format_and_unique">請確保你的 WebRTC ICE 伺服器地址是正確的格式,每行也有分隔和沒有重複。</string>
|
||||
<string name="network_disable_socks">使用直接互聯網連接?</string>
|
||||
<string name="network_disable_socks_info">如果你確定,你的訊息伺服器能夠看到你的 IP 位置,和你的網路供應商 - 你正在連接到哪些伺服器。</string>
|
||||
<string name="update_onion_hosts_settings_question">更新 .onion 主機設定?</string>
|
||||
<string name="delete_image">刪除圖片</string>
|
||||
<string name="callstate_starting">開始中 …</string>
|
||||
<string name="callstate_waiting_for_answer">等待對方回應…</string>
|
||||
@@ -496,7 +493,6 @@
|
||||
<string name="network_use_onion_hosts_no">不</string>
|
||||
<string name="network_use_onion_hosts_required">需要</string>
|
||||
<string name="network_use_onion_hosts_prefer_desc">Onion 主機會在可用時啟用。</string>
|
||||
<string name="network_use_onion_hosts_required_desc_in_alert">連接時將需要使用 Onion 主機。</string>
|
||||
<string name="delete_address__question">刪除聯絡地址?</string>
|
||||
<string name="your_profile_is_stored_on_device_and_shared_only_with_contacts_simplex_cannot_see_it">你的個人檔案只會儲存於你的裝置和只會分享給你的聯絡人。 SimpleX 伺服器並不會看到你的個人檔案。</string>
|
||||
<string name="save_and_notify_contact">儲存並通知你的聯絡人</string>
|
||||
@@ -825,7 +821,6 @@
|
||||
<string name="disappearing_messages_are_prohibited">自動銷毀訊息於這個群組內是禁用的。</string>
|
||||
<string name="feature_offered_item">已提供 %s</string>
|
||||
<string name="error_saving_group_profile">儲存群組檔案時出錯</string>
|
||||
<string name="network_options_revert">恢復</string>
|
||||
<string name="theme">主題</string>
|
||||
<string name="chat_preferences_you_allow">你允許</string>
|
||||
<string name="set_group_preferences">修改群組內的設定</string>
|
||||
|
||||
@@ -593,6 +593,7 @@ test-suite simplex-chat-test
|
||||
MessageBatching
|
||||
MobileTests
|
||||
ProtocolTests
|
||||
RandomServers
|
||||
RemoteTests
|
||||
SchemaDump
|
||||
ValidNames
|
||||
|
||||
+37
-18
@@ -148,8 +148,10 @@ defaultChatConfig =
|
||||
defaultServers =
|
||||
DefaultAgentServers
|
||||
{ smp = _defaultSMPServers,
|
||||
useSMP = 4,
|
||||
ntf = _defaultNtfServers,
|
||||
xftp = L.map (presetServerCfg True) defaultXFTPServers,
|
||||
useXFTP = L.length defaultXFTPServers,
|
||||
netCfg = defaultNetworkConfig
|
||||
},
|
||||
tbqSize = 1024,
|
||||
@@ -178,7 +180,13 @@ _defaultSMPServers =
|
||||
L.fromList $
|
||||
map
|
||||
(presetServerCfg True)
|
||||
[ "smp://h--vW7ZSkXPeOUpfxlFGgauQmXNFOzGoizak7Ult7cw=@smp15.simplex.im,oauu4bgijybyhczbnxtlggo6hiubahmeutaqineuyy23aojpih3dajad.onion",
|
||||
[ "smp://0YuTwO05YJWS8rkjn9eLJDjQhFKvIYd8d4xG8X1blIU=@smp8.simplex.im,beccx4yfxxbvyhqypaavemqurytl6hozr47wfc7uuecacjqdvwpw2xid.onion",
|
||||
"smp://SkIkI6EPd2D63F4xFKfHk7I1UGZVNn6k1QWZ5rcyr6w=@smp9.simplex.im,jssqzccmrcws6bhmn77vgmhfjmhwlyr3u7puw4erkyoosywgl67slqqd.onion",
|
||||
"smp://6iIcWT_dF2zN_w5xzZEY7HI2Prbh3ldP07YTyDexPjE=@smp10.simplex.im,rb2pbttocvnbrngnwziclp2f4ckjq65kebafws6g4hy22cdaiv5dwjqd.onion",
|
||||
"smp://1OwYGt-yqOfe2IyVHhxz3ohqo3aCCMjtB-8wn4X_aoY=@smp11.simplex.im,6ioorbm6i3yxmuoezrhjk6f6qgkc4syabh7m3so74xunb5nzr4pwgfqd.onion",
|
||||
"smp://UkMFNAXLXeAAe0beCa4w6X_zp18PwxSaSjY17BKUGXQ=@smp12.simplex.im,ie42b5weq7zdkghocs3mgxdjeuycheeqqmksntj57rmejagmg4eor5yd.onion",
|
||||
"smp://enEkec4hlR3UtKx2NMpOUK_K4ZuDxjWBO1d9Y4YXVaA=@smp14.simplex.im,aspkyu2sopsnizbyfabtsicikr2s4r3ti35jogbcekhm3fsoeyjvgrid.onion",
|
||||
"smp://h--vW7ZSkXPeOUpfxlFGgauQmXNFOzGoizak7Ult7cw=@smp15.simplex.im,oauu4bgijybyhczbnxtlggo6hiubahmeutaqineuyy23aojpih3dajad.onion",
|
||||
"smp://hejn2gVIqNU6xjtGM3OwQeuk8ZEbDXVJXAlnSBJBWUA=@smp16.simplex.im,p3ktngodzi6qrf7w64mmde3syuzrv57y55hxabqcq3l5p6oi7yzze6qd.onion",
|
||||
"smp://ZKe4uxF4Z_aLJJOEsC-Y6hSkXgQS5-oc442JQGkyP8M=@smp17.simplex.im,ogtwfxyi3h2h5weftjjpjmxclhb5ugufa5rcyrmg7j4xlch7qsr5nuqd.onion",
|
||||
"smp://PtsqghzQKU83kYTlQ1VKg996dW4Cw4x_bvpKmiv8uns=@smp18.simplex.im,lyqpnwbs2zqfr45jqkncwpywpbtq7jrhxnib5qddtr6npjyezuwd3nqd.onion",
|
||||
@@ -188,13 +196,7 @@ _defaultSMPServers =
|
||||
(presetServerCfg False)
|
||||
[ "smp://u2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU=@smp4.simplex.im,o5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion",
|
||||
"smp://hpq7_4gGJiilmz5Rf-CswuU5kZGkm_zOIooSw6yALRg=@smp5.simplex.im,jjbyvoemxysm7qxap7m5d5m35jzv5qq6gnlv7s4rsn7tdwwmuqciwpid.onion",
|
||||
"smp://PQUV2eL0t7OStZOoAsPEV2QYWt4-xilbakvGUGOItUo=@smp6.simplex.im,bylepyau3ty4czmn77q4fglvperknl4bi2eb2fdy2bh4jxtf32kf73yd.onion",
|
||||
"smp://0YuTwO05YJWS8rkjn9eLJDjQhFKvIYd8d4xG8X1blIU=@smp8.simplex.im,beccx4yfxxbvyhqypaavemqurytl6hozr47wfc7uuecacjqdvwpw2xid.onion",
|
||||
"smp://SkIkI6EPd2D63F4xFKfHk7I1UGZVNn6k1QWZ5rcyr6w=@smp9.simplex.im,jssqzccmrcws6bhmn77vgmhfjmhwlyr3u7puw4erkyoosywgl67slqqd.onion",
|
||||
"smp://6iIcWT_dF2zN_w5xzZEY7HI2Prbh3ldP07YTyDexPjE=@smp10.simplex.im,rb2pbttocvnbrngnwziclp2f4ckjq65kebafws6g4hy22cdaiv5dwjqd.onion",
|
||||
"smp://1OwYGt-yqOfe2IyVHhxz3ohqo3aCCMjtB-8wn4X_aoY=@smp11.simplex.im,6ioorbm6i3yxmuoezrhjk6f6qgkc4syabh7m3so74xunb5nzr4pwgfqd.onion",
|
||||
"smp://UkMFNAXLXeAAe0beCa4w6X_zp18PwxSaSjY17BKUGXQ=@smp12.simplex.im,ie42b5weq7zdkghocs3mgxdjeuycheeqqmksntj57rmejagmg4eor5yd.onion",
|
||||
"smp://enEkec4hlR3UtKx2NMpOUK_K4ZuDxjWBO1d9Y4YXVaA=@smp14.simplex.im,aspkyu2sopsnizbyfabtsicikr2s4r3ti35jogbcekhm3fsoeyjvgrid.onion"
|
||||
"smp://PQUV2eL0t7OStZOoAsPEV2QYWt4-xilbakvGUGOItUo=@smp6.simplex.im,bylepyau3ty4czmn77q4fglvperknl4bi2eb2fdy2bh4jxtf32kf73yd.onion"
|
||||
]
|
||||
|
||||
_defaultNtfServers :: [NtfServer]
|
||||
@@ -380,11 +382,31 @@ withFileLock name = withEntityLock name . CLFile
|
||||
useServers :: UserProtocol p => ChatConfig -> SProtocolType p -> [ServerCfg p] -> NonEmpty (ServerCfg p)
|
||||
useServers ChatConfig {defaultServers} p = fromMaybe (cfgServers p defaultServers) . nonEmpty
|
||||
|
||||
cfgServers :: UserProtocol p => SProtocolType p -> (DefaultAgentServers -> NonEmpty (ServerCfg p))
|
||||
randomServers :: forall p. UserProtocol p => SProtocolType p -> ChatConfig -> IO (NonEmpty (ServerCfg p), [ServerCfg p])
|
||||
randomServers p ChatConfig {defaultServers} = do
|
||||
let srvs = cfgServers p defaultServers
|
||||
(enbldSrvs, dsbldSrvs) = L.partition (\ServerCfg {enabled} -> enabled) srvs
|
||||
toUse = cfgServersToUse p defaultServers
|
||||
if length enbldSrvs <= toUse
|
||||
then pure (srvs, [])
|
||||
else do
|
||||
(enbldSrvs', srvsToDisable) <- splitAt toUse <$> shuffle enbldSrvs
|
||||
let dsbldSrvs' = map (\srv -> (srv :: ServerCfg p) {enabled = False}) srvsToDisable
|
||||
srvs' = sortOn server' $ enbldSrvs' <> dsbldSrvs' <> dsbldSrvs
|
||||
pure (fromMaybe srvs $ L.nonEmpty srvs', srvs')
|
||||
where
|
||||
server' ServerCfg {server = ProtoServerWithAuth srv _} = srv
|
||||
|
||||
cfgServers :: UserProtocol p => SProtocolType p -> DefaultAgentServers -> NonEmpty (ServerCfg p)
|
||||
cfgServers p DefaultAgentServers {smp, xftp} = case p of
|
||||
SPSMP -> smp
|
||||
SPXFTP -> xftp
|
||||
|
||||
cfgServersToUse :: UserProtocol p => SProtocolType p -> DefaultAgentServers -> Int
|
||||
cfgServersToUse p DefaultAgentServers {useSMP, useXFTP} = case p of
|
||||
SPSMP -> useSMP
|
||||
SPXFTP -> useXFTP
|
||||
|
||||
-- enableSndFiles has no effect when mainApp is True
|
||||
startChatController :: Bool -> Bool -> CM' (Async ())
|
||||
startChatController mainApp enableSndFiles = do
|
||||
@@ -523,7 +545,7 @@ processChatCommand cmd =
|
||||
processChatCommand' :: VersionRangeChat -> ChatCommand -> CM ChatResponse
|
||||
processChatCommand' vr = \case
|
||||
ShowActiveUser -> withUser' $ pure . CRActiveUser
|
||||
CreateActiveUser NewUser {profile, sameServers, pastTimestamp} -> do
|
||||
CreateActiveUser NewUser {profile, pastTimestamp} -> do
|
||||
forM_ profile $ \Profile {displayName} -> checkValidName displayName
|
||||
p@Profile {displayName} <- liftIO $ maybe generateRandomProfile pure profile
|
||||
u <- asks currentUser
|
||||
@@ -549,12 +571,10 @@ processChatCommand' vr = \case
|
||||
createContact db user simplexStatusContactProfile
|
||||
createContact db user simplexTeamContactProfile
|
||||
chooseServers :: (ProtocolTypeI p, UserProtocol p) => SProtocolType p -> CM (NonEmpty (ServerCfg p), [ServerCfg p])
|
||||
chooseServers protocol
|
||||
| sameServers =
|
||||
asks currentUser >>= readTVarIO >>= \case
|
||||
Nothing -> throwChatError CENoActiveUser
|
||||
Just user -> chosenServers =<< withFastStore' (`getProtocolServers` user)
|
||||
| otherwise = chosenServers []
|
||||
chooseServers protocol =
|
||||
asks currentUser >>= readTVarIO >>= \case
|
||||
Nothing -> asks config >>= liftIO . randomServers protocol
|
||||
Just user -> chosenServers =<< withFastStore' (`getProtocolServers` user)
|
||||
where
|
||||
chosenServers servers = do
|
||||
cfg <- asks config
|
||||
@@ -7914,10 +7934,9 @@ chatCommandP =
|
||||
onOffP = ("on" $> True) <|> ("off" $> False)
|
||||
profileNames = (,) <$> displayName <*> fullNameP
|
||||
newUserP = do
|
||||
sameServers <- "same_servers=" *> onOffP <* A.space <|> pure False
|
||||
(cName, fullName) <- profileNames
|
||||
let profile = Just Profile {displayName = cName, fullName, image = Nothing, contactLink = Nothing, preferences = Nothing}
|
||||
pure NewUser {profile, sameServers, pastTimestamp = False}
|
||||
pure NewUser {profile, pastTimestamp = False}
|
||||
jsonP :: J.FromJSON a => Parser a
|
||||
jsonP = J.eitherDecodeStrict' <$?> A.takeByteString
|
||||
groupProfile = do
|
||||
|
||||
@@ -174,8 +174,10 @@ defaultChatHooks =
|
||||
|
||||
data DefaultAgentServers = DefaultAgentServers
|
||||
{ smp :: NonEmpty (ServerCfg 'PSMP),
|
||||
useSMP :: Int,
|
||||
ntf :: [NtfServer],
|
||||
xftp :: NonEmpty (ServerCfg 'PXFTP),
|
||||
useXFTP :: Int,
|
||||
netCfg :: NetworkConfig
|
||||
}
|
||||
|
||||
|
||||
@@ -105,7 +105,7 @@ createActiveUser cc = do
|
||||
loop = do
|
||||
displayName <- T.pack <$> getWithPrompt "display name"
|
||||
let profile = Just Profile {displayName, fullName = "", image = Nothing, contactLink = Nothing, preferences = Nothing}
|
||||
execChatCommand' (CreateActiveUser NewUser {profile, sameServers = False, pastTimestamp = False}) `runReaderT` cc >>= \case
|
||||
execChatCommand' (CreateActiveUser NewUser {profile, pastTimestamp = False}) `runReaderT` cc >>= \case
|
||||
CRActiveUser user -> pure user
|
||||
r -> do
|
||||
ts <- getCurrentTime
|
||||
|
||||
@@ -39,8 +39,10 @@ terminalChatConfig =
|
||||
"smp://hpq7_4gGJiilmz5Rf-CswuU5kZGkm_zOIooSw6yALRg=@smp5.simplex.im,jjbyvoemxysm7qxap7m5d5m35jzv5qq6gnlv7s4rsn7tdwwmuqciwpid.onion",
|
||||
"smp://PQUV2eL0t7OStZOoAsPEV2QYWt4-xilbakvGUGOItUo=@smp6.simplex.im,bylepyau3ty4czmn77q4fglvperknl4bi2eb2fdy2bh4jxtf32kf73yd.onion"
|
||||
],
|
||||
useSMP = 3,
|
||||
ntf = ["ntf://FB-Uop7RTaZZEG0ZLD2CIaTjsPh-Fw0zFAnb7QyA8Ks=@ntf2.simplex.im,ntg7jdjy2i3qbib3sykiho3enekwiaqg3icctliqhtqcg6jmoh6cxiad.onion"],
|
||||
xftp = L.map (presetServerCfg True) defaultXFTPServers,
|
||||
useXFTP = L.length defaultXFTPServers,
|
||||
netCfg =
|
||||
defaultNetworkConfig
|
||||
{ smpProxyMode = SPMUnknown,
|
||||
|
||||
@@ -124,7 +124,6 @@ data User = User
|
||||
|
||||
data NewUser = NewUser
|
||||
{ profile :: Maybe Profile,
|
||||
sameServers :: Bool,
|
||||
pastTimestamp :: Bool
|
||||
}
|
||||
deriving (Show)
|
||||
|
||||
@@ -97,7 +97,6 @@ chatDirectTests = do
|
||||
it "create second user" testCreateSecondUser
|
||||
it "multiple users subscribe and receive messages after restart" testUsersSubscribeAfterRestart
|
||||
it "both users have contact link" testMultipleUserAddresses
|
||||
it "create user with default servers" testCreateUserDefaultServers
|
||||
it "create user with same servers" testCreateUserSameServers
|
||||
it "delete user" testDeleteUser
|
||||
it "users have different chat item TTL configuration, chat items expire" testUsersDifferentCIExpirationTTL
|
||||
@@ -1488,39 +1487,6 @@ testMultipleUserAddresses =
|
||||
showActiveUser alice "alice (Alice)"
|
||||
alice @@@ [("@bob", "hey alice")]
|
||||
|
||||
testCreateUserDefaultServers :: HasCallStack => FilePath -> IO ()
|
||||
testCreateUserDefaultServers =
|
||||
testChat2 aliceProfile bobProfile $
|
||||
\alice _ -> do
|
||||
alice #$> ("/smp smp://2345-w==@smp2.example.im smp://3456-w==@smp3.example.im:5224", id, "ok")
|
||||
alice #$> ("/xftp xftp://2345-w==@xftp2.example.im xftp://3456-w==@xftp3.example.im:5224", id, "ok")
|
||||
checkCustomServers alice
|
||||
|
||||
alice ##> "/create user alisa"
|
||||
showActiveUser alice "alisa"
|
||||
|
||||
alice #$> ("/smp", id, "smp://LcJUMfVhwD8yxjAiSaDzzGF3-kLG4Uh0Fl_ZIjrRwjI=:server_password@localhost:7001")
|
||||
alice #$> ("/xftp", id, "xftp://LcJUMfVhwD8yxjAiSaDzzGF3-kLG4Uh0Fl_ZIjrRwjI=:server_password@localhost:7002")
|
||||
|
||||
-- with same_servers=off
|
||||
alice ##> "/user alice"
|
||||
showActiveUser alice "alice (Alice)"
|
||||
checkCustomServers alice
|
||||
|
||||
alice ##> "/create user same_servers=off alisa2"
|
||||
showActiveUser alice "alisa2"
|
||||
|
||||
alice #$> ("/smp", id, "smp://LcJUMfVhwD8yxjAiSaDzzGF3-kLG4Uh0Fl_ZIjrRwjI=:server_password@localhost:7001")
|
||||
alice #$> ("/xftp", id, "xftp://LcJUMfVhwD8yxjAiSaDzzGF3-kLG4Uh0Fl_ZIjrRwjI=:server_password@localhost:7002")
|
||||
where
|
||||
checkCustomServers alice = do
|
||||
alice ##> "/smp"
|
||||
alice <## "smp://2345-w==@smp2.example.im"
|
||||
alice <## "smp://3456-w==@smp3.example.im:5224"
|
||||
alice ##> "/xftp"
|
||||
alice <## "xftp://2345-w==@xftp2.example.im"
|
||||
alice <## "xftp://3456-w==@xftp3.example.im:5224"
|
||||
|
||||
testCreateUserSameServers :: HasCallStack => FilePath -> IO ()
|
||||
testCreateUserSameServers =
|
||||
testChat2 aliceProfile bobProfile $
|
||||
@@ -1529,7 +1495,7 @@ testCreateUserSameServers =
|
||||
alice #$> ("/xftp xftp://2345-w==@xftp2.example.im xftp://3456-w==@xftp3.example.im:5224", id, "ok")
|
||||
checkCustomServers alice
|
||||
|
||||
alice ##> "/create user same_servers=on alisa"
|
||||
alice ##> "/create user alisa"
|
||||
showActiveUser alice "alisa"
|
||||
|
||||
checkCustomServers alice
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
{-# LANGUAGE NamedFieldPuns #-}
|
||||
{-# LANGUAGE ScopedTypeVariables #-}
|
||||
{-# LANGUAGE StandaloneDeriving #-}
|
||||
{-# OPTIONS_GHC -Wno-orphans #-}
|
||||
|
||||
module RandomServers where
|
||||
|
||||
import Control.Monad (replicateM)
|
||||
import qualified Data.List.NonEmpty as L
|
||||
import Simplex.Chat (cfgServers, cfgServersToUse, defaultChatConfig, randomServers)
|
||||
import Simplex.Chat.Controller (ChatConfig (..))
|
||||
import Simplex.Messaging.Agent.Env.SQLite (ServerCfg (..))
|
||||
import Simplex.Messaging.Protocol (ProtoServerWithAuth (..), SProtocolType (..), UserProtocol)
|
||||
import Test.Hspec
|
||||
|
||||
randomServersTests :: Spec
|
||||
randomServersTests = describe "choosig random servers" $ do
|
||||
it "should choose 4 random SMP servers and keep the rest disabled" testRandomSMPServers
|
||||
it "should keep all 6 XFTP servers" testRandomXFTPServers
|
||||
|
||||
deriving instance Eq (ServerCfg p)
|
||||
|
||||
testRandomSMPServers :: IO ()
|
||||
testRandomSMPServers = do
|
||||
[srvs1, srvs2, srvs3] <-
|
||||
replicateM 3 $
|
||||
checkEnabled SPSMP 4 False =<< randomServers SPSMP defaultChatConfig
|
||||
(srvs1 == srvs2 && srvs2 == srvs3) `shouldBe` False -- && to avoid rare failures
|
||||
|
||||
testRandomXFTPServers :: IO ()
|
||||
testRandomXFTPServers = do
|
||||
[srvs1, srvs2, srvs3] <-
|
||||
replicateM 3 $
|
||||
checkEnabled SPXFTP 6 True =<< randomServers SPXFTP defaultChatConfig
|
||||
(srvs1 == srvs2 && srvs2 == srvs3) `shouldBe` True
|
||||
|
||||
checkEnabled :: UserProtocol p => SProtocolType p -> Int -> Bool -> (L.NonEmpty (ServerCfg p), [ServerCfg p]) -> IO [ServerCfg p]
|
||||
checkEnabled p n allUsed (srvs, _) = do
|
||||
let def = defaultServers defaultChatConfig
|
||||
cfgSrvs = L.sortWith server' $ cfgServers p def
|
||||
toUse = cfgServersToUse p def
|
||||
srvs == cfgSrvs `shouldBe` allUsed
|
||||
L.map enable srvs `shouldBe` L.map enable cfgSrvs
|
||||
let enbldSrvs = L.filter (\ServerCfg {enabled} -> enabled) srvs
|
||||
toUse `shouldBe` n
|
||||
length enbldSrvs `shouldBe` n
|
||||
pure enbldSrvs
|
||||
where
|
||||
server' ServerCfg {server = ProtoServerWithAuth srv _} = srv
|
||||
enable :: forall p. ServerCfg p -> ServerCfg p
|
||||
enable srv = (srv :: ServerCfg p) {enabled = False}
|
||||
@@ -10,6 +10,7 @@ import MarkdownTests
|
||||
import MessageBatching
|
||||
import MobileTests
|
||||
import ProtocolTests
|
||||
import RandomServers
|
||||
import RemoteTests
|
||||
import SchemaDump
|
||||
import Test.Hspec hiding (it)
|
||||
@@ -30,6 +31,7 @@ main = do
|
||||
around tmpBracket $ describe "WebRTC encryption" webRTCTests
|
||||
describe "Valid names" validNameTests
|
||||
describe "Message batching" batchingTests
|
||||
describe "Random servers" randomServersTests
|
||||
around testBracket $ do
|
||||
describe "Mobile API Tests" mobileTests
|
||||
describe "SimpleX chat client" chatTests
|
||||
|
||||
Reference in New Issue
Block a user