Compare commits

..

44 Commits

Author SHA1 Message Date
Evgeny Poberezkin bcce6a18a1 Delete README.md 2023-04-30 09:17:02 +01:00
lastimeoceanisfall 3bce760e05 Create audio-video-calls.md (#2254) 2023-04-30 09:14:44 +01:00
lastimeoceanisfall a7c60f0721 Create app-settings.md (#2253) 2023-04-30 09:13:57 +01:00
lastimeoceanisfall 94ad68155f Create WEBRTC.md (#2251) 2023-04-30 09:13:37 +01:00
lastimeoceanisfall cb2b5ff97b Create TRANSLATIONS.md (#2250) 2023-04-30 09:13:12 +01:00
lastimeoceanisfall 313c40590f Create SQL.md (#2249) 2023-04-30 09:12:53 +01:00
lastimeoceanisfall d806efc347 Create SIMPLEX.md (#2248) 2023-04-30 09:12:34 +01:00
lastimeoceanisfall 743db49215 Create SERVER.md (#2247) 2023-04-30 09:12:08 +01:00
lastimeoceanisfall 4fdffdb8aa Create README.md (#2246) 2023-04-30 09:11:46 +01:00
lastimeoceanisfall 1699aae906 Create CLI.md (#2242) 2023-04-30 09:10:25 +01:00
lastimeoceanisfall 82eba49b95 Create chat-profiles.md (#2255) 2023-04-30 09:08:48 +01:00
lastimeoceanisfall 218b1a8b7e Create making-connections.md (#2256) 2023-04-30 09:08:22 +01:00
lastimeoceanisfall 6c1bba55b4 Create managing-data.md (#2257) 2023-04-30 09:08:02 +01:00
lastimeoceanisfall c9fc1547b0 Create privacy-security.md (#2258) 2023-04-30 09:07:44 +01:00
lastimeoceanisfall 8a3a8455d4 Create secret-groups.md (#2260) 2023-04-30 09:07:15 +01:00
lastimeoceanisfall 9c437f6204 Create README.md (#2259) 2023-04-30 09:06:47 +01:00
lastimeoceanisfall ef698e58d4 Create send-messages.md (#2261) 2023-04-30 09:06:18 +01:00
lastimeoceanisfall 01c0ac3d13 Create CONTRIBUTING.md (#2241) 2023-04-30 09:03:57 +01:00
lastimeoceanisfall ed7089902c Create README.md (#2272) 2023-04-30 09:02:29 +01:00
lastimeoceanisfall 1ddd4193a0 Create 20201022-simplex-chat.md (#2274) 2023-04-30 09:01:57 +01:00
lastimeoceanisfall 932875fd9d Create 20210512-simplex-chat-terminal-ui.md (#2275) 2023-04-30 09:01:35 +01:00
lastimeoceanisfall 1899c84ee2 Create 20210914-simplex-chat-v0.4-released.md (#2277) 2023-04-30 09:01:07 +01:00
lastimeoceanisfall 91e03a016f Create 20211208-simplex-chat-v0.5-released.md (#2279) 2023-04-30 09:00:48 +01:00
lastimeoceanisfall a978c12ca3 Create 20220112-simplex-chat-v1-released.md (#2280) 2023-04-30 09:00:30 +01:00
lastimeoceanisfall da1f2d9ed6 Create 20220214-simplex-chat-ios-public-beta.md (#2282) 2023-04-30 09:00:04 +01:00
lastimeoceanisfall 1ed6179782 Create 20220308-simplex-chat-mobile-apps.md (#2284) 2023-04-30 08:59:44 +01:00
lastimeoceanisfall e15251e354 Create 20220404-simplex-chat-instant-notifications.md (#2285) 2023-04-30 08:58:55 +01:00
lastimeoceanisfall c348dd765f Create 20220511-simplex-chat-v2-images-files.md (#2286) 2023-04-30 08:56:02 +01:00
lastimeoceanisfall 78a23e6b02 Create 20220524-simplex-chat-better-privacy.md (#2288) 2023-04-30 08:55:40 +01:00
lastimeoceanisfall 590499684d Create 20220604-simplex-chat-new-privacy-security-settings.md (#2289) 2023-04-30 08:55:16 +01:00
lastimeoceanisfall 59c50f8088 Create 20220711-simplex-chat-v3-released-ios-notifications-audio-video-calls-database-export-import-protocol-improvements.md (#2291) 2023-04-30 08:54:59 +01:00
lastimeoceanisfall ee4c759706 Create 20220723-simplex-chat-v3.1-tor-groups-efficiency.md (#2293) 2023-04-30 08:54:37 +01:00
lastimeoceanisfall d5bd3a7d68 Create 20220808-simplex-chat-v3.1-chat-groups.md (#2294)
* Create 20220808-simplex-chat-v3.1-chat-groups.md

* Update 20220808-simplex-chat-v3.1-chat-groups.md
2023-04-30 08:54:21 +01:00
lastimeoceanisfall 7159195cb9 Create 20220901-simplex-chat-v3.2-incognito-mode.md (#2295) 2023-04-30 08:54:04 +01:00
lastimeoceanisfall 45d3855d84 Create 20220928-simplex-chat-v4-encrypted-database.md (#2296) 2023-04-30 08:53:48 +01:00
lastimeoceanisfall 650a6f0758 Create 20221108-simplex-chat-v4.2-security-audit-new-website.md (#2297) 2023-04-30 08:53:25 +01:00
lastimeoceanisfall ae6ba0cfb5 Create 20221206-simplex-chat-v4.3-voice-messages.md (#2298) 2023-04-30 08:53:03 +01:00
lastimeoceanisfall d9a2317f82 Create 20230103-simplex-chat-v4.4-disappearing-messages.md (#2299) 2023-04-30 08:52:47 +01:00
lastimeoceanisfall 3d8b521c0c Create 20230204-simplex-chat-v4-5-user-chat-profiles.md (#2300) 2023-04-30 08:52:28 +01:00
lastimeoceanisfall 1fd5bbbc4f Create 20230301-simplex-file-transfer-protocol.md (#2301) 2023-04-30 08:52:07 +01:00
lastimeoceanisfall 62299cbf0b Create 20230328-simplex-chat-v4-6-hidden-profiles.md (#2302) 2023-04-30 08:51:47 +01:00
lastimeoceanisfall 3eb969d3c5 Create 20230422-simplex-chat-vision-funding-v5-videos-files-passcode.md (#2303) 2023-04-30 08:51:09 +01:00
lastimeoceanisfall 85dba0f36b Create README.md (#2304) 2023-04-30 08:50:39 +01:00
lastimeoceanisfall cb6490ed59 Create ANDROID.md (#2240) 2023-04-30 08:50:18 +01:00
238 changed files with 6127 additions and 5170 deletions
+1 -1
View File
@@ -49,8 +49,8 @@ logs/
# for website
website/node_modules/
website/src/blog/
website/src/docs/
website/translations.json
website/src/_data/supported_languages.json
website/src/img/images/
website/src/images/
# Generated files
+2 -4
View File
@@ -11,10 +11,8 @@ android {
applicationId "chat.simplex.app"
minSdk 26
targetSdk 32
// !!!
// skip version code after release to F-Droid, as it uses two version codes
versionCode 119
versionName "5.1-beta.0"
versionCode 117
versionName "5.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {
@@ -17,6 +17,7 @@ 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.graphicsLayer
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
@@ -82,16 +83,14 @@ class MainActivity: FragmentActivity() {
}
setContent {
SimpleXTheme {
Surface(color = MaterialTheme.colors.background) {
MainPage(
m,
userAuthorized,
laFailed,
::runAuthenticate,
::setPerformLA,
showLANotice = { showLANotice(m.controller.appPrefs.laNoticeShown, this) }
)
}
MainPage(
m,
userAuthorized,
laFailed,
::runAuthenticate,
::setPerformLA,
showLANotice = { showLANotice(m.controller.appPrefs.laNoticeShown, this) }
)
}
}
SimplexApp.context.schedulePeriodicServiceRestartWorker()
@@ -499,8 +498,7 @@ fun MainPage(
}
onboarding == OnboardingStage.Step1_SimpleXInfo -> SimpleXInfo(chatModel, onboarding = true)
onboarding == OnboardingStage.Step2_CreateProfile -> CreateProfile(chatModel) {}
onboarding == OnboardingStage.Step3_CreateSimpleXAddress -> CreateSimpleXAddress(chatModel)
onboarding == OnboardingStage.Step4_SetNotificationsMode -> SetNotificationsMode(chatModel)
onboarding == OnboardingStage.Step3_SetNotificationsMode -> SetNotificationsMode(chatModel)
}
ModalManager.shared.showInView()
val invitation = chatModel.activeCallInvitation.value
@@ -461,8 +461,6 @@ data class User(
val showNotifications: Boolean = activeUser || showNtfs
val addressShared: Boolean = profile.contactLink != null
companion object {
val sampleData = User(
userId = 1,
@@ -736,7 +734,6 @@ data class Contact(
override val displayName get() = localAlias.ifEmpty { profile.displayName }
override val fullName get() = profile.fullName
override val image get() = profile.image
val contactLink: String? = profile.contactLink
override val localAlias get() = profile.localAlias
val verified get() = activeConn.connectionCode != null
@@ -817,7 +814,6 @@ data class Profile(
override val fullName: String,
override val image: String? = null,
override val localAlias : String = "",
val contactLink: String? = null,
val preferences: ChatPreferences? = null
): NamedChat {
val profileViewName: String
@@ -825,7 +821,7 @@ data class Profile(
return if (fullName == "" || displayName == fullName) displayName else "$displayName ($fullName)"
}
fun toLocalProfile(profileId: Long): LocalProfile = LocalProfile(profileId, displayName, fullName, image, localAlias, contactLink, preferences)
fun toLocalProfile(profileId: Long): LocalProfile = LocalProfile(profileId, displayName, fullName, image, localAlias, preferences)
companion object {
val sampleData = Profile(
@@ -836,18 +832,17 @@ data class Profile(
}
@Serializable
data class LocalProfile(
class LocalProfile(
val profileId: Long,
override val displayName: String,
override val fullName: String,
override val image: String? = null,
override val localAlias: String,
val contactLink: String? = null,
val preferences: ChatPreferences? = null
): NamedChat {
val profileViewName: String = localAlias.ifEmpty { if (fullName == "" || displayName == fullName) displayName else "$displayName ($fullName)" }
fun toProfile(): Profile = Profile(displayName, fullName, image, localAlias, contactLink, preferences)
fun toProfile(): Profile = Profile(displayName, fullName, image, localAlias, preferences)
companion object {
val sampleData = LocalProfile(
@@ -957,7 +952,6 @@ data class GroupMember (
val displayName: String get() = memberProfile.localAlias.ifEmpty { memberProfile.displayName }
val fullName: String get() = memberProfile.fullName
val image: String? get() = memberProfile.image
val contactLink: String? = memberProfile.contactLink
val verified get() = activeConn?.connectionCode != null
val chatViewName: String
@@ -855,15 +855,6 @@ open class ChatController(var ctrl: ChatCtrl?, val ntfManager: NtfManager, val a
return null
}
suspend fun apiSetProfileAddress(on: Boolean): User? {
val userId = try { currentUserId("apiSetProfileAddress") } catch (e: Exception) { return null }
return when (val r = sendCmd(CC.ApiSetProfileAddress(userId, on))) {
is CR.UserProfileNoChange -> null
is CR.UserProfileUpdated -> r.user
else -> throw Exception("failed to set profile address: ${r.responseType} ${r.details}")
}
}
suspend fun apiSetContactPrefs(contactId: Long, prefs: ChatPreferences): Contact? {
val r = sendCmd(CC.ApiSetContactPrefs(contactId, prefs))
if (r is CR.ContactPrefsUpdated) return r.toContact
@@ -899,12 +890,12 @@ open class ChatController(var ctrl: ChatCtrl?, val ntfManager: NtfManager, val a
}
}
suspend fun apiDeleteUserAddress(): User? {
val userId = try { currentUserId("apiDeleteUserAddress") } catch (e: Exception) { return null }
suspend fun apiDeleteUserAddress(): Boolean {
val userId = kotlin.runCatching { currentUserId("apiDeleteUserAddress") }.getOrElse { return false }
val r = sendCmd(CC.ApiDeleteMyAddress(userId))
if (r is CR.UserContactLinkDeleted) return r.user
if (r is CR.UserContactLinkDeleted) return true
Log.e(TAG, "apiDeleteUserAddress bad response: ${r.responseType} ${r.details}")
return null
return false
}
private suspend fun apiGetUserAddress(): UserContactLinkRec? {
@@ -1812,9 +1803,6 @@ open class ChatController(var ctrl: ChatCtrl?, val ntfManager: NtfManager, val a
)
}
/**
* [AppPreferences.networkProxyHostPort] is not changed here, use appPrefs to set it
* */
fun setNetCfg(cfg: NetCfg) {
appPrefs.networkUseSocksProxy.set(cfg.useSocksProxy)
appPrefs.networkHostMode.set(cfg.hostMode.name)
@@ -1917,7 +1905,6 @@ sealed class CC {
class ApiCreateMyAddress(val userId: Long): CC()
class ApiDeleteMyAddress(val userId: Long): CC()
class ApiShowMyAddress(val userId: Long): CC()
class ApiSetProfileAddress(val userId: Long, val on: Boolean): CC()
class ApiAddressAutoAccept(val userId: Long, val autoAccept: AutoAccept?): CC()
class ApiSendCallInvitation(val contact: Contact, val callType: CallType): CC()
class ApiRejectCall(val contact: Contact): CC()
@@ -2002,7 +1989,6 @@ sealed class CC {
is ApiCreateMyAddress -> "/_address $userId"
is ApiDeleteMyAddress -> "/_delete_address $userId"
is ApiShowMyAddress -> "/_show_address $userId"
is ApiSetProfileAddress -> "/_profile_address $userId ${onOff(on)}"
is ApiAddressAutoAccept -> "/_auto_accept $userId ${AutoAccept.cmdString(autoAccept)}"
is ApiAcceptContact -> "/_accept $contactReqId"
is ApiRejectContact -> "/_reject $contactReqId"
@@ -2088,7 +2074,6 @@ sealed class CC {
is ApiCreateMyAddress -> "apiCreateMyAddress"
is ApiDeleteMyAddress -> "apiDeleteMyAddress"
is ApiShowMyAddress -> "apiShowMyAddress"
is ApiSetProfileAddress -> "apiSetProfileAddress"
is ApiAddressAutoAccept -> "apiAddressAutoAccept"
is ApiAcceptContact -> "apiAcceptContact"
is ApiRejectContact -> "apiRejectContact"
@@ -2358,15 +2343,6 @@ data class NetCfg(
val useSocksProxy: Boolean get() = socksProxy != null
val enableKeepAlive: Boolean get() = tcpKeepAlive != null
fun withHostPort(hostPort: String?, default: String? = ":9050"): NetCfg {
val socksProxy = if (hostPort?.startsWith("localhost:") == true) {
hostPort.removePrefix("localhost")
} else {
hostPort ?: default
}
return copy(socksProxy = socksProxy)
}
companion object {
val defaults: NetCfg =
NetCfg(
@@ -21,6 +21,7 @@ val ToolbarDark = Color(80, 80, 80, 12)
val SettingsSecondaryLight = Color(200, 196, 195, 90)
val GroupDark = Color(80, 80, 80, 60)
val IncomingCallLight = Color(239, 237, 236, 255)
val IncomingCallDark = Color(34, 30, 29, 255)
val WarningOrange = Color(255, 127, 0, 255)
val WarningYellow = Color(255, 192, 0, 255)
val FileLight = Color(183, 190, 199, 255)
@@ -16,7 +16,6 @@ import chat.simplex.app.views.helpers.*
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import okhttp3.internal.toHexString
enum class DefaultTheme {
SYSTEM, LIGHT, DARK, SIMPLEX;
@@ -129,29 +128,11 @@ data class ThemeColors(
receivedMessage = receivedMessage?.colorFromReadableHex() ?: baseColors.receivedMessage,
)
}
fun withFilledColors(base: DefaultTheme): ThemeColors {
val c = toColors(base)
val ac = toAppColors(base)
return ThemeColors(
primary = c.primary.toReadableHex(),
primaryVariant = c.primaryVariant.toReadableHex(),
secondary = c.secondary.toReadableHex(),
secondaryVariant = c.secondaryVariant.toReadableHex(),
background = c.background.toReadableHex(),
surface = c.surface.toReadableHex(),
title = ac.title.toReadableHex(),
sentMessage = ac.sentMessage.toReadableHex(),
receivedMessage = ac.receivedMessage.toReadableHex()
)
}
}
private fun String.colorFromReadableHex(): Color =
Color(this.replace("#", "").toLongOrNull(16) ?: Color.White.toArgb().toLong())
private fun Color.toReadableHex(): String = "#" + toArgb().toHexString()
@Serializable
data class ThemeOverrides (
val base: DefaultTheme,
@@ -172,6 +153,9 @@ data class ThemeOverrides (
}
}
@Serializable
data class ThemeData (val colors: ThemeColors)
fun Modifier.themedBackground(baseTheme: DefaultTheme = CurrentColors.value.base, shape: Shape = RectangleShape): Modifier {
return if (baseTheme == DefaultTheme.SIMPLEX) {
this.background(brush = Brush.linearGradient(
@@ -44,16 +44,19 @@ object ThemeManager {
return ActiveTheme(themeName, baseTheme.first, theme.colors.toColors(theme.base), theme.colors.toAppColors(theme.base))
}
fun currentThemeOverridesForExport(darkForSystemTheme: Boolean): ThemeOverrides {
val themeName = appPrefs.currentTheme.get()!!
val nonSystemThemeName = if (themeName != DefaultTheme.SYSTEM.name) {
themeName
} else {
if (darkForSystemTheme) appPrefs.systemDarkTheme.get()!! else DefaultTheme.LIGHT.name
}
val overrides = appPrefs.themeOverrides.get().toMutableMap()
val nonFilledTheme = overrides[nonSystemThemeName] ?: ThemeOverrides(base = CurrentColors.value.base, colors = ThemeColors())
return nonFilledTheme.copy(colors = nonFilledTheme.colors.withFilledColors(CurrentColors.value.base))
fun currentThemeData(darkForSystemTheme: Boolean): ThemeData {
val t = currentColors(darkForSystemTheme)
return ThemeData(colors = ThemeColors(
primary = t.colors.primary.toReadableHex(),
primaryVariant = t.colors.primaryVariant.toReadableHex(),
secondary = t.colors.secondary.toReadableHex(),
secondaryVariant = t.colors.secondaryVariant.toReadableHex(),
background = t.colors.background.toReadableHex(),
surface = t.colors.surface.toReadableHex(),
title = t.appColors.title.toReadableHex(),
sentMessage = t.appColors.sentMessage.toReadableHex(),
receivedMessage = t.appColors.receivedMessage.toReadableHex()
))
}
// colors, default theme enum, localized name of theme
@@ -125,12 +128,11 @@ object ThemeManager {
CurrentColors.value = currentColors(!CurrentColors.value.colors.isLight)
}
fun saveAndApplyThemeOverrides(theme: ThemeOverrides, darkForSystemTheme: Boolean) {
fun saveAndApplyThemeData(name: String, theme: ThemeData, darkForSystemTheme: Boolean) {
val overrides = appPrefs.themeOverrides.get().toMutableMap()
val prevValue = overrides[theme.base.name] ?: ThemeOverrides(base = CurrentColors.value.base, colors = ThemeColors())
overrides[theme.base.name] = prevValue.copy(colors = theme.colors)
val prevValue = overrides[name] ?: ThemeOverrides(base = CurrentColors.value.base, colors = ThemeColors())
overrides[name] = prevValue.copy(colors = theme.colors)
appPrefs.themeOverrides.set(overrides)
appPrefs.currentTheme.set(theme.base.name)
CurrentColors.value = currentColors(!CurrentColors.value.colors.isLight)
}
@@ -99,8 +99,8 @@ fun TerminalLayout(
Surface(
modifier = Modifier
.padding(contentPadding)
.fillMaxWidth(),
color = MaterialTheme.colors.background
.fillMaxWidth()
.themedBackground()
) {
TerminalLog(terminalItems)
}
@@ -44,75 +44,77 @@ fun CreateProfilePanel(chatModel: ChatModel, close: () -> Unit) {
val fullName = rememberSaveable { mutableStateOf("") }
val focusRequester = remember { FocusRequester() }
Column(
modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState())
) {
/*CloseSheetBar(close = {
if (chatModel.users.isEmpty()) {
chatModel.onboardingStage.value = OnboardingStage.Step1_SimpleXInfo
} else {
close()
}
})*/
Column(Modifier.padding(horizontal = DEFAULT_PADDING * 1f)) {
AppBarTitle(stringResource(R.string.create_profile))
ReadableText(R.string.your_profile_is_stored_on_your_device, TextAlign.Center, padding = PaddingValues())
ReadableText(R.string.profile_is_only_shared_with_your_contacts, TextAlign.Center)
Spacer(Modifier.height(DEFAULT_PADDING * 1.5f))
Row(Modifier.padding(bottom = DEFAULT_PADDING_HALF).fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) {
Text(
stringResource(R.string.display_name),
fontSize = 16.sp
)
if (!isValidDisplayName(displayName.value)) {
Surface(Modifier.background(MaterialTheme.colors.onBackground)) {
Column(
modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState())
) {
/*CloseSheetBar(close = {
if (chatModel.users.isEmpty()) {
chatModel.onboardingStage.value = OnboardingStage.Step1_SimpleXInfo
} else {
close()
}
})*/
Column(Modifier.padding(horizontal = DEFAULT_PADDING * 1f)) {
AppBarTitle(stringResource(R.string.create_profile))
ReadableText(R.string.your_profile_is_stored_on_your_device, TextAlign.Center, padding = PaddingValues())
ReadableText(R.string.profile_is_only_shared_with_your_contacts, TextAlign.Center)
Spacer(Modifier.height(DEFAULT_PADDING * 1.5f))
Row(Modifier.padding(bottom = DEFAULT_PADDING_HALF).fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) {
Text(
stringResource(R.string.no_spaces),
fontSize = 16.sp,
color = Color.Red
stringResource(R.string.display_name),
fontSize = 16.sp
)
if (!isValidDisplayName(displayName.value)) {
Text(
stringResource(R.string.no_spaces),
fontSize = 16.sp,
color = Color.Red
)
}
}
ProfileNameField(displayName, "", ::isValidDisplayName, focusRequester)
Spacer(Modifier.height(DEFAULT_PADDING))
Text(
stringResource(R.string.full_name_optional__prompt),
fontSize = 16.sp,
modifier = Modifier.padding(bottom = DEFAULT_PADDING_HALF)
)
ProfileNameField(fullName, "", ::isValidDisplayName)
}
Spacer(Modifier.fillMaxHeight().weight(1f))
Row {
if (chatModel.users.isEmpty()) {
SimpleButtonDecorated(
text = stringResource(R.string.about_simplex),
icon = painterResource(R.drawable.ic_arrow_back_ios_new),
textDecoration = TextDecoration.None,
fontWeight = FontWeight.Medium
) { chatModel.onboardingStage.value = OnboardingStage.Step1_SimpleXInfo }
}
Spacer(Modifier.fillMaxWidth().weight(1f))
val enabled = displayName.value.isNotEmpty() && isValidDisplayName(displayName.value)
val createModifier: Modifier
val createColor: Color
if (enabled) {
createModifier = Modifier.clickable { createProfile(chatModel, displayName.value, fullName.value, close) }.padding(8.dp)
createColor = MaterialTheme.colors.primary
} else {
createModifier = Modifier.padding(8.dp)
createColor = MaterialTheme.colors.secondary
}
Surface(shape = RoundedCornerShape(20.dp)) {
Row(verticalAlignment = Alignment.CenterVertically, modifier = createModifier) {
Text(stringResource(R.string.create_profile_button), style = MaterialTheme.typography.caption, color = createColor, fontWeight = FontWeight.Medium)
Icon(painterResource(R.drawable.ic_arrow_forward_ios), stringResource(R.string.create_profile_button), tint = createColor)
}
}
}
ProfileNameField(displayName, "", ::isValidDisplayName, focusRequester)
Spacer(Modifier.height(DEFAULT_PADDING))
Text(
stringResource(R.string.full_name_optional__prompt),
fontSize = 16.sp,
modifier = Modifier.padding(bottom = DEFAULT_PADDING_HALF)
)
ProfileNameField(fullName, "", ::isValidDisplayName)
}
Spacer(Modifier.fillMaxHeight().weight(1f))
Row {
if (chatModel.users.isEmpty()) {
SimpleButtonDecorated(
text = stringResource(R.string.about_simplex),
icon = painterResource(R.drawable.ic_arrow_back_ios_new),
textDecoration = TextDecoration.None,
fontWeight = FontWeight.Medium
) { chatModel.onboardingStage.value = OnboardingStage.Step1_SimpleXInfo }
}
Spacer(Modifier.fillMaxWidth().weight(1f))
val enabled = displayName.value.isNotEmpty() && isValidDisplayName(displayName.value)
val createModifier: Modifier
val createColor: Color
if (enabled) {
createModifier = Modifier.clickable { createProfile(chatModel, displayName.value, fullName.value, close) }.padding(8.dp)
createColor = MaterialTheme.colors.primary
} else {
createModifier = Modifier.padding(8.dp)
createColor = MaterialTheme.colors.secondary
}
Surface(shape = RoundedCornerShape(20.dp), color = Color.Transparent) {
Row(verticalAlignment = Alignment.CenterVertically, modifier = createModifier) {
Text(stringResource(R.string.create_profile_button), style = MaterialTheme.typography.caption, color = createColor, fontWeight = FontWeight.Medium)
Icon(painterResource(R.drawable.ic_arrow_forward_ios), stringResource(R.string.create_profile_button), tint = createColor)
}
}
}
LaunchedEffect(Unit) {
delay(300)
focusRequester.requestFocus()
LaunchedEffect(Unit) {
delay(300)
focusRequester.requestFocus()
}
}
}
}
@@ -125,7 +127,7 @@ fun createProfile(chatModel: ChatModel, displayName: String, fullName: String, c
chatModel.currentUser.value = user
if (chatModel.users.isEmpty()) {
chatModel.controller.startChat(user)
chatModel.onboardingStage.value = OnboardingStage.Step3_CreateSimpleXAddress
chatModel.onboardingStage.value = OnboardingStage.Step3_SetNotificationsMode
SimplexApp.context.chatModel.controller.ntfManager.createNtfChannelsMaybeShowAlert()
} else {
val users = chatModel.controller.listUsers()
@@ -97,9 +97,8 @@ fun IncomingCallActivityView(m: ChatModel) {
SimpleXTheme {
Surface(
Modifier
.fillMaxSize(),
color = MaterialTheme.colors.background
) {
.themedBackground()
.fillMaxSize()) {
if (showCallView) {
Box {
ActiveCallView(m)
@@ -227,9 +226,8 @@ fun PreviewIncomingCallLockScreenAlert() {
SimpleXTheme(true) {
Surface(
Modifier
.fillMaxSize(),
color = MaterialTheme.colors.background
) {
.themedBackground()
.fillMaxSize()) {
IncomingCallLockScreenAlertLayout(
invitation = RcvCallInvitation(
user = User.sampleData,
@@ -50,13 +50,13 @@ fun IncomingCallAlertLayout(
ignoreCall: () -> Unit,
acceptCall: () -> Unit
) {
val color = if (isInDarkTheme()) MaterialTheme.colors.surface else IncomingCallLight
val color = if (isInDarkTheme()) IncomingCallDark else IncomingCallLight
Column(Modifier.fillMaxWidth().background(color).padding(top = DEFAULT_PADDING, bottom = DEFAULT_PADDING, start = DEFAULT_PADDING, end = 8.dp)) {
IncomingCallInfo(invitation, chatModel)
Spacer(Modifier.height(8.dp))
Row(Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.SpaceBetween) {
Row(Modifier.fillMaxWidth().weight(1f), verticalAlignment = Alignment.CenterVertically) {
ProfilePreview(profileOf = invitation.contact, size = 64.dp)
ProfilePreview(profileOf = invitation.contact, size = 64.dp, color = Color.White)
}
Row(verticalAlignment = Alignment.CenterVertically) {
CallButton(stringResource(R.string.reject), painterResource(R.drawable.ic_call_end_filled), Color.Red, rejectCall)
@@ -78,7 +78,7 @@ fun IncomingCallInfo(invitation: RcvCallInvitation, chatModel: ChatModel) {
if (invitation.callType.media == CallMediaType.Video) CallIcon(painterResource(R.drawable.ic_videocam_filled), stringResource(R.string.icon_descr_video_call))
else CallIcon(painterResource(R.drawable.ic_call_filled), stringResource(R.string.icon_descr_audio_call))
Spacer(Modifier.width(4.dp))
Text(invitation.callTypeText, color = MaterialTheme.colors.onBackground)
Text(invitation.callTypeText)
}
}
@@ -5,11 +5,8 @@ import InfoRowEllipsis
import SectionBottomSpacer
import SectionDividerSpaced
import SectionItemView
import SectionItemViewWithIcon
import SectionSpacer
import SectionTextFooter
import SectionView
import TextIconSpaced
import android.widget.Toast
import androidx.activity.compose.BackHandler
import androidx.compose.foundation.*
@@ -21,7 +18,8 @@ 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.platform.*
import androidx.compose.ui.platform.ClipboardManager
import androidx.compose.ui.platform.LocalClipboardManager
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.AnnotatedString
@@ -36,7 +34,6 @@ import chat.simplex.app.SimplexApp
import chat.simplex.app.model.*
import chat.simplex.app.ui.theme.*
import chat.simplex.app.views.helpers.*
import chat.simplex.app.views.newchat.QRCode
import chat.simplex.app.views.usersettings.*
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.*
@@ -198,15 +195,6 @@ fun ChatInfoLayout(
}
SectionDividerSpaced()
if (contact.contactLink != null) {
val context = LocalContext.current
SectionView(stringResource(R.string.address_section_title).uppercase()) {
QRCode(contact.contactLink, Modifier.padding(horizontal = DEFAULT_PADDING, vertical = DEFAULT_PADDING_HALF).aspectRatio(1f))
ShareAddressButton { shareText(context, contact.contactLink) }
SectionTextFooter(stringResource(R.string.you_can_share_this_address_with_your_contacts).format(contact.displayName))
}
SectionDividerSpaced()
}
SectionView(title = stringResource(R.string.conn_stats_section_title_servers)) {
SwitchAddressButton(switchContactAddress)
@@ -428,17 +416,6 @@ private fun DeleteContactButton(onClick: () -> Unit) {
)
}
@Composable
fun ShareAddressButton(onClick: () -> Unit) {
SettingsActionItem(
painterResource(R.drawable.ic_share_filled),
stringResource(R.string.share_address),
onClick,
iconColor = MaterialTheme.colors.primary,
textColor = MaterialTheme.colors.primary,
)
}
private fun setContactAlias(contactApiId: Long, localAlias: String, chatModel: ChatModel) = withApi {
chatModel.controller.apiSetContactAlias(contactApiId, localAlias)?.let {
chatModel.updateContact(it)
@@ -326,6 +326,7 @@ fun ChatLayout(
Box(
Modifier
.fillMaxWidth()
.themedBackground()
) {
ProvideWindowInsets(windowInsetsAnimationsEnabled = true) {
ModalBottomSheetLayout(
@@ -854,7 +855,6 @@ private fun TopEndFloatingButton(
FloatingActionButton(
{}, // no action here
modifier.size(48.dp),
backgroundColor = MaterialTheme.colors.secondaryVariant,
elevation = FloatingActionButtonDefaults.elevation(0.dp, 0.dp),
interactionSource = interactionSource,
) {
@@ -881,8 +881,7 @@ private fun bottomEndFloatingButton(
FloatingActionButton(
onClick = onClickCounter,
elevation = FloatingActionButtonDefaults.elevation(0.dp, 0.dp, 0.dp, 0.dp),
modifier = Modifier.size(48.dp),
backgroundColor = MaterialTheme.colors.secondaryVariant,
modifier = Modifier.size(48.dp)
) {
Text(
unreadCountStr(unreadCount),
@@ -897,8 +896,7 @@ private fun bottomEndFloatingButton(
FloatingActionButton(
onClick = onClickArrowDown,
elevation = FloatingActionButtonDefaults.elevation(0.dp, 0.dp, 0.dp, 0.dp),
modifier = Modifier.size(48.dp),
backgroundColor = MaterialTheme.colors.secondaryVariant,
modifier = Modifier.size(48.dp)
) {
Icon(
painter = painterResource(R.drawable.ic_keyboard_arrow_down),
@@ -118,7 +118,7 @@ data class ComposeState(
val attachmentDisabled: Boolean
get() {
if (editing || liveMessage != null || inProgress) return true
if (editing || liveMessage != null) return true
return when (preview) {
ComposePreview.NoPreview -> false
is ComposePreview.CLinkPreview -> false
@@ -623,27 +623,23 @@ fun ComposeView(
fun previewView() {
when (val preview = composeState.value.preview) {
ComposePreview.NoPreview -> {}
is ComposePreview.CLinkPreview -> ComposeLinkView(
preview.linkPreview,
::cancelLinkPreview,
cancelEnabled = !composeState.value.inProgress
)
is ComposePreview.CLinkPreview -> ComposeLinkView(preview.linkPreview, ::cancelLinkPreview)
is ComposePreview.MediaPreview -> ComposeImageView(
preview,
::cancelImages,
cancelEnabled = !composeState.value.editing && !composeState.value.inProgress
cancelEnabled = !composeState.value.editing
)
is ComposePreview.VoicePreview -> ComposeVoiceView(
preview.voice,
preview.durationMs,
preview.finished,
cancelEnabled = !composeState.value.editing && !composeState.value.inProgress,
cancelEnabled = !composeState.value.editing,
::cancelVoice
)
is ComposePreview.FilePreview -> ComposeFileView(
preview.fileName,
::cancelFile,
cancelEnabled = !composeState.value.editing && !composeState.value.inProgress
cancelEnabled = !composeState.value.editing
)
}
}
@@ -661,14 +657,6 @@ fun ComposeView(
}
}
// In case a user sent something, state is in progress, the user rotates a screen to different orientation.
// Without clearing the state the user will be unable to send anything until re-enters ChatView
LaunchedEffect(Unit) {
if (composeState.value.inProgress) {
clearState()
}
}
LaunchedEffect(chatModel.sharedContent.value) {
// Important. If it's null, don't do anything, chat is not closed yet but will be after a moment
if (chatModel.chatId.value == null) return@LaunchedEffect
@@ -756,8 +744,6 @@ fun ComposeView(
resetLinkPreview()
clearCurrentDraft()
deleteUnusedFiles()
} else if (composeState.value.inProgress) {
clearCurrentDraft()
} else if (!composeState.value.empty) {
if (cs.preview is ComposePreview.VoicePreview && !cs.preview.finished) {
composeState.value = cs.copy(preview = cs.preview.copy(finished = true))
@@ -79,7 +79,7 @@ fun SendMsgView(
val showDeleteTextButton = rememberSaveable { mutableStateOf(false) }
NativeKeyboard(composeState, textStyle, showDeleteTextButton, userIsObserver, onMessageChange)
// Disable clicks on text field
if (cs.preview is ComposePreview.VoicePreview || !userCanSend || cs.inProgress) {
if (cs.preview is ComposePreview.VoicePreview || !userCanSend) {
Box(Modifier
.matchParentSize()
.clickable(enabled = !userCanSend, indication = null, interactionSource = remember { MutableInteractionSource() }, onClick = {
@@ -250,20 +250,14 @@ private fun NativeKeyboard(
Log.e(chat.simplex.app.TAG, e.stackTraceToString())
}
}
editText.doOnTextChanged { text, _, _, _ ->
if (!composeState.value.inProgress) {
onMessageChange(text.toString())
} else if (text.toString() != composeState.value.message) {
editText.setText(composeState.value.message)
}
}
editText.doOnTextChanged { text, _, _, _ -> onMessageChange(text.toString()) }
editText.doAfterTextChanged { text -> if (composeState.value.preview is ComposePreview.VoicePreview && text.toString() != "") editText.setText("") }
editText
}) {
it.setTextColor(textColor.toArgb())
it.textSize = textStyle.value.fontSize.value
DrawableCompat.setTint(it.background, tintColor.toArgb())
it.isFocusable = composeState.value.preview !is ComposePreview.VoicePreview && !cs.inProgress
it.isFocusable = composeState.value.preview !is ComposePreview.VoicePreview
it.isFocusableInTouchMode = it.isFocusable
if (cs.message != it.text.toString()) {
it.setText(cs.message)
@@ -276,7 +270,7 @@ private fun NativeKeyboard(
imm.showSoftInput(it, InputMethodManager.SHOW_IMPLICIT)
showKeyboard = false
}
showDeleteTextButton.value = it.lineCount >= 4 && !cs.inProgress
showDeleteTextButton.value = it.lineCount >= 4
}
if (composeState.value.preview is ComposePreview.VoicePreview) {
ComposeOverlay(R.string.voice_message_send_text, textStyle, padding)
@@ -175,8 +175,6 @@ fun GroupChatInfoLayout(
SectionView {
if (groupInfo.canEdit) {
EditGroupProfileButton(editGroupProfile)
}
if (groupInfo.groupProfile.description != null || groupInfo.canEdit) {
AddOrEditWelcomeMessage(groupInfo.groupProfile.description, addOrEditWelcomeMessage)
}
GroupPreferencesButton(openPreferences)
@@ -4,7 +4,6 @@ import InfoRow
import SectionBottomSpacer
import SectionDividerSpaced
import SectionSpacer
import SectionTextFooter
import SectionView
import androidx.activity.compose.BackHandler
import androidx.compose.foundation.*
@@ -14,7 +13,6 @@ import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
@@ -22,12 +20,10 @@ import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import chat.simplex.app.R
import chat.simplex.app.SimplexApp
import chat.simplex.app.model.*
import chat.simplex.app.ui.theme.*
import chat.simplex.app.views.chat.*
import chat.simplex.app.views.helpers.*
import chat.simplex.app.views.newchat.QRCode
import chat.simplex.app.views.usersettings.SettingsActionItem
import kotlinx.datetime.Clock
@@ -177,20 +173,10 @@ fun GroupMemberInfoLayout(
VerifyCodeButton(member.verified, verifyClicked)
}
}
SectionDividerSpaced()
SectionSpacer()
}
}
if (member.contactLink != null) {
val context = LocalContext.current
SectionView(stringResource(R.string.address_section_title).uppercase()) {
QRCode(member.contactLink, Modifier.padding(horizontal = DEFAULT_PADDING, vertical = DEFAULT_PADDING_HALF).aspectRatio(1f))
ShareAddressButton { shareText(context, member.contactLink) }
SectionTextFooter(stringResource(R.string.you_can_share_this_address_with_your_contacts).format(member.displayName))
}
SectionDividerSpaced()
}
SectionView(title = stringResource(R.string.member_info_section_title_member)) {
InfoRow(stringResource(R.string.info_row_group), groupInfo.displayName)
val roles = remember { member.canChangeRoleTo(groupInfo) }
@@ -1,30 +1,22 @@
package chat.simplex.app.views.chat.group
import SectionBottomSpacer
import SectionDividerSpaced
import SectionItemView
import SectionSpacer
import SectionView
import TextIconSpaced
import android.util.Log
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.*
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.runtime.*
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import chat.simplex.app.*
import chat.simplex.app.R
import chat.simplex.app.model.*
import chat.simplex.app.ui.theme.*
import chat.simplex.app.views.helpers.*
import kotlinx.coroutines.delay
import kotlinx.serialization.Serializable
import java.lang.Exception
@Composable
fun GroupWelcomeView(m: ChatModel, groupInfo: GroupInfo, close: () -> Unit) {
@@ -57,7 +49,6 @@ fun GroupWelcomeView(m: ChatModel, groupInfo: GroupInfo, close: () -> Unit) {
GroupWelcomeLayout(
welcomeText,
groupInfo,
m.controller.appPrefs.simplexLinkMode.get(),
save = ::save
)
}
@@ -67,43 +58,19 @@ fun GroupWelcomeView(m: ChatModel, groupInfo: GroupInfo, close: () -> Unit) {
private fun GroupWelcomeLayout(
welcomeText: MutableState<String>,
groupInfo: GroupInfo,
linkMode: SimplexLinkMode,
save: () -> Unit,
) {
Column(
Modifier.fillMaxWidth().verticalScroll(rememberScrollState()),
) {
val editMode = remember { mutableStateOf(true) }
AppBarTitle(stringResource(R.string.group_welcome_title))
val welcomeText = rememberSaveable { welcomeText }
if (groupInfo.canEdit) {
if (editMode.value) {
val focusRequester = remember { FocusRequester() }
TextEditor(welcomeText, Modifier.heightIn(min = 100.dp), stringResource(R.string.enter_welcome_message), focusRequester = focusRequester)
LaunchedEffect(Unit) {
delay(300)
focusRequester.requestFocus()
}
} else {
TextEditorPreview(welcomeText.value, linkMode)
}
ChangeModeButton(
editMode.value,
click = {
editMode.value = !editMode.value
},
welcomeText.value.isEmpty()
)
CopyTextButton { copyText(SimplexApp.context, welcomeText.value) }
SectionDividerSpaced(maxBottomPadding = false)
SaveButton(
save = save,
disabled = welcomeText.value == groupInfo.groupProfile.description || (welcomeText.value == "" && groupInfo.groupProfile.description == null)
)
} else {
TextEditorPreview(welcomeText.value, linkMode)
CopyTextButton { copyText(SimplexApp.context, welcomeText.value) }
}
val welcomeText = remember { welcomeText }
TextEditor(Modifier.padding(horizontal = DEFAULT_PADDING).height(160.dp), text = welcomeText)
SectionSpacer()
SaveButton(
save = save,
disabled = welcomeText.value == groupInfo.groupProfile.description || (welcomeText.value == "" && groupInfo.groupProfile.description == null)
)
SectionBottomSpacer()
}
}
@@ -117,35 +84,6 @@ private fun SaveButton(save: () -> Unit, disabled: Boolean) {
}
}
@Composable
private fun ChangeModeButton(editMode: Boolean, click: () -> Unit, disabled: Boolean) {
SectionItemView(click, disabled = disabled) {
Icon(
painterResource(if (editMode) R.drawable.ic_visibility else R.drawable.ic_edit),
contentDescription = generalGetString(R.string.edit_verb),
tint = if (disabled) MaterialTheme.colors.secondary else MaterialTheme.colors.primary,
)
TextIconSpaced()
Text(
stringResource(if (editMode) R.string.group_welcome_preview else R.string.edit_verb),
color = if (disabled) MaterialTheme.colors.secondary else MaterialTheme.colors.primary
)
}
}
@Composable
private fun CopyTextButton(click: () -> Unit) {
SectionItemView(click) {
Icon(
painterResource(R.drawable.ic_content_copy),
contentDescription = generalGetString(R.string.copy_verb),
tint = MaterialTheme.colors.primary,
)
TextIconSpaced()
Text(stringResource(R.string.copy_verb), color = MaterialTheme.colors.primary)
}
}
private fun showUnsavedChangesAlert(save: () -> Unit, revert: () -> Unit) {
AlertManager.shared.showAlertDialogStacked(
title = generalGetString(R.string.save_welcome_message_question),
@@ -8,6 +8,7 @@ import androidx.compose.ui.res.painterResource
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.font.FontWeight
@@ -17,7 +18,7 @@ import androidx.compose.ui.unit.sp
import chat.simplex.app.R
import chat.simplex.app.ui.theme.SimpleXTheme
import chat.simplex.app.views.helpers.annotatedStringResource
import chat.simplex.app.views.onboarding.ReadableTextWithLink
import chat.simplex.app.views.helpers.openUriCatching
import chat.simplex.app.views.usersettings.MarkdownHelpView
import chat.simplex.app.views.usersettings.simplexTeamUri
@@ -28,8 +29,17 @@ fun ChatHelpView(addContact: (() -> Unit)? = null) {
Column(
verticalArrangement = Arrangement.spacedBy(10.dp)
) {
val uriHandler = LocalUriHandler.current
Text(stringResource(R.string.thank_you_for_installing_simplex), lineHeight = 22.sp)
ReadableTextWithLink(R.string.you_can_connect_to_simplex_chat_founder, simplexTeamUri)
Text(
annotatedStringResource(R.string.you_can_connect_to_simplex_chat_founder),
modifier = Modifier.clickable(onClick = {
uriHandler.openUriCatching(simplexTeamUri)
}),
lineHeight = 22.sp
)
Column(
Modifier.padding(top = 24.dp),
verticalArrangement = Arrangement.spacedBy(10.dp)
@@ -35,6 +35,7 @@ fun ShareListView(chatModel: ChatModel, stopped: Boolean) {
Column(
modifier = Modifier
.fillMaxSize()
.themedBackground()
) {
if (chatModel.chats.isNotEmpty()) {
ShareList(chatModel, search = searchInList)
@@ -77,7 +77,7 @@ suspend fun getLinkPreview(url: String): LinkPreview? {
}
@Composable
fun ComposeLinkView(linkPreview: LinkPreview?, cancelPreview: () -> Unit, cancelEnabled: Boolean) {
fun ComposeLinkView(linkPreview: LinkPreview?, cancelPreview: () -> Unit) {
val sentColor = CurrentColors.collectAsState().value.appColors.sentMessage
Row(
Modifier.fillMaxWidth().padding(top = 8.dp).background(sentColor),
@@ -109,15 +109,13 @@ fun ComposeLinkView(linkPreview: LinkPreview?, cancelPreview: () -> Unit, cancel
)
}
}
if (cancelEnabled) {
IconButton(onClick = cancelPreview, modifier = Modifier.padding(0.dp)) {
Icon(
painterResource(R.drawable.ic_close),
contentDescription = stringResource(R.string.icon_descr_cancel_link_preview),
tint = MaterialTheme.colors.primary,
modifier = Modifier.padding(10.dp)
)
}
IconButton(onClick = cancelPreview, modifier = Modifier.padding(0.dp)) {
Icon(
painterResource(R.drawable.ic_close),
contentDescription = stringResource(R.string.icon_descr_cancel_link_preview),
tint = MaterialTheme.colors.primary,
modifier = Modifier.padding(10.dp)
)
}
}
}
@@ -195,7 +193,7 @@ fun PreviewChatItemLinkView() {
@Composable
fun PreviewComposeLinkView() {
SimpleXTheme {
ComposeLinkView(LinkPreview.sampleData, cancelPreview = { -> }, true)
ComposeLinkView(LinkPreview.sampleData) { -> }
}
}
@@ -203,6 +201,6 @@ fun PreviewComposeLinkView() {
@Composable
fun PreviewComposeLinkViewLoading() {
SimpleXTheme {
ComposeLinkView(null, cancelPreview = { -> }, true)
ComposeLinkView(null) { -> }
}
}
@@ -4,7 +4,6 @@ import android.Manifest
import android.content.*
import android.net.Uri
import android.provider.MediaStore
import android.util.Log
import android.webkit.MimeTypeMap
import android.widget.Toast
import androidx.activity.compose.ManagedActivityResultLauncher
@@ -49,17 +48,6 @@ fun copyText(cxt: Context, text: String) {
clipboard?.setPrimaryClip(ClipData.newPlainText("text", text))
}
fun sendEmail(context: Context, subject: String, body: CharSequence) {
val emailIntent = Intent(Intent.ACTION_SENDTO, Uri.parse("mailto:"))
emailIntent.putExtra(Intent.EXTRA_SUBJECT, subject)
emailIntent.putExtra(Intent.EXTRA_TEXT, body)
try {
context.startActivity(emailIntent)
} catch (e: ActivityNotFoundException) {
Log.e(TAG, "No activity was found for handling email intent")
}
}
@Composable
fun rememberSaveFileLauncher(cxt: Context, ciFile: CIFile?): ManagedActivityResultLauncher<String, Uri?> =
rememberLauncherForActivityResult(
@@ -1,130 +1,64 @@
package chat.simplex.app.views.helpers
import android.util.Log
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.BasicTextField
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.text.selection.SelectionContainer
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Surface
import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.*
import androidx.compose.ui.graphics.*
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.input.KeyboardCapitalization
import androidx.compose.ui.text.input.VisualTransformation
import androidx.compose.ui.unit.*
import chat.simplex.app.TAG
import chat.simplex.app.chatParseMarkdown
import chat.simplex.app.model.*
import chat.simplex.app.ui.theme.*
import chat.simplex.app.views.chat.item.MarkdownText
import com.google.accompanist.insets.navigationBarsWithImePadding
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.serialization.Serializable
import java.lang.Exception
import chat.simplex.app.ui.theme.DEFAULT_PADDING
@Composable
fun TextEditor(
value: MutableState<String>,
modifier: Modifier,
placeholder: String? = null,
contentPadding: PaddingValues = PaddingValues(horizontal = DEFAULT_PADDING),
isValid: (String) -> Boolean = { true },
focusRequester: FocusRequester? = null
text: MutableState<String>,
border: Boolean = true,
fontSize: TextUnit = 14.sp,
background: Color = MaterialTheme.colors.background,
onChange: ((String) -> Unit)? = null
) {
var valid by rememberSaveable { mutableStateOf(true) }
var focused by rememberSaveable { mutableStateOf(false) }
val strokeColor by remember {
derivedStateOf {
if (valid) {
if (focused) {
CurrentColors.value.colors.secondary.copy(alpha = 0.6f)
} else {
CurrentColors.value.colors.secondary.copy(alpha = 0.3f)
BasicTextField(
value = text.value,
onValueChange = { text.value = it; onChange?.invoke(it) },
textStyle = TextStyle(
fontFamily = FontFamily.Monospace, fontSize = fontSize,
color = MaterialTheme.colors.onBackground
),
keyboardOptions = KeyboardOptions.Default.copy(
capitalization = KeyboardCapitalization.None,
autoCorrect = false
),
modifier = modifier,
cursorBrush = SolidColor(MaterialTheme.colors.secondary),
decorationBox = { innerTextField ->
Surface(
shape = if (border) RoundedCornerShape(10.dp) else RectangleShape,
border = if (border) BorderStroke(1.dp, MaterialTheme.colors.secondaryVariant) else null
) {
Row(
Modifier.background(background),
verticalAlignment = Alignment.Top
) {
Box(
Modifier
.weight(1f)
.padding(vertical = 5.dp, horizontal = if (border) 7.dp else DEFAULT_PADDING)
) {
innerTextField()
}
}
} else Color.Red
}
}
}
Box(
Modifier
.fillMaxWidth()
.padding(contentPadding)
.heightIn(min = 52.dp),
// .border(border = BorderStroke(1.dp, strokeColor), shape = RoundedCornerShape(26.dp)),
contentAlignment = Alignment.Center,
) {
val modifier = modifier
.fillMaxWidth()
.navigationBarsWithImePadding()
.onFocusChanged { focused = it.isFocused }
BasicTextField(
value = value.value,
onValueChange = { value.value = it },
modifier = if (focusRequester == null) modifier else modifier.focusRequester(focusRequester),
textStyle = TextStyle(fontSize = 18.sp, color = MaterialTheme.colors.onBackground),
keyboardOptions = KeyboardOptions(
capitalization = KeyboardCapitalization.None,
autoCorrect = false
),
singleLine = false,
maxLines = 5,
cursorBrush = SolidColor(MaterialTheme.colors.secondary),
decorationBox = @Composable { innerTextField ->
TextFieldDefaults.TextFieldDecorationBox(
value = value.value,
innerTextField = innerTextField,
placeholder = if (placeholder != null) {{ Text(placeholder, fontSize = 18.sp, color = MaterialTheme.colors.secondary) }} else null,
contentPadding = PaddingValues(),
label = null,
visualTransformation = VisualTransformation.None,
leadingIcon = null,
trailingIcon = null,
singleLine = false,
enabled = true,
isError = false,
interactionSource = remember { MutableInteractionSource() },
)
}
)
}
LaunchedEffect(Unit) {
snapshotFlow { value.value }
.distinctUntilChanged()
.collect {
valid = isValid(it)
}
}
}
@Composable
fun TextEditorPreview(text: String, linkMode: SimplexLinkMode, markdown: Boolean = true) {
SelectionContainer {
MarkdownText(
text,
formattedText = if (markdown) remember(text) { parseToMarkdown(text) } else null,
modifier = Modifier.heightIn(min = 100.dp).padding(horizontal = DEFAULT_PADDING),
linkMode = linkMode,
style = TextStyle(fontSize = 18.sp, color = MaterialTheme.colors.onBackground)
)
}
}
@Serializable
data class ParsedFormattedText(
val formattedText: List<FormattedText>? = null
)
fun parseToMarkdown(text: String): List<FormattedText>? {
val formatted = chatParseMarkdown(text)
return try {
json.decodeFromString(ParsedFormattedText.serializer(), formatted).formattedText
} catch (e: Exception) {
Log.e(TAG, "Failed to parse into markdown: " + e.stackTraceToString())
null
}
)
}
@@ -37,6 +37,7 @@ import androidx.core.text.HtmlCompat
import chat.simplex.app.*
import chat.simplex.app.R
import chat.simplex.app.model.*
import chat.simplex.app.ui.theme.ThemeData
import chat.simplex.app.ui.theme.ThemeOverrides
import com.charleskorn.kaml.decodeFromStream
import kotlinx.coroutines.*
@@ -390,10 +391,10 @@ fun getDrawableFromUri(uri: Uri, withAlertOnException: Boolean = true): Drawable
}
}
fun getThemeFromUri(uri: Uri, withAlertOnException: Boolean = true): ThemeOverrides? {
fun getThemeFromUri(uri: Uri, withAlertOnException: Boolean = true): ThemeData? {
SimplexApp.context.contentResolver.openInputStream(uri).use {
runCatching {
return yaml.decodeFromStream<ThemeOverrides>(it!!)
return yaml.decodeFromStream<ThemeData>(it!!)
}.onFailure {
if (withAlertOnException) {
AlertManager.shared.showAlertMsg(
@@ -1,23 +0,0 @@
package chat.simplex.app.views.newchat
import androidx.compose.foundation.*
import androidx.compose.foundation.layout.Column
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import chat.simplex.app.R
import chat.simplex.app.views.helpers.AppBarTitle
import chat.simplex.app.views.onboarding.ReadableText
import chat.simplex.app.views.onboarding.ReadableTextWithLink
@Composable
fun AddContactLearnMore() {
Column(
Modifier.verticalScroll(rememberScrollState()),
) {
AppBarTitle(stringResource(R.string.one_time_link))
ReadableText(R.string.scan_qr_to_connect_to_contact)
ReadableText(R.string.if_you_cant_meet_in_person)
ReadableTextWithLink(R.string.read_more_in_user_guide_with_link, "https://simplex.chat/docs/guide/readme.html#connect-to-friends")
}
}
@@ -1,8 +1,6 @@
package chat.simplex.app.views.newchat
import SectionBottomSpacer
import SectionSpacer
import SectionView
import android.content.res.Configuration
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
@@ -17,10 +15,10 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import chat.simplex.app.R
import chat.simplex.app.ui.theme.*
import chat.simplex.app.views.helpers.*
import chat.simplex.app.views.usersettings.SettingsActionItem
@Composable
fun AddContactView(connReqInvitation: String, connIncognito: Boolean) {
@@ -28,92 +26,62 @@ fun AddContactView(connReqInvitation: String, connIncognito: Boolean) {
AddContactLayout(
connReq = connReqInvitation,
connIncognito = connIncognito,
share = { shareText(cxt, connReqInvitation) },
learnMore = {
ModalManager.shared.showModal {
Column(
Modifier
.fillMaxHeight()
.padding(horizontal = DEFAULT_PADDING),
verticalArrangement = Arrangement.SpaceBetween
) {
AddContactLearnMore()
}
}
}
share = { shareText(cxt, connReqInvitation) }
)
}
@Composable
fun AddContactLayout(connReq: String, connIncognito: Boolean, share: () -> Unit, learnMore: () -> Unit) {
Column(
Modifier
.verticalScroll(rememberScrollState()),
verticalArrangement = Arrangement.SpaceBetween,
) {
AppBarTitle(stringResource(R.string.add_contact))
OneTimeLinkProfileText(connIncognito)
SectionSpacer()
SectionView(stringResource(R.string.one_time_link_short).uppercase()) {
OneTimeLinkSection(connReq, share, learnMore)
}
SectionBottomSpacer()
}
}
@Composable
fun OneTimeLinkProfileText(connIncognito: Boolean) {
Row(Modifier.padding(horizontal = DEFAULT_PADDING)) {
InfoAboutIncognito(
connIncognito,
true,
generalGetString(R.string.incognito_random_profile_description),
generalGetString(R.string.your_profile_will_be_sent)
)
}
}
@Composable
fun ColumnScope.OneTimeLinkSection(connReq: String, share: () -> Unit, learnMore: () -> Unit) {
if (connReq.isNotEmpty()) {
QRCode(
connReq, Modifier
.padding(horizontal = DEFAULT_PADDING, vertical = DEFAULT_PADDING_HALF)
.aspectRatio(1f)
)
} else {
CircularProgressIndicator(
fun AddContactLayout(connReq: String, connIncognito: Boolean, share: () -> Unit) {
BoxWithConstraints {
val screenHeight = maxHeight
Column(
Modifier
.size(36.dp)
.padding(4.dp)
.align(Alignment.CenterHorizontally),
color = MaterialTheme.colors.secondary,
strokeWidth = 3.dp
)
.verticalScroll(rememberScrollState()),
verticalArrangement = Arrangement.SpaceBetween,
) {
AppBarTitle(stringResource(R.string.add_contact), false)
Text(
stringResource(R.string.show_QR_code_for_your_contact_to_scan_from_the_app__multiline),
)
Row {
InfoAboutIncognito(
connIncognito,
true,
generalGetString(R.string.incognito_random_profile_description),
generalGetString(R.string.your_profile_will_be_sent)
)
}
if (connReq.isNotEmpty()) {
QRCode(
connReq, Modifier
.aspectRatio(1f)
.padding(vertical = 3.dp)
)
} else {
CircularProgressIndicator(
Modifier
.size(36.dp)
.padding(4.dp)
.align(Alignment.CenterHorizontally),
color = MaterialTheme.colors.secondary,
strokeWidth = 3.dp
)
}
Text(
annotatedStringResource(R.string.if_you_cannot_meet_in_person_show_QR_in_video_call_or_via_another_channel),
lineHeight = 22.sp,
modifier = Modifier
.padding(top = DEFAULT_PADDING, bottom = if (screenHeight > 600.dp) DEFAULT_PADDING else 0.dp)
)
Row(
Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.Center
) {
SimpleButton(stringResource(R.string.share_invitation_link), icon = painterResource(R.drawable.ic_share), click = share)
}
SectionBottomSpacer()
}
}
ShareLinkButton(share)
OneTimeLinkLearnMoreButton(learnMore)
}
@Composable
fun ShareLinkButton(onClick: () -> Unit) {
SettingsActionItem(
painterResource(R.drawable.ic_share),
stringResource(R.string.share_invitation_link),
onClick,
iconColor = MaterialTheme.colors.primary,
textColor = MaterialTheme.colors.primary,
)
}
@Composable
fun OneTimeLinkLearnMoreButton(onClick: () -> Unit) {
SettingsActionItem(
painterResource(R.drawable.ic_info),
stringResource(R.string.learn_more),
onClick,
)
}
@Composable
@@ -165,8 +133,7 @@ fun PreviewAddContactView() {
AddContactLayout(
connReq = "https://simplex.chat/contact#/?v=1&smp=smp%3A%2F%2FPQUV2eL0t7OStZOoAsPEV2QYWt4-xilbakvGUGOItUo%3D%40smp6.simplex.im%2FK1rslx-m5bpXVIdMZg9NLUZ_8JBm8xTt%23MCowBQYDK2VuAyEALDeVe-sG8mRY22LsXlPgiwTNs9dbiLrNuA7f3ZMAJ2w%3D",
connIncognito = false,
share = {},
learnMore = {},
share = {}
)
}
}
@@ -159,7 +159,7 @@ fun CreateGroupButton(color: Color, modifier: Modifier) {
Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.End
) {
Surface(shape = RoundedCornerShape(20.dp), color = Color.Transparent) {
Surface(shape = RoundedCornerShape(20.dp)) {
Row(modifier, verticalAlignment = Alignment.CenterVertically) {
Text(stringResource(R.string.create_profile_button), style = MaterialTheme.typography.caption, color = color, fontWeight = FontWeight.Bold)
Icon(painterResource(R.drawable.ic_arrow_forward_ios), stringResource(R.string.create_profile_button), tint = color)
@@ -1,7 +1,6 @@
package chat.simplex.app.views.newchat
import SectionBottomSpacer
import SectionDividerSpaced
import SectionView
import android.content.res.Configuration
import androidx.compose.foundation.layout.*
@@ -11,7 +10,6 @@ import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
@@ -45,16 +43,13 @@ fun ContactConnectionInfoView(
}
}
}
val context = LocalContext.current
ContactConnectionInfoLayout(
connReq = connReqInvitation,
contactConnection,
connIncognito = contactConnection.incognito,
focusAlias,
deleteConnection = { deleteContactConnectionAlert(contactConnection, chatModel, close) },
onLocalAliasChanged = { setContactAlias(contactConnection, it, chatModel) },
share = { if (connReqInvitation != null) shareText(context, connReqInvitation) },
learnMore = {
showQr = {
ModalManager.shared.showModal {
Column(
Modifier
@@ -62,7 +57,7 @@ fun ContactConnectionInfoView(
.padding(horizontal = DEFAULT_PADDING),
verticalArrangement = Arrangement.SpaceBetween
) {
AddContactLearnMore()
AddContactView(connReqInvitation ?: return@showModal, contactConnection.incognito)
}
}
}
@@ -73,12 +68,10 @@ fun ContactConnectionInfoView(
private fun ContactConnectionInfoLayout(
connReq: String?,
contactConnection: PendingContactConnection,
connIncognito: Boolean,
focusAlias: Boolean,
deleteConnection: () -> Unit,
onLocalAliasChanged: (String) -> Unit,
share: () -> Unit,
learnMore: () -> Unit,
showQr: () -> Unit,
) {
Column(
Modifier
@@ -90,6 +83,11 @@ private fun ContactConnectionInfoLayout(
else R.string.you_accepted_connection
)
)
if (contactConnection.groupLinkId == null) {
Row(Modifier.padding(bottom = DEFAULT_PADDING)) {
LocalAliasEditor(contactConnection.localAlias, center = false, leadingIcon = true, focus = focusAlias, updateValue = onLocalAliasChanged)
}
}
Text(
stringResource(
if (contactConnection.viaContactUri)
@@ -99,28 +97,27 @@ private fun ContactConnectionInfoLayout(
),
Modifier.padding(start = DEFAULT_PADDING, end = DEFAULT_PADDING, bottom = DEFAULT_PADDING)
)
OneTimeLinkProfileText(connIncognito)
if (contactConnection.groupLinkId == null) {
LocalAliasEditor(contactConnection.localAlias, center = false, leadingIcon = true, focus = focusAlias, updateValue = onLocalAliasChanged)
}
SectionView {
if (!connReq.isNullOrEmpty() && contactConnection.initiated) {
OneTimeLinkSection(connReq, share, learnMore)
} else {
OneTimeLinkLearnMoreButton(learnMore)
ShowQrButton(contactConnection.incognito, showQr)
}
DeleteButton(deleteConnection)
}
SectionDividerSpaced(maxBottomPadding = false)
DeleteButton(deleteConnection)
SectionBottomSpacer()
}
}
@Composable
fun ShowQrButton(incognito: Boolean, onClick: () -> Unit) {
SettingsActionItem(
painterResource(R.drawable.ic_qr_code),
stringResource(R.string.show_QR_code),
click = onClick,
textColor = if (incognito) Indigo else MaterialTheme.colors.primary,
iconColor = if (incognito) Indigo else MaterialTheme.colors.primary,
)
}
@Composable
fun DeleteButton(onClick: () -> Unit) {
SettingsActionItem(
@@ -150,12 +147,10 @@ private fun PreviewContactConnectionInfoView() {
ContactConnectionInfoLayout(
connReq = "https://simplex.chat/contact#/?v=1&smp=smp%3A%2F%2FPQUV2eL0t7OStZOoAsPEV2QYWt4-xilbakvGUGOItUo%3D%40smp6.simplex.im%2FK1rslx-m5bpXVIdMZg9NLUZ_8JBm8xTt%23MCowBQYDK2VuAyEALDeVe-sG8mRY22LsXlPgiwTNs9dbiLrNuA7f3ZMAJ2w%3D",
PendingContactConnection.getSampleData(),
connIncognito = false,
focusAlias = false,
deleteConnection = {},
onLocalAliasChanged = {},
share = {},
learnMore = {}
showQr = {},
)
}
}
@@ -45,13 +45,14 @@ fun CreateLinkView(m: ChatModel, initialSelection: CreateLinkTab) {
when {
it == CreateLinkTab.ONE_TIME && connReqInvitation.value.isNullOrEmpty() -> stringResource(R.string.create_one_time_link)
it == CreateLinkTab.ONE_TIME -> stringResource(R.string.one_time_link)
it == CreateLinkTab.LONG_TERM -> stringResource(R.string.your_simplex_contact_address)
it == CreateLinkTab.LONG_TERM -> stringResource(R.string.your_contact_address)
else -> ""
}
}
Column(
Modifier
.fillMaxHeight(),
.fillMaxHeight()
.padding(horizontal = DEFAULT_PADDING),
verticalArrangement = Arrangement.SpaceBetween
) {
Column(Modifier.weight(1f)) {
@@ -60,7 +61,7 @@ fun CreateLinkView(m: ChatModel, initialSelection: CreateLinkTab) {
AddContactView(connReqInvitation.value ?: "", m.incognito.value)
}
CreateLinkTab.LONG_TERM -> {
UserAddressView(m, viaCreateLinkView = true, close = {})
UserAddressView(m)
}
}
}
@@ -173,7 +173,7 @@ fun ActionButton(
disabled: Boolean = false,
click: () -> Unit = {}
) {
Surface(shape = RoundedCornerShape(18.dp), color = Color.Transparent) {
Surface(shape = RoundedCornerShape(18.dp)) {
Column(
Modifier
.clickable(onClick = click)
@@ -85,7 +85,7 @@ fun PasteToConnectLayout(
)
Box(Modifier.padding(top = DEFAULT_PADDING, bottom = 6.dp)) {
TextEditor(connectionLink, Modifier.height(180.dp), contentPadding = PaddingValues())
TextEditor(Modifier.height(180.dp), text = connectionLink)
}
Row(
@@ -1,168 +0,0 @@
package chat.simplex.app.views.onboarding
import SectionBottomSpacer
import android.util.Log
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import chat.simplex.app.R
import chat.simplex.app.TAG
import chat.simplex.app.model.ChatModel
import chat.simplex.app.model.UserContactLinkRec
import chat.simplex.app.ui.theme.*
import chat.simplex.app.views.helpers.*
import chat.simplex.app.views.newchat.QRCode
@Composable
fun CreateSimpleXAddress(m: ChatModel) {
val context = LocalContext.current
var progressIndicator by remember { mutableStateOf(false) }
val userAddress = remember { m.userAddress }
CreateSimpleXAddressLayout(
userAddress.value,
share = { address: String -> shareText(context, address) },
sendEmail = { address ->
sendEmail(
context,
generalGetString(R.string.email_invite_subject),
generalGetString(R.string.email_invite_body).format(address.connReqContact)
)
},
createAddress = {
withApi {
progressIndicator = true
val connReqContact = m.controller.apiCreateUserAddress()
if (connReqContact != null) {
m.userAddress.value = UserContactLinkRec(connReqContact)
try {
val u = m.controller.apiSetProfileAddress(true)
if (u != null) {
m.updateUser(u)
}
} catch (e: Exception) {
Log.e(TAG, "CreateSimpleXAddress apiSetProfileAddress: ${e.stackTraceToString()}")
}
progressIndicator = false
}
}
},
nextStep = {
m.onboardingStage.value = OnboardingStage.Step4_SetNotificationsMode
},
)
if (progressIndicator) {
ProgressIndicator()
}
}
@Composable
private fun CreateSimpleXAddressLayout(
userAddress: UserContactLinkRec?,
share: (String) -> Unit,
sendEmail: (UserContactLinkRec) -> Unit,
createAddress: () -> Unit,
nextStep: () -> Unit,
) {
Column(
Modifier.fillMaxSize().verticalScroll(rememberScrollState()).padding(top = DEFAULT_PADDING),
horizontalAlignment = Alignment.CenterHorizontally,
) {
AppBarTitle(stringResource(R.string.simplex_address))
Spacer(Modifier.weight(1f))
if (userAddress != null) {
QRCode(userAddress.connReqContact, Modifier.padding(horizontal = DEFAULT_PADDING, vertical = DEFAULT_PADDING_HALF).aspectRatio(1f))
ShareAddressButton { share(userAddress.connReqContact) }
Spacer(Modifier.weight(1f))
ShareViaEmailButton { sendEmail(userAddress) }
Spacer(Modifier.weight(1f))
ContinueButton(nextStep)
} else {
CreateAddressButton(createAddress)
TextBelowButton(stringResource(R.string.your_contacts_will_see_it))
Spacer(Modifier.weight(1f))
SkipButton(nextStep)
}
SectionBottomSpacer()
}
}
@Composable
private fun CreateAddressButton(onClick: () -> Unit) {
TextButton(onClick) {
Text(stringResource(R.string.create_simplex_address), style = MaterialTheme.typography.h2, color = MaterialTheme.colors.primary)
}
}
@Composable
fun ShareAddressButton(onClick: () -> Unit) {
SimpleButtonFrame(onClick) {
Icon(
painterResource(R.drawable.ic_share_filled), generalGetString(R.string.share_verb), tint = MaterialTheme.colors.primary,
modifier = Modifier.padding(end = 8.dp).size(18.dp)
)
Text(stringResource(R.string.share_verb), style = MaterialTheme.typography.caption, color = MaterialTheme.colors.primary)
}
}
@Composable
fun ShareViaEmailButton(onClick: () -> Unit) {
SimpleButtonFrame(onClick) {
Icon(
painterResource(R.drawable.ic_mail), generalGetString(R.string.share_verb), tint = MaterialTheme.colors.primary,
modifier = Modifier.padding(end = 8.dp).size(30.dp)
)
Text(stringResource(R.string.invite_friends), style = MaterialTheme.typography.h6, color = MaterialTheme.colors.primary)
}
}
@Composable
private fun ContinueButton(onClick: () -> Unit) {
SimpleButtonIconEnded(stringResource(R.string.continue_to_next_step), painterResource(R.drawable.ic_chevron_right), click = onClick)
}
@Composable
private fun SkipButton(onClick: () -> Unit) {
SimpleButtonIconEnded(stringResource(R.string.dont_create_address), painterResource(R.drawable.ic_chevron_right), click = onClick)
TextBelowButton(stringResource(R.string.you_can_create_it_later))
}
@Composable
private fun TextBelowButton(text: String) {
Text(
text,
Modifier
.fillMaxWidth()
.padding(horizontal = DEFAULT_PADDING * 3),
style = MaterialTheme.typography.subtitle1,
textAlign = TextAlign.Center,
)
}
@Composable
private fun ProgressIndicator() {
Box(
Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
CircularProgressIndicator(
Modifier
.padding(horizontal = 2.dp)
.size(30.dp),
color = MaterialTheme.colors.secondary,
strokeWidth = 3.dp
)
}
}
@@ -4,23 +4,21 @@ import android.content.res.Configuration
import androidx.annotation.StringRes
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.runtime.*
import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.*
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import chat.simplex.app.R
import chat.simplex.app.SimplexApp
import chat.simplex.app.model.User
import chat.simplex.app.ui.theme.*
import chat.simplex.app.views.chat.item.MarkdownText
import chat.simplex.app.ui.theme.DEFAULT_PADDING
import chat.simplex.app.ui.theme.SimpleXTheme
import chat.simplex.app.views.helpers.*
@Composable
@@ -35,7 +33,12 @@ fun HowItWorks(user: User?, onboardingStage: MutableState<OnboardingStage?>? = n
ReadableText(R.string.you_control_servers_to_receive_your_contacts_to_send)
ReadableText(R.string.only_client_devices_store_contacts_groups_e2e_encrypted_messages)
if (onboardingStage == null) {
ReadableTextWithLink(R.string.read_more_in_github_with_link, "https://github.com/simplex-chat/simplex-chat#readme")
val uriHandler = LocalUriHandler.current
Text(
annotatedStringResource(R.string.read_more_in_github_with_link),
modifier = Modifier.padding(bottom = 12.dp).clickable { uriHandler.openUriCatching("https://github.com/simplex-chat/simplex-chat#readme") },
lineHeight = 22.sp
)
} else {
ReadableText(R.string.read_more_in_github)
}
@@ -56,42 +59,11 @@ fun ReadableText(@StringRes stringResId: Int, textAlign: TextAlign = TextAlign.S
Text(annotatedStringResource(stringResId), modifier = Modifier.padding(padding), textAlign = textAlign, lineHeight = 22.sp)
}
@Composable
fun ReadableTextWithLink(@StringRes stringResId: Int, link: String, textAlign: TextAlign = TextAlign.Start, padding: PaddingValues = PaddingValues(bottom = 12.dp)) {
val annotated = annotatedStringResource(stringResId)
val primary = MaterialTheme.colors.primary
// This replaces links in text highlighted with specific color, e.g. SimplexBlue
val newStyles = remember(stringResId) {
val newStyles = ArrayList<AnnotatedString.Range<SpanStyle>>()
annotated.spanStyles.forEach {
if (it.item.color == SimplexBlue) {
newStyles.add(it.copy(item = it.item.copy(primary)))
} else {
newStyles.add(it)
}
}
newStyles
}
val uriHandler = LocalUriHandler.current
Text(AnnotatedString(annotated.text, newStyles), modifier = Modifier.padding(padding).clickable { uriHandler.openUriCatching(link) }, textAlign = textAlign, lineHeight = 22.sp)
}
@Composable
fun ReadableText(text: String, textAlign: TextAlign = TextAlign.Start, padding: PaddingValues = PaddingValues(bottom = 12.dp)) {
Text(text, modifier = Modifier.padding(padding), textAlign = textAlign, lineHeight = 22.sp)
}
@Composable
fun ReadableMarkdownText(text: String, textAlign: TextAlign = TextAlign.Start, padding: PaddingValues = PaddingValues(bottom = 12.dp)) {
MarkdownText(
text,
formattedText = remember(text) { parseToMarkdown(text) },
modifier = Modifier.padding(padding),
style = TextStyle(textAlign = textAlign, lineHeight = 22.sp, fontSize = 16.sp),
linkMode = SimplexApp.context.chatModel.controller.appPrefs.simplexLinkMode.get(),
)
}
@Preview(showBackground = true)
@Preview(
uiMode = Configuration.UI_MODE_NIGHT_YES,
@@ -1,7 +1,9 @@
package chat.simplex.app.views.onboarding
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
import androidx.compose.material.MaterialTheme
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
@@ -14,8 +16,7 @@ import kotlinx.coroutines.launch
enum class OnboardingStage {
Step1_SimpleXInfo,
Step2_CreateProfile,
Step3_CreateSimpleXAddress,
Step4_SetNotificationsMode,
Step3_SetNotificationsMode,
OnboardingComplete
}
@@ -30,6 +31,7 @@ fun CreateProfile(chatModel: ChatModel, close: () -> Unit) {
Box(
modifier = Modifier
.fillMaxSize()
.background(color = MaterialTheme.colors.background)
.padding(20.dp)
) {
CreateProfilePanel(chatModel, close)
@@ -261,7 +261,7 @@ private val versionDescriptions: List<VersionDescription> = listOf(
icon = R.drawable.ic_translate,
titleId = R.string.v4_5_italian_interface,
descrId = R.string.v4_5_italian_interface_descr,
link = "https://github.com/simplex-chat/simplex-chat/tree/stable#help-translating-simplex-chat"
link = "https://github.com/simplex-chat/simplex-chat/tree/stable#translate-the-apps"
)
)
),
@@ -297,7 +297,7 @@ private val versionDescriptions: List<VersionDescription> = listOf(
icon = R.drawable.ic_translate,
titleId = R.string.v4_6_chinese_spanish_interface,
descrId = R.string.v4_6_chinese_spanish_interface_descr,
link = "https://github.com/simplex-chat/simplex-chat/tree/stable#help-translating-simplex-chat"
link = "https://github.com/simplex-chat/simplex-chat/tree/stable#translate-the-apps"
)
)
),
@@ -318,7 +318,7 @@ private val versionDescriptions: List<VersionDescription> = listOf(
icon = R.drawable.ic_translate,
titleId = R.string.v5_0_polish_interface,
descrId = R.string.v5_0_polish_interface_descr,
link = "https://github.com/simplex-chat/simplex-chat/tree/stable#help-translating-simplex-chat"
link = "https://github.com/simplex-chat/simplex-chat/tree/stable#translate-the-apps"
)
)
)
@@ -0,0 +1,160 @@
package chat.simplex.app.views.usersettings
import SectionBottomSpacer
import SectionCustomFooter
import SectionView
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.ui.res.painterResource
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import chat.simplex.app.R
import chat.simplex.app.model.*
import chat.simplex.app.ui.theme.*
import chat.simplex.app.views.helpers.*
@Composable
fun AcceptRequestsView(m: ChatModel, contactLink: UserContactLinkRec) {
var contactLink by remember { mutableStateOf(contactLink) }
AcceptRequestsLayout(
contactLink,
saveState = { new: MutableState<AutoAcceptState>, old: MutableState<AutoAcceptState> ->
withApi {
val link = m.controller.userAddressAutoAccept(new.value.autoAccept)
if (link != null) {
contactLink = link
m.userAddress.value = link
old.value = new.value
}
}
}
)
}
@Composable
private fun AcceptRequestsLayout(
contactLink: UserContactLinkRec,
saveState: (new: MutableState<AutoAcceptState>, old: MutableState<AutoAcceptState>) -> Unit,
) {
Column(
Modifier.fillMaxWidth().verticalScroll(rememberScrollState()),
) {
AppBarTitle(stringResource(R.string.contact_requests))
val autoAcceptState = remember { mutableStateOf(AutoAcceptState(contactLink)) }
val autoAcceptStateSaved = remember { mutableStateOf(autoAcceptState.value) }
SectionView(stringResource(R.string.accept_requests).uppercase()) {
PreferenceToggleWithIcon(stringResource(R.string.accept_automatically), painterResource(R.drawable.ic_check), checked = autoAcceptState.value.enable) {
autoAcceptState.value = if (!it)
AutoAcceptState()
else
AutoAcceptState(it, autoAcceptState.value.incognito, autoAcceptState.value.welcomeText)
}
if (autoAcceptState.value.enable) {
PreferenceToggleWithIcon(
stringResource(R.string.incognito),
if (autoAcceptState.value.incognito) painterResource(R.drawable.ic_theater_comedy_filled) else painterResource(R.drawable.ic_theater_comedy),
if (autoAcceptState.value.incognito) Indigo else MaterialTheme.colors.secondary,
autoAcceptState.value.incognito,
) {
autoAcceptState.value = AutoAcceptState(autoAcceptState.value.enable, it, autoAcceptState.value.welcomeText)
}
}
}
val welcomeText = remember { mutableStateOf(autoAcceptState.value.welcomeText) }
SectionCustomFooter(PaddingValues(horizontal = DEFAULT_PADDING)) {
ButtonsFooter(
cancel = {
autoAcceptState.value = autoAcceptStateSaved.value
welcomeText.value = autoAcceptStateSaved.value.welcomeText
},
save = { saveState(autoAcceptState, autoAcceptStateSaved) },
disabled = autoAcceptState.value == autoAcceptStateSaved.value
)
}
Spacer(Modifier.height(DEFAULT_PADDING))
if (autoAcceptState.value.enable) {
Text(
stringResource(R.string.section_title_welcome_message), color = MaterialTheme.colors.secondary, style = MaterialTheme.typography.body2,
modifier = Modifier.padding(start = DEFAULT_PADDING, bottom = 5.dp), fontSize = 12.sp
)
TextEditor(Modifier.padding(horizontal = DEFAULT_PADDING).height(160.dp), text = welcomeText)
LaunchedEffect(welcomeText.value) {
if (welcomeText.value != autoAcceptState.value.welcomeText) {
autoAcceptState.value = AutoAcceptState(autoAcceptState.value.enable, autoAcceptState.value.incognito, welcomeText.value)
}
}
}
SectionBottomSpacer()
}
}
@Composable
private fun ButtonsFooter(cancel: () -> Unit, save: () -> Unit, disabled: Boolean) {
Row(
Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
FooterButton(painterResource(R.drawable.ic_replay), stringResource(R.string.cancel_verb), cancel, disabled)
FooterButton(painterResource(R.drawable.ic_check), stringResource(R.string.save_verb), save, disabled)
}
}
private class AutoAcceptState {
var enable: Boolean = false
private set
var incognito: Boolean = false
private set
var welcomeText: String = ""
private set
constructor(enable: Boolean = false, incognito: Boolean = false, welcomeText: String = "") {
this.enable = enable
this.incognito = incognito
this.welcomeText = welcomeText
}
constructor(contactLink: UserContactLinkRec) {
contactLink.autoAccept?.let { aa ->
enable = true
incognito = aa.acceptIncognito
aa.autoReply?.let { msg ->
welcomeText = msg.text
} ?: run {
welcomeText = ""
}
}
}
val autoAccept: AutoAccept?
get() {
if (enable) {
var autoReply: MsgContent? = null
val s = welcomeText.trim()
if (s != "") {
autoReply = MsgContent.MCText(s)
}
return AutoAccept(incognito, autoReply)
}
return null
}
override fun equals(other: Any?): Boolean {
if (other !is AutoAcceptState) return false
return this.enable == other.enable && this.incognito == other.incognito && this.welcomeText == other.welcomeText
}
override fun hashCode(): Int {
var result = enable.hashCode()
result = 31 * result + incognito.hashCode()
result = 31 * result + welcomeText.hashCode()
return result
}
}
@@ -240,8 +240,8 @@ fun CustomizeThemeView(editColor: (ThemeColor, Color) -> Unit) {
val theme = remember { mutableStateOf(null as String?) }
val exportThemeLauncher = rememberSaveThemeLauncher(context, theme)
SectionItemView({
val overrides = ThemeManager.currentThemeOverridesForExport(isInDarkTheme)
theme.value = yaml.encodeToString<ThemeOverrides>(overrides)
val themeData = ThemeManager.currentThemeData(isInDarkTheme)
theme.value = yaml.encodeToString<ThemeData>(themeData)
exportThemeLauncher.launch("simplex.theme")
}) {
Text(generalGetString(R.string.export_theme), color = colors.primary)
@@ -251,7 +251,7 @@ fun CustomizeThemeView(editColor: (ThemeColor, Color) -> Unit) {
if (uri != null) {
val theme = getThemeFromUri(uri)
if (theme != null) {
ThemeManager.saveAndApplyThemeOverrides(theme, isInDarkTheme)
ThemeManager.saveAndApplyThemeData(currentTheme.name, theme, isInDarkTheme)
}
}
}
@@ -48,13 +48,12 @@ fun NetworkAndServersView(
chatModel.userSMPServersUnsaved.value = null
}
val proxyPort = remember { derivedStateOf { chatModel.controller.appPrefs.networkProxyHostPort.state.value?.split(":")?.lastOrNull()?.toIntOrNull() ?: 9050 } }
NetworkAndServersLayout(
developerTools = developerTools,
networkUseSocksProxy = networkUseSocksProxy,
onionHosts = onionHosts,
sessionMode = sessionMode,
proxyPort = proxyPort,
proxyPort = remember { derivedStateOf { chatModel.controller.appPrefs.networkProxyHostPort.state.value?.split(":")?.lastOrNull()?.toIntOrNull() ?: 9050 } },
showModal = showModal,
showSettingsModal = showSettingsModal,
showCustomModal = showCustomModal,
@@ -62,15 +61,14 @@ fun NetworkAndServersView(
if (enable) {
AlertManager.shared.showAlertDialog(
title = generalGetString(R.string.network_enable_socks),
text = generalGetString(R.string.network_enable_socks_info).format(proxyPort.value),
text = generalGetString(R.string.network_enable_socks_info),
confirmText = generalGetString(R.string.confirm_verb),
onConfirm = {
withApi {
val conf = NetCfg.proxyDefaults.withHostPort(chatModel.controller.appPrefs.networkProxyHostPort.get())
chatModel.controller.apiSetNetworkConfig(conf)
chatModel.controller.setNetCfg(conf)
chatModel.controller.apiSetNetworkConfig(NetCfg.proxyDefaults)
chatModel.controller.setNetCfg(NetCfg.proxyDefaults)
networkUseSocksProxy.value = true
onionHosts.value = conf.onionHosts
onionHosts.value = NetCfg.proxyDefaults.onionHosts
}
}
)
@@ -81,11 +79,10 @@ fun NetworkAndServersView(
confirmText = generalGetString(R.string.confirm_verb),
onConfirm = {
withApi {
val conf = NetCfg.defaults
chatModel.controller.apiSetNetworkConfig(conf)
chatModel.controller.setNetCfg(conf)
chatModel.controller.apiSetNetworkConfig(NetCfg.defaults)
chatModel.controller.setNetCfg(NetCfg.defaults)
networkUseSocksProxy.value = false
onionHosts.value = conf.onionHosts
onionHosts.value = NetCfg.defaults.onionHosts
}
}
)
@@ -209,31 +206,35 @@ fun UseSocksProxySwitch(
) {
Icon(
painterResource(R.drawable.ic_settings_ethernet),
stringResource(R.string.network_socks_toggle_use_socks_proxy),
stringResource(R.string.network_socks_toggle),
tint = MaterialTheme.colors.secondary
)
TextIconSpaced(false)
val text = buildAnnotatedString {
append(generalGetString(R.string.network_socks_toggle_use_socks_proxy) + " (")
val style = SpanStyle(color = MaterialTheme.colors.primary)
withAnnotation(tag = "PORT", annotation = generalGetString(R.string.network_proxy_port).format(proxyPort.value)) {
withStyle(style) { append(generalGetString(R.string.network_proxy_port).format(proxyPort.value)) }
}
append(")")
}
ClickableText(
text,
style = TextStyle(color = MaterialTheme.colors.onBackground, fontSize = 16.sp, fontFamily = FontFamily(Font(R.font.inter_regular))),
onClick = { offset ->
text.getStringAnnotations(tag = "PORT", start = offset, end = offset)
.firstOrNull()?.let { _ ->
showSettingsModal { SockProxySettings(it) }()
if (networkUseSocksProxy.value) {
val text = buildAnnotatedString {
append(generalGetString(R.string.network_socks_toggle_use_socks_proxy) + " (")
val style = SpanStyle(color = MaterialTheme.colors.primary)
withAnnotation(tag = "PORT", annotation = generalGetString(R.string.network_proxy_port).format(proxyPort.value)) {
withStyle(style) { append(generalGetString(R.string.network_proxy_port).format(proxyPort.value)) }
}
},
shouldConsumeEvent = { offset ->
text.getStringAnnotations(tag = "PORT", start = offset, end = offset).any()
}
)
append(")")
}
ClickableText(
text,
style = TextStyle(color = MaterialTheme.colors.onBackground, fontSize = 16.sp, fontFamily = FontFamily(Font(R.font.inter_regular))),
onClick = { offset ->
text.getStringAnnotations(tag = "PORT", start = offset, end = offset)
.firstOrNull()?.let { _ ->
showSettingsModal { SockProxySettings(it) }()
}
},
shouldConsumeEvent = { offset ->
text.getStringAnnotations(tag = "PORT", start = offset, end = offset).any()
}
)
} else {
Text(stringResource(R.string.network_socks_toggle))
}
}
DefaultSwitch(
checked = networkUseSocksProxy.value,
@@ -261,15 +262,13 @@ fun SockProxySettings(m: ChatModel) {
val save = {
withBGApi {
m.controller.appPrefs.networkProxyHostPort.set(hostUnsaved.value.text + ":" + portUnsaved.value.text)
if (m.controller.appPrefs.networkUseSocksProxy.get()) {
m.controller.apiSetNetworkConfig(m.controller.getNetCfg())
}
m.controller.apiSetNetworkConfig(m.controller.getNetCfg())
}
}
SectionView {
SectionItemView {
ResetToDefaultsButton({
val reset = {
showUpdateNetworkSettingsDialog {
m.controller.appPrefs.networkProxyHostPort.set(defaultHostPort)
val newHost = defaultHostPort.split(":").first()
val newPort = defaultHostPort.split(":").last()
@@ -277,13 +276,6 @@ fun SockProxySettings(m: ChatModel) {
portUnsaved.value = portUnsaved.value.copy(newPort, TextRange(newPort.length))
save()
}
if (m.controller.appPrefs.networkUseSocksProxy.get()) {
showUpdateNetworkSettingsDialog {
reset()
}
} else {
reset()
}
}, disabled = hostPort == defaultHostPort)
}
SectionItemView {
@@ -315,7 +307,7 @@ fun SockProxySettings(m: ChatModel) {
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()) showUpdateNetworkSettingsDialog { save() } else save() },
save = { showUpdateNetworkSettingsDialog { save() } },
revertDisabled = hostPort == (hostUnsaved.value.text + ":" + portUnsaved.value.text),
saveDisabled = hostPort == (hostUnsaved.value.text + ":" + portUnsaved.value.text) ||
remember { derivedStateOf { !validHost(hostUnsaved.value.text) } }.value ||
@@ -27,8 +27,6 @@ import chat.simplex.app.model.ServerAddress.Companion.parseServerAddress
import chat.simplex.app.ui.theme.*
import chat.simplex.app.views.helpers.*
import chat.simplex.app.views.newchat.QRCode
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
@@ -142,16 +140,14 @@ private fun CustomServer(
) {
val testedPreviously = remember { mutableMapOf<String, Boolean?>() }
TextEditor(
serverAddress,
Modifier.height(144.dp)
)
LaunchedEffect(Unit) {
snapshotFlow { serverAddress.value }
.distinctUntilChanged()
.collect {
testedPreviously[server.server] = server.tested
onUpdate(server.copy(server = it, tested = testedPreviously[serverAddress.value]))
}
Modifier.height(144.dp),
text = serverAddress,
border = false,
fontSize = 16.sp,
background = if (isInDarkTheme()) GroupDark else MaterialTheme.colors.background
) {
testedPreviously[server.server] = server.tested
onUpdate(server.copy(server = it, tested = testedPreviously[serverAddress.value]))
}
}
SectionDividerSpaced()
@@ -266,7 +266,7 @@ private fun HowToButton() {
SettingsActionItem(
painterResource(R.drawable.ic_open_in_new),
stringResource(R.string.how_to_use_your_servers),
{ uriHandler.openUriCatching("https://simplex.chat/docs/server.html") },
{ uriHandler.openUriCatching("https://github.com/simplex-chat/simplex-chat/blob/stable/docs/SERVER.md") },
textColor = MaterialTheme.colors.primary,
iconColor = MaterialTheme.colors.primary
)
@@ -120,7 +120,7 @@ fun RTCServersLayout(
} else {
Text(stringResource(R.string.enter_one_ICE_server_per_line))
if (editRTCServers) {
TextEditor(userRTCServersStr, Modifier.height(160.dp), contentPadding = PaddingValues())
TextEditor(Modifier.height(160.dp), text = userRTCServersStr)
Row(
Modifier.fillMaxWidth(),
@@ -197,7 +197,7 @@ private fun howToButton() {
val uriHandler = LocalUriHandler.current
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.clickable { uriHandler.openUriCatching("https://simplex.chat/docs/webrtc.html#configure-mobile-apps") }
modifier = Modifier.clickable { uriHandler.openUriCatching("https://github.com/simplex-chat/simplex-chat/blob/stable/docs/WEBRTC.md#configure-mobile-apps") }
) {
Text(stringResource(R.string.how_to), color = MaterialTheme.colors.primary)
Icon(
@@ -8,6 +8,7 @@ import SectionView
import TextIconSpaced
import android.content.Context
import android.content.res.Configuration
import androidx.activity.compose.BackHandler
import androidx.compose.foundation.*
import androidx.compose.foundation.layout.*
import androidx.compose.material.*
@@ -150,7 +151,7 @@ fun SettingsLayout(
val profileHidden = rememberSaveable { mutableStateOf(false) }
SettingsActionItem(painterResource(R.drawable.ic_manage_accounts), stringResource(R.string.your_chat_profiles), { withAuth(generalGetString(R.string.auth_open_chat_profiles), generalGetString(R.string.auth_log_in_using_credential)) { showSettingsModalWithSearch { it, search -> UserProfilesView(it, search, profileHidden) } } }, disabled = stopped, extraPadding = true)
SettingsIncognitoActionItem(incognitoPref, incognito, stopped) { showModal { IncognitoView() }() }
SettingsActionItem(painterResource(R.drawable.ic_qr_code), stringResource(R.string.your_simplex_contact_address), showCustomModal { it, close -> UserAddressView(it, shareViaProfile = it.currentUser.value!!.addressShared, close = close) }, disabled = stopped, extraPadding = true)
SettingsActionItem(painterResource(R.drawable.ic_qr_code), stringResource(R.string.your_simplex_contact_address), showModal { CreateLinkView(it, CreateLinkTab.LONG_TERM) }, disabled = stopped, extraPadding = true)
ChatPreferencesItem(showCustomModal, stopped = stopped)
}
SectionDividerSpaced()
@@ -361,15 +362,15 @@ fun ChatLockItem(
Text("v${BuildConfig.VERSION_NAME} (${BuildConfig.VERSION_CODE})")
}
@Composable fun ProfilePreview(profileOf: NamedChat, size: Dp = 60.dp, iconColor: Color = MaterialTheme.colors.secondaryVariant, textColor: Color = MaterialTheme.colors.onBackground, stopped: Boolean = false) {
ProfileImage(size = size, image = profileOf.image, color = iconColor)
@Composable fun ProfilePreview(profileOf: NamedChat, size: Dp = 60.dp, color: Color = MaterialTheme.colors.secondaryVariant, stopped: Boolean = false) {
ProfileImage(size = size, image = profileOf.image, color = color)
Spacer(Modifier.padding(horizontal = 8.dp))
Column(Modifier.height(size), verticalArrangement = Arrangement.Center) {
Text(
profileOf.displayName,
style = MaterialTheme.typography.caption,
fontWeight = FontWeight.Bold,
color = if (stopped) MaterialTheme.colors.secondary else textColor,
color = if (stopped) MaterialTheme.colors.secondary else Color.Unspecified,
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
@@ -377,7 +378,7 @@ fun ChatLockItem(
Text(
profileOf.fullName,
Modifier.padding(vertical = 5.dp),
color = if (stopped) MaterialTheme.colors.secondary else textColor,
color = if (stopped) MaterialTheme.colors.secondary else Color.Unspecified,
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
@@ -1,24 +0,0 @@
package chat.simplex.app.views.usersettings
import androidx.compose.foundation.*
import androidx.compose.foundation.layout.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import chat.simplex.app.R
import chat.simplex.app.views.helpers.*
import chat.simplex.app.views.onboarding.ReadableText
import chat.simplex.app.views.onboarding.ReadableTextWithLink
@Composable
fun UserAddressLearnMore() {
Column(
Modifier.verticalScroll(rememberScrollState()),
) {
AppBarTitle(stringResource(R.string.simplex_address))
ReadableText(R.string.you_can_share_your_address)
ReadableText(R.string.you_wont_lose_your_contacts_if_delete_address)
ReadableText(R.string.you_can_accept_or_reject_connection)
ReadableTextWithLink(R.string.read_more_in_user_guide_with_link, "https://simplex.chat/docs/guide/app-settings.html#your-simplex-contact-address")
}
}
@@ -1,423 +1,118 @@
package chat.simplex.app.views.usersettings
import SectionBottomSpacer
import SectionDividerSpaced
import SectionItemView
import SectionTextFooter
import SectionView
import android.content.res.Configuration
import android.util.Log
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import chat.simplex.app.R
import chat.simplex.app.TAG
import chat.simplex.app.model.*
import chat.simplex.app.model.ChatModel
import chat.simplex.app.model.UserContactLinkRec
import chat.simplex.app.ui.theme.*
import chat.simplex.app.views.chat.ShareAddressButton
import chat.simplex.app.views.helpers.*
import chat.simplex.app.views.newchat.QRCode
@Composable
fun UserAddressView(
chatModel: ChatModel,
viaCreateLinkView: Boolean = false,
shareViaProfile: Boolean = false,
close: () -> Unit
) {
val context = LocalContext.current
val shareViaProfile = remember { mutableStateOf(shareViaProfile) }
var progressIndicator by remember { mutableStateOf(false) }
val onCloseHandler: MutableState<(close: () -> Unit) -> Unit> = remember { mutableStateOf({ _ -> }) }
fun setProfileAddress(on: Boolean) {
progressIndicator = true
withBGApi {
try {
val u = chatModel.controller.apiSetProfileAddress(on)
if (u != null) {
chatModel.updateUser(u)
fun UserAddressView(chatModel: ChatModel) {
val cxt = LocalContext.current
UserAddressLayout(
userAddress = remember { chatModel.userAddress }.value,
createAddress = {
withApi {
val connReqContact = chatModel.controller.apiCreateUserAddress()
if (connReqContact != null) {
chatModel.userAddress.value = UserContactLinkRec(connReqContact)
}
} catch (e: Exception) {
Log.e(TAG, "UserAddressView apiSetProfileAddress: ${e.stackTraceToString()}")
} finally {
progressIndicator = false
}
}
}
val userAddress = remember { chatModel.userAddress }
val showLayout = @Composable {
UserAddressLayout(
userAddress = userAddress.value,
shareViaProfile,
onCloseHandler,
createAddress = {
withApi {
progressIndicator = true
val connReqContact = chatModel.controller.apiCreateUserAddress()
if (connReqContact != null) {
chatModel.userAddress.value = UserContactLinkRec(connReqContact)
AlertManager.shared.showAlertDialog(
title = generalGetString(R.string.share_address_with_contacts_question),
text = generalGetString(R.string.add_address_to_your_profile),
confirmText = generalGetString(R.string.share_verb),
onConfirm = {
setProfileAddress(true)
shareViaProfile.value = true
}
)
}
progressIndicator = false
}
},
learnMore = {
ModalManager.shared.showModal {
Column(
Modifier
.fillMaxHeight()
.padding(horizontal = DEFAULT_PADDING),
verticalArrangement = Arrangement.SpaceBetween
) {
UserAddressLearnMore()
}
}
},
share = { userAddress: String -> shareText(context, userAddress) },
sendEmail = { userAddress ->
sendEmail(
context,
generalGetString(R.string.email_invite_subject),
generalGetString(R.string.email_invite_body).format(userAddress.connReqContact)
)
},
setProfileAddress = ::setProfileAddress,
deleteAddress = {
AlertManager.shared.showAlertDialog(
title = generalGetString(R.string.delete_address__question),
text = if (shareViaProfile.value) generalGetString(R.string.all_your_contacts_will_remain_connected_update_sent) else generalGetString(R.string.all_your_contacts_will_remain_connected),
confirmText = generalGetString(R.string.delete_verb),
onConfirm = {
progressIndicator = true
withApi {
val u = chatModel.controller.apiDeleteUserAddress()
if (u != null) {
chatModel.userAddress.value = null
chatModel.updateUser(u)
shareViaProfile.value = false
progressIndicator = false
}
}
},
destructive = true,
)
},
saveAas = { aas: AutoAcceptState, savedAAS: MutableState<AutoAcceptState> ->
withBGApi {
val address = chatModel.controller.userAddressAutoAccept(aas.autoAccept)
if (address != null) {
chatModel.userAddress.value = address
savedAAS.value = aas
}
}
},
)
}
if (viaCreateLinkView) {
showLayout()
} else {
ModalView(close = { onCloseHandler.value(close) }) {
showLayout()
}
}
if (progressIndicator) {
Box(
Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
if (userAddress.value != null) {
Surface(Modifier.size(50.dp), color = MaterialTheme.colors.background.copy(0.9f), shape = RoundedCornerShape(50)){}
},
share = { userAddress: String -> shareText(cxt, userAddress) },
acceptRequests = {
chatModel.userAddress.value?.let { address ->
ModalManager.shared.showModal(settings = true) { AcceptRequestsView(chatModel, address) }
}
CircularProgressIndicator(
Modifier
.padding(horizontal = 2.dp)
.size(30.dp),
color = MaterialTheme.colors.secondary,
strokeWidth = 3.dp
},
deleteAddress = {
AlertManager.shared.showAlertDialog(
title = generalGetString(R.string.delete_address__question),
text = generalGetString(R.string.all_your_contacts_will_remain_connected),
confirmText = generalGetString(R.string.delete_verb),
onConfirm = {
withApi {
chatModel.controller.apiDeleteUserAddress()
chatModel.userAddress.value = null
}
},
destructive = true,
)
}
}
)
}
@Composable
private fun UserAddressLayout(
fun UserAddressLayout(
userAddress: UserContactLinkRec?,
shareViaProfile: MutableState<Boolean>,
onCloseHandler: MutableState<(close: () -> Unit) -> Unit>,
createAddress: () -> Unit,
learnMore: () -> Unit,
share: (String) -> Unit,
sendEmail: (UserContactLinkRec) -> Unit,
setProfileAddress: (Boolean) -> Unit,
deleteAddress: () -> Unit,
saveAas: (AutoAcceptState, MutableState<AutoAcceptState>) -> Unit,
acceptRequests: () -> Unit,
deleteAddress: () -> Unit
) {
Column(
Modifier.verticalScroll(rememberScrollState()),
) {
AppBarTitle(stringResource(R.string.simplex_address), false)
AppBarTitle(stringResource(R.string.your_contact_address), false)
Text(
stringResource(R.string.you_can_share_your_address_anybody_will_be_able_to_connect),
Modifier.padding(bottom = 12.dp),
lineHeight = 22.sp
)
Column(
Modifier.fillMaxWidth().padding(bottom = DEFAULT_PADDING_HALF),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.SpaceEvenly
) {
if (userAddress == null) {
SectionView {
CreateAddressButton(createAddress)
SectionTextFooter(stringResource(R.string.create_address_and_let_people_connect))
}
SectionDividerSpaced(maxBottomPadding = false)
SectionView {
LearnMoreButton(learnMore)
}
LaunchedEffect(Unit) {
onCloseHandler.value = { close -> close() }
}
SimpleButton(stringResource(R.string.create_address), icon = painterResource(R.drawable.ic_qr_code), click = createAddress)
} else {
val autoAcceptState = remember { mutableStateOf(AutoAcceptState(userAddress)) }
val autoAcceptStateSaved = remember { mutableStateOf(autoAcceptState.value) }
SectionView(stringResource(R.string.address_section_title).uppercase()) {
QRCode(userAddress.connReqContact, Modifier.padding(horizontal = DEFAULT_PADDING, vertical = DEFAULT_PADDING_HALF).aspectRatio(1f))
ShareAddressButton { share(userAddress.connReqContact) }
ShareViaEmailButton { sendEmail(userAddress) }
ShareWithContactsButton(shareViaProfile, setProfileAddress)
AutoAcceptToggle(autoAcceptState) { saveAas(autoAcceptState.value, autoAcceptStateSaved) }
LearnMoreButton(learnMore)
}
if (autoAcceptState.value.enable) {
SectionDividerSpaced()
AutoAcceptSection(autoAcceptState, autoAcceptStateSaved, saveAas)
}
SectionDividerSpaced(maxBottomPadding = false)
SectionView {
DeleteAddressButton(deleteAddress)
SectionTextFooter(stringResource(R.string.your_contacts_will_remain_connected))
}
LaunchedEffect(Unit) {
onCloseHandler.value = { close ->
if (autoAcceptState.value == autoAcceptStateSaved.value) close()
else showUnsavedChangesAlert({ saveAas(autoAcceptState.value, autoAcceptStateSaved); close() }, close)
}
QRCode(userAddress.connReqContact, Modifier.aspectRatio(1f))
Row(
horizontalArrangement = Arrangement.spacedBy(10.dp),
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.padding(vertical = DEFAULT_PADDING)
) {
SimpleButton(
stringResource(R.string.share_link),
icon = painterResource(R.drawable.ic_share),
click = { share(userAddress.connReqContact) })
SimpleButtonIconEnded(
stringResource(R.string.contact_requests),
icon = painterResource(R.drawable.ic_chevron_right),
click = acceptRequests
)
}
SimpleButton(
stringResource(R.string.delete_address),
icon = painterResource(R.drawable.ic_delete),
color = Color.Red,
click = deleteAddress
)
}
}
SectionBottomSpacer()
}
}
@Composable
private fun CreateAddressButton(onClick: () -> Unit) {
SettingsActionItem(
painterResource(R.drawable.ic_qr_code),
stringResource(R.string.create_simplex_address),
onClick,
iconColor = MaterialTheme.colors.primary,
textColor = MaterialTheme.colors.primary,
)
}
@Composable
private fun LearnMoreButton(onClick: () -> Unit) {
SettingsActionItem(
painterResource(R.drawable.ic_info),
stringResource(R.string.learn_more_about_address),
onClick,
)
}
@Composable
fun ShareViaEmailButton(onClick: () -> Unit) {
SettingsActionItem(
painterResource(R.drawable.ic_mail),
stringResource(R.string.invite_friends),
onClick,
iconColor = MaterialTheme.colors.primary,
textColor = MaterialTheme.colors.primary,
)
}
@Composable
fun ShareWithContactsButton(shareViaProfile: MutableState<Boolean>, setProfileAddress: (Boolean) -> Unit) {
PreferenceToggleWithIcon(
stringResource(R.string.share_with_contacts),
painterResource(R.drawable.ic_person),
checked = shareViaProfile.value,
) { on ->
shareViaProfile.value = on
if (on) {
AlertManager.shared.showAlertDialog(
title = generalGetString(R.string.share_address_with_contacts_question),
text = generalGetString(R.string.profile_update_will_be_sent_to_contacts),
confirmText = generalGetString(R.string.share_verb),
onConfirm = {
setProfileAddress(on)
},
onDismiss = {
shareViaProfile.value = !on
},
onDismissRequest = {
shareViaProfile.value = !on
})
} else {
AlertManager.shared.showAlertDialog(
title = generalGetString(R.string.stop_sharing_address),
text = generalGetString(R.string.profile_update_will_be_sent_to_contacts),
confirmText = generalGetString(R.string.stop_sharing),
onConfirm = {
setProfileAddress(on)
},
onDismiss = {
shareViaProfile.value = !on
},
onDismissRequest = {
shareViaProfile.value = !on
})
}
}
}
@Composable
private fun AutoAcceptToggle(autoAcceptState: MutableState<AutoAcceptState>, saveAas: (AutoAcceptState) -> Unit) {
PreferenceToggleWithIcon(stringResource(R.string.auto_accept_contact), painterResource(R.drawable.ic_check), checked = autoAcceptState.value.enable) {
autoAcceptState.value = if (!it)
AutoAcceptState()
else
AutoAcceptState(it, autoAcceptState.value.incognito, autoAcceptState.value.welcomeText)
saveAas(autoAcceptState.value)
}
}
@Composable
private fun DeleteAddressButton(onClick: () -> Unit) {
SettingsActionItem(
painterResource(R.drawable.ic_delete),
stringResource(R.string.delete_address),
onClick,
iconColor = MaterialTheme.colors.error,
textColor = MaterialTheme.colors.error,
)
}
private class AutoAcceptState {
var enable: Boolean = false
private set
var incognito: Boolean = false
private set
var welcomeText: String = ""
private set
constructor(enable: Boolean = false, incognito: Boolean = false, welcomeText: String = "") {
this.enable = enable
this.incognito = incognito
this.welcomeText = welcomeText
}
constructor(contactLink: UserContactLinkRec) {
contactLink.autoAccept?.let { aa ->
enable = true
incognito = aa.acceptIncognito
aa.autoReply?.let { msg ->
welcomeText = msg.text
} ?: run {
welcomeText = ""
}
}
}
val autoAccept: AutoAccept?
get() {
if (enable) {
var autoReply: MsgContent? = null
val s = welcomeText.trim()
if (s != "") {
autoReply = MsgContent.MCText(s)
}
return AutoAccept(incognito, autoReply)
}
return null
}
override fun equals(other: Any?): Boolean {
if (other !is AutoAcceptState) return false
return this.enable == other.enable && this.incognito == other.incognito && this.welcomeText == other.welcomeText
}
override fun hashCode(): Int {
var result = enable.hashCode()
result = 31 * result + incognito.hashCode()
result = 31 * result + welcomeText.hashCode()
return result
}
}
@Composable
private fun AutoAcceptSection(
autoAcceptState: MutableState<AutoAcceptState>,
savedAutoAcceptState: MutableState<AutoAcceptState>,
saveAas: (AutoAcceptState, MutableState<AutoAcceptState>) -> Unit
) {
SectionView(stringResource(R.string.auto_accept_contact).uppercase()) {
AcceptIncognitoToggle(autoAcceptState)
WelcomeMessageEditor(autoAcceptState)
SaveAASButton(autoAcceptState.value == savedAutoAcceptState.value) { saveAas(autoAcceptState.value, savedAutoAcceptState) }
}
}
@Composable
private fun AcceptIncognitoToggle(autoAcceptState: MutableState<AutoAcceptState>) {
PreferenceToggleWithIcon(
stringResource(R.string.accept_contact_incognito_button),
if (autoAcceptState.value.incognito) painterResource(R.drawable.ic_theater_comedy_filled) else painterResource(R.drawable.ic_theater_comedy),
if (autoAcceptState.value.incognito) Indigo else MaterialTheme.colors.secondary,
autoAcceptState.value.incognito,
) {
autoAcceptState.value = AutoAcceptState(autoAcceptState.value.enable, it, autoAcceptState.value.welcomeText)
}
}
@Composable
private fun WelcomeMessageEditor(autoAcceptState: MutableState<AutoAcceptState>) {
val welcomeText = rememberSaveable { mutableStateOf(autoAcceptState.value.welcomeText) }
TextEditor(welcomeText, Modifier.height(100.dp), placeholder = stringResource(R.string.enter_welcome_message_optional))
LaunchedEffect(welcomeText.value) {
if (welcomeText.value != autoAcceptState.value.welcomeText) {
autoAcceptState.value = AutoAcceptState(autoAcceptState.value.enable, autoAcceptState.value.incognito, welcomeText.value)
}
}
}
@Composable
private fun SaveAASButton(disabled: Boolean, onClick: () -> Unit) {
SectionItemView(onClick, disabled = disabled) {
Text(stringResource(R.string.save_verb), color = if (disabled) MaterialTheme.colors.secondary else MaterialTheme.colors.primary)
}
}
@Preview(showBackground = true)
@Preview(
uiMode = Configuration.UI_MODE_NIGHT_YES,
@@ -431,27 +126,12 @@ fun PreviewUserAddressLayoutNoAddress() {
userAddress = null,
createAddress = {},
share = { _ -> },
acceptRequests = {},
deleteAddress = {},
saveAas = { _, _ -> },
setProfileAddress = { _ -> },
learnMore = {},
shareViaProfile = remember { mutableStateOf(false) },
onCloseHandler = remember { mutableStateOf({}) },
sendEmail = {},
)
}
}
private fun showUnsavedChangesAlert(save: () -> Unit, revert: () -> Unit) {
AlertManager.shared.showAlertDialogStacked(
title = generalGetString(R.string.save_settings_question),
confirmText = generalGetString(R.string.save_auto_accept_settings),
dismissText = generalGetString(R.string.exit_without_saving),
onConfirm = save,
onDismiss = revert,
)
}
@Preview(showBackground = true)
@Preview(
uiMode = Configuration.UI_MODE_NIGHT_YES,
@@ -465,13 +145,8 @@ fun PreviewUserAddressLayoutAddressCreated() {
userAddress = UserContactLinkRec("https://simplex.chat/contact#/?v=1&smp=smp%3A%2F%2FPQUV2eL0t7OStZOoAsPEV2QYWt4-xilbakvGUGOItUo%3D%40smp6.simplex.im%2FK1rslx-m5bpXVIdMZg9NLUZ_8JBm8xTt%23MCowBQYDK2VuAyEALDeVe-sG8mRY22LsXlPgiwTNs9dbiLrNuA7f3ZMAJ2w%3D"),
createAddress = {},
share = { _ -> },
acceptRequests = {},
deleteAddress = {},
saveAas = { _, _ -> },
setProfileAddress = { _ -> },
learnMore = {},
shareViaProfile = remember { mutableStateOf(false) },
onCloseHandler = remember { mutableStateOf({}) },
sendEmail = {},
)
}
}
@@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:fillColor="#FF000000"
android:pathData="M480.02,479.5q-65.52,0 -106.52,-40.98t-41,-106.5q0,-65.52 40.98,-106.52t106.5,-41q65.52,0 106.52,40.98t41,106.5q0,65.52 -40.98,106.52t-106.5,41ZM738,793.5L222,793.5q-23.72,0 -40.61,-16.89Q164.5,759.72 164.5,736v-33.51q0,-37.49 18.75,-63.99t48.43,-40.17Q298,569 358.5,554T480,539q61,0 121,15.25t126.4,44.43q30.82,13.64 49.46,39.85Q795.5,664.75 795.5,702.47v33.77q0,23.45 -16.89,40.36Q761.72,793.5 738,793.5ZM222,736h516v-33.37q0,-16.32 -9.75,-30.97Q718.5,657 705,650q-64,-30.5 -116.29,-42t-108.57,-11.5Q423.5,596.5 370.5,608t-116,42q-14,7 -23.25,21.73T222,702.74L222,736ZM480,422q39,0 64.5,-25.5T570,332q0,-39 -25.5,-64.5T480,242q-39,0 -64.5,25.5T390,332q0,39 25.5,64.5T480,422ZM480,332ZM480,736Z"/>
</vector>
@@ -30,7 +30,8 @@
<string name="smp_servers_preset_add">أضف خوادم محددة مسبقًا</string>
<string name="smp_servers_add_to_another_device">أضف إلى جهاز آخر</string>
<string name="users_delete_all_chats_deleted">سيتم حذف جميع الدردشات والرسائل - لا يمكن التراجع عن هذا!</string>
<string name="network_enable_socks_info">الوصول إلى الخوادم عبر بروكسي SOCKS على المنفذ %d؟ يجب بدء تشغيل الوكيل قبل تمكين هذا الخيار.</string>
<string name="network_enable_socks_info">الوصول إلى الخوادم عبر بروكسي SOCKS على المنفذ 9050؟ يجب بدء تشغيل الوكيل قبل تمكين هذا الخيار.</string>
<string name="accept_requests">قبول طلبات</string>
<string name="smp_servers_add">إضافة خادم …</string>
<string name="network_settings">إعدادات الشبكة المتقدمة</string>
<string name="all_group_members_will_remain_connected">سيبقى جميع أعضاء المجموعة على اتصال.</string>
@@ -9,11 +9,12 @@
<string name="network_settings">Pokročilá nastavení sítě</string>
<string name="accept">Přijmout</string>
<string name="smp_servers_add">Přidat server…</string>
<string name="network_enable_socks_info">Přistupovat k serverům přes SOCKS proxy na portu %d\? Před povolením této možnosti musí být spuštěna proxy.</string>
<string name="network_enable_socks_info">Přistupovat k serverům přes SOCKS proxy na portu 9050\? Před povolením této možnosti musí být spuštěna proxy.</string>
<string name="accept_feature">Přijmout</string>
<string name="allow_your_contacts_to_send_disappearing_messages">Povolte svým kontaktům odesílat mizící zprávy.</string>
<string name="about_simplex_chat">O <xliff:g id="appNameFull">SimpleX Chat</xliff:g></string>
<string name="smp_servers_add_to_another_device">Přidat do jiného zařízení</string>
<string name="accept_requests">Přijímat žádosti</string>
<string name="allow_verb">Povolit</string>
<string name="allow_voice_messages_question">Povolit hlasové zprávy\?</string>
<string name="about_simplex">O SimpleX</string>
@@ -240,6 +241,8 @@
<string name="network_session_mode_entity">Připojení</string>
<string name="core_simplexmq_version">simplexmq: v%s (%2s)</string>
<string name="create_address">Vytvořit adresu</string>
<string name="accept_automatically">Automaticky</string>
<string name="section_title_welcome_message">UVÍTACÍ ZPRÁVA</string>
<string name="save_and_notify_group_members">Uložit a upozornit členy skupiny</string>
<string name="exit_without_saving">Ukončit bez uložení</string>
<string name="the_messaging_and_app_platform_protecting_your_privacy_and_security">Platforma pro zasílání zpráv a aplikace chránící vaše soukromí a bezpečnost.</string>
@@ -375,6 +378,7 @@
<string name="delete_pending_connection__question">Smazat čekající připojení\?</string>
<string name="icon_descr_settings">Nastavení</string>
<string name="image_descr_qr_code">QR kód</string>
<string name="show_QR_code_for_your_contact_to_scan_from_the_app__multiline">Váš kontakt může z aplikace naskenovat QR kód.</string>
<string name="if_you_cannot_meet_in_person_show_QR_in_video_call_or_via_another_channel">Pokud se nemůžete setkat osobně, ukažte ve <b>videohovoru QR kód</b> nebo sdílejte odkaz.</string>
<string name="scan_code">Skenovat kód</string>
<string name="incorrect_code">Nesprávný bezpečnostní kód!</string>
@@ -392,6 +396,7 @@
<string name="network_use_onion_hosts_required_desc">Pro připojení budou vyžadováni Onion hostitelé.</string>
<string name="update_network_session_mode_question">Aktualizovat režim dopravní izolace\?</string>
<string name="app_version_code">Sestavení aplikace: %s</string>
<string name="you_can_share_your_address_anybody_will_be_able_to_connect">Můžete sdílet svou adresu jako odkaz nebo jako QR kód - kdokoli se k vám bude moci připojit. O své kontakty nepřijdete, pokud ji později smažete.</string>
<string name="share_link">Sdílet odkaz</string>
<string name="delete_address">Smazat adresu</string>
<string name="full_name__field">Celé jméno:</string>
@@ -635,6 +640,7 @@
<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="network_socks_toggle">Použít proxy server SOCKS (port 9050)</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>
@@ -653,6 +659,7 @@
<string name="core_version">Verze jádra: v%s</string>
<string name="delete_address__question">Smazat adresu\?</string>
<string name="all_your_contacts_will_remain_connected">Všechny vaše kontakty zůstanou připojeny.</string>
<string name="contact_requests">Žádosti o kontakt</string>
<string name="display_name__field">Zobrazované jméno:</string>
<string name="your_profile_is_stored_on_device_and_shared_only_with_contacts_simplex_cannot_see_it">Váš profil je uložen v zařízení a je sdílen pouze s vašimi kontakty. <xliff:g id="appName">SimpleX</xliff:g> servery váš profil vidět nemohou.</string>
<string name="save_preferences_question">Uložit předvolby\?</string>
@@ -950,6 +957,7 @@
<string name="v4_5_italian_interface">Italské rozhraní</string>
<string name="v4_5_italian_interface_descr">Díky uživatelům - překládejte prostřednictvím Weblate!</string>
<string name="you_will_be_connected_when_your_contacts_device_is_online">Budete připojeni, jakmile bude zařízení vašeho kontaktu online, vyčkejte prosím nebo se podívejte později!</string>
<string name="your_contact_address">Vaše adresa</string>
<string name="your_chat_profile_will_be_sent_to_your_contact">Váš chat profil bude odeslán
\nvašemu kontaktu</string>
<string name="your_chats">Vaše konverzace</string>
@@ -328,6 +328,7 @@
<string name="you_will_be_connected_when_group_host_device_is_online">Sie werden mit der Gruppe verbunden, sobald das Endgerät des Gruppen-Hosts online ist. Bitte warten oder schauen Sie später nochmal nach!</string>
<string name="you_will_be_connected_when_your_connection_request_is_accepted">Sie werden verbunden, sobald Ihre Verbindungsanfrage akzeptiert wird. Bitte warten oder schauen Sie später nochmal nach!</string>
<string name="you_will_be_connected_when_your_contacts_device_is_online">Sie werden verbunden, sobald das Endgerät Ihres Kontakts online ist. Bitte warten oder schauen Sie später nochmal nach!</string>
<string name="show_QR_code_for_your_contact_to_scan_from_the_app__multiline">Zeigen Sie Ihrem Kontakt den QR-Code aus der App zum Scannen.</string>
<string name="if_you_cannot_meet_in_person_show_QR_in_video_call_or_via_another_channel">Wenn Sie sich nicht persönlich treffen können, können Sie <b>den QR-Code während eines Videoanrufs anzeigen</b> oder einen Einladungslink über einen anderen Kanal mit Ihrem Kontakt teilen.</string>
<string name="your_chat_profile_will_be_sent_to_your_contact">Ihr Chat-Profil wird
\nan Ihren Kontakt gesendet</string>
@@ -344,6 +345,7 @@
<!-- CreateLinkView.kt -->
<string name="create_one_time_link">Link / QR-Code erstellen</string>
<string name="one_time_link">Einmaliger Einladungs-Link</string>
<string name="your_contact_address">Meine Kontaktadresse</string>
<!-- settings - SettingsView.kt -->
<string name="your_settings">Meine Einstellungen</string>
<string name="your_simplex_contact_address">Meine <xliff:g id="appName">SimpleX</xliff:g> Kontaktadresse</string>
@@ -395,8 +397,9 @@
<string name="network_and_servers">Netzwerk &amp; Server</string>
<string name="network_settings">Erweiterte Netzwerkeinstellungen</string>
<string name="network_settings_title">Netzwerkeinstellungen</string>
<string name="network_socks_toggle">SOCKS-Proxy verwenden (Port 9050)</string>
<string name="network_enable_socks">SOCKS-Proxy verwenden?</string>
<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_enable_socks_info">Zugriff auf die Server über SOCKS-Proxy auf Port 9050? 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 und 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>
@@ -415,8 +418,14 @@
<string name="create_address">Adresse erstellen</string>
<string name="delete_address__question">Adresse löschen?</string>
<string name="all_your_contacts_will_remain_connected">Alle Ihre Kontakte bleiben verbunden.</string>
<string name="you_can_share_your_address_anybody_will_be_able_to_connect">Sie können Ihre Adresse als Link oder als QR-Code teilen Jede Person kann sich darüber mit Ihnen verbinden. Sie werden Ihre mit dieser Adresse verbundenen Kontakte nicht verlieren, wenn Sie diese Adresse später löschen.</string>
<string name="share_link">Link teilen</string>
<string name="delete_address">Adresse löschen</string>
<!-- AcceptRequestsView.kt -->
<string name="contact_requests">Kontaktanfragen</string>
<string name="accept_requests">Anfragen annehmen</string>
<string name="accept_automatically">Automatisch</string>
<string name="section_title_welcome_message">Begrüßungsmeldung</string>
<!-- User profile details - UserProfileView.kt -->
<string name="display_name__field">Angezeigter Name:</string>
<string name="full_name__field">"Vollständiger Name:</string>
@@ -33,7 +33,7 @@
<string name="accept_contact_incognito_button">Aceptar incógnito</string>
<string name="clear_chat_warning">Se eliminarán todos los mensajes SOLO para tí. ¡No puede deshacerse!</string>
<string name="smp_servers_add">Añadir servidor…</string>
<string name="network_enable_socks_info">¿Acceder a los servidores a través del proxy SOCKS en el puerto %d\? El proxy debe iniciarse antes de activar esta opción.</string>
<string name="network_enable_socks_info">¿Acceder a los servidores a través del proxy SOCKS en el puerto 9050\? El proxy debe iniciarse antes de activar esta opción.</string>
<string name="all_your_contacts_will_remain_connected">Todos tus contactos permanecerán conectados.</string>
<string name="appearance_settings">Apariencia</string>
<string name="app_version_title">Versión</string>
@@ -75,6 +75,8 @@
<string name="about_simplex_chat">Sobre <xliff:g id="appNameFull">SimpleX Chat</xliff:g></string>
<string name="smp_servers_add_to_another_device">Añadir a otro dispositivo</string>
<string name="app_version_name">Versión de la aplicación: v%s</string>
<string name="accept_requests">Aceptar solicitudes</string>
<string name="accept_automatically">Automáticamente</string>
<string name="icon_descr_asked_to_receive">Solicita recibir la imagen</string>
<string name="impossible_to_recover_passphrase"><b>Ten en cuenta</b>: NO podrás recuperar o cambiar la contraseña si la pierdes.</string>
<string name="both_you_and_your_contact_can_send_voice">Tanto tú como tu contacto podéis enviar mensajes de voz.</string>
@@ -252,6 +254,7 @@
\nContraseña</string>
<string name="contribute">Contribuye</string>
<string name="core_version">Core versión: v%s</string>
<string name="contact_requests">Solicitud del contacto</string>
<string name="delete_image">Eliminar imagen</string>
<string name="edit_image">Editar imagen</string>
<string name="settings_section_title_chats">CHATS</string>
@@ -738,6 +741,7 @@
<string name="share_verb">Compartir</string>
<string name="icon_descr_sent_msg_status_unauthorized_send">envío no autorizado</string>
<string name="set_contact_name">Escribe un nombre para el contacto</string>
<string name="network_socks_toggle">Usar proxy SOCKS (puerto 9050)</string>
<string name="unknown_error">Error desconocido</string>
<string name="member_role_will_be_changed_with_notification">El rol cambiará a \"%s\". Se notificará a todos los miembros del grupo.</string>
<string name="v4_2_security_assessment_desc">La seguridad de SimpleX Chat fue auditada por Trail of Bits.</string>
@@ -854,6 +858,7 @@
<string name="description_via_one_time_link">mediante enlace de un uso</string>
<string name="your_chats">Tus chats</string>
<string name="voice_message_send_text">Mensaje de voz…</string>
<string name="your_contact_address">Mi dirección de contacto</string>
<string name="icon_descr_video_off">Desactivar vídeo</string>
<string name="icon_descr_video_on">Activar vídeo</string>
<string name="wrong_passphrase">Contraseña de base de datos incorrecta</string>
@@ -883,6 +888,7 @@
<string name="failed_to_create_user_duplicate_desc">Tienes un perfil de chat con el mismo nombre mostrado. Debes elegir otro nombre.</string>
<string name="you_can_also_connect_by_clicking_the_link">También puedes conectarte haciendo clic en el enlace. Si se abre en el navegador, haz clic en <b>Abrir en aplicación móvil</b>.</string>
<string name="you_can_connect_to_simplex_chat_founder">Puedes <font color="#0088ff">ponerte en contacto con los desarrolladores de <xliff:g id="appNameFull">SimpleX Chat</xliff:g> para consultas y para recibir actualizaciones</font>.</string>
<string name="you_can_share_your_address_anybody_will_be_able_to_connect">Puedes compartir tu dirección como enlace o como código QR: cualquiera podrá conectarse contigo. Si lo eliminas más tarde tus contactos no se perderán.</string>
<string name="observer_cant_send_message_title">¡No puedes enviar mensajes!</string>
<string name="you_can_use_markdown_to_format_messages__prompt">Puedes usar la sintaxis markdown para dar formato a los mensajes:</string>
<string name="you_must_use_the_most_recent_version_of_database">Debes usar la versión más reciente de tu base de datos ÚNICAMENTE en un dispositivo, de lo contrario podrías dejar de recibir mensajes de algunos contactos.</string>
@@ -917,6 +923,7 @@
<string name="you_accepted_connection">Has aceptado la conexión</string>
<string name="you_invited_your_contact">Has invitado a tu contacto</string>
<string name="you_will_be_connected_when_group_host_device_is_online">Te conectarás al grupo cuando el dispositivo del anfitrión esté en línea, por favor espera o compruébalo más tarde.</string>
<string name="show_QR_code_for_your_contact_to_scan_from_the_app__multiline">Tu contacto puede escanear el código QR desde la aplicación.</string>
<string name="your_settings">Mi configuración</string>
<string name="your_SMP_servers">Tus servidores SMP</string>
<string name="you_control_your_chat">¡Tú controlas tu chat!</string>
@@ -965,6 +972,7 @@
<string name="your_simplex_contact_address">Mi dirección de contacto <xliff:g id="appName">SimpleX</xliff:g></string>
<string name="smp_servers_your_server">Tu servidor</string>
<string name="smp_servers_your_server_address">Dirección de tu servidor</string>
<string name="section_title_welcome_message">MENSAJE DE BIENVENIDA</string>
<string name="your_current_profile">Tu perfil actual</string>
<string name="your_profile_is_stored_on_device_and_shared_only_with_contacts_simplex_cannot_see_it">Tu perfil se almacena en tu dispositivo y sólo se comparte con tus contactos. Los servidores <xliff:g id="appName">SimpleX</xliff:g> no pueden ver tu perfil.</string>
<string name="language_system">Sistema</string>
@@ -240,6 +240,7 @@
<string name="this_QR_code_is_not_a_link">Ce code QR n\'est pas un lien !</string>
<string name="you_will_be_connected_when_your_connection_request_is_accepted">Vous serez connecté·e lorsque votre demande de connexion sera acceptée, veuillez attendre ou vérifier plus tard !</string>
<string name="you_will_be_connected_when_your_contacts_device_is_online">Vous serez connecté·e lorsque l\'appareil de votre contact sera en ligne, veuillez attendre ou vérifier plus tard !</string>
<string name="show_QR_code_for_your_contact_to_scan_from_the_app__multiline">Votre contact peut scanner le code QR depuis l\'app.</string>
<string name="your_chat_profile_will_be_sent_to_your_contact">Votre profil de chat sera envoyé
\nà votre contact</string>
<string name="share_invitation_link">Partager le lien d\'invitation</string>
@@ -259,6 +260,7 @@
<string name="connect_via_link">Se connecter via un lien</string>
<string name="clear_verification">Retirer la vérification</string>
<string name="one_time_link">Lien d\'invitation unique</string>
<string name="your_contact_address">Votre adresse de contact</string>
<string name="scan_code">Scanner le code</string>
<string name="incorrect_code">Code de sécurité incorrect !</string>
<string name="security_code">Code de sécurité</string>
@@ -324,7 +326,7 @@
<string name="use_simplex_chat_servers__question">Utiliser les serveurs <xliff:g id="appNameFull">SimpleX Chat</xliff:g> \?</string>
<string name="smp_servers_delete_server">Supprimer le serveur</string>
<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_enable_socks_info">Accéder aux serveurs via un proxy SOCKS sur le port 9050 \? 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>
@@ -350,6 +352,7 @@
<string name="configure_ICE_servers">Configurer les serveurs ICE</string>
<string name="network_settings">Paramètres réseau avancés</string>
<string name="network_settings_title">Paramètres réseau</string>
<string name="network_socks_toggle">Utiliser un proxy SOCKS (port 9050)</string>
<string name="network_enable_socks">Utiliser un proxy SOCKS \?</string>
<string name="network_disable_socks">Utiliser une connexion Internet directe \?</string>
<string name="network_disable_socks_info">Si vous confirmez, les serveurs de messagerie seront en mesure de voir votre adresse IP, votre fournisseur ainsi que les serveurs auxquels vous vous connectez.</string>
@@ -358,6 +361,7 @@
<string name="network_use_onion_hosts_prefer_desc">Les hôtes .onion seront utilisés lorsqu\'ils sont disponibles.</string>
<string name="appearance_settings">Apparence</string>
<string name="create_address">Créer une adresse</string>
<string name="you_can_share_your_address_anybody_will_be_able_to_connect">Vous pouvez partager votre adresse sous forme de lien ou de code QR - n\'importe qui pourra se connecter à vous. Vous ne perdrez pas vos contacts si vous la supprimez par la suite.</string>
<string name="your_current_profile">Votre profil de chat</string>
<string name="edit_image">Modifier l\'image</string>
<string name="save_and_notify_contacts">Sauvegarder et notifier les contacts</string>
@@ -429,6 +433,10 @@
<string name="all_your_contacts_will_remain_connected">Tous vos contacts resteront connectés.</string>
<string name="share_link">Partager le lien</string>
<string name="delete_address">Supprimer l\'adresse</string>
<string name="contact_requests">Demandes de contact</string>
<string name="accept_requests">Accepter les demandes</string>
<string name="accept_automatically">Automatiquement</string>
<string name="section_title_welcome_message">MESSAGE DE BIENVENUE</string>
<string name="display_name__field">Nom affiché :</string>
<string name="full_name__field">Nom complet :</string>
<string name="your_profile_is_stored_on_device_and_shared_only_with_contacts_simplex_cannot_see_it">Votre profil est stocké sur votre appareil et partagé uniquement avec vos contacts. Les serveurs <xliff:g id="appName">SimpleX</xliff:g> ne peuvent pas voir votre profil.</string>
@@ -10,6 +10,7 @@
<string name="above_then_preposition_continuation">ऊपर,तब:</string>
<string name="accept_contact_button">स्वीकार करना</string>
<string name="connect_button">जुडिये</string>
<string name="your_contact_address">आपका संपर्क पता</string>
<string name="smp_servers_add_to_another_device">दूसरे उपकरण में जोड़ें</string>
<string name="bold">निडर</string>
<string name="answer_call">कॉल का उत्तर दें</string>
@@ -34,6 +35,7 @@
<string name="accept_connection_request__question">संबंध अनुरोध स्वीकार करें\?</string>
<string name="callstatus_accepted">स्वीकृत कॉल</string>
<string name="accept_contact_incognito_button">गुप्त स्वीकार करें</string>
<string name="accept_requests">निवेदन स्वीकार करो</string>
<string name="smp_servers_preset_add">पूर्वनिर्धारित सर्वर जोड़ें</string>
<string name="users_add">प्रोफ़ाइल जोड़ें</string>
<string name="smp_servers_add">सर्वर जोड़े…</string>
@@ -65,6 +67,7 @@
<string name="chat_preferences_you_allow">आप आज्ञा दें</string>
<string name="welcome">स्वागत!</string>
<string name="la_notice_turn_on">चालू करो</string>
<string name="section_title_welcome_message">स्वागत संदेश</string>
<string name="unknown_message_format">अज्ञात संदेश प्रारूप</string>
<string name="personal_welcome">स्वागत <xliff:g>%1$s</xliff:g>!</string>
<string name="callstate_starting">शुरुआत</string>
@@ -232,6 +235,7 @@
<string name="chat_console">चैट कंसोल</string>
<string name="all_your_contacts_will_remain_connected">आपके सभी संपर्क जुड़े रहेंगे।</string>
<string name="network_session_mode_user">चैट प्रोफ़ाइल</string>
<string name="contact_requests">संपर्क अनुरोध</string>
<string name="create_profile_button">बनाएं</string>
<string name="callstatus_error">कॉल त्रुटि</string>
<string name="callstatus_in_progress">कॉल चल रहा है</string>
@@ -239,7 +239,8 @@
<string name="allow_disappearing_messages_only_if">Consenti i messaggi a tempo solo se il tuo contatto li consente.</string>
<string name="allow_to_delete_messages">Permetti di eliminare irreversibilmente i messaggi inviati.</string>
<string name="allow_your_contacts_to_send_disappearing_messages">Permetti ai tuoi contatti di inviare messaggi a tempo.</string>
<string name="network_enable_socks_info">Accedere ai server via proxy SOCKS sulla porta %d\? Il proxy deve essere avviato prima di attivare questa opzione.</string>
<string name="accept_requests">Accetta le richieste</string>
<string name="network_enable_socks_info">Accedere ai server via proxy SOCKS sulla porta 9050\? Il proxy deve essere avviato prima di attivare questa opzione.</string>
<string name="v4_3_improved_server_configuration_desc">Aggiungi server scansionando codici QR.</string>
<string name="all_group_members_will_remain_connected">Tutti i membri del gruppo resteranno connessi.</string>
<string name="allow_irreversible_message_deletion_only_if">Consenti l\'eliminazione irreversibile dei messaggi solo se il contatto la consente a te.</string>
@@ -283,6 +284,7 @@
<string name="snd_conn_event_switch_queue_phase_changing">cambio indirizzo…</string>
<string name="chat_is_stopped">Chat fermata</string>
<string name="group_member_status_introduced">connessione (presentato)</string>
<string name="contact_requests">Richieste del contatto</string>
<string name="connection_request_sent">Richiesta di connessione inviata!</string>
<string name="delete_link_question">Eliminare il link\?</string>
<string name="delete_link">Elimina link</string>
@@ -337,6 +339,7 @@
<string name="how_to">Come si fa</string>
<string name="how_to_use_your_servers">Come usare i tuoi server</string>
<string name="enter_one_ICE_server_per_line">Server ICE (uno per riga)</string>
<string name="accept_automatically">Automaticamente</string>
<string name="bold">grassetto</string>
<string name="callstatus_ended">chiamata terminata <xliff:g id="duration" example="01:15">%1$s</xliff:g></string>
<string name="callstatus_error">errore di chiamata</string>
@@ -572,6 +575,7 @@
<string name="you_invited_your_contact">Hai invitato il contatto</string>
<string name="your_chat_profile_will_be_sent_to_your_contact">Il tuo profilo di chat verrà inviato
\nal tuo contatto</string>
<string name="show_QR_code_for_your_contact_to_scan_from_the_app__multiline">Il tuo contatto può scansionare il codice QR dall\'app.</string>
<string name="alert_text_connection_pending_they_need_to_be_online_can_delete_and_retry">Il tuo contatto deve essere in linea per completare la connessione.
\nPuoi annullare questa connessione e rimuovere il contatto (e riprovare più tardi con un link nuovo).</string>
<string name="you_will_be_connected_when_your_connection_request_is_accepted">Verrai connesso/a quando la tua richiesta di connessione verrà accettata, attendi o controlla più tardi!</string>
@@ -608,6 +612,7 @@
<string name="smp_servers_use_server">Usa il server</string>
<string name="you_can_also_connect_by_clicking_the_link">Puoi anche connetterti cliccando il link. Se si apre nel browser, clicca il pulsante <b>Apri nell\'app mobile</b>.</string>
<string name="your_profile_will_be_sent">Il tuo profilo di chat verrà inviato al tuo contatto</string>
<string name="your_contact_address">Il tuo indirizzo di contatto</string>
<string name="smp_servers_your_server">Il tuo server</string>
<string name="smp_servers_your_server_address">L\'indirizzo del tuo server</string>
<string name="your_simplex_contact_address">Il tuo indirizzo di contatto di <xliff:g id="appName">SimpleX</xliff:g></string>
@@ -633,9 +638,11 @@
<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>
<string name="network_socks_toggle">Usa il proxy SOCKS (porta 9050)</string>
<string name="use_simplex_chat_servers__question">Usare i server di <xliff:g id="appNameFull">SimpleX Chat</xliff:g>\?</string>
<string name="using_simplex_chat_servers">Stai usando i server di <xliff:g id="appNameFull">SimpleX Chat</xliff:g>.</string>
<string name="network_use_onion_hosts_prefer">Quando disponibili</string>
<string name="you_can_share_your_address_anybody_will_be_able_to_connect">Puoi condividere il tuo indirizzo come link o come codice QR: chiunque potrà connettersi a te. Non perderai i tuoi contatti se in seguito lo elimini.</string>
<string name="your_ICE_servers">I tuoi server ICE</string>
<string name="your_SMP_servers">I tuoi server SMP</string>
<string name="italic">corsivo</string>
@@ -655,6 +662,7 @@
<string name="callstate_waiting_for_answer">in attesa di risposta…</string>
<string name="callstate_waiting_for_confirmation">in attesa di conferma…</string>
<string name="we_do_not_store_contacts_or_messages_on_servers">Non memorizziamo nessuno dei tuoi contatti o messaggi (una volta recapitati) sui server.</string>
<string name="section_title_welcome_message">MESSAGGIO DI BENVENUTO</string>
<string name="you_can_use_markdown_to_format_messages__prompt">Puoi usare il markdown per formattare i messaggi:</string>
<string name="you_control_your_chat">Sei tu a controllare la tua chat!</string>
<string name="your_current_profile">Il tuo profilo attuale</string>
@@ -22,7 +22,7 @@
<string name="smp_servers_add_to_another_device">別の端末に追加</string>
<string name="users_add">プロフィールを追加</string>
<string name="smp_servers_add">サーバを追加…</string>
<string name="network_enable_socks_info">SOCKSプロキシ(ポート%d)経由で接続しますか?(※設定する前にプロキシ起動が必要※)</string>
<string name="network_enable_socks_info">SOCKSプロキシ(ポート9050)経由で接続しますか?(※設定する前にプロキシ起動が必要※)</string>
<string name="users_delete_all_chats_deleted">全チャットとメッセージが削除されます(※元に戻せません※)!</string>
<string name="allow_your_contacts_to_send_voice_messages">送信相手からの音声メッセージを許可する。</string>
<string name="both_you_and_your_contact_can_send_voice">あなたと連絡相手が音声メッセージを送信できます。</string>
@@ -31,6 +31,8 @@
<string name="attach">添付する</string>
<string name="app_version_code">アプリ・ビルド番号: %s</string>
<string name="all_your_contacts_will_remain_connected">あなたの連絡先が繋がったまま継続します。</string>
<string name="accept_requests">リクエストを承諾</string>
<string name="accept_automatically">自動的に</string>
<string name="icon_descr_audio_on">音声オン</string>
<string name="integrity_msg_bad_hash">メッセージのハッシュ値問題</string>
<string name="integrity_msg_bad_id">メッセージIDの問題</string>
@@ -225,6 +227,7 @@
<string name="contact_preferences">連絡先の設定</string>
<string name="status_contact_has_no_e2e_encryption">連絡先はエンドツーエンド暗号化がありません。</string>
<string name="alert_title_contact_connection_pending">連絡先がまだ繋がってません!</string>
<string name="contact_requests">連絡先のリクエスト</string>
<string name="icon_descr_context">追加情報アイコン</string>
<string name="network_use_onion_hosts_prefer_desc">オニオンのホストが利用可能時に使われます。</string>
<string name="network_use_onion_hosts_no_desc">オニオンのホストが使われません。</string>
@@ -726,6 +729,7 @@
<string name="this_link_is_not_a_valid_connection_link">このリンクは有効な接続リンクではありません!</string>
<string name="this_QR_code_is_not_a_link">このQRコードはリンクではありません!</string>
<string name="you_will_be_connected_when_group_host_device_is_online">グループのホスト端末がオンラインになったら、接続されます。後でチェックするか、しばらくお待ちください。</string>
<string name="show_QR_code_for_your_contact_to_scan_from_the_app__multiline">連絡相手がアプリからQRコードを読み込めます。</string>
<string name="you_will_be_connected_when_your_contacts_device_is_online">連絡先がオンラインになったら、接続されます。後でチェックするか、しばらくお待ちください。</string>
<string name="your_chat_profile_will_be_sent_to_your_contact">あなたのチャットプロフィールが
\n連絡相手に送られます。</string>
@@ -735,6 +739,7 @@
<string name="scan_code_from_contacts_app">連絡相手のアプリからセキュリティコードを読み込む</string>
<string name="chat_lock">SimpleXロック</string>
<string name="is_not_verified">%s は未認証</string>
<string name="your_contact_address">あなたのチャットアドレス</string>
<string name="your_settings">あなたの設定</string>
<string name="smp_servers_test_server">テストサーバ</string>
<string name="smp_servers_save">サーバを保存</string>
@@ -748,6 +753,7 @@
<string name="your_ICE_servers">あなたのICEサーバ</string>
<string name="network_disable_socks">直接にインタネットに繋がりますか?</string>
<string name="network_enable_socks">SOCKSプロキシを使いますか?</string>
<string name="network_socks_toggle">SOCKSプロキシ (ポート9050) を使う</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>
@@ -884,6 +890,8 @@
<string name="using_simplex_chat_servers"><xliff:g id="appNameFull">SimpleX Chat</xliff:g>を使っています。</string>
<string name="share_link">リンクを送る</string>
<string name="core_simplexmq_version">simplexmq: バージョン%s (%2s)</string>
<string name="you_can_share_your_address_anybody_will_be_able_to_connect">あなたと繋がるリンク、またはQRコードを共有できます。誰でも接続できます。後で削除しても、連絡先がそのままのこります。</string>
<string name="section_title_welcome_message">歓迎メッセージ</string>
<string name="callstate_waiting_for_answer">応答待ち…</string>
<string name="callstate_waiting_for_confirmation">確認待ち…</string>
<string name="first_platform_without_user_ids">世界初のユーザーIDのないプラットフォーム|設計も元からプライベート</string>
@@ -52,10 +52,13 @@
<string name="network_settings">고급 네트워크 설정</string>
<string name="network_session_mode_user">채팅 프로필</string>
<string name="network_session_mode_entity">연결</string>
<string name="accept_requests">요청 수락</string>
<string name="app_version_code">앱 빌드 : %s</string>
<string name="appearance_settings">외관</string>
<string name="app_version_title">앱 버전</string>
<string name="app_version_name">앱 버전 : v%s</string>
<string name="accept_automatically">자동</string>
<string name="contact_requests">대화 상대의 요청</string>
<string name="core_version">코어 버전 : v%s</string>
<string name="callstatus_accepted">전화 받음</string>
<string name="bold">굵게</string>
@@ -140,7 +143,7 @@
<string name="accept_call_on_lock_screen">응답</string>
<string name="accept_connection_request__question">연결 요청을 수락할까요\?</string>
<string name="accept_feature">수락</string>
<string name="network_enable_socks_info">SOCKS 프록시(포트 %d)를 통해 서버에 액세스할까요\? 이 설정을 활성화하기 전에 프록시를 시작해야 해요.</string>
<string name="network_enable_socks_info">SOCKS 프록시(포트 9050)를 통해 서버에 액세스할까요\? 이 설정을 활성화하기 전에 프록시를 시작해야 해요.</string>
<string name="smp_servers_add_to_another_device">다른 기기에 추가</string>
<string name="v4_3_improved_server_configuration_desc">QR 코드 스캔으로 서버 추가</string>
<string name="button_add_welcome_message">환영 메시지 추가</string>
@@ -667,6 +670,7 @@
<string name="mark_unread">읽지 않음으로 표시</string>
<string name="mute_chat">음소거</string>
<string name="markdown_in_messages">메시지에 사용된 마크다운</string>
<string name="network_socks_toggle">SOCKS 프록시 사용 (포트 9050)</string>
<string name="network_disable_socks">직접적인 인터넷 연결을 사용할까요\?</string>
<string name="network_enable_socks">SOCKS 프록시를 사용할까요\?</string>
<string name="network_disable_socks_info">설정하면 메시징 서버에서 내 IP 주소와 내가 연결하려는 서버를 볼 수 있어요.</string>
@@ -824,10 +828,12 @@
<string name="send_live_message_desc">라이브 메시지 보내기 - 입력 과정을 실시간으로 상대에게 보여줘요.</string>
<string name="send_verb">보내기</string>
<string name="share_invitation_link">초대 링크 공유</string>
<string name="show_QR_code_for_your_contact_to_scan_from_the_app__multiline">연락하고자 하는 사람이 앱에서 QR 코드를 스캔할 수 있어요.</string>
<string name="security_code">보안 코드</string>
<string name="smp_servers_scan_qr">서버 QR코드 스캔</string>
<string name="smp_servers_test_some_failed">일부 서버가 테스트에 통과하지 못했습니다 :</string>
<string name="smp_servers_test_failed">서버 테스트 실패!</string>
<string name="section_title_welcome_message">환영 메시지</string>
<string name="share_link">링크 공유</string>
<string name="show_call_on_lock_screen">표시하기</string>
<string name="select_contacts">연락처 선택</string>
@@ -12,6 +12,7 @@
<string name="app_version_title">Programėlės versija</string>
<string name="app_version_name">Programėlės versija: v%s</string>
<string name="app_version_code">Programėlės darinys: %s</string>
<string name="accept_automatically">Automatiškai</string>
<string name="callstatus_calling">skambinama…</string>
<string name="callstatus_error">skambučio klaida</string>
<string name="call_already_ended">Skambutis jau baigtas!</string>
@@ -278,6 +279,7 @@
<string name="use_camera_button">Naudoti kamerą</string>
<string name="thank_you_for_installing_simplex">Dėkojame, kad įdiegėte <xliff:g id="appNameFull">SimpleX Chat</xliff:g>!</string>
<string name="smp_servers_use_server">Naudoti serverį</string>
<string name="network_socks_toggle">Naudoti SOCKS įgaliotąjį serverį (prievadas 9050)</string>
<string name="network_enable_socks">Naudoti SOCKS įgaliotąjį serverį\?</string>
<string name="core_simplexmq_version">simplexmq: v%s (%2s)</string>
<string name="share_link">Bendrinti nuorodą</string>
@@ -16,7 +16,7 @@
<string name="icon_descr_asked_to_receive">Gevraagd om de afbeelding te ontvangen</string>
<string name="change_verb">Wijziging</string>
<string name="network_settings">Geavanceerde netwerk instellingen</string>
<string name="network_enable_socks_info">Toegang tot de servers via SOCKS proxy op poort %d\? De proxy moet worden gestart voordat u deze optie inschakelt.</string>
<string name="network_enable_socks_info">Toegang tot de servers via SOCKS proxy op poort 9050\? De proxy moet worden gestart voordat u deze optie inschakelt.</string>
<string name="alert_title_cant_invite_contacts">Kan geen contacten uitnodigen!</string>
<string name="allow_direct_messages">Sta het verzenden van directe berichten naar leden toe.</string>
<string name="allow_to_delete_messages">Sta toe om verzonden berichten onomkeerbaar te verwijderen.</string>
@@ -75,6 +75,7 @@
<string name="about_simplex">Over SimpleX</string>
<string name="about_simplex_chat">Over <xliff:g id="appNameFull">SimpleX Chat</xliff:g></string>
<string name="above_then_preposition_continuation">hier boven, dan:</string>
<string name="accept_requests">Verzoeken accepteren</string>
<string name="users_delete_all_chats_deleted">Alle gesprekken en berichten worden verwijderd, dit kan niet ongedaan worden gemaakt!</string>
<string name="clear_chat_warning">Alle berichten worden verwijderd, dit kan niet ongedaan worden gemaakt! De berichten worden ALLEEN voor jou verwijderd.</string>
<string name="allow_disappearing_messages_only_if">Sta verdwijnende berichten alleen toe als uw contactpersoon dit toestaat.</string>
@@ -95,6 +96,7 @@
<string name="app_version_name">App versie: v%s</string>
<string name="network_session_mode_user_description">Er wordt een aparte TCP-verbinding (en SOCKS-referentie) gebruikt <b> voor elk chat profiel dat je in de app hebt </b>.</string>
<string name="audio_call_no_encryption">audio oproep (niet e2e versleuteld)</string>
<string name="accept_automatically">Automatisch</string>
<string name="notifications_mode_service_desc">Achtergrondservice is altijd actief, meldingen worden weergegeven zodra de berichten beschikbaar zijn.</string>
<string name="add_new_contact_to_create_one_time_QR_code"><b>Nieuw contact toevoegen</b>: om uw eenmalige QR-code voor uw contact te maken.</string>
<string name="icon_descr_call_ended">Oproep beëindigd</string>
@@ -208,6 +210,7 @@
<string name="create_one_time_link">Maak een eenmalige uitnodiging link</string>
<string name="colored">gekleurd</string>
<string name="callstatus_connecting">Oproep verbinden…</string>
<string name="contact_requests">Contact verzoeken</string>
<string name="create_profile_button">Maak</string>
<string name="create_profile">Maak een profiel aan</string>
<string name="delete_address">Adres verwijderen</string>
@@ -622,8 +625,10 @@
<string name="icon_descr_simplex_team"><xliff:g id="appName">SimpleX</xliff:g>-Team</string>
<string name="this_QR_code_is_not_a_link">Deze QR-code is geen link!</string>
<string name="this_link_is_not_a_valid_connection_link">Deze link is geen geldige link!</string>
<string name="show_QR_code_for_your_contact_to_scan_from_the_app__multiline">Uw contactpersoon kan de QR-code vanuit de app scannen.</string>
<string name="share_invitation_link">Uitnodiging link delen</string>
<string name="scan_code">Code scannen</string>
<string name="your_contact_address">Uw contact adres</string>
<string name="your_settings">Uw instellingen</string>
<string name="share_link">Deel link</string>
<string name="you_control_your_chat">Jij beheert je gesprek!</string>
@@ -720,8 +725,10 @@
<string name="smp_servers_your_server_address">Uw server adres</string>
<string name="smp_servers_your_server">Uw server</string>
<string name="network_session_mode_transport_isolation">Transport isolation</string>
<string name="network_socks_toggle">SOCKS-proxy gebruiken (poort 9050)</string>
<string name="save_preferences_question">Voorkeuren opslaan\?</string>
<string name="save_and_notify_contact">Opslaan en Contact melden</string>
<string name="section_title_welcome_message">WELKOMST BERICHT</string>
<string name="your_current_profile">Je huidige profiel</string>
<string name="save_and_notify_contacts">Opslaan en Contacten melden</string>
<string name="save_and_notify_group_members">Opslaan en Groepsleden melden</string>
@@ -920,6 +927,7 @@
<string name="use_simplex_chat_servers__question"><xliff:g id="appNameFull">SimpleX Chat</xliff:g> servers gebruiken\?</string>
<string name="voice_messages_are_prohibited">Spraak berichten zijn verboden in deze groep.</string>
<string name="personal_welcome">Welkom <xliff:g>%1$s</xliff:g>!</string>
<string name="you_can_share_your_address_anybody_will_be_able_to_connect">U kunt uw adres delen als een link of als een QR-code. Iedereen kan verbinding met u maken. U verliest uw contacten niet als u deze later verwijdert.</string>
<string name="you_can_start_chat_via_setting_or_by_restarting_the_app">U kunt de chat starten via app Instellingen / Database of door de app opnieuw op te starten.</string>
<string name="snd_conn_event_switch_queue_phase_completed_for_member">je hebt het adres gewijzigd voor %s</string>
<string name="snd_group_event_member_deleted">je hebt <xliff:g id="member profile" example="alice (Alice)">%1$s</xliff:g> verwijderd</string>
@@ -290,6 +290,7 @@
<string name="your_chat_profile_will_be_sent_to_your_contact">Twój profil czatu zostanie wysłany
\ndo Twojego kontaktu</string>
<string name="your_profile_will_be_sent">Twój profil czatu zostanie wysłany do Twojego kontaktu</string>
<string name="your_contact_address">Twój adres kontaktowy</string>
<string name="you_will_be_connected_when_group_host_device_is_online">Zostaniesz połączony do grupy, gdy urządzenie gospodarza grupy będzie online, proszę czekać lub sprawdzić później!</string>
<string name="you_will_be_connected_when_your_contacts_device_is_online">Zostaniesz połączony, gdy urządzenie Twojego kontaktu będzie online, proszę czekać lub sprawdzić później!</string>
<string name="smp_servers_preset_add">Dodaj gotowe serwery</string>
@@ -331,7 +332,7 @@
<string name="smp_servers_your_server_address">Twój adres serwera</string>
<string name="your_simplex_contact_address">Twój adres kontaktowy <xliff:g id="appName">SimpleX</xliff:g></string>
<string name="contribute">Przyczyń się</string>
<string name="network_enable_socks_info">Uzyskiwać dostęp do serwerów przez SOCKS proxy na porcie %d\? Proxy musi zostać uruchomione przed włączeniem tej opcji.</string>
<string name="network_enable_socks_info">Uzyskiwać dostęp do serwerów przez SOCKS proxy na porcie 9050\? Proxy musi zostać uruchomione przed włączeniem tej opcji.</string>
<string name="network_settings">Zaawansowane ustawienia sieci</string>
<string name="app_version_code">Kompilacja aplikacji: %s</string>
<string name="appearance_settings">Wygląd</string>
@@ -362,7 +363,11 @@
<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>
<string name="network_enable_socks">Użyć proxy SOCKS\?</string>
<string name="network_socks_toggle">Użyj proxy SOCKS (port 9050)</string>
<string name="accept_requests">Akceptuj prośby</string>
<string name="all_your_contacts_will_remain_connected">Wszystkie Twoje kontakty pozostaną połączone.</string>
<string name="accept_automatically">Automatycznie</string>
<string name="contact_requests">Prośby kontaktu</string>
<string name="create_address">Utwórz adres</string>
<string name="developer_options">ID bazy danych i opcja izolacji transportu.</string>
<string name="delete_address">Usuń adres</string>
@@ -382,6 +387,8 @@
<string name="show_dev_options">Pokaż:</string>
<string name="show_developer_options">Pokaż opcje dewelopera</string>
<string name="core_simplexmq_version">simplexmq: v%s (%2s)</string>
<string name="section_title_welcome_message">WIADOMOŚĆ POWITALNA</string>
<string name="you_can_share_your_address_anybody_will_be_able_to_connect">Możesz udostępnić swój adres jako link lub jako kod QR - każdy będzie mógł się z Tobą połączyć. Nie stracisz swoich kontaktów, jeśli później go usuniesz.</string>
<string name="your_current_profile">Twój obecny profil</string>
<string name="confirm_password">Potwierdź hasło</string>
<string name="create_profile">Utwórz profil</string>
@@ -1034,6 +1041,7 @@
<string name="you_must_use_the_most_recent_version_of_database">Musisz używać najnowszej wersji bazy danych czatu TYLKO na jednym urządzeniu, w przeciwnym razie możesz przestać otrzymywać wiadomości od niektórych kontaktów.</string>
<string name="you_can_start_chat_via_setting_or_by_restarting_the_app">Możesz rozpocząć czat poprzez Ustawienia aplikacji / Bazę danych lub poprzez ponowne uruchomienie aplikacji.</string>
<string name="your_settings">Twoje ustawienia</string>
<string name="show_QR_code_for_your_contact_to_scan_from_the_app__multiline">Twój kontakt może zeskanować kod QR z aplikacji.</string>
<string name="your_current_chat_database_will_be_deleted_and_replaced_with_the_imported_one">Twoja obecna baza danych czatu zostanie USUNIĘTA i ZASTĄPIONA zaimportowaną.
\nTej czynności nie można cofnąć - Twój profil, kontakty, wiadomości i pliki zostaną nieodwracalnie utracone.</string>
<string name="contact_sent_large_file">Twój kontakt wysłał plik, który jest większy niż obecnie obsługiwany maksymalny rozmiar (<xliff:g id="maxFileSize">%1$s</xliff:g>).</string>
@@ -50,6 +50,7 @@
<string name="icon_descr_close_button">Botão Fechar</string>
<string name="clear_verification">Limpar verificação</string>
<string name="app_version_title">Versão do App</string>
<string name="accept_automatically">Automaticamente</string>
<string name="bold">negrito</string>
<string name="callstatus_error">erro de chamada</string>
<string name="settings_audio_video_calls">Chamadas de áudio e vídeo</string>
@@ -66,6 +67,7 @@
<string name="incognito_random_profile_description">Um perfil aleatório será enviado para o seu contato</string>
<string name="chat_preferences">Preferências de chat</string>
<string name="network_session_mode_user">perfil de chat</string>
<string name="accept_requests">Aceitar solicitações</string>
<string name="icon_descr_audio_off">Áudio desligado</string>
<string name="auto_accept_images">Aceitar imagens automaticamente</string>
<string name="chat_database_deleted">Banco de dados de chat excluído</string>
@@ -121,6 +123,7 @@
<string name="copied">Copiado para a área de transferência</string>
<string name="accept_connection_request__question">Aceitar solicitação de conexão\?</string>
<string name="network_settings">Configurações de rede avançadas</string>
<string name="contact_requests">Solicitações de contato</string>
<string name="create_address">Criar endereço</string>
<string name="all_your_contacts_will_remain_connected">Todos os seus contatos permanecerão conectados.</string>
<string name="callstatus_accepted">chamada aceita</string>
@@ -154,7 +157,7 @@
<string name="alert_title_contact_connection_pending">Contato ainda não está conectado!</string>
<string name="contribute">Contribuir</string>
<string name="create_profile_button">Criar</string>
<string name="network_enable_socks_info">Acessar os servidores via proxy SOCKS na porta %d\? O proxy deve ser iniciado antes de habilitar esta opção.</string>
<string name="network_enable_socks_info">Acessar os servidores via proxy SOCKS na porta 9050\? O proxy deve ser iniciado antes de habilitar esta opção.</string>
<string name="allow_your_contacts_irreversibly_delete">Permitir que seus contatos excluam de forma irreversível as mensagens enviadas.</string>
<string name="smp_servers_add_to_another_device">Adicionar a outro dispositivo</string>
<string name="v4_2_group_links_desc">Os administradores podem criar os links para ingressar em grupos.</string>
@@ -459,6 +462,7 @@
<string name="reject_contact_button">Rejeitar</string>
<string name="feature_offered_item">ofereceu %s</string>
<string name="icon_descr_address"><xliff:g id="appName">Endereço</xliff:g> SimpleX</string>
<string name="show_QR_code_for_your_contact_to_scan_from_the_app__multiline">Seu contato pode escanear o código QR do aplicativo.</string>
<string name="feature_offered_item_with_param">ofereceu %s: %2s</string>
<string name="paste_connection_link_below_to_connect">Cole o link que você recebeu na caixa abaixo para conectar com o seu contato.</string>
<string name="new_in_version">Novo em %s</string>
@@ -653,6 +657,7 @@
<string name="this_QR_code_is_not_a_link">Esse código QR não é um link!</string>
<string name="your_chat_profile_will_be_sent_to_your_contact">Seu perfil de chat será enviado para seu
\ncontato</string>
<string name="your_contact_address">Seu endereço de contato</string>
<string name="you_will_be_connected_when_your_contacts_device_is_online">Você será conectado quando o dispositivo do seu contato estiver online, aguarde ou verifique mais tarde!</string>
<string name="how_to">Como</string>
<string name="smp_servers_test_failed">Teste do servidor falhou!</string>
@@ -779,6 +784,7 @@
<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="you_can_share_your_address_anybody_will_be_able_to_connect">Você pode compartilhar seu endereço como um link ou como um código QR - qualquer pessoa poderá se conectar a você. Você não perderá seus contatos se excluí-los posteriormente.</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>
@@ -809,6 +815,7 @@
<string name="network_settings_title">Configurações de conexão</string>
<string name="no_details">sem detalhes</string>
<string name="add_contact">Link de convite de uso único</string>
<string name="network_socks_toggle">Usar proxy SOCKS (porta 9050)</string>
<string name="smp_servers_your_server_address">Seu endereço de servidor</string>
<string name="your_settings">Suas configurações</string>
<string name="is_verified">%s é verificado</string>
@@ -914,6 +921,7 @@
<string name="you_are_observer">você é um observador</string>
<string name="voice_message_with_duration">Mensagem de voz (<xliff:g id="duration">%1$s</xliff:g>)</string>
<string name="share_link">Compartilhar link</string>
<string name="section_title_welcome_message">MENSAGEM DE BOAS-VINDAS</string>
<string name="to_protect_privacy_simplex_has_ids_for_queues">Para proteger a privacidade, em vez dos IDs de usuário usados por todas as outras plataformas, <xliff:g id="appName">SimpleX</xliff:g> tem identificadores para filas de mensagens, separados para cada um de seus contatos.</string>
<string name="icon_descr_video_call">chamada de vídeo</string>
<string name="show_call_on_lock_screen">Mostrar</string>
@@ -330,6 +330,7 @@
<string name="you_will_be_connected_when_group_host_device_is_online">Соединение с группой будет установлено, когда хост группы будет онлайн. Пожалуйста, подождите или проверьте позже!</string>
<string name="you_will_be_connected_when_your_connection_request_is_accepted">Соединение будет установлено, когда Ваш запрос будет принят. Пожалуйста, подождите или проверьте позже!</string>
<string name="you_will_be_connected_when_your_contacts_device_is_online">Соединение будет установлено, когда Ваш контакт будет онлайн. Пожалуйста, подождите или проверьте позже!</string>
<string name="show_QR_code_for_your_contact_to_scan_from_the_app__multiline">Ваш контакт может сосканировать QR код в приложении.</string>
<string name="if_you_cannot_meet_in_person_show_QR_in_video_call_or_via_another_channel">Если Вы не можете встретиться лично, Вы можете <b>показать QR код во время видеозвонка</b> или поделиться ссылкой.</string>
<string name="your_chat_profile_will_be_sent_to_your_contact">Ваш профиль будет отправлен
\nВашему контакту</string>
@@ -343,6 +344,7 @@
<!-- CreateLinkView.kt -->
<string name="create_one_time_link">Создать одноразовую ссылку</string>
<string name="one_time_link">Одноразовая ссылка</string>
<string name="your_contact_address">Ваш SimpleX адрес</string>
<!-- settings - SettingsView.kt -->
<string name="your_settings">Настройки</string>
<string name="your_simplex_contact_address">Ваш <xliff:g id="appName">SimpleX</xliff:g> адрес</string>
@@ -394,8 +396,9 @@
<string name="network_and_servers">Сеть и серверы</string>
<string name="network_settings">Настройки сети</string>
<string name="network_settings_title">Настройки сети</string>
<string name="network_socks_toggle">Использовать SOCKS прокси (порт 9050)</string>
<string name="network_enable_socks">Использовать SOCKS прокси?</string>
<string name="network_enable_socks_info">Соединяться с серверами через SOCKS прокси через порт %d? Прокси должен быть запущен до включения этой опции.</string>
<string name="network_enable_socks_info">Соединяться с серверами через SOCKS прокси через порт 9050? Прокси должен быть запущен до включения этой опции.</string>
<string name="network_disable_socks">Использовать прямое соединение с Интернет?</string>
<string name="network_disable_socks_info">Если Вы подтвердите, серверы смогут видеть Ваш IP адрес, а провайдер - с какими серверами Вы соединяетесь.</string>
<string name="update_onion_hosts_settings_question">Обновить настройки .onion хостов?</string>
@@ -414,8 +417,14 @@
<string name="create_address">Создать адрес</string>
<string name="delete_address__question">Удалить адрес?</string>
<string name="all_your_contacts_will_remain_connected">Все контакты, которые соединились через этот адрес, сохранятся.</string>
<string name="you_can_share_your_address_anybody_will_be_able_to_connect">Вы можете использовать Ваш адрес как ссылку или как QR код - кто угодно сможет соединиться с Вами. Вы сможете удалить адрес, сохранив контакты, которые через него соединились.</string>
<string name="share_link">Поделиться\nссылкой</string>
<string name="delete_address">Удалить адрес</string>
<string name="delete_address">Удалить\nадрес</string>
<!-- AcceptRequestsView.kt -->
<string name="contact_requests">Запросы контактов</string>
<string name="accept_requests">Принимать запросы</string>
<string name="accept_automatically">Автоматически</string>
<string name="section_title_welcome_message">ПРИВЕТСТВЕННОЕ СООБЩЕНИЕ</string>
<!-- User profile details - UserProfileView.kt -->
<string name="display_name__field">Имя профиля:</string>
<string name="full_name__field">"Полное имя:</string>
@@ -14,7 +14,7 @@
<string name="color_primary">色调</string>
<string name="callstatus_accepted">已接受通话</string>
<string name="accept">接受</string>
<string name="network_enable_socks_info">通过 SOCKS 代理访问服务器在端口%d?允许该选项前必须开始代理。</string>
<string name="network_enable_socks_info">通过 SOCKS 代理访问服务器在端口9050?允许该选项前必须开始代理。</string>
<string name="smp_servers_add">添加服务器……</string>
<string name="smp_servers_add_to_another_device">添加另一设备</string>
<string name="group_member_role_admin">管理员</string>
@@ -23,6 +23,7 @@
<string name="accept_connection_request__question">接受连接请求?</string>
<string name="accept_contact_incognito_button">接受隐身聊天</string>
<string name="v4_2_group_links_desc">管理员可以创建链接以加入群组。</string>
<string name="accept_requests">接受请求</string>
<string name="smp_servers_preset_add">添加预设服务器</string>
<string name="connect_via_link">通过链接连接</string>
<string name="display_name_connection_established">已建立连接</string>
@@ -111,6 +112,7 @@
<string name="integrity_msg_bad_hash">错误消息散列</string>
<string name="integrity_msg_bad_id">错误消息 ID</string>
<string name="settings_audio_video_calls">语音和视频通话</string>
<string name="accept_automatically">自动</string>
<string name="turning_off_service_and_periodic">激活电池优化,关闭了后台服务和新消息的定期请求。您可以通过设置重新启用它们。</string>
<string name="notifications_mode_service_desc">后台服务一直在运行——一旦有消息,就会显示通知。</string>
<string name="icon_descr_audio_off">关闭音频</string>
@@ -326,6 +328,7 @@
<string name="delete_contact_all_messages_deleted_cannot_undo_warning">联系人和所有的消息都将被删除——这是不可逆回的!</string>
<string name="notification_preview_mode_contact">联系人姓名</string>
<string name="group_member_status_intro_invitation">连接(介绍邀请)</string>
<string name="contact_requests">联系人请求</string>
<string name="callstate_connecting">连接中……</string>
<string name="contacts_can_mark_messages_for_deletion">联系人可以将信息标记为删除;您将可以查看这些信息。</string>
<string name="contribute">贡献</string>
@@ -513,6 +516,7 @@
<string name="you_must_use_the_most_recent_version_of_database">您只能在一台设备上使用最新版本的聊天数据库,否则您可能会停止接收来自某些联系人的消息。</string>
<string name="new_passphrase">新密码……</string>
<string name="member_role_will_be_changed_with_notification">该角色将更改为“%s”。群组中每个人都会收到通知。</string>
<string name="your_contact_address">您的联系人地址</string>
<string name="chat_lock">SimpleX 锁定</string>
<string name="periodic_notifications">定期通知</string>
<string name="notifications_mode_periodic">定期启动</string>
@@ -872,6 +876,7 @@
<string name="you_will_be_connected_when_your_contacts_device_is_online">当您的联系人设备在线时,您将可以连接,请稍等或稍后查看!</string>
<string name="rate_the_app">评价此应用程序</string>
<string name="network_enable_socks">使用 SOCKS 代理?</string>
<string name="network_socks_toggle">使用 SOCKS 代理(端口 9050</string>
<string name="total_files_count_and_size">%d 个文件,总大小为 %s</string>
<string name="you_joined_this_group">您已加入此群组</string>
<string name="you_are_invited_to_group">您被邀请加入群组</string>
@@ -886,7 +891,9 @@
<string name="icon_descr_simplex_team"><xliff:g id="appName">SimpleX</xliff:g> 团队</string>
<string name="group_info_section_title_num_members"><xliff:g id="num_members">%1$s</xliff:g> 成员</string>
<string name="chat_preferences_yes"></string>
<string name="you_can_share_your_address_anybody_will_be_able_to_connect">您可以将您的地址作为链接或二维码共享——任何人都可以连接到您。 如果您以后删除它,您不会丢失您的联系人。</string>
<string name="you_control_servers_to_receive_your_contacts_to_send">您可以控制通过哪些服务器<b>接收</b>消息,您的联系人 - 您用来向他们发送消息的服务器。</string>
<string name="show_QR_code_for_your_contact_to_scan_from_the_app__multiline">您的联系人可以从应用程序中扫描二维码。</string>
<string name="you_will_be_connected_when_group_host_device_is_online">您将在组主设备上线时连接到该群组,请稍等或稍后再检查!</string>
<string name="auth_you_will_be_required_to_authenticate_when_you_start_or_resume">当您启动应用或在应用程序驻留后台超过30 秒后,您将需要进行身份验证。</string>
<string name="archive_created_on_ts">创建于 <xliff:g id="archive_ts">%1$s</xliff:g></string>
@@ -935,6 +942,7 @@
<string name="network_use_onion_hosts">使用 .onion 主机</string>
<string name="your_ICE_servers">您的 ICE 服务器</string>
<string name="core_simplexmq_version">simplexmq: v%s (%2s)</string>
<string name="section_title_welcome_message">欢迎消息</string>
<string name="you_control_your_chat">您的聊天由您掌控!</string>
<string name="you_can_use_markdown_to_format_messages__prompt">您可以使用 markdown 来编排消息格式:</string>
<string name="ttl_h">%dh</string>
@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="chat_item_ttl_week">1 個星期</string>
<string name="accept_requests">接受請求</string>
<string name="a_plus_b">a + b</string>
<string name="about_simplex">關於 SimpleX</string>
<string name="accept_call_on_lock_screen">接受</string>
@@ -69,6 +70,7 @@
<string name="app_version_code">程式建構:%s</string>
<string name="app_version_name">應用程式版本:v%s</string>
<string name="share_link">分享連結</string>
<string name="accept_automatically">自動接受所有請求</string>
<string name="your_current_profile">你目前的個人檔案</string>
<string name="display_name_cannot_contain_whitespace">顯示的名稱字與字中間不能有空白。</string>
<string name="save_preferences_question">儲存設定?</string>
@@ -432,6 +434,8 @@
<string name="core_version">核心版本:v%s</string>
<string name="core_simplexmq_version">simplexmq: v%s (%2s)</string>
<string name="create_address">建立地址</string>
<string name="contact_requests">聯絡人請求</string>
<string name="section_title_welcome_message">歡迎訊息</string>
<string name="edit_image">編輯圖片</string>
<string name="italic">斜體</string>
<string name="callstatus_rejected">已拒絕通話</string>
@@ -483,6 +487,7 @@
<string name="this_string_is_not_a_connection_link">這些字串不是連接連結!</string>
<string name="you_can_also_connect_by_clicking_the_link">你也可以點擊連結連接。如果在瀏覧器中開啟,點擊 <b>程式內的開啟</b> 按扭。</string>
<string name="one_time_link">一次性邀請連結</string>
<string name="your_contact_address">你的聯絡人地址</string>
<string name="scan_code">掃描二碼碼</string>
<string name="incorrect_code">錯誤的安全碼!</string>
<string name="scan_code_from_contacts_app">在你聯絡人的程式內掃描安全碼</string>
@@ -506,6 +511,7 @@
<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="you_can_share_your_address_anybody_will_be_able_to_connect">你可以使用連結或二維碼分享你的地址 - 任何人也可以和你連線。如果你不主動刪除你的聯絡人,你並不會遺失你的聯絡人</string>
<string name="your_profile_is_stored_on_device_and_shared_only_with_contacts_simplex_cannot_see_it">你的個人檔案只會儲存於你的裝置和只會分享給你的聯絡人。 <xliff:g id="appName">SimpleX</xliff:g> 伺服器並不會看到你的個人檔案。</string>
<string name="save_and_notify_contact">儲存並通知你的聯絡人</string>
<string name="save_and_notify_contacts">儲存並通知你的多個聯絡人</string>
@@ -519,9 +525,11 @@
<string name="callstate_received_answer">收到回應 …</string>
<string name="callstate_connecting">連接中 …</string>
<string name="callstate_ended">通話完結</string>
<string name="show_QR_code_for_your_contact_to_scan_from_the_app__multiline">你的聯絡人可以在程式內使用二維碼</string>
<string name="connect_button">連接</string>
<string name="network_and_servers">網路 &amp; 伺服器</string>
<string name="network_settings_title">網路設定</string>
<string name="network_socks_toggle">使用 SOCKS 代理伺服器 (端口 9050)</string>
<string name="network_enable_socks">使用 SOCKS 代理伺服器</string>
<string name="save_and_notify_group_members">儲存並通知群組內的聯絡人</string>
<string name="exit_without_saving">退出並且不儲存記錄</string>
@@ -103,7 +103,6 @@
<string name="error_smp_test_server_auth">Server requires authorization to create queues, check password</string>
<string name="error_xftp_test_server_auth">Server requires authorization to upload, check password</string>
<string name="error_smp_test_certificate">Possibly, certificate fingerprint in server address is incorrect</string>
<string name="error_setting_address">Error setting address</string>
<string name="smp_server_test_connect">Connect</string>
<string name="smp_server_test_disconnect">Disconnect</string>
<string name="smp_server_test_create_queue">Create queue</string>
@@ -447,24 +446,13 @@
<string name="you_will_be_connected_when_group_host_device_is_online">You will be connected to group when the group host\'s device is online, please wait or check later!</string>
<string name="you_will_be_connected_when_your_connection_request_is_accepted">You will be connected when your connection request is accepted, please wait or check later!</string>
<string name="you_will_be_connected_when_your_contacts_device_is_online">You will be connected when your contact\'s device is online, please wait or check later!</string>
<string name="show_QR_code_for_your_contact_to_scan_from_the_app__multiline">Your contact can scan QR code from the app.</string>
<string name="if_you_cannot_meet_in_person_show_QR_in_video_call_or_via_another_channel">If you can\'t meet in person, <b>show QR code in the video call</b>, or share the link.</string>
<string name="your_chat_profile_will_be_sent_to_your_contact">Your chat profile will be sent\nto your contact</string>
<string name="if_you_cannot_meet_in_person_scan_QR_in_video_call_or_ask_for_invitation_link">If you cannot meet in person, you can <b>scan QR code in the video call</b>, or your contact can share an invitation link.</string>
<string name="share_invitation_link">Share 1-time link</string>
<string name="share_invitation_link">Share invitation link</string>
<string name="paste_connection_link_below_to_connect">Paste the link you received into the box below to connect with your contact.</string>
<string name="your_profile_will_be_sent">Your chat profile will be sent to your contact</string>
<string name="learn_more">Learn more</string>
<string name="learn_more_about_address">About SimpleX address</string>
<!-- Add Contact Learn More - AddContactLearnMore.kt -->
<string name="scan_qr_to_connect_to_contact">To connect, your contact can scan QR code or use the link in the app.</string>
<string name="if_you_cant_meet_in_person">If you can\'t meet in person, show QR code in a video call, or share the link.</string>
<!-- User Address Learn More - UserAddressLearnMore.kt -->
<string name="you_can_share_your_address">You can share your address as a link or QR code - anybody can connect to you.</string>
<string name="you_wont_lose_your_contacts_if_delete_address">You won\'t lose your contacts if you later delete your address.</string>
<string name="you_can_accept_or_reject_connection">When people request to connect, you can accept or reject it.</string>
<string name="read_more_in_user_guide_with_link">Read more in <font color="#0088ff">User Guide</font>.</string>
<!-- PasteToConnect.kt -->
<string name="connect_via_link">Connect via link</string>
@@ -476,8 +464,7 @@
<!-- CreateLinkView.kt -->
<string name="create_one_time_link">Create one-time invitation link</string>
<string name="one_time_link">One-time invitation link</string>
<string name="one_time_link_short">1-time link</string>
<string name="simplex_address">SimpleX address</string>
<string name="your_contact_address">Your contact address</string>
<!-- ScanCodeView.kt -->
<string name="scan_code">Scan code</string>
@@ -494,7 +481,7 @@
<!-- settings - SettingsView.kt -->
<string name="your_settings">Your settings</string>
<string name="your_simplex_contact_address">Your SimpleX address</string>
<string name="your_simplex_contact_address">Your <xliff:g id="appName">SimpleX</xliff:g> contact address</string>
<string name="your_chat_profiles">Your chat profiles</string>
<string name="database_passphrase_and_export">Database passphrase &amp; export</string>
<string name="about_simplex_chat">About <xliff:g id="appNameFull">SimpleX Chat</xliff:g></string>
@@ -548,13 +535,14 @@
<string name="network_and_servers">Network &amp; servers</string>
<string name="network_settings">Advanced network settings</string>
<string name="network_settings_title">Network settings</string>
<string name="network_socks_toggle">Use SOCKS proxy (port 9050)</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>
<string name="host_verb">Host</string>
<string name="port_verb">Port</string>
<string name="network_enable_socks">Use SOCKS proxy?</string>
<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_enable_socks_info">Access the servers via SOCKS proxy on port 9050? 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>
@@ -591,32 +579,16 @@
<!-- Address Items - UserAddressView.kt -->
<string name="create_address">Create address</string>
<string name="delete_address__question">Delete address?</string>
<string name="your_contacts_will_remain_connected">Your contacts will remain connected.</string>
<string name="all_your_contacts_will_remain_connected">All your contacts will remain connected.</string>
<string name="all_your_contacts_will_remain_connected_update_sent">All your contacts will remain connected. Profile update will be sent to your contacts.</string>
<string name="you_can_share_your_address_anybody_will_be_able_to_connect">You can share your address as a link or as a QR code - anybody will be able to connect to you. You won\'t lose your contacts if you later delete it.</string>
<string name="share_link">Share link</string>
<string name="add_address_to_your_profile">Add address to your profile, so that your contacts can share it with other people. Profile update will be sent to your contacts.</string>
<string name="create_address_and_let_people_connect">Create an address to let people connect with you.</string>
<string name="create_simplex_address">Create SimpleX address</string>
<string name="share_with_contacts">Share with contacts</string>
<string name="share_address_with_contacts_question">Share address with contacts?</string>
<string name="profile_update_will_be_sent_to_contacts">Profile update will be sent to your contacts.</string>
<string name="stop_sharing_address">Stop sharing address?</string>
<string name="stop_sharing">Stop sharing</string>
<string name="auto_accept_contact">Auto-accept</string>
<string name="enter_welcome_message_optional">Enter welcome message… (optional)</string>
<string name="save_settings_question">Save settings?</string>
<string name="save_auto_accept_settings">Save auto-accept settings</string>
<string name="delete_address">Delete address</string>
<string name="invite_friends">Invite friends</string>
<string name="email_invite_subject">Let\'s talk in SimpleX Chat</string>
<string name="email_invite_body">Hi!\nConnect to me via SimpleX Chat: %s</string>
<!-- CreateSimpleXAddress.kt -->
<string name="continue_to_next_step">Continue</string>
<string name="dont_create_address">Don\'t create address</string>
<string name="you_can_create_it_later">You can create it later</string>
<string name="your_contacts_will_see_it">Your contacts in SimpleX will see it.\nYou can change it in Settings.</string>
<!-- AcceptRequestsView.kt -->
<string name="contact_requests">Contact requests</string>
<string name="accept_requests">Accept requests</string>
<string name="accept_automatically">Automatically</string>
<string name="section_title_welcome_message">WELCOME MESSAGE</string>
<!-- User profile details - UserProfileView.kt -->
<string name="display_name__field">Display name:</string>
@@ -1078,9 +1050,6 @@
<string name="error_updating_link_for_group">Error updating group link</string>
<string name="error_deleting_link_for_group">Error deleting group link</string>
<string name="only_group_owners_can_change_prefs">Only group owners can change group preferences.</string>
<string name="address_section_title">Address</string>
<string name="share_address">Share address</string>
<string name="you_can_share_this_address_with_your_contacts">You can share this address with your contacts to let them connect with %s.</string>
<!-- For Console chat info section -->
<string name="section_title_for_console">FOR CONSOLE</string>
@@ -1111,8 +1080,6 @@
<string name="group_welcome_title">Welcome message</string>
<string name="save_welcome_message_question">Save welcome message?</string>
<string name="save_and_update_group_profile">Save and update group profile</string>
<string name="group_welcome_preview">Preview</string>
<string name="enter_welcome_message">Enter welcome message…</string>
<!-- ConnectionStats -->
<string name="conn_stats_section_title_servers">SERVERS</string>
+9 -13
View File
@@ -618,16 +618,6 @@ func apiUpdateProfile(profile: Profile) async throws -> Profile? {
}
}
func apiSetProfileAddress(on: Bool) async throws -> User? {
let userId = try currentUserId("apiSetProfileAddress")
let r = await chatSendCmd(.apiSetProfileAddress(userId: userId, on: on))
switch r {
case .userProfileNoChange: return nil
case let .userProfileUpdated(user, _, _): return user
default: throw r
}
}
func apiSetContactPrefs(contactId: Int64, preferences: Preferences) async throws -> Contact? {
let r = await chatSendCmd(.apiSetContactPrefs(contactId: contactId, preferences: preferences))
if case let .contactPrefsUpdated(_, _, toContact) = r { return toContact }
@@ -653,10 +643,10 @@ func apiCreateUserAddress() async throws -> String {
throw r
}
func apiDeleteUserAddress() async throws -> User? {
func apiDeleteUserAddress() async throws {
let userId = try currentUserId("apiDeleteUserAddress")
let r = await chatSendCmd(.apiDeleteMyAddress(userId: userId))
if case let .userContactLinkDeleted(user) = r { return user }
if case .userContactLinkDeleted = r { return }
throw r
}
@@ -953,6 +943,12 @@ func apiListMembers(_ groupId: Int64) async -> [GroupMember] {
return []
}
func apiListMembersSync(_ groupId: Int64) -> [GroupMember] {
let r = chatSendCmdSync(.apiListMembers(groupId: groupId))
if case let .groupMembers(_, group) = r { return group.members }
return []
}
func filterMembersToAdd(_ ms: [GroupMember]) -> [Contact] {
let memberContactIds = ms.compactMap{ m in m.memberCurrent ? m.memberContactId : nil }
return ChatModel.shared.chats
@@ -1051,7 +1047,7 @@ func startChat(refreshInvitations: Bool = true) throws {
}
withAnimation {
m.onboardingStage = m.onboardingStage == .step2_CreateProfile && m.users.count == 1
? .step3_CreateSimpleXAddress
? .step3_SetNotificationsMode
: .onboardingComplete
}
}
@@ -116,21 +116,6 @@ struct ChatInfoView: View {
contactPreferencesButton()
}
if let contactLink = contact.contactLink {
Section {
QRCode(uri: contactLink)
Button {
showShareSheet(items: [contactLink])
} label: {
Label("Share address", systemImage: "square.and.arrow.up")
}
} header: {
Text("Address")
} footer: {
Text("You can share this address with your contacts to let them connect with **\(contact.displayName)**.")
}
}
Section("Servers") {
networkStatusRow()
.onTapGesture {
File diff suppressed because one or more lines are too long
@@ -154,7 +154,7 @@ struct ComposeState {
}
var attachmentDisabled: Bool {
if editing || liveMessage != nil || inProgress { return true }
if editing || liveMessage != nil { return true }
switch preview {
case .noPreview: return false
case .linkPreview: return false
@@ -427,8 +427,6 @@ struct ComposeView: View {
clearCurrentDraft()
sendMessage()
resetLinkPreview()
} else if (composeState.inProgress) {
clearCurrentDraft()
} else if !composeState.empty {
saveCurrentDraft()
} else {
@@ -524,11 +522,7 @@ struct ComposeView: View {
case .noPreview:
EmptyView()
case let .linkPreview(linkPreview: preview):
ComposeLinkView(
linkPreview: preview,
cancelPreview: cancelLinkPreview,
cancelEnabled: !composeState.inProgress
)
ComposeLinkView(linkPreview: preview, cancelPreview: cancelLinkPreview)
case let .mediaPreviews(mediaPreviews: media):
ComposeImageView(
images: media.map { (img, _) in img },
@@ -536,7 +530,7 @@ struct ComposeView: View {
composeState = composeState.copy(preview: .noPreview)
chosenMedia = []
},
cancelEnabled: !composeState.editing && !composeState.inProgress)
cancelEnabled: !composeState.editing)
case let .voicePreview(recordingFileName, _):
ComposeVoiceView(
recordingFileName: recordingFileName,
@@ -546,7 +540,7 @@ struct ComposeView: View {
cancelVoiceMessageRecording($0)
clearState()
},
cancelEnabled: !composeState.editing && !composeState.inProgress,
cancelEnabled: !composeState.editing,
stopPlayback: $stopPlayback
)
case let .filePreview(fileName, _):
@@ -555,7 +549,7 @@ struct ComposeView: View {
cancelFile: {
composeState = composeState.copy(preview: .noPreview)
},
cancelEnabled: !composeState.editing && !composeState.inProgress)
cancelEnabled: !composeState.editing)
}
}
@@ -13,7 +13,6 @@ import PhotosUI
struct NativeTextEditor: UIViewRepresentable {
@Binding var text: String
@Binding var disableEditing: Bool
let height: CGFloat
let font: UIFont
@FocusState.Binding var focused: Bool
@@ -27,11 +26,7 @@ struct NativeTextEditor: UIViewRepresentable {
field.textAlignment = alignment == .leading ? .left : .right
field.autocapitalizationType = .sentences
field.setOnTextChangedListener { newText, images in
if !disableEditing {
text = newText
} else {
field.text = text
}
text = newText
if !images.isEmpty {
onImagesAdded(images)
}
@@ -145,7 +140,6 @@ struct NativeTextEditor_Previews: PreviewProvider{
@FocusState var keyboardVisible: Bool
return NativeTextEditor(
text: Binding.constant("Hello, world!"),
disableEditing: Binding.constant(false),
height: 100,
font: UIFont.preferredFont(forTextStyle: .body),
focused: $keyboardVisible,
@@ -65,7 +65,6 @@ struct SendMessageView: View {
NativeTextEditor(
text: $composeState.message,
disableEditing: $composeState.inProgress,
height: teHeight,
font: teUiFont,
focused: $keyboardVisible,
@@ -84,7 +83,7 @@ struct SendMessageView: View {
.padding([.bottom, .trailing], 3)
} else {
VStack(alignment: .trailing) {
if teHeight > 100 && !composeState.inProgress {
if teHeight > 100 {
deleteTextButton()
Spacer()
}
@@ -10,22 +10,13 @@ import SwiftUI
import SimpleXChat
struct AddGroupMembersView: View {
@Environment(\.dismiss) var dismiss: DismissAction
var chat: Chat
var groupInfo: GroupInfo
var body: some View {
AddGroupMembersViewCommon(chat: chat, groupInfo: groupInfo, addedMembersCb: { _ in dismiss() })
}
}
struct AddGroupMembersViewCommon: View {
@EnvironmentObject var chatModel: ChatModel
@Environment(\.dismiss) var dismiss: DismissAction
var chat: Chat
@State var groupInfo: GroupInfo
var creatingGroup: Bool = false
var showFooterCounter: Bool = true
var addedMembersCb: ((Set<Int64>) -> Void)
var addedMembersCb: ((Set<Int64>) -> Void)? = nil
@State private var selectedContacts = Set<Int64>()
@State private var selectedRole: GroupMemberRole = .member
@State private var alert: AddGroupMembersAlert?
@@ -48,7 +39,7 @@ struct AddGroupMembersViewCommon: View {
addGroupMembersView()
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
Button ("Skip") { addedMembersCb(selectedContacts) }
Button ("Skip") { addedMembersCb?(selectedContacts) }
}
}
}
@@ -137,7 +128,8 @@ struct AddGroupMembersViewCommon: View {
let member = try await apiAddMember(groupInfo.groupId, contactId, selectedRole)
await MainActor.run { _ = ChatModel.shared.upsertGroupMember(groupInfo, member) }
}
addedMembersCb(selectedContacts)
await MainActor.run { dismiss() }
if let cb = addedMembersCb { cb(selectedContacts) }
} catch {
let a = getErrorAlert(error, "Error adding member(s)")
alert = .error(title: a.title, error: a.message)
@@ -45,8 +45,6 @@ struct GroupChatInfoView: View {
Section {
if groupInfo.canEdit {
editGroupButton()
}
if groupInfo.groupProfile.description != nil || groupInfo.canEdit {
addOrEditWelcomeMessage()
}
groupPreferencesButton($groupInfo)
@@ -144,12 +142,7 @@ struct GroupChatInfoView: View {
NavigationLink {
AddGroupMembersView(chat: chat, groupInfo: groupInfo)
.onAppear {
Task {
let groupMembers = await apiListMembers(groupInfo.groupId)
await MainActor.run {
ChatModel.shared.groupMembers = groupMembers
}
}
ChatModel.shared.groupMembers = apiListMembersSync(groupInfo.groupId)
}
} label: {
Label("Invite members", systemImage: "plus")
@@ -65,21 +65,6 @@ struct GroupMemberInfoView: View {
}
}
if let contactLink = member.contactLink {
Section {
QRCode(uri: contactLink)
Button {
showShareSheet(items: [contactLink])
} label: {
Label("Share address", systemImage: "square.and.arrow.up")
}
} header: {
Text("Address")
} footer: {
Text("You can share this address with your contacts to let them connect with **\(member.displayName)**.")
}
}
Section("Member") {
infoRow("Group", groupInfo.displayName)
@@ -15,101 +15,43 @@ struct GroupWelcomeView: View {
var groupId: Int64
@Binding var groupInfo: GroupInfo
@State private var welcomeText: String = ""
@State private var editMode = true
@FocusState private var keyboardVisible: Bool
@State private var showSaveDialog = false
var body: some View {
VStack {
if groupInfo.canEdit {
editorView()
.modifier(BackButton {
if welcomeText == groupInfo.groupProfile.description || (welcomeText == "" && groupInfo.groupProfile.description == nil) {
dismiss()
} else {
showSaveDialog = true
}
})
.confirmationDialog("Save welcome message?", isPresented: $showSaveDialog) {
Button("Save and update group profile") {
save()
dismiss()
}
Button("Exit without saving") { dismiss() }
}
} else {
List {
Section {
textPreview()
copyButton()
}
}
}
}
.onAppear {
welcomeText = groupInfo.groupProfile.description ?? ""
keyboardVisible = true
}
}
private func textPreview() -> some View {
messageText(welcomeText, parseSimpleXMarkdown(welcomeText), nil)
.allowsHitTesting(false)
}
private func editorView() -> some View {
List {
Section {
if editMode {
ZStack {
Group {
if welcomeText.isEmpty {
TextEditor(text: Binding.constant(NSLocalizedString("Enter welcome message…", comment: "placeholder")))
.foregroundColor(.secondary)
.disabled(true)
}
TextEditor(text: $welcomeText)
.focused($keyboardVisible)
}
.padding(.horizontal, -5)
.padding(.top, -8)
.frame(height: 90, alignment: .topLeading)
.frame(maxWidth: .infinity, alignment: .leading)
}
} else {
textPreview()
.frame(height: 90, alignment: .topLeading)
}
Button {
editMode = !editMode
keyboardVisible = editMode
} label: {
if editMode {
Label ("Preview", systemImage: "character")
} else {
Label ("Edit", systemImage: "pencil")
}
}
.disabled(welcomeText.isEmpty)
copyButton()
TextEditor(text: $welcomeText)
.focused($keyboardVisible)
.padding(.horizontal, -5)
.padding(.top, -8)
.frame(height: 90, alignment: .topLeading)
.frame(maxWidth: .infinity, alignment: .leading)
}
Section {
saveButton()
}
}
}
private func copyButton() -> some View {
Button {
UIPasteboard.general.string = welcomeText
} label: {
Label ("Copy", systemImage: "doc.on.doc")
.onAppear {
welcomeText = groupInfo.groupProfile.description ?? ""
}
.modifier(BackButton {
if welcomeText == groupInfo.groupProfile.description || (welcomeText == "" && groupInfo.groupProfile.description == nil) {
dismiss()
} else {
showSaveDialog = true
}
})
.confirmationDialog("Save welcome message?", isPresented: $showSaveDialog) {
Button("Save and update group profile") {
save()
dismiss()
}
Button("Exit without saving") { dismiss() }
}
}
private func saveButton() -> some View {
@ViewBuilder private func saveButton() -> some View {
Button("Save and update group profile") {
save()
}
@@ -39,11 +39,6 @@ struct ContactConnectionInfo: View {
.padding(.bottom, 16)
Text(contactConnectionText(contactConnection))
.padding(.bottom, 16)
if let connReqInv = contactConnection.connReqInv {
OneTimeLinkProfileText(contactConnection: contactConnection, connReqInvitation: connReqInv)
}
}
.listRowBackground(Color.clear)
.listRowSeparator(.hidden)
@@ -52,7 +47,11 @@ struct ContactConnectionInfo: View {
Section {
if contactConnection.groupLinkId == nil {
settingsRow("pencil") {
HStack(spacing: 20) {
Image(systemName: "pencil")
.foregroundColor(.secondary)
.padding(.leading, 6)
.onTapGesture { aliasTextFieldFocused = true }
TextField("Set contact name…", text: $localAlias)
.autocapitalization(.none)
.autocorrectionDisabled(true)
@@ -60,18 +59,20 @@ struct ContactConnectionInfo: View {
.submitLabel(.done)
.onSubmit(setConnectionAlias)
}
.onTapGesture { aliasTextFieldFocused = true }
}
if contactConnection.initiated,
let connReqInv = contactConnection.connReqInv {
oneTimeLinkSection(contactConnection: contactConnection, connReqInvitation: connReqInv)
} else {
oneTimeLinkLearnMoreButton()
NavigationLink {
AddContactView(contactConnection: contactConnection, connReqInvitation: connReqInv)
.navigationTitle(CreateLinkTab.oneTime.title)
.navigationBarTitleDisplayMode(.large)
} label: {
Label("Show QR code", systemImage: "qrcode")
.foregroundColor(contactConnection.incognito ? .indigo : .accentColor)
}
}
}
Section {
Button(role: .destructive) {
alert = .deleteInvitationAlert
} label: {
@@ -80,6 +81,7 @@ struct ContactConnectionInfo: View {
}
}
}
.listStyle(.insetGrouped)
}
.alert(item: $alert) { _alert in
switch _alert {
@@ -94,6 +96,7 @@ struct ContactConnectionInfo: View {
}
.onAppear {
localAlias = contactConnection.localAlias
aliasTextFieldFocused = true
}
}
@@ -109,7 +109,7 @@ struct MigrateToAppGroupView: View {
do {
resetChatCtrl()
try initializeChat(start: true)
chatModel.onboardingStage = .step4_SetNotificationsMode
chatModel.onboardingStage = .step3_SetNotificationsMode
setV3DBMigration(.ready)
} catch let error {
dbContainerGroupDefault.set(.documents)
@@ -1,61 +0,0 @@
//
// MailView.swift
// SimpleX (iOS)
//
// Created by spaced4ndy on 01.05.2023.
// Copyright © 2023 SimpleX Chat. All rights reserved.
//
import SwiftUI
import UIKit
import MessageUI
struct MailView: UIViewControllerRepresentable {
@Binding var isShowing: Bool
@Binding var result: Result<MFMailComposeResult, Error>?
var subject = ""
var messageBody = ""
class Coordinator: NSObject, MFMailComposeViewControllerDelegate {
@Binding var isShowing: Bool
@Binding var result: Result<MFMailComposeResult, Error>?
init(isShowing: Binding<Bool>,
result: Binding<Result<MFMailComposeResult, Error>?>) {
_isShowing = isShowing
_result = result
}
func mailComposeController(
_ controller: MFMailComposeViewController,
didFinishWith result: MFMailComposeResult,
error: Error?
) {
defer {
isShowing = false
}
if let error = error {
self.result = .failure(error)
return
}
self.result = .success(result)
}
}
func makeCoordinator() -> Coordinator {
return Coordinator(isShowing: $isShowing, result: $result)
}
func makeUIViewController(context: UIViewControllerRepresentableContext<MailView>) -> MFMailComposeViewController {
let vc = MFMailComposeViewController()
vc.setSubject(subject)
vc.setMessageBody(messageBody, isHTML: true)
vc.mailComposeDelegate = context.coordinator
return vc
}
func updateUIViewController(_ uiViewController: MFMailComposeViewController,
context: UIViewControllerRepresentableContext<MailView>) {
}
}
@@ -1,28 +0,0 @@
//
// AddContactLearnMore.swift
// SimpleX (iOS)
//
// Created by spaced4ndy on 27.04.2023.
// Copyright © 2023 SimpleX Chat. All rights reserved.
//
import SwiftUI
struct AddContactLearnMore: View {
var body: some View {
List {
VStack(alignment: .leading, spacing: 18) {
Text("To connect, your contact can scan QR code or use the link in the app.")
Text("If you can't meet in person, show QR code in a video call, or share the link.")
Text("Read more in [User Guide](https://simplex.chat/docs/guide/readme.html#connect-to-friends).")
}
.listRowBackground(Color.clear)
}
}
}
struct AddContactLearnMore_Previews: PreviewProvider {
static var previews: some View {
AddContactLearnMore()
}
}
@@ -16,73 +16,50 @@ struct AddContactView: View {
var connReqInvitation: String
var body: some View {
List {
OneTimeLinkProfileText(contactConnection: contactConnection, connReqInvitation: connReqInvitation)
.listRowBackground(Color.clear)
.listRowInsets(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0))
Section("1-time link") {
oneTimeLinkSection(contactConnection: contactConnection, connReqInvitation: connReqInvitation)
ScrollView {
VStack(alignment: .leading) {
Text("Your contact can scan it from the app.")
.padding(.bottom, 4)
if (contactConnection?.incognito ?? chatModel.incognito) {
HStack {
Image(systemName: "theatermasks").foregroundColor(.indigo).font(.footnote)
Spacer().frame(width: 8)
Text("A random profile will be sent to your contact").font(.footnote)
}
.padding(.bottom)
} else {
HStack {
Image(systemName: "info.circle").foregroundColor(.secondary).font(.footnote)
Spacer().frame(width: 8)
Text("Your chat profile will be sent to your contact").font(.footnote)
}
.padding(.bottom)
}
if connReqInvitation != "" {
QRCode(uri: connReqInvitation).padding(.bottom)
} else {
ProgressView()
.progressViewStyle(.circular)
.scaleEffect(2)
.frame(maxWidth: .infinity)
.padding(.vertical)
}
Text("If you can't meet in person, **show QR code in the video call**, or share the link.")
.padding(.bottom)
Button {
showShareSheet(items: [connReqInvitation])
} label: {
Label("Share invitation link", systemImage: "square.and.arrow.up")
}
.frame(maxWidth: .infinity, alignment: .center)
}
.padding()
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .top)
}
.onAppear { chatModel.connReqInv = connReqInvitation }
}
}
@ViewBuilder func oneTimeLinkSection(contactConnection: PendingContactConnection? = nil, connReqInvitation: String) -> some View {
if connReqInvitation != "" {
QRCode(uri: connReqInvitation)
} else {
ProgressView()
.progressViewStyle(.circular)
.scaleEffect(2)
.frame(maxWidth: .infinity)
.padding(.vertical)
}
shareLinkButton(connReqInvitation)
oneTimeLinkLearnMoreButton()
}
private func shareLinkButton(_ connReqInvitation: String) -> some View {
Button {
showShareSheet(items: [connReqInvitation])
} label: {
settingsRow("square.and.arrow.up") {
Text("Share 1-time link")
}
}
}
func oneTimeLinkLearnMoreButton() -> some View {
NavigationLink {
AddContactLearnMore()
.navigationTitle("One-time invitation link")
.navigationBarTitleDisplayMode(.large)
} label: {
settingsRow("info.circle") {
Text("Learn more")
}
}
}
struct OneTimeLinkProfileText: View {
@EnvironmentObject private var chatModel: ChatModel
var contactConnection: PendingContactConnection? = nil
var connReqInvitation: String
var body: some View {
HStack {
if (contactConnection?.incognito ?? chatModel.incognito) {
Image(systemName: "theatermasks").foregroundColor(.indigo)
Text("A random profile will be sent to your contact")
} else {
Image(systemName: "info.circle").foregroundColor(.secondary)
Text("Your chat profile will be sent to your contact")
}
}
}
}
struct AddContactView_Previews: PreviewProvider {
static var previews: some View {
AddContactView(connReqInvitation: "https://simplex.chat/invitation#/?v=1&smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FFe5ICmvrm4wkrr6X1LTMii-lhBqLeB76%23MCowBQYDK2VuAyEAdhZZsHpuaAk3Hh1q0uNb_6hGTpuwBIrsp2z9U2T0oC0%3D&e2e=v%3D1%26x3dh%3DMEIwBQYDK2VvAzkAcz6jJk71InuxA0bOX7OUhddfB8Ov7xwQIlIDeXBRZaOntUU4brU5Y3rBzroZBdQJi0FKdtt_D7I%3D%2CMEIwBQYDK2VvAzkA-hDvk1duBi1hlOr08VWSI-Ou4JNNSQjseY69QyKm7Kgg1zZjbpGfyBqSZ2eqys6xtoV4ZtoQUXQ%3D")
@@ -24,14 +24,14 @@ struct AddGroupView: View {
var body: some View {
if let chat = chat, let groupInfo = groupInfo {
AddGroupMembersViewCommon(
AddGroupMembersView(
chat: chat,
groupInfo: groupInfo,
creatingGroup: true,
showFooterCounter: false
) { _ in
dismiss()
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
DispatchQueue.main.async {
m.chatId = groupInfo.id
}
}
@@ -15,7 +15,7 @@ enum CreateLinkTab {
var title: LocalizedStringKey {
switch self {
case .oneTime: return "One-time invitation link"
case .longTerm: return "Your SimpleX address"
case .longTerm: return "Your contact address"
}
}
}
@@ -49,9 +49,9 @@ struct CreateLinkView: View {
)
}
.tag(CreateLinkTab.oneTime)
UserAddressView(viaCreateLinkView: true)
UserAddress()
.tabItem {
Label("Your SimpleX address", systemImage: "infinity.circle")
Label("Your contact address", systemImage: "infinity.circle")
}
.tag(CreateLinkTab.longTerm)
}
@@ -34,9 +34,7 @@ struct CreateProfile: View {
VStack(alignment: .leading) {
Text("Create your profile")
.font(.largeTitle)
.bold()
.padding(.bottom, 4)
.frame(maxWidth: .infinity)
Text("Your profile, contacts and delivered messages are stored on your device.")
.padding(.bottom, 4)
Text("The profile is only shared with your contacts.")
@@ -124,7 +122,7 @@ struct CreateProfile: View {
m.currentUser = try apiCreateActiveUser(profile)
if m.users.isEmpty {
try startChat()
withAnimation { m.onboardingStage = .step3_CreateSimpleXAddress }
withAnimation { m.onboardingStage = .step3_SetNotificationsMode }
} else {
dismiss()
m.users = try listUsers()
@@ -1,210 +0,0 @@
//
// CreateSimpleXAddress.swift
// SimpleX (iOS)
//
// Created by spaced4ndy on 28.04.2023.
// Copyright © 2023 SimpleX Chat. All rights reserved.
//
import SwiftUI
import Contacts
import ContactsUI
import MessageUI
import SimpleXChat
struct CreateSimpleXAddress: View {
@EnvironmentObject var m: ChatModel
@State private var progressIndicator = false
@State private var showMailView = false
@State private var mailViewResult: Result<MFMailComposeResult, Error>? = nil
var body: some View {
GeometryReader { g in
ScrollView {
ZStack {
VStack(alignment: .leading) {
Text("SimpleX Address")
.font(.largeTitle)
.bold()
.frame(maxWidth: .infinity)
Spacer()
if let userAddress = m.userAddress {
QRCode(uri: userAddress.connReqContact)
.frame(maxHeight: g.size.width)
shareQRCodeButton(userAddress)
.frame(maxWidth: .infinity)
if MFMailComposeViewController.canSendMail() {
Spacer()
shareViaEmailButton(userAddress)
.frame(maxWidth: .infinity)
}
Spacer()
continueButton()
.padding(.bottom, 8)
.frame(maxWidth: .infinity)
} else {
createAddressButton()
.frame(maxWidth: .infinity)
Spacer()
skipButton()
.padding(.bottom, 56)
.frame(maxWidth: .infinity)
}
}
.frame(minHeight: g.size.height)
if progressIndicator {
ProgressView().scaleEffect(2)
}
}
}
}
.frame(maxHeight: .infinity)
.padding()
}
private func createAddressButton() -> some View {
VStack(spacing: 8) {
Button {
progressIndicator = true
Task {
do {
let connReqContact = try await apiCreateUserAddress()
DispatchQueue.main.async {
m.userAddress = UserContactLink(connReqContact: connReqContact)
}
if let u = try await apiSetProfileAddress(on: true) {
DispatchQueue.main.async {
m.updateUser(u)
}
}
await MainActor.run { progressIndicator = false }
} catch let error {
logger.error("CreateSimpleXAddress create address: \(responseError(error))")
await MainActor.run { progressIndicator = false }
let a = getErrorAlert(error, "Error creating address")
AlertManager.shared.showAlertMsg(
title: a.title,
message: a.message
)
}
}
} label: {
Text("Create SimpleX address").font(.title)
}
Group {
Text("Your contacts in SimpleX will see it.\nYou can change it in Settings.")
}
.multilineTextAlignment(.center)
.font(.footnote)
.padding(.horizontal, 32)
}
}
private func skipButton() -> some View {
VStack(spacing: 8) {
Button {
withAnimation {
m.onboardingStage = .step4_SetNotificationsMode
}
} label: {
HStack {
Text("Don't create address")
Image(systemName: "chevron.right")
}
}
Text("You can create it later").font(.footnote)
}
}
private func shareQRCodeButton(_ userAddress: UserContactLink) -> some View {
Button {
showShareSheet(items: [userAddress.connReqContact])
} label: {
Label("Share", systemImage: "square.and.arrow.up")
}
}
private func shareViaEmailButton(_ userAddress: UserContactLink) -> some View {
Button {
showMailView = true
} label: {
Label("Invite friends", systemImage: "envelope")
.font(.title2)
}
.sheet(isPresented: $showMailView) {
SendAddressMailView(
showMailView: $showMailView,
mailViewResult: $mailViewResult,
userAddress: userAddress
)
.edgesIgnoringSafeArea(.bottom)
}
.onChange(of: mailViewResult == nil) { _ in
if let r = mailViewResult {
switch r {
case let .success(composeResult):
switch composeResult {
case .sent:
m.onboardingStage = .step4_SetNotificationsMode
default: ()
}
case let .failure(error):
logger.error("CreateSimpleXAddress share via email: \(responseError(error))")
let a = getErrorAlert(error, "Error sending email")
AlertManager.shared.showAlertMsg(
title: a.title,
message: a.message
)
}
mailViewResult = nil
}
}
}
private func continueButton() -> some View {
Button {
withAnimation {
m.onboardingStage = .step4_SetNotificationsMode
}
} label: {
HStack {
Text("Continue")
Image(systemName: "greaterthan")
}
}
}
}
struct SendAddressMailView: View {
@Binding var showMailView: Bool
@Binding var mailViewResult: Result<MFMailComposeResult, Error>?
var userAddress: UserContactLink
var body: some View {
let messageBody = String(format: NSLocalizedString("""
<p>Hi!</p>
<p><a href="%@">Connect to me via SimpleX Chat</a></p>
""", comment: "email text"), userAddress.connReqContact)
MailView(
isShowing: self.$showMailView,
result: $mailViewResult,
subject: NSLocalizedString("Let's talk in SimpleX Chat", comment: "email subject"),
messageBody: messageBody
)
}
}
struct CreateSimpleXAddress_Previews: PreviewProvider {
static var previews: some View {
CreateSimpleXAddress()
}
}
@@ -15,8 +15,7 @@ struct OnboardingView: View {
switch onboarding {
case .step1_SimpleXInfo: SimpleXInfo(onboarding: true)
case .step2_CreateProfile: CreateProfile()
case .step3_CreateSimpleXAddress: CreateSimpleXAddress()
case .step4_SetNotificationsMode: SetNotificationsMode()
case .step3_SetNotificationsMode: SetNotificationsMode()
case .onboardingComplete: EmptyView()
}
}
@@ -25,8 +24,7 @@ struct OnboardingView: View {
enum OnboardingStage {
case step1_SimpleXInfo
case step2_CreateProfile
case step3_CreateSimpleXAddress
case step4_SetNotificationsMode
case step3_SetNotificationsMode
case onboardingComplete
}
@@ -17,10 +17,7 @@ struct SetNotificationsMode: View {
var body: some View {
ScrollView {
VStack(alignment: .leading, spacing: 16) {
Text("Push notifications")
.font(.largeTitle)
.bold()
.frame(maxWidth: .infinity)
Text("Push notifications").font(.largeTitle)
Text("Send notifications:")
ForEach(NotificationsMode.values) { mode in
@@ -65,10 +62,9 @@ struct SetNotificationsMode: View {
m.notificationMode = mode
}
} catch let error {
let a = getErrorAlert(error, "Error enabling notifications")
AlertManager.shared.showAlertMsg(
title: a.title,
message: a.message
title: "Error enabling notifications",
message: "\(responseError(error))"
)
}
}
@@ -126,7 +126,7 @@ private let versionDescriptions: [VersionDescription] = [
FeatureDescription(
icon: "character",
title: "Italian interface",
description: "Thanks to the users [contribute via Weblate](https://github.com/simplex-chat/simplex-chat/tree/stable#help-translating-simplex-chat)!"
description: "Thanks to the users [contribute via Weblate](https://github.com/simplex-chat/simplex-chat/tree/stable#translate-the-apps)!"
)
]
),
@@ -161,7 +161,7 @@ private let versionDescriptions: [VersionDescription] = [
FeatureDescription(
icon: "character",
title: "Chinese and Spanish interface",
description: "Thanks to the users [contribute via Weblate](https://github.com/simplex-chat/simplex-chat/tree/stable#help-translating-simplex-chat)!"
description: "Thanks to the users [contribute via Weblate](https://github.com/simplex-chat/simplex-chat/tree/stable#translate-the-apps)!"
),
]
),
@@ -181,7 +181,7 @@ private let versionDescriptions: [VersionDescription] = [
FeatureDescription(
icon: "character",
title: "Polish interface",
description: "Thanks to the users [contribute via Weblate](https://github.com/simplex-chat/simplex-chat/tree/stable#help-translating-simplex-chat)!"
description: "Thanks to the users [contribute via Weblate](https://github.com/simplex-chat/simplex-chat/tree/stable#translate-the-apps)!"
),
]
)
@@ -0,0 +1,131 @@
//
// AcceptRequestsView.swift
// SimpleX (iOS)
//
// Created by Evgeny on 23/10/2022.
// Copyright © 2022 SimpleX Chat. All rights reserved.
//
import SwiftUI
import SimpleXChat
struct AcceptRequestsView: View {
@EnvironmentObject private var m: ChatModel
@State var contactLink: UserContactLink
@State private var a = AutoAcceptState()
@State private var saved = AutoAcceptState()
@FocusState private var keyboardVisible: Bool
var body: some View {
List {
Section {
settingsRow("checkmark") {
Toggle("Automatically", isOn: $a.enable)
}
if a.enable {
settingsRow(
a.incognito ? "theatermasks.fill" : "theatermasks",
color: a.incognito ? .indigo : .secondary
) {
Toggle("Incognito", isOn: $a.incognito)
}
}
} header: {
Text("Accept requests")
} footer: {
saveButtons()
}
if a.enable {
Section {
TextEditor(text: $a.welcomeText)
.focused($keyboardVisible)
.padding(.horizontal, -5)
.padding(.top, -8)
.frame(height: 90, alignment: .topLeading)
.frame(maxWidth: .infinity, alignment: .leading)
} header: {
Text("Welcome message")
}
}
}
.onAppear {
a = AutoAcceptState(contactLink: contactLink)
saved = a
}
.onChange(of: a.enable) { _ in
if !a.enable { a = AutoAcceptState() }
}
}
@ViewBuilder private func saveButtons() -> some View {
HStack {
Button {
a = saved
} label: {
Label("Cancel", systemImage: "arrow.counterclockwise")
}
Spacer()
Button {
Task {
do {
if let link = try await userAddressAutoAccept(a.autoAccept) {
contactLink = link
m.userAddress = link
saved = a
}
} catch let error {
logger.error("userAddressAutoAccept error: \(responseError(error))")
}
}
} label: {
Label("Save", systemImage: "checkmark")
}
}
.font(.body)
.disabled(a == saved)
}
private struct AutoAcceptState: Equatable {
var enable = false
var incognito = false
var welcomeText = ""
init(enable: Bool = false, incognito: Bool = false, welcomeText: String = "") {
self.enable = enable
self.incognito = incognito
self.welcomeText = welcomeText
}
init(contactLink: UserContactLink) {
if let aa = contactLink.autoAccept {
enable = true
incognito = aa.acceptIncognito
if let msg = aa.autoReply {
welcomeText = msg.text
} else {
welcomeText = ""
}
} else {
enable = false
incognito = false
welcomeText = ""
}
}
var autoAccept: AutoAccept? {
if enable {
var autoReply: MsgContent? = nil
let s = welcomeText.trimmingCharacters(in: .whitespacesAndNewlines)
if s != "" { autoReply = .text(s) }
return AutoAccept(acceptIncognito: incognito, autoReply: autoReply)
}
return nil
}
}
}
struct AcceptRequestsView_Previews: PreviewProvider {
static var previews: some View {
AcceptRequestsView(contactLink: UserContactLink(connReqContact: ""))
}
}
@@ -9,7 +9,7 @@
import SwiftUI
import SimpleXChat
private let howToUrl = URL(string: "https://simplex.chat/docs/server.html")!
private let howToUrl = URL(string: "https://github.com/simplex-chat/simplex-chat/blob/stable/docs/SERVER.md")!
struct ProtocolServersView: View {
@Environment(\.dismiss) var dismiss: DismissAction
@@ -8,7 +8,7 @@
import SwiftUI
private let howToUrl = URL(string: "https://simplex.chat/docs/webrtc.html#configure-mobile-apps")!
private let howToUrl = URL(string: "https://github.com/simplex-chat/simplex-chat/blob/stable/docs/WEBRTC.md#configure-mobile-apps")!
let serversFont = Font.custom("Menlo", size: 14)
@@ -147,11 +147,10 @@ struct SettingsView: View {
incognitoRow()
NavigationLink {
UserAddressView(shareViaProfile: chatModel.currentUser!.addressShared)
.navigationTitle("SimpleX address")
.navigationBarTitleDisplayMode(.large)
CreateLinkView(selection: .longTerm, viaNavLink: true)
.navigationBarTitleDisplayMode(.inline)
} label: {
settingsRow("qrcode") { Text("Your SimpleX address") }
settingsRow("qrcode") { Text("Your SimpleX contact address") }
}
NavigationLink {
@@ -0,0 +1,128 @@
//
// UserAddress.swift
// SimpleX
//
// Created by Evgeny Poberezkin on 31/01/2022.
// Copyright © 2022 SimpleX Chat. All rights reserved.
//
import SwiftUI
import SimpleXChat
struct UserAddress: View {
@EnvironmentObject private var chatModel: ChatModel
@State private var alert: UserAddressAlert?
@State private var showAcceptRequests = false
private enum UserAddressAlert: Identifiable {
case deleteAddress
case error(title: LocalizedStringKey, error: LocalizedStringKey = "")
var id: String {
switch self {
case .deleteAddress: return "deleteAddress"
case let .error(title, _): return "error \(title)"
}
}
}
var body: some View {
ScrollView {
VStack (alignment: .leading) {
Text("You can share your address as a link or as a QR code - anybody will be able to connect to you. You won't lose your contacts if you later delete it.")
.padding(.bottom)
if let userAdress = chatModel.userAddress {
QRCode(uri: userAdress.connReqContact)
HStack {
Button {
showShareSheet(items: [userAdress.connReqContact])
} label: {
HStack {
Image(systemName: "square.and.arrow.up")
Text("Share link")
}
}
.padding()
NavigationLink {
if let contactLink = chatModel.userAddress {
AcceptRequestsView(contactLink: contactLink)
.navigationTitle("Contact requests")
.navigationBarTitleDisplayMode(.large)
}
} label: {
HStack {
Text("Contact requests")
Image(systemName: "chevron.right")
}
}
.padding()
}
.frame(maxWidth: .infinity)
Button(role: .destructive) { alert = .deleteAddress } label: {
Label("Delete address", systemImage: "trash")
}
.frame(maxWidth: .infinity)
} else {
Button {
Task {
do {
let connReqContact = try await apiCreateUserAddress()
DispatchQueue.main.async {
chatModel.userAddress = UserContactLink(connReqContact: connReqContact)
}
} catch let error {
logger.error("UserAddress apiCreateUserAddress: \(responseError(error))")
let a = getErrorAlert(error, "Error creating address")
alert = .error(title: a.title, error: a.message)
}
}
} label: { Label("Create address", systemImage: "qrcode") }
.frame(maxWidth: .infinity)
}
}
.padding()
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .top)
.sheet(isPresented: $showAcceptRequests) {
if let contactLink = chatModel.userAddress {
AcceptRequestsView(contactLink: contactLink)
}
}
.alert(item: $alert) { alert in
switch alert {
case .deleteAddress:
return Alert(
title: Text("Delete address?"),
message: Text("All your contacts will remain connected"),
primaryButton: .destructive(Text("Delete")) {
Task {
do {
try await apiDeleteUserAddress()
DispatchQueue.main.async {
chatModel.userAddress = nil
}
} catch let error {
logger.error("UserAddress apiDeleteUserAddress: \(responseError(error))")
}
}
}, secondaryButton: .cancel()
)
case let .error(title, error):
return Alert(title: Text(title), message: Text(error))
}
}
}
}
}
struct UserAddress_Previews: PreviewProvider {
static var previews: some View {
let chatModel = ChatModel()
chatModel.userAddress = UserContactLink(connReqContact: "https://simplex.chat/contact#/?v=1&smp=smp%3A%2F%2FPQUV2eL0t7OStZOoAsPEV2QYWt4-xilbakvGUGOItUo%3D%40smp6.simplex.im%2FK1rslx-m5bpXVIdMZg9NLUZ_8JBm8xTt%23MCowBQYDK2VuAyEALDeVe-sG8mRY22LsXlPgiwTNs9dbiLrNuA7f3ZMAJ2w%3D")
return Group {
UserAddress()
.environmentObject(chatModel)
UserAddress()
.environmentObject(ChatModel())
}
}
}
@@ -1,29 +0,0 @@
//
// UserAddressLearnMore.swift
// SimpleX (iOS)
//
// Created by spaced4ndy on 27.04.2023.
// Copyright © 2023 SimpleX Chat. All rights reserved.
//
import SwiftUI
struct UserAddressLearnMore: View {
var body: some View {
List {
VStack(alignment: .leading, spacing: 18) {
Text("You can share your address as a link or QR code - anybody can connect to you.")
Text("You won't lose your contacts if you later delete your address.")
Text("When people request to connect, you can accept or reject it.")
Text("Read more in [User Guide](https://simplex.chat/docs/guide/app-settings.html#your-simplex-contact-address).")
}
.listRowBackground(Color.clear)
}
}
}
struct UserAddressLearnMore_Previews: PreviewProvider {
static var previews: some View {
UserAddressLearnMore()
}
}
@@ -1,450 +0,0 @@
//
// UserAddressView.swift
// SimpleX (iOS)
//
// Created by spaced4ndy on 26.04.2023.
// Copyright © 2023 SimpleX Chat. All rights reserved.
//
import SwiftUI
import MessageUI
import SimpleXChat
struct UserAddressView: View {
@Environment(\.dismiss) var dismiss: DismissAction
@EnvironmentObject private var chatModel: ChatModel
@State var viaCreateLinkView = false
@State var shareViaProfile = false
@State private var aas = AutoAcceptState()
@State private var savedAAS = AutoAcceptState()
@State private var ignoreShareViaProfileChange = false
@State private var showMailView = false
@State private var mailViewResult: Result<MFMailComposeResult, Error>? = nil
@State private var alert: UserAddressAlert?
@State private var showSaveDialogue = false
@State private var progressIndicator = false
@FocusState private var keyboardVisible: Bool
private enum UserAddressAlert: Identifiable {
case deleteAddress
case profileAddress(on: Bool)
case shareOnCreate
case error(title: LocalizedStringKey, error: LocalizedStringKey = "")
var id: String {
switch self {
case .deleteAddress: return "deleteAddress"
case let .profileAddress(on): return "profileAddress \(on)"
case .shareOnCreate: return "shareOnCreate"
case let .error(title, _): return "error \(title)"
}
}
}
var body: some View {
ZStack {
if viaCreateLinkView {
userAddressScrollView()
} else {
userAddressScrollView()
.modifier(BackButton {
if savedAAS == aas {
dismiss()
} else {
keyboardVisible = false
showSaveDialogue = true
}
})
.confirmationDialog("Save settings?", isPresented: $showSaveDialogue) {
Button("Save auto-accept settings") {
saveAAS()
dismiss()
}
Button("Exit without saving") { dismiss() }
}
}
if progressIndicator {
ZStack {
if chatModel.userAddress != nil {
Circle()
.fill(.white)
.opacity(0.7)
.frame(width: 56, height: 56)
}
ProgressView().scaleEffect(2)
}
}
}
}
@Namespace private var bottomID
private func userAddressScrollView() -> some View {
ScrollViewReader { proxy in
userAddressView()
.onChange(of: keyboardVisible) { _ in
if keyboardVisible {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
withAnimation {
proxy.scrollTo(bottomID, anchor: .top)
}
}
}
}
}
}
private func userAddressView() -> some View {
List {
if let userAddress = chatModel.userAddress {
existingAddressView(userAddress)
.onAppear {
aas = AutoAcceptState(userAddress: userAddress)
savedAAS = aas
}
.onChange(of: aas.enable) { _ in
if !aas.enable { aas = AutoAcceptState() }
}
} else {
Section {
createAddressButton()
} footer: {
Text("Create an address to let people connect with you.")
}
Section {
learnMoreButton()
}
}
}
.alert(item: $alert) { alert in
switch alert {
case .deleteAddress:
return Alert(
title: Text("Delete address?"),
message:
shareViaProfile
? Text("All your contacts will remain connected. Profile update will be sent to your contacts.")
: Text("All your contacts will remain connected."),
primaryButton: .destructive(Text("Delete")) {
progressIndicator = true
Task {
do {
if let u = try await apiDeleteUserAddress() {
DispatchQueue.main.async {
chatModel.userAddress = nil
chatModel.updateUser(u)
if shareViaProfile {
ignoreShareViaProfileChange = true
shareViaProfile = false
}
}
}
await MainActor.run { progressIndicator = false }
} catch let error {
logger.error("UserAddressView apiDeleteUserAddress: \(responseError(error))")
await MainActor.run { progressIndicator = false }
}
}
}, secondaryButton: .cancel()
)
case let .profileAddress(on):
if on {
return Alert(
title: Text("Share address with contacts?"),
message: Text("Profile update will be sent to your contacts."),
primaryButton: .default(Text("Share")) {
setProfileAddress(on)
}, secondaryButton: .cancel() {
ignoreShareViaProfileChange = true
shareViaProfile = !on
}
)
} else {
return Alert(
title: Text("Stop sharing address?"),
message: Text("Profile update will be sent to your contacts."),
primaryButton: .default(Text("Stop sharing")) {
setProfileAddress(on)
}, secondaryButton: .cancel() {
ignoreShareViaProfileChange = true
shareViaProfile = !on
}
)
}
case .shareOnCreate:
return Alert(
title: Text("Share address with contacts?"),
message: Text("Add address to your profile, so that your contacts can share it with other people. Profile update will be sent to your contacts."),
primaryButton: .default(Text("Share")) {
setProfileAddress(true)
ignoreShareViaProfileChange = true
shareViaProfile = true
}, secondaryButton: .cancel()
)
case let .error(title, error):
return Alert(title: Text(title), message: Text(error))
}
}
}
@ViewBuilder private func existingAddressView(_ userAddress: UserContactLink) -> some View {
Section {
QRCode(uri: userAddress.connReqContact)
shareQRCodeButton(userAddress)
if MFMailComposeViewController.canSendMail() {
shareViaEmailButton(userAddress)
}
shareWithContactsButton()
autoAcceptToggle()
learnMoreButton()
} header: {
Text("Address")
}
if aas.enable {
autoAcceptSection()
}
Section {
deleteAddressButton()
} footer: {
Text("Your contacts will remain connected.")
}
.id(bottomID)
}
private func createAddressButton() -> some View {
Button {
progressIndicator = true
Task {
do {
let connReqContact = try await apiCreateUserAddress()
DispatchQueue.main.async {
chatModel.userAddress = UserContactLink(connReqContact: connReqContact)
alert = .shareOnCreate
progressIndicator = false
}
} catch let error {
logger.error("UserAddressView apiCreateUserAddress: \(responseError(error))")
let a = getErrorAlert(error, "Error creating address")
alert = .error(title: a.title, error: a.message)
await MainActor.run { progressIndicator = false }
}
}
} label: {
Label("Create SimpleX address", systemImage: "qrcode")
}
}
private func deleteAddressButton() -> some View {
Button(role: .destructive) {
alert = .deleteAddress
} label: {
Label("Delete address", systemImage: "trash")
.foregroundColor(Color.red)
}
}
private func shareQRCodeButton(_ userAddress: UserContactLink) -> some View {
Button {
showShareSheet(items: [userAddress.connReqContact])
} label: {
settingsRow("square.and.arrow.up") {
Text("Share address")
}
}
}
private func shareViaEmailButton(_ userAddress: UserContactLink) -> some View {
Button {
showMailView = true
} label: {
settingsRow("envelope") {
Text("Invite friends")
}
}
.sheet(isPresented: $showMailView) {
SendAddressMailView(
showMailView: $showMailView,
mailViewResult: $mailViewResult,
userAddress: userAddress
)
.edgesIgnoringSafeArea(.bottom)
}
.onChange(of: mailViewResult == nil) { _ in
if let r = mailViewResult {
switch r {
case .success: ()
case let .failure(error):
logger.error("UserAddressView share via email: \(responseError(error))")
let a = getErrorAlert(error, "Error sending email")
alert = .error(title: a.title, error: a.message)
}
mailViewResult = nil
}
}
}
private func autoAcceptToggle() -> some View {
settingsRow("checkmark") {
Toggle("Auto-accept", isOn: $aas.enable)
.onChange(of: aas.enable) { _ in
saveAAS()
}
}
}
private func learnMoreButton() -> some View {
NavigationLink {
UserAddressLearnMore()
.navigationTitle("SimpleX address")
.navigationBarTitleDisplayMode(.large)
} label: {
settingsRow("info.circle") {
Text("About SimpleX address")
}
}
}
private func shareWithContactsButton() -> some View {
settingsRow("person") {
Toggle("Share with contacts", isOn: $shareViaProfile)
.onChange(of: shareViaProfile) { on in
if ignoreShareViaProfileChange {
ignoreShareViaProfileChange = false
} else {
alert = .profileAddress(on: on)
}
}
}
}
private func setProfileAddress(_ on: Bool) {
progressIndicator = true
Task {
do {
if let u = try await apiSetProfileAddress(on: on) {
DispatchQueue.main.async {
chatModel.updateUser(u)
}
}
await MainActor.run { progressIndicator = false }
} catch let error {
logger.error("UserAddressView apiSetProfileAddress: \(responseError(error))")
await MainActor.run { progressIndicator = false }
}
}
}
private struct AutoAcceptState: Equatable {
var enable = false
var incognito = false
var welcomeText = ""
init(enable: Bool = false, incognito: Bool = false, welcomeText: String = "") {
self.enable = enable
self.incognito = incognito
self.welcomeText = welcomeText
}
init(userAddress: UserContactLink) {
if let aa = userAddress.autoAccept {
enable = true
incognito = aa.acceptIncognito
if let msg = aa.autoReply {
welcomeText = msg.text
} else {
welcomeText = ""
}
} else {
enable = false
incognito = false
welcomeText = ""
}
}
var autoAccept: AutoAccept? {
if enable {
var autoReply: MsgContent? = nil
let s = welcomeText.trimmingCharacters(in: .whitespacesAndNewlines)
if s != "" { autoReply = .text(s) }
return AutoAccept(acceptIncognito: incognito, autoReply: autoReply)
}
return nil
}
}
@ViewBuilder private func autoAcceptSection() -> some View {
Section {
acceptIncognitoToggle()
welcomeMessageEditor()
saveAASButton()
.disabled(aas == savedAAS)
} header: {
Text("Auto-accept")
}
}
private func acceptIncognitoToggle() -> some View {
settingsRow(
aas.incognito ? "theatermasks.fill" : "theatermasks",
color: aas.incognito ? .indigo : .secondary
) {
Toggle("Accept incognito", isOn: $aas.incognito)
}
}
private func welcomeMessageEditor() -> some View {
ZStack {
Group {
if aas.welcomeText.isEmpty {
TextEditor(text: Binding.constant(NSLocalizedString("Enter welcome message… (optional)", comment: "placeholder")))
.foregroundColor(.secondary)
.disabled(true)
}
TextEditor(text: $aas.welcomeText)
.focused($keyboardVisible)
}
.padding(.horizontal, -5)
.padding(.top, -8)
.frame(height: 90, alignment: .topLeading)
.frame(maxWidth: .infinity, alignment: .leading)
}
}
private func saveAASButton() -> some View {
Button {
keyboardVisible = false
saveAAS()
} label: {
Text("Save")
}
}
private func saveAAS() {
Task {
do {
if let address = try await userAddressAutoAccept(aas.autoAccept) {
chatModel.userAddress = address
savedAAS = aas
}
} catch let error {
logger.error("userAddressAutoAccept error: \(responseError(error))")
}
}
}
}
struct UserAddressView_Previews: PreviewProvider {
static var previews: some View {
let chatModel = ChatModel()
chatModel.userAddress = UserContactLink(connReqContact: "https://simplex.chat/contact#/?v=1&smp=smp%3A%2F%2FPQUV2eL0t7OStZOoAsPEV2QYWt4-xilbakvGUGOItUo%3D%40smp6.simplex.im%2FK1rslx-m5bpXVIdMZg9NLUZ_8JBm8xTt%23MCowBQYDK2VuAyEALDeVe-sG8mRY22LsXlPgiwTNs9dbiLrNuA7f3ZMAJ2w%3D")
return Group {
UserAddressView()
.environmentObject(chatModel)
UserAddressView()
.environmentObject(ChatModel())
}
}
}
@@ -2573,8 +2573,8 @@ We will be adding server redundancy to prevent lost messages.</source>
<source>Thank you for installing SimpleX Chat!</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Thanks to the users [contribute via Weblate](https://github.com/simplex-chat/simplex-chat/tree/stable#help-translating-simplex-chat)!" xml:space="preserve">
<source>Thanks to the users [contribute via Weblate](https://github.com/simplex-chat/simplex-chat/tree/stable#help-translating-simplex-chat)!</source>
<trans-unit id="Thanks to the users [contribute via Weblate](https://github.com/simplex-chat/simplex-chat/tree/stable#translate-the-apps)!" xml:space="preserve">
<source>Thanks to the users [contribute via Weblate](https://github.com/simplex-chat/simplex-chat/tree/stable#translate-the-apps)!</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Thanks to the users contribute via Weblate!" xml:space="preserve">
@@ -361,10 +361,6 @@ Dostupné ve verzi 5.1</target>
<target>O SimpleX chat</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="About SimpleX address" xml:space="preserve">
<source>About SimpleX address</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Accent color" xml:space="preserve">
<source>Accent color</source>
<target>Zbarvení</target>
@@ -391,8 +387,9 @@ Dostupné ve verzi 5.1</target>
<target>Přijmout inkognito</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add address to your profile, so that your contacts can share it with other people. Profile update will be sent to your contacts." xml:space="preserve">
<source>Add address to your profile, so that your contacts can share it with other people. Profile update will be sent to your contacts.</source>
<trans-unit id="Accept requests" xml:space="preserve">
<source>Accept requests</source>
<target>Přijímat žádosti</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add preset servers" xml:space="preserve">
@@ -425,10 +422,6 @@ Dostupné ve verzi 5.1</target>
<target>Přidat uvítací zprávu</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Address" xml:space="preserve">
<source>Address</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Admins can create the links to join groups." xml:space="preserve">
<source>Admins can create the links to join groups.</source>
<target>Správci mohou vytvářet odkazy pro připojení ke skupinám.</target>
@@ -454,12 +447,9 @@ Dostupné ve verzi 5.1</target>
<target>Všechny zprávy budou smazány tuto akci nelze vrátit zpět! Zprávy budou smazány POUZE pro vás.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All your contacts will remain connected." xml:space="preserve">
<source>All your contacts will remain connected.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All your contacts will remain connected. Profile update will be sent to your contacts." xml:space="preserve">
<source>All your contacts will remain connected. Profile update will be sent to your contacts.</source>
<trans-unit id="All your contacts will remain connected" xml:space="preserve">
<source>All your contacts will remain connected</source>
<target>Všechny vaše kontakty zůstanou připojeny</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow" xml:space="preserve">
@@ -622,10 +612,6 @@ Dostupné ve verzi 5.1</target>
<target>Ověřování není k dispozici</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Auto-accept" xml:space="preserve">
<source>Auto-accept</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Auto-accept contact requests" xml:space="preserve">
<source>Auto-accept contact requests</source>
<target>Automatické přijímání žádostí o kontakt</target>
@@ -636,6 +622,11 @@ Dostupné ve verzi 5.1</target>
<target>Automaticky přijímat obrázky</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Automatically" xml:space="preserve">
<source>Automatically</source>
<target>Automaticky</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Back" xml:space="preserve">
<source>Back</source>
<target>Zpět</target>
@@ -1001,6 +992,11 @@ Dostupné ve verzi 5.1</target>
<target>Předvolby kontaktů</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Contact requests" xml:space="preserve">
<source>Contact requests</source>
<target>Žádosti o kontakt</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Contacts can mark messages for deletion; you will be able to view them." xml:space="preserve">
<source>Contacts can mark messages for deletion; you will be able to view them.</source>
<target>Kontakty mohou označit zprávy ke smazání; vy je budete moci zobrazit.</target>
@@ -1021,12 +1017,9 @@ Dostupné ve verzi 5.1</target>
<target>Vytvořit</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Create SimpleX address" xml:space="preserve">
<source>Create SimpleX address</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Create an address to let people connect with you." xml:space="preserve">
<source>Create an address to let people connect with you.</source>
<trans-unit id="Create address" xml:space="preserve">
<source>Create address</source>
<target>Vytvořit adresu</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Create file" xml:space="preserve">
@@ -1597,10 +1590,6 @@ Dostupné ve verzi 5.1</target>
<target>Zadejte server ručně</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Enter welcome message… (optional)" xml:space="preserve">
<source>Enter welcome message… (optional)</source>
<note>placeholder</note>
</trans-unit>
<trans-unit id="Error" xml:space="preserve">
<source>Error</source>
<target>Chyba</target>
@@ -2354,10 +2343,6 @@ Dostupné ve verzi 5.1</target>
<target>Velký soubor!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Read more in [User Guide](https://simplex.chat/docs/guide/app-settings.html#your-simplex-contact-address)." xml:space="preserve">
<source>Read more in [User Guide](https://simplex.chat/docs/guide/app-settings.html#your-simplex-contact-address).</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Leave" xml:space="preserve">
<source>Leave</source>
<target>Opustit</target>
@@ -3002,10 +2987,6 @@ Dostupné ve verzi 5.1</target>
<target>Heslo profilu</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Profile update will be sent to your contacts." xml:space="preserve">
<source>Profile update will be sent to your contacts.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Prohibit audio/video calls." xml:space="preserve">
<source>Prohibit audio/video calls.</source>
<target>Zákaz audio/video hovorů.</target>
@@ -3266,10 +3247,6 @@ Dostupné ve verzi 5.1</target>
<target>Uložit archiv</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Save auto-accept settings" xml:space="preserve">
<source>Save auto-accept settings</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Save group profile" xml:space="preserve">
<source>Save group profile</source>
<target>Uložení profilu skupiny</target>
@@ -3305,10 +3282,6 @@ Dostupné ve verzi 5.1</target>
<target>Uložit servery?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Save settings?" xml:space="preserve">
<source>Save settings?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Save welcome message?" xml:space="preserve">
<source>Save welcome message?</source>
<target>Uložit uvítací zprávu?</target>
@@ -3499,14 +3472,6 @@ Dostupné ve verzi 5.1</target>
<target>Sdílet</target>
<note>chat item action</note>
</trans-unit>
<trans-unit id="Share address" xml:space="preserve">
<source>Share address</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Share address with contacts?" xml:space="preserve">
<source>Share address with contacts?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Share invitation link" xml:space="preserve">
<source>Share invitation link</source>
<target>Sdílet odkaz na pozvánku</target>
@@ -3522,10 +3487,6 @@ Dostupné ve verzi 5.1</target>
<target>Jednorázový zvací odkaz</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Share with contacts" xml:space="preserve">
<source>Share with contacts</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Show QR code" xml:space="preserve">
<source>Show QR code</source>
<target>Zobrazit QR kód</target>
@@ -3576,10 +3537,6 @@ Dostupné ve verzi 5.1</target>
<target>Zapnutý zámek SimpleX Lock</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="SimpleX address" xml:space="preserve">
<source>SimpleX address</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="SimpleX contact address" xml:space="preserve">
<source>SimpleX contact address</source>
<target>SimpleX kontaktní adresa</target>
@@ -3675,14 +3632,6 @@ Dostupné ve verzi 5.1</target>
<target>Zastavit odesílání souboru?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Stop sharing" xml:space="preserve">
<source>Stop sharing</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Stop sharing address?" xml:space="preserve">
<source>Stop sharing address?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Submit" xml:space="preserve">
<source>Submit</source>
<target>Odeslat</target>
@@ -3778,9 +3727,9 @@ Dostupné ve verzi 5.1</target>
<target>Děkujeme, že jste si nainstalovali SimpleX Chat!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Thanks to the users [contribute via Weblate](https://github.com/simplex-chat/simplex-chat/tree/stable#help-translating-simplex-chat)!" xml:space="preserve">
<source>Thanks to the users [contribute via Weblate](https://github.com/simplex-chat/simplex-chat/tree/stable#help-translating-simplex-chat)!</source>
<target>Díky uživatelům - [přispějte přes Weblate](https://github.com/simplex-chat/simplex-chat/tree/stable#help-translating-simplex-chat)!</target>
<trans-unit id="Thanks to the users [contribute via Weblate](https://github.com/simplex-chat/simplex-chat/tree/stable#translate-the-apps)!" xml:space="preserve">
<source>Thanks to the users [contribute via Weblate](https://github.com/simplex-chat/simplex-chat/tree/stable#translate-the-apps)!</source>
<target>Díky uživatelům - [přispějte přes Weblate](https://github.com/simplex-chat/simplex-chat/tree/stable#translate-the-apps)!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Thanks to the users contribute via Weblate!" xml:space="preserve">
@@ -4279,10 +4228,6 @@ Chcete-li se připojit, požádejte svůj kontakt o vytvoření dalšího odkazu
<target>Když je k dispozici</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="When people request to connect, you can accept or reject it." xml:space="preserve">
<source>When people request to connect, you can accept or reject it.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="When you share an incognito profile with somebody, this profile will be used for the groups they invite you to." xml:space="preserve">
<source>When you share an incognito profile with somebody, this profile will be used for the groups they invite you to.</source>
<target>Pokud s někým sdílíte inkognito profil, bude tento profil použit pro skupiny, do kterých vás pozve.</target>
@@ -4375,13 +4320,9 @@ SimpleX zámek musí být povolen.</target>
<target>Můžete sdílet odkaz nebo QR kód - ke skupině se bude moci připojit kdokoli. O členy skupiny nepřijdete, pokud ji později odstraníte.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You can share this address with your contacts to let them connect with **%@**." xml:space="preserve">
<source>You can share this address with your contacts to let them connect with **%@**.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You can share your address as a link or QR code - anybody can connect to you." xml:space="preserve">
<source>You can share your address as a link or QR code - anybody can connect to you.</source>
<target>Můžete sdílet svou adresu jako odkaz nebo jako QR kód - kdokoli se k vám bude moci připojit.</target>
<trans-unit id="You can share your address as a link or as a QR code - anybody will be able to connect to you. You won't lose your contacts if you later delete it." xml:space="preserve">
<source>You can share your address as a link or as a QR code - anybody will be able to connect to you. You won't lose your contacts if you later delete it.</source>
<target>Můžete sdílet svou adresu jako odkaz nebo jako QR kód - kdokoli se k vám bude moci připojit. O své kontakty nepřijdete, pokud ji později smažete.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You can start chat via app Settings / Database or by restarting the app" xml:space="preserve">
@@ -4494,11 +4435,6 @@ SimpleX zámek musí být povolen.</target>
<target>Přestanete dostávat zprávy z této skupiny. Historie chatu bude zachována.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You won't lose your contacts if you later delete your address." xml:space="preserve">
<source>You won't lose your contacts if you later delete your address.</source>
<target>O své kontakty nepřijdete, pokud ji později smažete.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You're trying to invite contact with whom you've shared an incognito profile to the group in which you're using your main profile" xml:space="preserve">
<source>You're trying to invite contact with whom you've shared an incognito profile to the group in which you're using your main profile</source>
<target>Snažíte se pozvat kontakt, se kterým jste sdíleli inkognito profil, do skupiny, ve které používáte svůj hlavní profil</target>
@@ -4526,7 +4462,7 @@ SimpleX zámek musí být povolen.</target>
</trans-unit>
<trans-unit id="Your SimpleX contact address" xml:space="preserve">
<source>Your SimpleX contact address</source>
<target>Vaše adresa SimpleX</target>
<target>Vaše kontaktní adresa SimpleX</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Your XFTP servers" xml:space="preserve">
@@ -4596,10 +4532,6 @@ Toto připojení můžete zrušit a kontakt odebrat (a zkusit to později s nov
<target>Vaše kontakty mohou povolit úplné mazání zpráv.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Your contacts will remain connected." xml:space="preserve">
<source>Your contacts will remain connected.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Your current chat database will be DELETED and REPLACED with the imported one." xml:space="preserve">
<source>Your current chat database will be DELETED and REPLACED with the imported one.</source>
<target>Vaše aktuální chat databáze bude ODSTRANĚNA a NAHRAZENA importovanou.</target>
@@ -361,10 +361,6 @@ Verfügbar ab v5.1</target>
<target>Über SimpleX Chat</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="About SimpleX address" xml:space="preserve">
<source>About SimpleX address</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Accent color" xml:space="preserve">
<source>Accent color</source>
<target>Akzentfarbe</target>
@@ -391,8 +387,9 @@ Verfügbar ab v5.1</target>
<target>Inkognito akzeptieren</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add address to your profile, so that your contacts can share it with other people. Profile update will be sent to your contacts." xml:space="preserve">
<source>Add address to your profile, so that your contacts can share it with other people. Profile update will be sent to your contacts.</source>
<trans-unit id="Accept requests" xml:space="preserve">
<source>Accept requests</source>
<target>Anfragen annehmen</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add preset servers" xml:space="preserve">
@@ -425,10 +422,6 @@ Verfügbar ab v5.1</target>
<target>Begrüßungsmeldung hinzufügen</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Address" xml:space="preserve">
<source>Address</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Admins can create the links to join groups." xml:space="preserve">
<source>Admins can create the links to join groups.</source>
<target>Administratoren können Links für den Beitritt zu Gruppen erzeugen.</target>
@@ -454,12 +447,9 @@ Verfügbar ab v5.1</target>
<target>Alle Nachrichten werden gelöscht - dies kann nicht rückgängig gemacht werden! Die Nachrichten werden NUR bei Ihnen gelöscht.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All your contacts will remain connected." xml:space="preserve">
<source>All your contacts will remain connected.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All your contacts will remain connected. Profile update will be sent to your contacts." xml:space="preserve">
<source>All your contacts will remain connected. Profile update will be sent to your contacts.</source>
<trans-unit id="All your contacts will remain connected" xml:space="preserve">
<source>All your contacts will remain connected</source>
<target>Alle Ihre Kontakte bleiben verbunden</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow" xml:space="preserve">
@@ -622,10 +612,6 @@ Verfügbar ab v5.1</target>
<target>Authentifizierung nicht verfügbar</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Auto-accept" xml:space="preserve">
<source>Auto-accept</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Auto-accept contact requests" xml:space="preserve">
<source>Auto-accept contact requests</source>
<target>Kontaktanfragen automatisch annehmen</target>
@@ -636,6 +622,11 @@ Verfügbar ab v5.1</target>
<target>Bilder automatisch akzeptieren</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Automatically" xml:space="preserve">
<source>Automatically</source>
<target>Automatisch</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Back" xml:space="preserve">
<source>Back</source>
<target>Zurück</target>
@@ -1001,6 +992,11 @@ Verfügbar ab v5.1</target>
<target>Kontakt Präferenzen</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Contact requests" xml:space="preserve">
<source>Contact requests</source>
<target>Kontaktanfragen</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Contacts can mark messages for deletion; you will be able to view them." xml:space="preserve">
<source>Contacts can mark messages for deletion; you will be able to view them.</source>
<target>Ihre Kontakte können Nachrichten zum Löschen markieren. Sie können diese Nachrichten trotzdem anschauen.</target>
@@ -1021,12 +1017,9 @@ Verfügbar ab v5.1</target>
<target>Erstellen</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Create SimpleX address" xml:space="preserve">
<source>Create SimpleX address</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Create an address to let people connect with you." xml:space="preserve">
<source>Create an address to let people connect with you.</source>
<trans-unit id="Create address" xml:space="preserve">
<source>Create address</source>
<target>Adresse erstellen</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Create file" xml:space="preserve">
@@ -1597,10 +1590,6 @@ Verfügbar ab v5.1</target>
<target>Geben Sie den Server manuell ein</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Enter welcome message… (optional)" xml:space="preserve">
<source>Enter welcome message… (optional)</source>
<note>placeholder</note>
</trans-unit>
<trans-unit id="Error" xml:space="preserve">
<source>Error</source>
<target>Fehler</target>
@@ -2354,10 +2343,6 @@ Verfügbar ab v5.1</target>
<target>Große Datei!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Read more in [User Guide](https://simplex.chat/docs/guide/app-settings.html#your-simplex-contact-address)." xml:space="preserve">
<source>Read more in [User Guide](https://simplex.chat/docs/guide/app-settings.html#your-simplex-contact-address).</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Leave" xml:space="preserve">
<source>Leave</source>
<target>Verlassen</target>
@@ -3002,10 +2987,6 @@ Verfügbar ab v5.1</target>
<target>Passwort für Profil</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Profile update will be sent to your contacts." xml:space="preserve">
<source>Profile update will be sent to your contacts.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Prohibit audio/video calls." xml:space="preserve">
<source>Prohibit audio/video calls.</source>
<target>Audio/Video Anrufe nicht erlauben.</target>
@@ -3266,10 +3247,6 @@ Verfügbar ab v5.1</target>
<target>Archiv speichern</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Save auto-accept settings" xml:space="preserve">
<source>Save auto-accept settings</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Save group profile" xml:space="preserve">
<source>Save group profile</source>
<target>Gruppenprofil speichern</target>
@@ -3305,10 +3282,6 @@ Verfügbar ab v5.1</target>
<target>Alle Server speichern?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Save settings?" xml:space="preserve">
<source>Save settings?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Save welcome message?" xml:space="preserve">
<source>Save welcome message?</source>
<target>Begrüßungsmeldung speichern?</target>
@@ -3499,14 +3472,6 @@ Verfügbar ab v5.1</target>
<target>Teilen</target>
<note>chat item action</note>
</trans-unit>
<trans-unit id="Share address" xml:space="preserve">
<source>Share address</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Share address with contacts?" xml:space="preserve">
<source>Share address with contacts?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Share invitation link" xml:space="preserve">
<source>Share invitation link</source>
<target>Einladungslink teilen</target>
@@ -3522,10 +3487,6 @@ Verfügbar ab v5.1</target>
<target>Einmal-Einladungslink teilen</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Share with contacts" xml:space="preserve">
<source>Share with contacts</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Show QR code" xml:space="preserve">
<source>Show QR code</source>
<target>QR-Code anzeigen</target>
@@ -3576,10 +3537,6 @@ Verfügbar ab v5.1</target>
<target>SimpleX Sperre aktiviert</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="SimpleX address" xml:space="preserve">
<source>SimpleX address</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="SimpleX contact address" xml:space="preserve">
<source>SimpleX contact address</source>
<target>SimpleX Kontaktadressen-Link</target>
@@ -3675,14 +3632,6 @@ Verfügbar ab v5.1</target>
<target>Das Senden der Datei beenden?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Stop sharing" xml:space="preserve">
<source>Stop sharing</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Stop sharing address?" xml:space="preserve">
<source>Stop sharing address?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Submit" xml:space="preserve">
<source>Submit</source>
<target>Übermitteln</target>
@@ -3778,9 +3727,9 @@ Verfügbar ab v5.1</target>
<target>Vielen Dank, dass Sie SimpleX Chat installiert haben!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Thanks to the users [contribute via Weblate](https://github.com/simplex-chat/simplex-chat/tree/stable#help-translating-simplex-chat)!" xml:space="preserve">
<source>Thanks to the users [contribute via Weblate](https://github.com/simplex-chat/simplex-chat/tree/stable#help-translating-simplex-chat)!</source>
<target>Dank der Nutzer - [Tragen Sie per Weblate bei](https://github.com/simplex-chat/simplex-chat/tree/stable#help-translating-simplex-chat)!</target>
<trans-unit id="Thanks to the users [contribute via Weblate](https://github.com/simplex-chat/simplex-chat/tree/stable#translate-the-apps)!" xml:space="preserve">
<source>Thanks to the users [contribute via Weblate](https://github.com/simplex-chat/simplex-chat/tree/stable#translate-the-apps)!</source>
<target>Dank der Nutzer - [Tragen Sie per Weblate bei](https://github.com/simplex-chat/simplex-chat/tree/stable#translate-the-apps)!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Thanks to the users contribute via Weblate!" xml:space="preserve">
@@ -4279,10 +4228,6 @@ Bitten Sie Ihren Kontakt darum einen weiteren Verbindungs-Link zu erzeugen, um s
<target>Wenn verfügbar</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="When people request to connect, you can accept or reject it." xml:space="preserve">
<source>When people request to connect, you can accept or reject it.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="When you share an incognito profile with somebody, this profile will be used for the groups they invite you to." xml:space="preserve">
<source>When you share an incognito profile with somebody, this profile will be used for the groups they invite you to.</source>
<target>Wenn Sie ein Inkognito-Profil mit Jemandem teilen, wird dieses Profil auch für die Gruppen verwendet, für die Sie von diesem Kontakt eingeladen werden.</target>
@@ -4375,13 +4320,9 @@ Dafür muss die SimpleX Sperre aktiviert sein.</target>
<target>Sie können diesen Link oder QR-Code teilen - Damit kann jede Person der Gruppe beitreten. Wenn Sie den Link später löschen, werden Sie keine Gruppenmitglieder verlieren, die der Gruppe darüber beigetreten sind.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You can share this address with your contacts to let them connect with **%@**." xml:space="preserve">
<source>You can share this address with your contacts to let them connect with **%@**.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You can share your address as a link or QR code - anybody can connect to you." xml:space="preserve">
<source>You can share your address as a link or QR code - anybody can connect to you.</source>
<target>Sie können Ihre Adresse als Link oder als QR-Code teilen Jede Person kann sich darüber mit Ihnen verbinden.</target>
<trans-unit id="You can share your address as a link or as a QR code - anybody will be able to connect to you. You won't lose your contacts if you later delete it." xml:space="preserve">
<source>You can share your address as a link or as a QR code - anybody will be able to connect to you. You won't lose your contacts if you later delete it.</source>
<target>Sie können Ihre Adresse als Link oder als QR-Code teilen Jede Person kann sich darüber mit Ihnen verbinden. Sie werden Ihre mit dieser Adresse verbundenen Kontakte nicht verlieren, wenn Sie diese Adresse später löschen.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You can start chat via app Settings / Database or by restarting the app" xml:space="preserve">
@@ -4494,11 +4435,6 @@ Dafür muss die SimpleX Sperre aktiviert sein.</target>
<target>Sie werden von dieser Gruppe keine Nachrichten mehr erhalten. Der Chatverlauf wird beibehalten.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You won't lose your contacts if you later delete your address." xml:space="preserve">
<source>You won't lose your contacts if you later delete your address.</source>
<target>Sie werden Ihre mit dieser Adresse verbundenen Kontakte nicht verlieren, wenn Sie diese Adresse später löschen.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You're trying to invite contact with whom you've shared an incognito profile to the group in which you're using your main profile" xml:space="preserve">
<source>You're trying to invite contact with whom you've shared an incognito profile to the group in which you're using your main profile</source>
<target>Sie versuchen, einen Kontakt, mit dem Sie ein Inkognito-Profil geteilt haben, in die Gruppe einzuladen, in der Sie Ihr Hauptprofil verwenden</target>
@@ -4596,10 +4532,6 @@ Sie können diese Verbindung abbrechen und den Kontakt entfernen (und es später
<target>Ihre Kontakte können die unwiederbringliche Löschung von Nachrichten erlauben.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Your contacts will remain connected." xml:space="preserve">
<source>Your contacts will remain connected.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Your current chat database will be DELETED and REPLACED with the imported one." xml:space="preserve">
<source>Your current chat database will be DELETED and REPLACED with the imported one.</source>
<target>Ihre aktuelle Chat-Datenbank wird GELÖSCHT und durch die Importierte ERSETZT.</target>
@@ -361,11 +361,6 @@ Available in v5.1</target>
<target>About SimpleX Chat</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="About SimpleX address" xml:space="preserve">
<source>About SimpleX address</source>
<target>About SimpleX address</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Accent color" xml:space="preserve">
<source>Accent color</source>
<target>Accent color</target>
@@ -392,9 +387,9 @@ Available in v5.1</target>
<target>Accept incognito</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add address to your profile, so that your contacts can share it with other people. Profile update will be sent to your contacts." xml:space="preserve">
<source>Add address to your profile, so that your contacts can share it with other people. Profile update will be sent to your contacts.</source>
<target>Add address to your profile, so that your contacts can share it with other people. Profile update will be sent to your contacts.</target>
<trans-unit id="Accept requests" xml:space="preserve">
<source>Accept requests</source>
<target>Accept requests</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add preset servers" xml:space="preserve">
@@ -427,11 +422,6 @@ Available in v5.1</target>
<target>Add welcome message</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Address" xml:space="preserve">
<source>Address</source>
<target>Address</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Admins can create the links to join groups." xml:space="preserve">
<source>Admins can create the links to join groups.</source>
<target>Admins can create the links to join groups.</target>
@@ -457,14 +447,9 @@ Available in v5.1</target>
<target>All messages will be deleted - this cannot be undone! The messages will be deleted ONLY for you.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All your contacts will remain connected." xml:space="preserve">
<source>All your contacts will remain connected.</source>
<target>All your contacts will remain connected.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All your contacts will remain connected. Profile update will be sent to your contacts." xml:space="preserve">
<source>All your contacts will remain connected. Profile update will be sent to your contacts.</source>
<target>All your contacts will remain connected. Profile update will be sent to your contacts.</target>
<trans-unit id="All your contacts will remain connected" xml:space="preserve">
<source>All your contacts will remain connected</source>
<target>All your contacts will remain connected</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow" xml:space="preserve">
@@ -627,11 +612,6 @@ Available in v5.1</target>
<target>Authentication unavailable</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Auto-accept" xml:space="preserve">
<source>Auto-accept</source>
<target>Auto-accept</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Auto-accept contact requests" xml:space="preserve">
<source>Auto-accept contact requests</source>
<target>Auto-accept contact requests</target>
@@ -642,6 +622,11 @@ Available in v5.1</target>
<target>Auto-accept images</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Automatically" xml:space="preserve">
<source>Automatically</source>
<target>Automatically</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Back" xml:space="preserve">
<source>Back</source>
<target>Back</target>
@@ -1007,6 +992,11 @@ Available in v5.1</target>
<target>Contact preferences</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Contact requests" xml:space="preserve">
<source>Contact requests</source>
<target>Contact requests</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Contacts can mark messages for deletion; you will be able to view them." xml:space="preserve">
<source>Contacts can mark messages for deletion; you will be able to view them.</source>
<target>Contacts can mark messages for deletion; you will be able to view them.</target>
@@ -1027,14 +1017,9 @@ Available in v5.1</target>
<target>Create</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Create SimpleX address" xml:space="preserve">
<source>Create SimpleX address</source>
<target>Create SimpleX address</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Create an address to let people connect with you." xml:space="preserve">
<source>Create an address to let people connect with you.</source>
<target>Create an address to let people connect with you.</target>
<trans-unit id="Create address" xml:space="preserve">
<source>Create address</source>
<target>Create address</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Create file" xml:space="preserve">
@@ -1605,11 +1590,6 @@ Available in v5.1</target>
<target>Enter server manually</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Enter welcome message… (optional)" xml:space="preserve">
<source>Enter welcome message… (optional)</source>
<target>Enter welcome message… (optional)</target>
<note>placeholder</note>
</trans-unit>
<trans-unit id="Error" xml:space="preserve">
<source>Error</source>
<target>Error</target>
@@ -2363,11 +2343,6 @@ Available in v5.1</target>
<target>Large file!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Read more in [User Guide](https://simplex.chat/docs/guide/app-settings.html#your-simplex-contact-address)." xml:space="preserve">
<source>Read more in [User Guide](https://simplex.chat/docs/guide/app-settings.html#your-simplex-contact-address).</source>
<target>Read more in [User Guide](https://simplex.chat/docs/guide/app-settings.html#your-simplex-contact-address).</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Leave" xml:space="preserve">
<source>Leave</source>
<target>Leave</target>
@@ -3012,11 +2987,6 @@ Available in v5.1</target>
<target>Profile password</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Profile update will be sent to your contacts." xml:space="preserve">
<source>Profile update will be sent to your contacts.</source>
<target>Profile update will be sent to your contacts.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Prohibit audio/video calls." xml:space="preserve">
<source>Prohibit audio/video calls.</source>
<target>Prohibit audio/video calls.</target>
@@ -3277,11 +3247,6 @@ Available in v5.1</target>
<target>Save archive</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Save auto-accept settings" xml:space="preserve">
<source>Save auto-accept settings</source>
<target>Save auto-accept settings</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Save group profile" xml:space="preserve">
<source>Save group profile</source>
<target>Save group profile</target>
@@ -3317,11 +3282,6 @@ Available in v5.1</target>
<target>Save servers?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Save settings?" xml:space="preserve">
<source>Save settings?</source>
<target>Save settings?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Save welcome message?" xml:space="preserve">
<source>Save welcome message?</source>
<target>Save welcome message?</target>
@@ -3512,16 +3472,6 @@ Available in v5.1</target>
<target>Share</target>
<note>chat item action</note>
</trans-unit>
<trans-unit id="Share address" xml:space="preserve">
<source>Share address</source>
<target>Share address</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Share address with contacts?" xml:space="preserve">
<source>Share address with contacts?</source>
<target>Share address with contacts?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Share invitation link" xml:space="preserve">
<source>Share invitation link</source>
<target>Share invitation link</target>
@@ -3537,11 +3487,6 @@ Available in v5.1</target>
<target>Share one-time invitation link</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Share with contacts" xml:space="preserve">
<source>Share with contacts</source>
<target>Share with contacts</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Show QR code" xml:space="preserve">
<source>Show QR code</source>
<target>Show QR code</target>
@@ -3592,11 +3537,6 @@ Available in v5.1</target>
<target>SimpleX Lock turned on</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="SimpleX address" xml:space="preserve">
<source>SimpleX address</source>
<target>SimpleX address</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="SimpleX contact address" xml:space="preserve">
<source>SimpleX contact address</source>
<target>SimpleX contact address</target>
@@ -3692,16 +3632,6 @@ Available in v5.1</target>
<target>Stop sending file?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Stop sharing" xml:space="preserve">
<source>Stop sharing</source>
<target>Stop sharing</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Stop sharing address?" xml:space="preserve">
<source>Stop sharing address?</source>
<target>Stop sharing address?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Submit" xml:space="preserve">
<source>Submit</source>
<target>Submit</target>
@@ -3797,9 +3727,9 @@ Available in v5.1</target>
<target>Thank you for installing SimpleX Chat!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Thanks to the users [contribute via Weblate](https://github.com/simplex-chat/simplex-chat/tree/stable#help-translating-simplex-chat)!" xml:space="preserve">
<source>Thanks to the users [contribute via Weblate](https://github.com/simplex-chat/simplex-chat/tree/stable#help-translating-simplex-chat)!</source>
<target>Thanks to the users [contribute via Weblate](https://github.com/simplex-chat/simplex-chat/tree/stable#help-translating-simplex-chat)!</target>
<trans-unit id="Thanks to the users [contribute via Weblate](https://github.com/simplex-chat/simplex-chat/tree/stable#translate-the-apps)!" xml:space="preserve">
<source>Thanks to the users [contribute via Weblate](https://github.com/simplex-chat/simplex-chat/tree/stable#translate-the-apps)!</source>
<target>Thanks to the users [contribute via Weblate](https://github.com/simplex-chat/simplex-chat/tree/stable#translate-the-apps)!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Thanks to the users contribute via Weblate!" xml:space="preserve">
@@ -4298,11 +4228,6 @@ To connect, please ask your contact to create another connection link and check
<target>When available</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="When people request to connect, you can accept or reject it." xml:space="preserve">
<source>When people request to connect, you can accept or reject it.</source>
<target>When people request to connect, you can accept or reject it.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="When you share an incognito profile with somebody, this profile will be used for the groups they invite you to." xml:space="preserve">
<source>When you share an incognito profile with somebody, this profile will be used for the groups they invite you to.</source>
<target>When you share an incognito profile with somebody, this profile will be used for the groups they invite you to.</target>
@@ -4395,14 +4320,9 @@ SimpleX Lock must be enabled.</target>
<target>You can share a link or a QR code - anybody will be able to join the group. You won't lose members of the group if you later delete it.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You can share this address with your contacts to let them connect with **%@**." xml:space="preserve">
<source>You can share this address with your contacts to let them connect with **%@**.</source>
<target>You can share this address with your contacts to let them connect with **%@**.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You can share your address as a link or QR code - anybody can connect to you." xml:space="preserve">
<source>You can share your address as a link or QR code - anybody can connect to you.</source>
<target>You can share your address as a link or QR code - anybody can connect to you.</target>
<trans-unit id="You can share your address as a link or as a QR code - anybody will be able to connect to you. You won't lose your contacts if you later delete it." xml:space="preserve">
<source>You can share your address as a link or as a QR code - anybody will be able to connect to you. You won't lose your contacts if you later delete it.</source>
<target>You can share your address as a link or as a QR code - anybody will be able to connect to you. You won't lose your contacts if you later delete it.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You can start chat via app Settings / Database or by restarting the app" xml:space="preserve">
@@ -4515,11 +4435,6 @@ SimpleX Lock must be enabled.</target>
<target>You will stop receiving messages from this group. Chat history will be preserved.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You won't lose your contacts if you later delete your address." xml:space="preserve">
<source>You won't lose your contacts if you later delete your address.</source>
<target>You won't lose your contacts if you later delete your address.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You're trying to invite contact with whom you've shared an incognito profile to the group in which you're using your main profile" xml:space="preserve">
<source>You're trying to invite contact with whom you've shared an incognito profile to the group in which you're using your main profile</source>
<target>You're trying to invite contact with whom you've shared an incognito profile to the group in which you're using your main profile</target>
@@ -4545,9 +4460,9 @@ SimpleX Lock must be enabled.</target>
<target>Your SMP servers</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Your SimpleX address" xml:space="preserve">
<source>Your SimpleX address</source>
<target>Your SimpleX address</target>
<trans-unit id="Your SimpleX contact address" xml:space="preserve">
<source>Your SimpleX contact address</source>
<target>Your SimpleX contact address</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Your XFTP servers" xml:space="preserve">
@@ -4617,11 +4532,6 @@ You can cancel this connection and remove the contact (and try later with a new
<target>Your contacts can allow full message deletion.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Your contacts will remain connected." xml:space="preserve">
<source>Your contacts will remain connected.</source>
<target>Your contacts will remain connected.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Your current chat database will be DELETED and REPLACED with the imported one." xml:space="preserve">
<source>Your current chat database will be DELETED and REPLACED with the imported one.</source>
<target>Your current chat database will be DELETED and REPLACED with the imported one.</target>
@@ -361,10 +361,6 @@ Disponible en v5.1</target>
<target>Acerca de SimpleX Chat</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="About SimpleX address" xml:space="preserve">
<source>About SimpleX address</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Accent color" xml:space="preserve">
<source>Accent color</source>
<target>Color</target>
@@ -391,8 +387,9 @@ Disponible en v5.1</target>
<target>Aceptar incógnito</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add address to your profile, so that your contacts can share it with other people. Profile update will be sent to your contacts." xml:space="preserve">
<source>Add address to your profile, so that your contacts can share it with other people. Profile update will be sent to your contacts.</source>
<trans-unit id="Accept requests" xml:space="preserve">
<source>Accept requests</source>
<target>Aceptar solicitudes</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add preset servers" xml:space="preserve">
@@ -425,10 +422,6 @@ Disponible en v5.1</target>
<target>Agregar mensaje de bienvenida</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Address" xml:space="preserve">
<source>Address</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Admins can create the links to join groups." xml:space="preserve">
<source>Admins can create the links to join groups.</source>
<target>Los administradores pueden crear los enlaces para unirse a los grupos.</target>
@@ -454,12 +447,9 @@ Disponible en v5.1</target>
<target>Se eliminarán todos los mensajes SOLO para tí. ¡No puede deshacerse!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All your contacts will remain connected." xml:space="preserve">
<source>All your contacts will remain connected.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All your contacts will remain connected. Profile update will be sent to your contacts." xml:space="preserve">
<source>All your contacts will remain connected. Profile update will be sent to your contacts.</source>
<trans-unit id="All your contacts will remain connected" xml:space="preserve">
<source>All your contacts will remain connected</source>
<target>Todos tus contactos permanecerán conectados</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow" xml:space="preserve">
@@ -622,10 +612,6 @@ Disponible en v5.1</target>
<target>Autenticación no disponible</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Auto-accept" xml:space="preserve">
<source>Auto-accept</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Auto-accept contact requests" xml:space="preserve">
<source>Auto-accept contact requests</source>
<target>Aceptar automáticamente solicitudes del contacto</target>
@@ -636,6 +622,11 @@ Disponible en v5.1</target>
<target>Aceptar automáticamente imágenes</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Automatically" xml:space="preserve">
<source>Automatically</source>
<target>Automáticamente</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Back" xml:space="preserve">
<source>Back</source>
<target>Volver</target>
@@ -1001,6 +992,11 @@ Disponible en v5.1</target>
<target>Preferencias de contacto</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Contact requests" xml:space="preserve">
<source>Contact requests</source>
<target>Solicitud del contacto</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Contacts can mark messages for deletion; you will be able to view them." xml:space="preserve">
<source>Contacts can mark messages for deletion; you will be able to view them.</source>
<target>El contacto solo puede marcar los mensajes para eliminar. Tu podrás verlos.</target>
@@ -1021,12 +1017,9 @@ Disponible en v5.1</target>
<target>Crear</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Create SimpleX address" xml:space="preserve">
<source>Create SimpleX address</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Create an address to let people connect with you." xml:space="preserve">
<source>Create an address to let people connect with you.</source>
<trans-unit id="Create address" xml:space="preserve">
<source>Create address</source>
<target>Crear dirección</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Create file" xml:space="preserve">
@@ -1597,10 +1590,6 @@ Disponible en v5.1</target>
<target>Introduce el servidor manualmente</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Enter welcome message… (optional)" xml:space="preserve">
<source>Enter welcome message… (optional)</source>
<note>placeholder</note>
</trans-unit>
<trans-unit id="Error" xml:space="preserve">
<source>Error</source>
<target>Error</target>
@@ -2354,10 +2343,6 @@ Disponible en v5.1</target>
<target>¡Archivo grande!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Read more in [User Guide](https://simplex.chat/docs/guide/app-settings.html#your-simplex-contact-address)." xml:space="preserve">
<source>Read more in [User Guide](https://simplex.chat/docs/guide/app-settings.html#your-simplex-contact-address).</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Leave" xml:space="preserve">
<source>Leave</source>
<target>Salir</target>
@@ -3002,10 +2987,6 @@ Disponible en v5.1</target>
<target>Contraseña del perfil</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Profile update will be sent to your contacts." xml:space="preserve">
<source>Profile update will be sent to your contacts.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Prohibit audio/video calls." xml:space="preserve">
<source>Prohibit audio/video calls.</source>
<target>Prohibir las llamadas/videollamadas.</target>
@@ -3266,10 +3247,6 @@ Disponible en v5.1</target>
<target>Guardar archivo</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Save auto-accept settings" xml:space="preserve">
<source>Save auto-accept settings</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Save group profile" xml:space="preserve">
<source>Save group profile</source>
<target>Guardar perfil de grupo</target>
@@ -3305,10 +3282,6 @@ Disponible en v5.1</target>
<target>¿Guardar servidores?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Save settings?" xml:space="preserve">
<source>Save settings?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Save welcome message?" xml:space="preserve">
<source>Save welcome message?</source>
<target>¿Guardar mensaje de bienvenida?</target>
@@ -3499,14 +3472,6 @@ Disponible en v5.1</target>
<target>Compartir</target>
<note>chat item action</note>
</trans-unit>
<trans-unit id="Share address" xml:space="preserve">
<source>Share address</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Share address with contacts?" xml:space="preserve">
<source>Share address with contacts?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Share invitation link" xml:space="preserve">
<source>Share invitation link</source>
<target>Compartir enlace de invitación</target>
@@ -3522,10 +3487,6 @@ Disponible en v5.1</target>
<target>Compartir enlace de invitación de un uso</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Share with contacts" xml:space="preserve">
<source>Share with contacts</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Show QR code" xml:space="preserve">
<source>Show QR code</source>
<target>Mostrar código QR</target>
@@ -3576,10 +3537,6 @@ Disponible en v5.1</target>
<target>Bloqueo SimpleX activado</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="SimpleX address" xml:space="preserve">
<source>SimpleX address</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="SimpleX contact address" xml:space="preserve">
<source>SimpleX contact address</source>
<target>Dirección de contacto SimpleX</target>
@@ -3675,14 +3632,6 @@ Disponible en v5.1</target>
<target>¿Dejar de enviar el archivo?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Stop sharing" xml:space="preserve">
<source>Stop sharing</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Stop sharing address?" xml:space="preserve">
<source>Stop sharing address?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Submit" xml:space="preserve">
<source>Submit</source>
<target>Enviar</target>
@@ -3778,8 +3727,8 @@ Disponible en v5.1</target>
<target>¡Gracias por instalar SimpleX Chat!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Thanks to the users [contribute via Weblate](https://github.com/simplex-chat/simplex-chat/tree/stable#help-translating-simplex-chat)!" xml:space="preserve">
<source>Thanks to the users [contribute via Weblate](https://github.com/simplex-chat/simplex-chat/tree/stable#help-translating-simplex-chat)!</source>
<trans-unit id="Thanks to the users [contribute via Weblate](https://github.com/simplex-chat/simplex-chat/tree/stable#translate-the-apps)!" xml:space="preserve">
<source>Thanks to the users [contribute via Weblate](https://github.com/simplex-chat/simplex-chat/tree/stable#translate-the-apps)!</source>
<target>Gracias a los usuarios: [contribuye vía Weblate](https://github.com/simplex-chat/simplex-chat/tree/stable#traducir-el-aplicaciones)!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
@@ -4280,10 +4229,6 @@ Para conectarte, pide a tu contacto que cree otro enlace de conexión y comprueb
<target>Cuando esté disponible</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="When people request to connect, you can accept or reject it." xml:space="preserve">
<source>When people request to connect, you can accept or reject it.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="When you share an incognito profile with somebody, this profile will be used for the groups they invite you to." xml:space="preserve">
<source>When you share an incognito profile with somebody, this profile will be used for the groups they invite you to.</source>
<target>Cuando compartes un perfil incógnito con alguien, este perfil también se usará para los grupos a los que te inviten.</target>
@@ -4376,13 +4321,9 @@ Bloqueo SimpleX debe estar activado.</target>
<target>Puedes compartir un enlace o un código QR: cualquiera podrá unirse al grupo. Si lo eliminas más tarde los miembros del grupo no se perderán.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You can share this address with your contacts to let them connect with **%@**." xml:space="preserve">
<source>You can share this address with your contacts to let them connect with **%@**.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You can share your address as a link or QR code - anybody can connect to you." xml:space="preserve">
<source>You can share your address as a link or QR code - anybody can connect to you.</source>
<target>Puedes compartir tu dirección como enlace o como código QR: cualquiera podrá conectarse contigo.</target>
<trans-unit id="You can share your address as a link or as a QR code - anybody will be able to connect to you. You won't lose your contacts if you later delete it." xml:space="preserve">
<source>You can share your address as a link or as a QR code - anybody will be able to connect to you. You won't lose your contacts if you later delete it.</source>
<target>Puedes compartir tu dirección como enlace o como código QR: cualquiera podrá conectarse contigo. Si lo eliminas más tarde tus contactos no se perderán.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You can start chat via app Settings / Database or by restarting the app" xml:space="preserve">
@@ -4495,11 +4436,6 @@ Bloqueo SimpleX debe estar activado.</target>
<target>Dejarás de recibir mensajes de este grupo. El historial del chat se conservará.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You won't lose your contacts if you later delete your address." xml:space="preserve">
<source>You won't lose your contacts if you later delete your address.</source>
<target>Si lo eliminas más tarde tus contactos no se perderán.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You're trying to invite contact with whom you've shared an incognito profile to the group in which you're using your main profile" xml:space="preserve">
<source>You're trying to invite contact with whom you've shared an incognito profile to the group in which you're using your main profile</source>
<target>Estás intentando invitar a un contacto con el que compartes un perfil incógnito a un grupo en el que usas tu perfil principal</target>
@@ -4527,7 +4463,7 @@ Bloqueo SimpleX debe estar activado.</target>
</trans-unit>
<trans-unit id="Your SimpleX contact address" xml:space="preserve">
<source>Your SimpleX contact address</source>
<target>Mi dirección SimpleX</target>
<target>Mi dirección de contacto SimpleX</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Your XFTP servers" xml:space="preserve">
@@ -4597,10 +4533,6 @@ Puedes cancelar esta conexión y eliminar el contacto (e intentarlo más tarde c
<target>Tus contactos pueden permitir la eliminación completa de mensajes.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Your contacts will remain connected." xml:space="preserve">
<source>Your contacts will remain connected.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Your current chat database will be DELETED and REPLACED with the imported one." xml:space="preserve">
<source>Your current chat database will be DELETED and REPLACED with the imported one.</source>
<target>La base de datos actual será ELIMINADA y SUSTITUIDA por la importada.</target>
@@ -2640,8 +2640,8 @@ We will be adding server redundancy to prevent lost messages.</source>
<source>Thank you for installing SimpleX Chat!</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Thanks to the users [contribute via Weblate](https://github.com/simplex-chat/simplex-chat/tree/stable#help-translating-simplex-chat)!" xml:space="preserve">
<source>Thanks to the users [contribute via Weblate](https://github.com/simplex-chat/simplex-chat/tree/stable#help-translating-simplex-chat)!</source>
<trans-unit id="Thanks to the users [contribute via Weblate](https://github.com/simplex-chat/simplex-chat/tree/stable#translate-the-apps)!" xml:space="preserve">
<source>Thanks to the users [contribute via Weblate](https://github.com/simplex-chat/simplex-chat/tree/stable#translate-the-apps)!</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Thanks to the users contribute via Weblate!" xml:space="preserve">
@@ -361,10 +361,6 @@ Disponible dans la v5.1</target>
<target>À propos de SimpleX Chat</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="About SimpleX address" xml:space="preserve">
<source>About SimpleX address</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Accent color" xml:space="preserve">
<source>Accent color</source>
<target>Couleur principale</target>
@@ -391,8 +387,9 @@ Disponible dans la v5.1</target>
<target>Accepter en incognito</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add address to your profile, so that your contacts can share it with other people. Profile update will be sent to your contacts." xml:space="preserve">
<source>Add address to your profile, so that your contacts can share it with other people. Profile update will be sent to your contacts.</source>
<trans-unit id="Accept requests" xml:space="preserve">
<source>Accept requests</source>
<target>Accepter les demandes</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add preset servers" xml:space="preserve">
@@ -425,10 +422,6 @@ Disponible dans la v5.1</target>
<target>Ajouter un message d'accueil</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Address" xml:space="preserve">
<source>Address</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Admins can create the links to join groups." xml:space="preserve">
<source>Admins can create the links to join groups.</source>
<target>Les admins peuvent créer les liens qui permettent de rejoindre les groupes.</target>
@@ -454,12 +447,9 @@ Disponible dans la v5.1</target>
<target>Tous les messages seront supprimés - impossible de revenir en arrière ! Les messages seront supprimés UNIQUEMENT pour vous.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All your contacts will remain connected." xml:space="preserve">
<source>All your contacts will remain connected.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All your contacts will remain connected. Profile update will be sent to your contacts." xml:space="preserve">
<source>All your contacts will remain connected. Profile update will be sent to your contacts.</source>
<trans-unit id="All your contacts will remain connected" xml:space="preserve">
<source>All your contacts will remain connected</source>
<target>Tous vos contacts resteront connectés</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow" xml:space="preserve">
@@ -622,10 +612,6 @@ Disponible dans la v5.1</target>
<target>Authentification indisponible</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Auto-accept" xml:space="preserve">
<source>Auto-accept</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Auto-accept contact requests" xml:space="preserve">
<source>Auto-accept contact requests</source>
<target>Demandes de contact auto-acceptées</target>
@@ -636,6 +622,11 @@ Disponible dans la v5.1</target>
<target>Images auto-acceptées</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Automatically" xml:space="preserve">
<source>Automatically</source>
<target>Automatiquement</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Back" xml:space="preserve">
<source>Back</source>
<target>Retour</target>
@@ -1001,6 +992,11 @@ Disponible dans la v5.1</target>
<target>Préférences de contact</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Contact requests" xml:space="preserve">
<source>Contact requests</source>
<target>Demandes de contact</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Contacts can mark messages for deletion; you will be able to view them." xml:space="preserve">
<source>Contacts can mark messages for deletion; you will be able to view them.</source>
<target>Vos contacts peuvent marquer les messages pour les supprimer ; vous pourrez les consulter.</target>
@@ -1021,12 +1017,9 @@ Disponible dans la v5.1</target>
<target>Créer</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Create SimpleX address" xml:space="preserve">
<source>Create SimpleX address</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Create an address to let people connect with you." xml:space="preserve">
<source>Create an address to let people connect with you.</source>
<trans-unit id="Create address" xml:space="preserve">
<source>Create address</source>
<target>Créer une adresse</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Create file" xml:space="preserve">
@@ -1597,10 +1590,6 @@ Disponible dans la v5.1</target>
<target>Entrer un serveur manuellement</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Enter welcome message… (optional)" xml:space="preserve">
<source>Enter welcome message… (optional)</source>
<note>placeholder</note>
</trans-unit>
<trans-unit id="Error" xml:space="preserve">
<source>Error</source>
<target>Erreur</target>
@@ -2354,10 +2343,6 @@ Disponible dans la v5.1</target>
<target>Fichier trop lourd !</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Read more in [User Guide](https://simplex.chat/docs/guide/app-settings.html#your-simplex-contact-address)." xml:space="preserve">
<source>Read more in [User Guide](https://simplex.chat/docs/guide/app-settings.html#your-simplex-contact-address).</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Leave" xml:space="preserve">
<source>Leave</source>
<target>Quitter</target>
@@ -3002,10 +2987,6 @@ Disponible dans la v5.1</target>
<target>Mot de passe de profil</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Profile update will be sent to your contacts." xml:space="preserve">
<source>Profile update will be sent to your contacts.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Prohibit audio/video calls." xml:space="preserve">
<source>Prohibit audio/video calls.</source>
<target>Interdire les appels audio/vidéo.</target>
@@ -3266,10 +3247,6 @@ Disponible dans la v5.1</target>
<target>Sauvegarder l'archive</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Save auto-accept settings" xml:space="preserve">
<source>Save auto-accept settings</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Save group profile" xml:space="preserve">
<source>Save group profile</source>
<target>Sauvegarder le profil du groupe</target>
@@ -3305,10 +3282,6 @@ Disponible dans la v5.1</target>
<target>Sauvegarder les serveurs ?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Save settings?" xml:space="preserve">
<source>Save settings?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Save welcome message?" xml:space="preserve">
<source>Save welcome message?</source>
<target>Sauvegarder le message d'accueil ?</target>
@@ -3499,14 +3472,6 @@ Disponible dans la v5.1</target>
<target>Partager</target>
<note>chat item action</note>
</trans-unit>
<trans-unit id="Share address" xml:space="preserve">
<source>Share address</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Share address with contacts?" xml:space="preserve">
<source>Share address with contacts?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Share invitation link" xml:space="preserve">
<source>Share invitation link</source>
<target>Partager le lien d'invitation</target>
@@ -3522,10 +3487,6 @@ Disponible dans la v5.1</target>
<target>Partager un lien d'invitation unique</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Share with contacts" xml:space="preserve">
<source>Share with contacts</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Show QR code" xml:space="preserve">
<source>Show QR code</source>
<target>Afficher le code QR</target>
@@ -3576,10 +3537,6 @@ Disponible dans la v5.1</target>
<target>SimpleX Lock activé</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="SimpleX address" xml:space="preserve">
<source>SimpleX address</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="SimpleX contact address" xml:space="preserve">
<source>SimpleX contact address</source>
<target>Adresse de contact SimpleX</target>
@@ -3675,14 +3632,6 @@ Disponible dans la v5.1</target>
<target>Arrêter l'envoi du fichier ?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Stop sharing" xml:space="preserve">
<source>Stop sharing</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Stop sharing address?" xml:space="preserve">
<source>Stop sharing address?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Submit" xml:space="preserve">
<source>Submit</source>
<target>Soumettre</target>
@@ -3778,9 +3727,9 @@ Disponible dans la v5.1</target>
<target>Merci d'avoir installé SimpleX Chat!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Thanks to the users [contribute via Weblate](https://github.com/simplex-chat/simplex-chat/tree/stable#help-translating-simplex-chat)!" xml:space="preserve">
<source>Thanks to the users [contribute via Weblate](https://github.com/simplex-chat/simplex-chat/tree/stable#help-translating-simplex-chat)!</source>
<target>Merci aux utilisateurs - [contribuer via Weblate](https://github.com/simplex-chat/simplex-chat/tree/stable#help-translating-simplex-chat) !</target>
<trans-unit id="Thanks to the users [contribute via Weblate](https://github.com/simplex-chat/simplex-chat/tree/stable#translate-the-apps)!" xml:space="preserve">
<source>Thanks to the users [contribute via Weblate](https://github.com/simplex-chat/simplex-chat/tree/stable#translate-the-apps)!</source>
<target>Merci aux utilisateurs - [contribuer via Weblate](https://github.com/simplex-chat/simplex-chat/tree/stable#translate-the-apps) !</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Thanks to the users contribute via Weblate!" xml:space="preserve">
@@ -4279,10 +4228,6 @@ Pour vous connecter, veuillez demander à votre contact de créer un autre lien
<target>Quand disponible</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="When people request to connect, you can accept or reject it." xml:space="preserve">
<source>When people request to connect, you can accept or reject it.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="When you share an incognito profile with somebody, this profile will be used for the groups they invite you to." xml:space="preserve">
<source>When you share an incognito profile with somebody, this profile will be used for the groups they invite you to.</source>
<target>Lorsque vous partagez un profil incognito avec quelqu'un, ce profil sera utilisé pour les groupes auxquels il vous invite.</target>
@@ -4375,13 +4320,9 @@ SimpleX Lock doit être activé.</target>
<target>Vous pouvez partager un lien ou un code QR - n'importe qui pourra rejoindre le groupe. Vous ne perdrez pas les membres du groupe si vous le supprimez par la suite.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You can share this address with your contacts to let them connect with **%@**." xml:space="preserve">
<source>You can share this address with your contacts to let them connect with **%@**.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You can share your address as a link or QR code - anybody can connect to you." xml:space="preserve">
<source>You can share your address as a link or QR code - anybody can connect to you.</source>
<target>Vous pouvez partager votre adresse sous forme de lien ou de code QR - n'importe qui pourra se connecter à vous.</target>
<trans-unit id="You can share your address as a link or as a QR code - anybody will be able to connect to you. You won't lose your contacts if you later delete it." xml:space="preserve">
<source>You can share your address as a link or as a QR code - anybody will be able to connect to you. You won't lose your contacts if you later delete it.</source>
<target>Vous pouvez partager votre adresse sous forme de lien ou de code QR - n'importe qui pourra se connecter à vous. Vous ne perdrez pas vos contacts si vous la supprimez par la suite.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You can start chat via app Settings / Database or by restarting the app" xml:space="preserve">
@@ -4494,11 +4435,6 @@ SimpleX Lock doit être activé.</target>
<target>Vous ne recevrez plus de messages de ce groupe. L'historique du chat sera conservé.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You won't lose your contacts if you later delete your address." xml:space="preserve">
<source>You won't lose your contacts if you later delete your address.</source>
<target>Vous ne perdrez pas vos contacts si vous la supprimez par la suite.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You're trying to invite contact with whom you've shared an incognito profile to the group in which you're using your main profile" xml:space="preserve">
<source>You're trying to invite contact with whom you've shared an incognito profile to the group in which you're using your main profile</source>
<target>Vous essayez d'inviter un contact avec lequel vous avez partagé un profil incognito à rejoindre le groupe dans lequel vous utilisez votre profil principal</target>
@@ -4526,7 +4462,7 @@ SimpleX Lock doit être activé.</target>
</trans-unit>
<trans-unit id="Your SimpleX contact address" xml:space="preserve">
<source>Your SimpleX contact address</source>
<target>Votre adresse SimpleX</target>
<target>Votre adresse de contact SimpleX</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Your XFTP servers" xml:space="preserve">
@@ -4596,10 +4532,6 @@ Vous pouvez annuler la connexion et supprimer le contact (et réessayer plus tar
<target>Vos contacts peuvent autoriser la suppression complète des messages.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Your contacts will remain connected." xml:space="preserve">
<source>Your contacts will remain connected.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Your current chat database will be DELETED and REPLACED with the imported one." xml:space="preserve">
<source>Your current chat database will be DELETED and REPLACED with the imported one.</source>
<target>Votre base de données de chat actuelle va être SUPPRIMEE et REMPLACEE par celle importée.</target>
@@ -2569,8 +2569,8 @@ We will be adding server redundancy to prevent lost messages.</source>
<source>Thank you for installing SimpleX Chat!</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Thanks to the users [contribute via Weblate](https://github.com/simplex-chat/simplex-chat/tree/stable#help-translating-simplex-chat)!" xml:space="preserve">
<source>Thanks to the users [contribute via Weblate](https://github.com/simplex-chat/simplex-chat/tree/stable#help-translating-simplex-chat)!</source>
<trans-unit id="Thanks to the users [contribute via Weblate](https://github.com/simplex-chat/simplex-chat/tree/stable#translate-the-apps)!" xml:space="preserve">
<source>Thanks to the users [contribute via Weblate](https://github.com/simplex-chat/simplex-chat/tree/stable#translate-the-apps)!</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Thanks to the users contribute via Weblate!" xml:space="preserve">

Some files were not shown because too many files have changed in this diff Show More