mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2024-12-17 17:20:21 +01:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4947cf2c0c | |||
| 2e205b055d |
@@ -44,6 +44,7 @@ struct ComposeState {
|
||||
var contextItem: ComposeContextItem
|
||||
var voiceMessageRecordingState: VoiceMessageRecordingState
|
||||
var inProgress = false
|
||||
var disabled = false
|
||||
var useLinkPreviews: Bool = UserDefaults.standard.bool(forKey: DEFAULT_PRIVACY_LINK_PREVIEWS)
|
||||
|
||||
init(
|
||||
@@ -654,7 +655,10 @@ struct ComposeView: View {
|
||||
return sent
|
||||
|
||||
func sending() async {
|
||||
await MainActor.run { composeState.inProgress = true }
|
||||
await MainActor.run { composeState.disabled = true }
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
||||
if composeState.disabled { composeState.inProgress = true }
|
||||
}
|
||||
}
|
||||
|
||||
func updateMessage(_ ei: ChatItem, live: Bool) async -> ChatItem? {
|
||||
@@ -848,6 +852,7 @@ struct ComposeView: View {
|
||||
|
||||
private func clearState(live: Bool = false) {
|
||||
if live {
|
||||
composeState.disabled = false
|
||||
composeState.inProgress = false
|
||||
} else {
|
||||
composeState = ComposeState()
|
||||
|
||||
@@ -36,7 +36,6 @@ struct SendMessageView: View {
|
||||
@State private var showCustomDisappearingMessageDialogue = false
|
||||
@State private var showCustomTimePicker = false
|
||||
@State private var selectedDisappearingMessageTime: Int? = customDisappearingMessageTimeDefault.get()
|
||||
@State private var progressByTimeout = false
|
||||
var maxHeight: CGFloat = 360
|
||||
var minHeight: CGFloat = 37
|
||||
@AppStorage(DEFAULT_LIVE_MESSAGE_ALERT_SHOWN) private var liveMessageAlertShown = false
|
||||
@@ -82,7 +81,7 @@ struct SendMessageView: View {
|
||||
}
|
||||
}
|
||||
|
||||
if progressByTimeout {
|
||||
if composeState.inProgress {
|
||||
ProgressView()
|
||||
.scaleEffect(1.4)
|
||||
.frame(width: 31, height: 31, alignment: .center)
|
||||
@@ -103,15 +102,6 @@ struct SendMessageView: View {
|
||||
.strokeBorder(.secondary, lineWidth: 0.3, antialiased: true)
|
||||
.frame(height: teHeight)
|
||||
}
|
||||
.onChange(of: composeState.inProgress) { inProgress in
|
||||
if inProgress {
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
|
||||
progressByTimeout = composeState.inProgress
|
||||
}
|
||||
} else {
|
||||
progressByTimeout = false
|
||||
}
|
||||
}
|
||||
.padding(.vertical, 8)
|
||||
}
|
||||
|
||||
@@ -129,7 +119,7 @@ struct SendMessageView: View {
|
||||
startVoiceMessageRecording: startVoiceMessageRecording,
|
||||
finishVoiceMessageRecording: finishVoiceMessageRecording,
|
||||
holdingVMR: $holdingVMR,
|
||||
disabled: composeState.inProgress
|
||||
disabled: composeState.disabled
|
||||
)
|
||||
} else {
|
||||
voiceMessageNotAllowedButton()
|
||||
@@ -175,7 +165,7 @@ struct SendMessageView: View {
|
||||
}
|
||||
.disabled(
|
||||
!composeState.sendEnabled ||
|
||||
composeState.inProgress ||
|
||||
composeState.disabled ||
|
||||
(!voiceMessageAllowed && composeState.voicePreview) ||
|
||||
composeState.endLiveDisabled
|
||||
)
|
||||
@@ -303,7 +293,7 @@ struct SendMessageView: View {
|
||||
Image(systemName: "mic")
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
.disabled(composeState.inProgress)
|
||||
.disabled(composeState.disabled)
|
||||
.frame(width: 29, height: 29)
|
||||
.padding([.bottom, .trailing], 4)
|
||||
}
|
||||
@@ -388,7 +378,7 @@ struct SendMessageView: View {
|
||||
Image(systemName: "stop.fill")
|
||||
.foregroundColor(.accentColor)
|
||||
}
|
||||
.disabled(composeState.inProgress)
|
||||
.disabled(composeState.disabled)
|
||||
.frame(width: 29, height: 29)
|
||||
.padding([.bottom, .trailing], 4)
|
||||
}
|
||||
|
||||
@@ -127,7 +127,7 @@ class NotificationService: UNNotificationServiceExtension {
|
||||
logger.debug("NotificationService: receiveNtfMessages: apiGetNtfMessage \(String(describing: ntfMsgInfo), privacy: .public)")
|
||||
if let connEntity = ntfMsgInfo.connEntity {
|
||||
setBestAttemptNtf(
|
||||
ntfMsgInfo.ntfsEnabled
|
||||
ntfMsgInfo.user.showNotifications
|
||||
? .nse(notification: createConnectionEventNtf(ntfMsgInfo.user, connEntity))
|
||||
: .empty
|
||||
)
|
||||
@@ -401,8 +401,4 @@ struct NtfMessages {
|
||||
var connEntity: ConnectionEntity?
|
||||
var msgTs: Date?
|
||||
var ntfMessages: [NtfMsgInfo]
|
||||
|
||||
var ntfsEnabled: Bool {
|
||||
user.showNotifications && (connEntity?.ntfsEnabled ?? false)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,11 @@
|
||||
5C00168128C4FE760094D739 /* KeyChain.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C00168028C4FE760094D739 /* KeyChain.swift */; };
|
||||
5C029EA82837DBB3004A9677 /* CICallItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C029EA72837DBB3004A9677 /* CICallItemView.swift */; };
|
||||
5C029EAA283942EA004A9677 /* CallController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C029EA9283942EA004A9677 /* CallController.swift */; };
|
||||
5C0403922A7EAA41006ACFE8 /* libHSsimplex-chat-5.3.0.2-57EsBXX08D1H5qwhz1zMA5-ghc8.10.7.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C04038D2A7EAA41006ACFE8 /* libHSsimplex-chat-5.3.0.2-57EsBXX08D1H5qwhz1zMA5-ghc8.10.7.a */; };
|
||||
5C0403932A7EAA41006ACFE8 /* libHSsimplex-chat-5.3.0.2-57EsBXX08D1H5qwhz1zMA5.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C04038E2A7EAA41006ACFE8 /* libHSsimplex-chat-5.3.0.2-57EsBXX08D1H5qwhz1zMA5.a */; };
|
||||
5C0403942A7EAA41006ACFE8 /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C04038F2A7EAA41006ACFE8 /* libffi.a */; };
|
||||
5C0403952A7EAA41006ACFE8 /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C0403902A7EAA41006ACFE8 /* libgmp.a */; };
|
||||
5C0403962A7EAA41006ACFE8 /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C0403912A7EAA41006ACFE8 /* libgmpxx.a */; };
|
||||
5C05DF532840AA1D00C683F9 /* CallSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C05DF522840AA1D00C683F9 /* CallSettings.swift */; };
|
||||
5C063D2727A4564100AEC577 /* ChatPreviewView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C063D2627A4564100AEC577 /* ChatPreviewView.swift */; };
|
||||
5C10D88828EED12E00E58BF0 /* ContactConnectionInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C10D88728EED12E00E58BF0 /* ContactConnectionInfo.swift */; };
|
||||
@@ -43,11 +48,6 @@
|
||||
5C3F1D562842B68D00EC8A82 /* IntegrityErrorItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C3F1D552842B68D00EC8A82 /* IntegrityErrorItemView.swift */; };
|
||||
5C3F1D58284363C400EC8A82 /* PrivacySettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C3F1D57284363C400EC8A82 /* PrivacySettings.swift */; };
|
||||
5C4B3B0A285FB130003915F2 /* DatabaseView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C4B3B09285FB130003915F2 /* DatabaseView.swift */; };
|
||||
5C4CC1B02A88383C006BF552 /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C4CC1AB2A88383C006BF552 /* libffi.a */; };
|
||||
5C4CC1B12A88383C006BF552 /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C4CC1AC2A88383C006BF552 /* libgmpxx.a */; };
|
||||
5C4CC1B22A88383C006BF552 /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C4CC1AD2A88383C006BF552 /* libgmp.a */; };
|
||||
5C4CC1B32A88383C006BF552 /* libHSsimplex-chat-5.3.0.4-FE3hjvmcZIPFfEovdlxWAx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C4CC1AE2A88383C006BF552 /* libHSsimplex-chat-5.3.0.4-FE3hjvmcZIPFfEovdlxWAx.a */; };
|
||||
5C4CC1B42A88383C006BF552 /* libHSsimplex-chat-5.3.0.4-FE3hjvmcZIPFfEovdlxWAx-ghc8.10.7.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C4CC1AF2A88383C006BF552 /* libHSsimplex-chat-5.3.0.4-FE3hjvmcZIPFfEovdlxWAx-ghc8.10.7.a */; };
|
||||
5C5346A827B59A6A004DF848 /* ChatHelp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C5346A727B59A6A004DF848 /* ChatHelp.swift */; };
|
||||
5C55A91F283AD0E400C4E99E /* CallManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C55A91E283AD0E400C4E99E /* CallManager.swift */; };
|
||||
5C55A921283CCCB700C4E99E /* IncomingCallView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C55A920283CCCB700C4E99E /* IncomingCallView.swift */; };
|
||||
@@ -263,6 +263,11 @@
|
||||
5C00168028C4FE760094D739 /* KeyChain.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyChain.swift; sourceTree = "<group>"; };
|
||||
5C029EA72837DBB3004A9677 /* CICallItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CICallItemView.swift; sourceTree = "<group>"; };
|
||||
5C029EA9283942EA004A9677 /* CallController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallController.swift; sourceTree = "<group>"; };
|
||||
5C04038D2A7EAA41006ACFE8 /* libHSsimplex-chat-5.3.0.2-57EsBXX08D1H5qwhz1zMA5-ghc8.10.7.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.3.0.2-57EsBXX08D1H5qwhz1zMA5-ghc8.10.7.a"; sourceTree = "<group>"; };
|
||||
5C04038E2A7EAA41006ACFE8 /* libHSsimplex-chat-5.3.0.2-57EsBXX08D1H5qwhz1zMA5.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.3.0.2-57EsBXX08D1H5qwhz1zMA5.a"; sourceTree = "<group>"; };
|
||||
5C04038F2A7EAA41006ACFE8 /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = "<group>"; };
|
||||
5C0403902A7EAA41006ACFE8 /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = "<group>"; };
|
||||
5C0403912A7EAA41006ACFE8 /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = "<group>"; };
|
||||
5C05DF522840AA1D00C683F9 /* CallSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallSettings.swift; sourceTree = "<group>"; };
|
||||
5C063D2627A4564100AEC577 /* ChatPreviewView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatPreviewView.swift; sourceTree = "<group>"; };
|
||||
5C10D88728EED12E00E58BF0 /* ContactConnectionInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactConnectionInfo.swift; sourceTree = "<group>"; };
|
||||
@@ -284,11 +289,6 @@
|
||||
5C3F1D57284363C400EC8A82 /* PrivacySettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivacySettings.swift; sourceTree = "<group>"; };
|
||||
5C422A7C27A9A6FA0097A1E1 /* SimpleX (iOS).entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "SimpleX (iOS).entitlements"; sourceTree = "<group>"; };
|
||||
5C4B3B09285FB130003915F2 /* DatabaseView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DatabaseView.swift; sourceTree = "<group>"; };
|
||||
5C4CC1AB2A88383C006BF552 /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = "<group>"; };
|
||||
5C4CC1AC2A88383C006BF552 /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = "<group>"; };
|
||||
5C4CC1AD2A88383C006BF552 /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = "<group>"; };
|
||||
5C4CC1AE2A88383C006BF552 /* libHSsimplex-chat-5.3.0.4-FE3hjvmcZIPFfEovdlxWAx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.3.0.4-FE3hjvmcZIPFfEovdlxWAx.a"; sourceTree = "<group>"; };
|
||||
5C4CC1AF2A88383C006BF552 /* libHSsimplex-chat-5.3.0.4-FE3hjvmcZIPFfEovdlxWAx-ghc8.10.7.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.3.0.4-FE3hjvmcZIPFfEovdlxWAx-ghc8.10.7.a"; sourceTree = "<group>"; };
|
||||
5C5346A727B59A6A004DF848 /* ChatHelp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatHelp.swift; sourceTree = "<group>"; };
|
||||
5C55A91E283AD0E400C4E99E /* CallManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallManager.swift; sourceTree = "<group>"; };
|
||||
5C55A920283CCCB700C4E99E /* IncomingCallView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IncomingCallView.swift; sourceTree = "<group>"; };
|
||||
@@ -501,13 +501,13 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
5C4CC1B12A88383C006BF552 /* libgmpxx.a in Frameworks */,
|
||||
5C4CC1B32A88383C006BF552 /* libHSsimplex-chat-5.3.0.4-FE3hjvmcZIPFfEovdlxWAx.a in Frameworks */,
|
||||
5C4CC1B22A88383C006BF552 /* libgmp.a in Frameworks */,
|
||||
5C0403932A7EAA41006ACFE8 /* libHSsimplex-chat-5.3.0.2-57EsBXX08D1H5qwhz1zMA5.a in Frameworks */,
|
||||
5C0403922A7EAA41006ACFE8 /* libHSsimplex-chat-5.3.0.2-57EsBXX08D1H5qwhz1zMA5-ghc8.10.7.a in Frameworks */,
|
||||
5CE2BA93284534B000EC33A6 /* libiconv.tbd in Frameworks */,
|
||||
5C4CC1B02A88383C006BF552 /* libffi.a in Frameworks */,
|
||||
5C0403942A7EAA41006ACFE8 /* libffi.a in Frameworks */,
|
||||
5C0403952A7EAA41006ACFE8 /* libgmp.a in Frameworks */,
|
||||
5CE2BA94284534BB00EC33A6 /* libz.tbd in Frameworks */,
|
||||
5C4CC1B42A88383C006BF552 /* libHSsimplex-chat-5.3.0.4-FE3hjvmcZIPFfEovdlxWAx-ghc8.10.7.a in Frameworks */,
|
||||
5C0403962A7EAA41006ACFE8 /* libgmpxx.a in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -568,11 +568,11 @@
|
||||
5C764E5C279C70B7000C6508 /* Libraries */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5C4CC1AB2A88383C006BF552 /* libffi.a */,
|
||||
5C4CC1AD2A88383C006BF552 /* libgmp.a */,
|
||||
5C4CC1AC2A88383C006BF552 /* libgmpxx.a */,
|
||||
5C4CC1AF2A88383C006BF552 /* libHSsimplex-chat-5.3.0.4-FE3hjvmcZIPFfEovdlxWAx-ghc8.10.7.a */,
|
||||
5C4CC1AE2A88383C006BF552 /* libHSsimplex-chat-5.3.0.4-FE3hjvmcZIPFfEovdlxWAx.a */,
|
||||
5C04038F2A7EAA41006ACFE8 /* libffi.a */,
|
||||
5C0403902A7EAA41006ACFE8 /* libgmp.a */,
|
||||
5C0403912A7EAA41006ACFE8 /* libgmpxx.a */,
|
||||
5C04038D2A7EAA41006ACFE8 /* libHSsimplex-chat-5.3.0.2-57EsBXX08D1H5qwhz1zMA5-ghc8.10.7.a */,
|
||||
5C04038E2A7EAA41006ACFE8 /* libHSsimplex-chat-5.3.0.2-57EsBXX08D1H5qwhz1zMA5.a */,
|
||||
);
|
||||
path = Libraries;
|
||||
sourceTree = "<group>";
|
||||
@@ -1478,7 +1478,7 @@
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 167;
|
||||
CURRENT_PROJECT_VERSION = 164;
|
||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||
ENABLE_BITCODE = NO;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
@@ -1520,7 +1520,7 @@
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 167;
|
||||
CURRENT_PROJECT_VERSION = 164;
|
||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||
ENABLE_BITCODE = NO;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
@@ -1600,7 +1600,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements";
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 167;
|
||||
CURRENT_PROJECT_VERSION = 164;
|
||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||
ENABLE_BITCODE = NO;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
@@ -1632,7 +1632,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements";
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 167;
|
||||
CURRENT_PROJECT_VERSION = 164;
|
||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||
ENABLE_BITCODE = NO;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
@@ -1664,7 +1664,7 @@
|
||||
APPLICATION_EXTENSION_API_ONLY = YES;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 167;
|
||||
CURRENT_PROJECT_VERSION = 164;
|
||||
DEFINES_MODULE = YES;
|
||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
@@ -1688,7 +1688,7 @@
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/Libraries/sim",
|
||||
);
|
||||
MARKETING_VERSION = 5.3;
|
||||
MARKETING_VERSION = 5.2.2;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.SimpleXChat;
|
||||
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
|
||||
SDKROOT = iphoneos;
|
||||
@@ -1710,7 +1710,7 @@
|
||||
APPLICATION_EXTENSION_API_ONLY = YES;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 167;
|
||||
CURRENT_PROJECT_VERSION = 164;
|
||||
DEFINES_MODULE = YES;
|
||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
@@ -1734,7 +1734,7 @@
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/Libraries/sim",
|
||||
);
|
||||
MARKETING_VERSION = 5.3;
|
||||
MARKETING_VERSION = 5.2.2;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.SimpleXChat;
|
||||
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
|
||||
SDKROOT = iphoneos;
|
||||
|
||||
@@ -1466,8 +1466,6 @@ public struct SecurityCode: Decodable, Equatable {
|
||||
|
||||
public struct UserContact: Decodable {
|
||||
public var userContactLinkId: Int64
|
||||
// public var connReqContact: String
|
||||
public var groupId: Int64?
|
||||
|
||||
public init(userContactLinkId: Int64) {
|
||||
self.userContactLinkId = userContactLinkId
|
||||
@@ -1929,16 +1927,6 @@ public enum ConnectionEntity: Decodable {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
public var ntfsEnabled: Bool {
|
||||
switch self {
|
||||
case let .rcvDirectMsgConnection(contact): return contact?.chatSettings.enableNtfs ?? false
|
||||
case let .rcvGroupMsgConnection(groupInfo, _): return groupInfo.chatSettings.enableNtfs
|
||||
case .sndFileConnection: return false
|
||||
case .rcvFileConnection: return false
|
||||
case let .userContactConnection(userContact): return userContact.groupId == nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public struct NtfMsgInfo: Decodable {
|
||||
|
||||
@@ -8,12 +8,13 @@ plugins {
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdkVersion(33)
|
||||
namespace = "chat.simplex.app"
|
||||
compileSdk = 33
|
||||
|
||||
defaultConfig {
|
||||
applicationId = "chat.simplex.app"
|
||||
minSdkVersion(26)
|
||||
targetSdkVersion(33)
|
||||
minSdk = 26
|
||||
targetSdk = 33
|
||||
// !!!
|
||||
// skip version code after release to F-Droid, as it uses two version codes
|
||||
versionCode = (extra["android.version_code"] as String).toInt()
|
||||
@@ -56,8 +57,6 @@ android {
|
||||
freeCompilerArgs += "-opt-in=androidx.compose.foundation.ExperimentalFoundationApi"
|
||||
freeCompilerArgs += "-opt-in=androidx.compose.ui.text.ExperimentalTextApi"
|
||||
freeCompilerArgs += "-opt-in=androidx.compose.material.ExperimentalMaterialApi"
|
||||
freeCompilerArgs += "-opt-in=com.google.accompanist.insets.ExperimentalAnimatedInsets"
|
||||
freeCompilerArgs += "-opt-in=com.google.accompanist.permissions.ExperimentalPermissionsApi"
|
||||
freeCompilerArgs += "-opt-in=kotlinx.serialization.InternalSerializationApi"
|
||||
freeCompilerArgs += "-opt-in=kotlinx.serialization.ExperimentalSerializationApi"
|
||||
}
|
||||
@@ -83,7 +82,6 @@ android {
|
||||
// Comma separated list of languages that will be included in the apk
|
||||
android.defaultConfig.resConfigs(
|
||||
"en",
|
||||
"bg",
|
||||
"cs",
|
||||
"de",
|
||||
"es",
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="chat.simplex.app">
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<uses-feature android:name="android.hardware.camera" />
|
||||
|
||||
@@ -24,8 +23,9 @@
|
||||
|
||||
<application
|
||||
android:name="SimplexApp"
|
||||
android:allowBackup="false"
|
||||
android:fullBackupOnly="false"
|
||||
android:allowBackup="true"
|
||||
android:fullBackupOnly="true"
|
||||
android:backupAgent="BackupAgent"
|
||||
android:icon="@mipmap/icon"
|
||||
android:label="${app_name}"
|
||||
android:extractNativeLibs="${extract_native_libs}"
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
package chat.simplex.app
|
||||
|
||||
import android.app.backup.BackupAgentHelper
|
||||
import android.app.backup.FullBackupDataOutput
|
||||
import android.content.Context
|
||||
import chat.simplex.common.model.AppPreferences
|
||||
import chat.simplex.common.model.AppPreferences.Companion.SHARED_PREFS_PRIVACY_FULL_BACKUP
|
||||
|
||||
class BackupAgent: BackupAgentHelper() {
|
||||
override fun onFullBackup(data: FullBackupDataOutput?) {
|
||||
if (applicationContext
|
||||
.getSharedPreferences(AppPreferences.SHARED_PREFS_ID, Context.MODE_PRIVATE)
|
||||
.getBoolean(SHARED_PREFS_PRIVACY_FULL_BACKUP, true)
|
||||
) {
|
||||
super.onFullBackup(data)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,4 @@
|
||||
import org.gradle.initialization.Environment.Properties
|
||||
import java.io.File
|
||||
import java.io.FileInputStream
|
||||
|
||||
buildscript {
|
||||
val prop = java.util.Properties().apply {
|
||||
@@ -33,7 +31,6 @@ buildscript {
|
||||
dependencies {
|
||||
classpath("com.android.tools.build:gradle:${rootProject.extra["gradle.plugin.version"]}")
|
||||
classpath(kotlin("gradle-plugin", version = rootProject.extra["kotlin.version"] as String))
|
||||
classpath("org.jetbrains.kotlin:kotlin-serialization:1.3.2")
|
||||
classpath("dev.icerock.moko:resources-generator:0.22.3")
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
|
||||
@@ -22,7 +22,6 @@ kotlin {
|
||||
optIn("androidx.compose.foundation.ExperimentalFoundationApi")
|
||||
optIn("androidx.compose.ui.text.ExperimentalTextApi")
|
||||
optIn("androidx.compose.material.ExperimentalMaterialApi")
|
||||
optIn("com.arkivanov.decompose.ExperimentalDecomposeApi")
|
||||
optIn("kotlinx.serialization.InternalSerializationApi")
|
||||
optIn("kotlinx.serialization.ExperimentalSerializationApi")
|
||||
optIn("androidx.compose.ui.ExperimentalComposeUiApi")
|
||||
@@ -104,11 +103,11 @@ kotlin {
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdkVersion(33)
|
||||
namespace = "chat.simplex.common"
|
||||
compileSdk = 33
|
||||
sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml")
|
||||
defaultConfig {
|
||||
minSdkVersion(26)
|
||||
targetSdkVersion(33)
|
||||
minSdk = 26
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
@@ -123,11 +122,17 @@ android {
|
||||
// No other ways to exclude a file work but it's large and should be excluded
|
||||
kotlin.sourceSets["commonMain"].resources.exclude("/MR/fonts/NotoColorEmoji-Regular.ttf")
|
||||
}
|
||||
kotlin {
|
||||
jvmToolchain(8)
|
||||
}
|
||||
lint {
|
||||
disable += "MissingTranslation"
|
||||
disable += "ExtraTranslation"
|
||||
}
|
||||
}
|
||||
|
||||
multiplatformResources {
|
||||
multiplatformResourcesPackage = "chat.simplex.res"
|
||||
// multiplatformResourcesClassName = "MR"
|
||||
}
|
||||
|
||||
buildConfig {
|
||||
@@ -137,97 +142,3 @@ buildConfig {
|
||||
buildConfigField("String", "DESKTOP_VERSION_NAME", "\"${extra["desktop.version_name"]}\"")
|
||||
}
|
||||
}
|
||||
|
||||
afterEvaluate {
|
||||
tasks.named("generateMRcommonMain") {
|
||||
dependsOn("adjustFormatting")
|
||||
}
|
||||
tasks.create("adjustFormatting") {
|
||||
doLast {
|
||||
val debug = false
|
||||
val stringRegex = Regex(".*<string .*</string>.*")
|
||||
val startStringRegex = Regex("<string [^>]*>")
|
||||
val endStringRegex = Regex("</string>[ ]*")
|
||||
val endTagRegex = Regex("</")
|
||||
val anyHtmlRegex = Regex("[^>]*>.*(<|>).*</string>|[^>]*>.*(<|>).*</string>")
|
||||
val correctHtmlRegex = Regex("[^>]*>.*<b>.*</b>.*</string>|[^>]*>.*<i>.*</i>.*</string>|[^>]*>.*<u>.*</u>.*</string>|[^>]*>.*<font[^>]*>.*</font>.*</string>")
|
||||
|
||||
fun String.removeCDATA(): String =
|
||||
if (contains("<![CDATA")) {
|
||||
replace("<![CDATA[", "").replace("]]></string>", "</string>")
|
||||
} else {
|
||||
this
|
||||
}
|
||||
|
||||
fun String.addCDATA(filepath: String): String {
|
||||
//return this
|
||||
if (anyHtmlRegex.matches(this)) {
|
||||
val countOfStartTag = count { it == '<' }
|
||||
val countOfEndTag = count { it == '>' }
|
||||
if (countOfStartTag != countOfEndTag || countOfStartTag != endTagRegex.findAll(this).count() * 2 || !correctHtmlRegex.matches(this)) {
|
||||
if (debug) {
|
||||
println("Wrong string:")
|
||||
println(this)
|
||||
println("in $filepath")
|
||||
println(" ")
|
||||
} else {
|
||||
throw Exception("Wrong string: $this \nin $filepath")
|
||||
}
|
||||
}
|
||||
val res = replace(startStringRegex) { it.value + "<![CDATA[" }.replace(endStringRegex) { "]]>" + it.value }
|
||||
if (debug) {
|
||||
println("Changed string:")
|
||||
println(this)
|
||||
println(res)
|
||||
println(" ")
|
||||
}
|
||||
return res
|
||||
}
|
||||
if (debug) {
|
||||
println("Correct string:")
|
||||
println(this)
|
||||
println(" ")
|
||||
}
|
||||
return this
|
||||
}
|
||||
val fileRegex = Regex("MR/../strings.xml$|MR/..-.../strings.xml$|MR/..-../strings.xml$|MR/base/strings.xml$")
|
||||
kotlin.sourceSets["commonMain"].resources.filter { fileRegex.containsMatchIn(it.absolutePath) }.asFileTree.forEach { file ->
|
||||
val initialLines = ArrayList<String>()
|
||||
val finalLines = ArrayList<String>()
|
||||
file.useLines { lines ->
|
||||
val multiline = ArrayList<String>()
|
||||
lines.forEach { line ->
|
||||
initialLines.add(line)
|
||||
if (stringRegex.matches(line)) {
|
||||
finalLines.add(line.removeCDATA().addCDATA(file.absolutePath))
|
||||
} else if (multiline.isEmpty() && startStringRegex.containsMatchIn(line)) {
|
||||
multiline.add(line)
|
||||
} else if (multiline.isNotEmpty() && endStringRegex.containsMatchIn(line)) {
|
||||
multiline.add(line)
|
||||
finalLines.addAll(multiline.joinToString("\n").removeCDATA().addCDATA(file.absolutePath).split("\n"))
|
||||
multiline.clear()
|
||||
} else if (multiline.isNotEmpty()) {
|
||||
multiline.add(line)
|
||||
} else {
|
||||
finalLines.add(line)
|
||||
}
|
||||
}
|
||||
if (multiline.isNotEmpty()) {
|
||||
throw Exception("Unclosed string tag: ${multiline.joinToString("\n")} \nin ${file.absolutePath}")
|
||||
}
|
||||
}
|
||||
|
||||
if (!debug && finalLines != initialLines) {
|
||||
file.writer().use {
|
||||
finalLines.forEachIndexed { index, line ->
|
||||
it.write(line)
|
||||
if (index != finalLines.lastIndex) {
|
||||
it.write("\n")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="chat.simplex.common">
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
</manifest>
|
||||
|
||||
+21
-3
@@ -92,6 +92,7 @@ class AppPreferences {
|
||||
set = fun(mode: SimplexLinkMode) { _simplexLinkMode.set(mode.name) }
|
||||
)
|
||||
val privacyDeliveryReceiptsSet = mkBoolPreference(SHARED_PREFS_PRIVACY_DELIVERY_RECEIPTS_SET, false)
|
||||
val privacyFullBackup = mkBoolPreference(SHARED_PREFS_PRIVACY_FULL_BACKUP, false)
|
||||
val experimentalCalls = mkBoolPreference(SHARED_PREFS_EXPERIMENTAL_CALLS, false)
|
||||
val showUnreadAndFavorites = mkBoolPreference(SHARED_PREFS_SHOW_UNREAD_AND_FAVORITES, false)
|
||||
val chatArchiveName = mkStrPreference(SHARED_PREFS_CHAT_ARCHIVE_NAME, null)
|
||||
@@ -400,15 +401,19 @@ object ChatController {
|
||||
|
||||
return withContext(Dispatchers.IO) {
|
||||
val c = cmd.cmdString
|
||||
chatModel.addTerminalItem(TerminalItem.cmd(cmd.obfuscated))
|
||||
Log.d(TAG, "sendCmd: ${cmd.cmdType}")
|
||||
if (cmd !is CC.ApiParseMarkdown) {
|
||||
chatModel.addTerminalItem(TerminalItem.cmd(cmd.obfuscated))
|
||||
Log.d(TAG, "sendCmd: ${cmd.cmdType}")
|
||||
}
|
||||
val json = chatSendCmd(ctrl, c)
|
||||
val r = APIResponse.decodeStr(json)
|
||||
Log.d(TAG, "sendCmd response type ${r.resp.responseType}")
|
||||
if (r.resp is CR.Response || r.resp is CR.Invalid) {
|
||||
Log.d(TAG, "sendCmd response json $json")
|
||||
}
|
||||
chatModel.addTerminalItem(TerminalItem.resp(r.resp))
|
||||
if (r.resp !is CR.ParsedMarkdown) {
|
||||
chatModel.addTerminalItem(TerminalItem.resp(r.resp))
|
||||
}
|
||||
r.resp
|
||||
}
|
||||
}
|
||||
@@ -1285,6 +1290,13 @@ object ChatController {
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun apiParseMarkdown(text: String): List<FormattedText>? {
|
||||
val r = sendCmd(CC.ApiParseMarkdown(text))
|
||||
if (r is CR.ParsedMarkdown) return r.formattedText
|
||||
Log.e(TAG, "apiParseMarkdown bad response: ${r.responseType} ${r.details}")
|
||||
return null
|
||||
}
|
||||
|
||||
private fun networkErrorAlert(r: CR): Boolean {
|
||||
return when {
|
||||
r is CR.ChatCmdError && r.chatError is ChatError.ChatErrorAgent
|
||||
@@ -1845,6 +1857,7 @@ sealed class CC {
|
||||
class ApiListContacts(val userId: Long): CC()
|
||||
class ApiUpdateProfile(val userId: Long, val profile: Profile): CC()
|
||||
class ApiSetContactPrefs(val contactId: Long, val prefs: ChatPreferences): CC()
|
||||
class ApiParseMarkdown(val text: String): CC()
|
||||
class ApiSetContactAlias(val contactId: Long, val localAlias: String): CC()
|
||||
class ApiSetConnectionAlias(val connId: Long, val localAlias: String): CC()
|
||||
class ApiCreateMyAddress(val userId: Long): CC()
|
||||
@@ -1950,6 +1963,7 @@ sealed class CC {
|
||||
is ApiListContacts -> "/_contacts $userId"
|
||||
is ApiUpdateProfile -> "/_profile $userId ${json.encodeToString(profile)}"
|
||||
is ApiSetContactPrefs -> "/_set prefs @$contactId ${json.encodeToString(prefs)}"
|
||||
is ApiParseMarkdown -> "/_parse $text"
|
||||
is ApiSetContactAlias -> "/_set alias @$contactId ${localAlias.trim()}"
|
||||
is ApiSetConnectionAlias -> "/_set alias :$connId ${localAlias.trim()}"
|
||||
is ApiCreateMyAddress -> "/_address $userId"
|
||||
@@ -2044,6 +2058,7 @@ sealed class CC {
|
||||
is ApiListContacts -> "apiListContacts"
|
||||
is ApiUpdateProfile -> "apiUpdateProfile"
|
||||
is ApiSetContactPrefs -> "apiSetContactPrefs"
|
||||
is ApiParseMarkdown -> "apiParseMarkdown"
|
||||
is ApiSetContactAlias -> "apiSetContactAlias"
|
||||
is ApiSetConnectionAlias -> "apiSetConnectionAlias"
|
||||
is ApiCreateMyAddress -> "apiCreateMyAddress"
|
||||
@@ -3325,6 +3340,7 @@ sealed class CR {
|
||||
@Serializable @SerialName("newContactConnection") class NewContactConnection(val user: User, val connection: PendingContactConnection): CR()
|
||||
@Serializable @SerialName("contactConnectionDeleted") class ContactConnectionDeleted(val user: User, val connection: PendingContactConnection): CR()
|
||||
@Serializable @SerialName("versionInfo") class VersionInfo(val versionInfo: CoreVersionInfo, val chatMigrations: List<UpMigration>, val agentMigrations: List<UpMigration>): CR()
|
||||
@Serializable @SerialName("apiParsedMarkdown") class ParsedMarkdown(val formattedText: List<FormattedText>? = null): CR()
|
||||
@Serializable @SerialName("cmdOk") class CmdOk(val user: User?): CR()
|
||||
@Serializable @SerialName("chatCmdError") class ChatCmdError(val user_: User?, val chatError: ChatError): CR()
|
||||
@Serializable @SerialName("chatError") class ChatRespError(val user_: User?, val chatError: ChatError): CR()
|
||||
@@ -3449,6 +3465,7 @@ sealed class CR {
|
||||
is NewContactConnection -> "newContactConnection"
|
||||
is ContactConnectionDeleted -> "contactConnectionDeleted"
|
||||
is VersionInfo -> "versionInfo"
|
||||
is ParsedMarkdown -> "apiParsedMarkdown"
|
||||
is CmdOk -> "cmdOk"
|
||||
is ChatCmdError -> "chatCmdError"
|
||||
is ChatRespError -> "chatError"
|
||||
@@ -3501,6 +3518,7 @@ sealed class CR {
|
||||
is ContactAliasUpdated -> withUser(user, json.encodeToString(toContact))
|
||||
is ConnectionAliasUpdated -> withUser(user, json.encodeToString(toConnection))
|
||||
is ContactPrefsUpdated -> withUser(user, "fromContact: $fromContact\ntoContact: \n${json.encodeToString(toContact)}")
|
||||
is ParsedMarkdown -> json.encodeToString(formattedText)
|
||||
is UserContactLink -> withUser(user, contactLink.responseDetails)
|
||||
is UserContactLinkUpdated -> withUser(user, contactLink.responseDetails)
|
||||
is UserContactLinkCreated -> withUser(user, connReqContact)
|
||||
|
||||
+3
-8
@@ -400,7 +400,6 @@ fun LocalAliasEditor(
|
||||
updateValue: (String) -> Unit
|
||||
) {
|
||||
var value by rememberSaveable { mutableStateOf(initialValue) }
|
||||
var updatedValueAtLeastOnce = remember { false }
|
||||
val modifier = if (center)
|
||||
Modifier.padding(horizontal = if (!leadingIcon) DEFAULT_PADDING else 0.dp).widthIn(min = 100.dp)
|
||||
else
|
||||
@@ -425,23 +424,19 @@ fun LocalAliasEditor(
|
||||
keyboardActions = KeyboardActions(onDone = { updateValue(value) })
|
||||
) {
|
||||
value = it
|
||||
updatedValueAtLeastOnce = true
|
||||
}
|
||||
}
|
||||
LaunchedEffect(Unit) {
|
||||
var prevValue = value
|
||||
snapshotFlow { value }
|
||||
.distinctUntilChanged()
|
||||
.onEach { delay(500) } // wait a little after every new character, don't emit until user stops typing
|
||||
.conflate() // get the latest value
|
||||
.filter { it == value && it != prevValue } // don't process old ones
|
||||
.filter { it == value } // don't process old ones
|
||||
.collect {
|
||||
updateValue(it)
|
||||
prevValue = it
|
||||
updateValue(value)
|
||||
}
|
||||
}
|
||||
DisposableEffect(Unit) {
|
||||
onDispose { if (updatedValueAtLeastOnce) updateValue(value) } // just in case snapshotFlow will be canceled when user presses Back too fast
|
||||
onDispose { updateValue(value) } // just in case snapshotFlow will be canceled when user presses Back too fast
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -240,7 +240,7 @@ fun ComposeView(
|
||||
link.startsWith("https://simplex.chat", true) || link.startsWith("http://simplex.chat", true)
|
||||
|
||||
fun parseMessage(msg: String): String? {
|
||||
val parsedMsg = parseToMarkdown(msg)
|
||||
val parsedMsg = runBlocking { chatModel.controller.apiParseMarkdown(msg) }
|
||||
val link = parsedMsg?.firstOrNull { ft -> ft.format is Format.Uri && !cancelledLinks.contains(ft.text) && !isSimplexLink(ft.text) }
|
||||
return link?.text
|
||||
}
|
||||
|
||||
+3
-13
@@ -64,22 +64,12 @@ fun SendMsgView(
|
||||
|
||||
Box(Modifier.padding(vertical = 8.dp)) {
|
||||
val cs = composeState.value
|
||||
var progressByTimeout by rememberSaveable { mutableStateOf(false) }
|
||||
LaunchedEffect(composeState.value.inProgress) {
|
||||
progressByTimeout = if (composeState.value.inProgress) {
|
||||
delay(500)
|
||||
composeState.value.inProgress
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
val showProgress = cs.inProgress && (cs.preview is ComposePreview.MediaPreview || cs.preview is ComposePreview.FilePreview)
|
||||
val showVoiceButton = cs.message.isEmpty() && showVoiceRecordIcon && !composeState.value.editing &&
|
||||
cs.liveMessage == null && (cs.preview is ComposePreview.NoPreview || recState.value is RecordingState.Started)
|
||||
val showDeleteTextButton = rememberSaveable { mutableStateOf(false) }
|
||||
PlatformTextField(composeState, textStyle, showDeleteTextButton, userIsObserver, onMessageChange, editPrevMessage) {
|
||||
if (!cs.inProgress) {
|
||||
sendMessage(null)
|
||||
}
|
||||
sendMessage(null)
|
||||
}
|
||||
// Disable clicks on text field
|
||||
if (cs.preview is ComposePreview.VoicePreview || !userCanSend || cs.inProgress) {
|
||||
@@ -108,7 +98,7 @@ fun SendMsgView(
|
||||
}
|
||||
}
|
||||
when {
|
||||
progressByTimeout -> ProgressIndicator()
|
||||
showProgress -> ProgressIndicator()
|
||||
showVoiceButton -> {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
val stopRecOnNextClick = remember { mutableStateOf(false) }
|
||||
|
||||
+29
-7
@@ -78,6 +78,7 @@ fun DatabaseView(
|
||||
chatArchiveName,
|
||||
chatArchiveTime,
|
||||
chatLastStart,
|
||||
m.controller.appPrefs.privacyFullBackup,
|
||||
appFilesCountAndSize,
|
||||
chatItemTTL,
|
||||
m.currentUser.value,
|
||||
@@ -127,6 +128,7 @@ fun DatabaseLayout(
|
||||
chatArchiveName: MutableState<String?>,
|
||||
chatArchiveTime: MutableState<Instant?>,
|
||||
chatLastStart: MutableState<Instant?>,
|
||||
privacyFullBackup: SharedPreference<Boolean>,
|
||||
appFilesCountAndSize: MutableState<Pair<Int, Long>>,
|
||||
chatItemTTL: MutableState<ChatItemTTL>,
|
||||
currentUser: User?,
|
||||
@@ -166,13 +168,6 @@ fun DatabaseLayout(
|
||||
SectionView(stringResource(MR.strings.run_chat_section)) {
|
||||
RunChatSetting(runChat, stopped, startChat, stopChatAlert)
|
||||
}
|
||||
SectionTextFooter(
|
||||
if (stopped) {
|
||||
stringResource(MR.strings.you_must_use_the_most_recent_version_of_database)
|
||||
} else {
|
||||
stringResource(MR.strings.stop_chat_to_enable_database_actions)
|
||||
}
|
||||
)
|
||||
SectionDividerSpaced()
|
||||
|
||||
SectionView(stringResource(MR.strings.chat_database_section)) {
|
||||
@@ -185,6 +180,8 @@ fun DatabaseLayout(
|
||||
iconColor = if (unencrypted) WarningOrange else MaterialTheme.colors.secondary,
|
||||
disabled = operationsDisabled
|
||||
)
|
||||
AppDataBackupPreference(privacyFullBackup, initialRandomDBPassphrase)
|
||||
SectionDividerSpaced(maxBottomPadding = false)
|
||||
SettingsActionItem(
|
||||
painterResource(MR.images.ic_ios_share),
|
||||
stringResource(MR.strings.export_database),
|
||||
@@ -228,6 +225,13 @@ fun DatabaseLayout(
|
||||
disabled = operationsDisabled
|
||||
)
|
||||
}
|
||||
SectionTextFooter(
|
||||
if (stopped) {
|
||||
stringResource(MR.strings.you_must_use_the_most_recent_version_of_database)
|
||||
} else {
|
||||
stringResource(MR.strings.stop_chat_to_enable_database_actions)
|
||||
}
|
||||
)
|
||||
SectionDividerSpaced(maxTopPadding = true)
|
||||
|
||||
SectionView(stringResource(MR.strings.files_and_media_section).uppercase()) {
|
||||
@@ -254,6 +258,23 @@ fun DatabaseLayout(
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun AppDataBackupPreference(privacyFullBackup: SharedPreference<Boolean>, initialRandomDBPassphrase: SharedPreference<Boolean>) {
|
||||
SettingsPreferenceItem(
|
||||
painterResource(MR.images.ic_backup),
|
||||
iconColor = MaterialTheme.colors.secondary,
|
||||
pref = privacyFullBackup,
|
||||
text = stringResource(MR.strings.full_backup)
|
||||
) {
|
||||
if (initialRandomDBPassphrase.get()) {
|
||||
exportProhibitedAlert()
|
||||
privacyFullBackup.set(false)
|
||||
} else {
|
||||
privacyFullBackup.set(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setChatItemTTLAlert(
|
||||
m: ChatModel, selectedChatItemTTL: MutableState<ChatItemTTL>,
|
||||
progressIndicator: MutableState<Boolean>,
|
||||
@@ -662,6 +683,7 @@ fun PreviewDatabaseLayout() {
|
||||
chatArchiveName = remember { mutableStateOf("dummy_archive") },
|
||||
chatArchiveTime = remember { mutableStateOf(Clock.System.now()) },
|
||||
chatLastStart = remember { mutableStateOf(Clock.System.now()) },
|
||||
privacyFullBackup = SharedPreference({ true }, {}),
|
||||
appFilesCountAndSize = remember { mutableStateOf(0 to 0L) },
|
||||
chatItemTTL = remember { mutableStateOf(ChatItemTTL.None) },
|
||||
currentUser = User.sampleData,
|
||||
|
||||
+2
-5
@@ -201,7 +201,6 @@ object AppearanceScope {
|
||||
val supportedLanguages = mapOf(
|
||||
"system" to generalGetString(MR.strings.language_system),
|
||||
"en" to "English",
|
||||
"bg" to "Български",
|
||||
"cs" to "Čeština",
|
||||
"de" to "Deutsch",
|
||||
"es" to "Español",
|
||||
@@ -214,7 +213,7 @@ object AppearanceScope {
|
||||
"ru" to "Русский",
|
||||
"zh-CN" to "简体中文"
|
||||
)
|
||||
val values by remember(ChatController.appPrefs.appLanguage.state.value) { mutableStateOf(supportedLanguages.map { it.key to it.value }) }
|
||||
val values by remember { mutableStateOf(supportedLanguages.map { it.key to it.value }) }
|
||||
ExposedDropDownSettingRow(
|
||||
generalGetString(MR.strings.settings_section_title_language).lowercase().replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.US) else it.toString() },
|
||||
values,
|
||||
@@ -228,9 +227,7 @@ object AppearanceScope {
|
||||
@Composable
|
||||
private fun ThemeSelector(state: State<String>, onSelected: (String) -> Unit) {
|
||||
val darkTheme = chat.simplex.common.ui.theme.isSystemInDarkTheme()
|
||||
val values by remember(ChatController.appPrefs.appLanguage.state.value) {
|
||||
mutableStateOf(ThemeManager.allThemes(darkTheme).map { it.second.name to it.third })
|
||||
}
|
||||
val values by remember { mutableStateOf(ThemeManager.allThemes(darkTheme).map { it.second.name to it.third }) }
|
||||
ExposedDropDownSettingRow(
|
||||
generalGetString(MR.strings.theme),
|
||||
values,
|
||||
|
||||
@@ -147,7 +147,7 @@
|
||||
<string name="rcv_conn_event_switch_queue_phase_completed">تم تغيير العنوان من أجلك</string>
|
||||
<string name="cant_delete_user_profile">لا يمكن حذف ملف تعريف المستخدم!</string>
|
||||
<string name="icon_descr_video_asked_to_receive">طلب لاستلام الفيديو</string>
|
||||
<string name="add_new_contact_to_create_one_time_QR_code"><![CDATA[<b> إضافة جهة اتصال جديدة </b>: لإنشاء رمز الاستجابة السريعة الخاص بك لمرة واحدة لجهة اتصالك.]]></string>
|
||||
<string name="add_new_contact_to_create_one_time_QR_code"><b> إضافة جهة اتصال جديدة </b>: لإنشاء رمز الاستجابة السريعة الخاص بك لمرة واحدة لجهة اتصالك.</string>
|
||||
<string name="scan_QR_code_to_connect_to_contact_who_shows_QR_code"><![CDATA[<b> امسح رمز الاستجابة السريعة </b>: للاتصال بجهة الاتصال التي تعرض لك رمز الاستجابة السريعة.]]></string>
|
||||
<string name="callstatus_in_progress">مكالمتك تحت الإجراء</string>
|
||||
<string name="callstatus_ended">انتهت المكالمة</string>
|
||||
@@ -414,7 +414,7 @@
|
||||
<string name="settings_developer_tools">أدوات المطور</string>
|
||||
<string name="smp_server_test_delete_queue">حذف قائمة الانتظار</string>
|
||||
<string name="error_updating_user_privacy">خطأ في تحديث خصوصية المستخدم</string>
|
||||
<string name="desktop_scan_QR_code_from_app_via_scan_QR_code"><![CDATA[💻 سطح المكتب: امسح رمز الاستجابة السريعة (QR) المعروض من التطبيق، عبر <b>مسح رمز QR</b>.]]></string>
|
||||
<string name="desktop_scan_QR_code_from_app_via_scan_QR_code">💻 سطح المكتب: امسح رمز الاستجابة السريعة (QR) المعروض من التطبيق، عبر <b>مسح رمز QR</b>.</string>
|
||||
<string name="delete_profile">حذف ملف التعريف</string>
|
||||
<string name="smp_servers_delete_server">حذف الخادم</string>
|
||||
<string name="error_updating_link_for_group">خطأ في تحديث ارتباط المجموعة</string>
|
||||
@@ -498,7 +498,7 @@
|
||||
<string name="custom_time_unit_hours">ساعات</string>
|
||||
<string name="edit_history">السجل</string>
|
||||
<string name="image_will_be_received_when_contact_completes_uploading">سيتم استلام الصورة عند اكتمال تحميل جهة اتصالك.</string>
|
||||
<string name="if_you_cannot_meet_in_person_show_QR_in_video_call_or_via_another_channel"><![CDATA[إذا لم تتمكن من الالتقاء شخصيًا، <b>اعرض رمز الاستجابة السريعة في مكالمة الفيديو</b>، أو شارك الرابط.]]></string>
|
||||
<string name="if_you_cannot_meet_in_person_show_QR_in_video_call_or_via_another_channel">إذا لم تتمكن من الالتقاء شخصيًا، <b>اعرض رمز الاستجابة السريعة في مكالمة الفيديو</b>، أو شارك الرابط.</string>
|
||||
<string name="install_simplex_chat_for_terminal">ثبّت SimpleX Chat لطرفية</string>
|
||||
<string name="network_disable_socks_info">إذا قمت بالتأكيد، فستتمكن خوادم المراسلة من رؤية عنوان IP الخاص بك ومزود الخدمة الخاص بك - أي الخوادم التي تتصل بها.</string>
|
||||
<string name="hide_dev_options">إخفاء:</string>
|
||||
@@ -521,7 +521,7 @@
|
||||
<string name="info_menu">المعلومات</string>
|
||||
<string name="v4_3_improved_privacy_and_security_desc">إخفاء شاشة التطبيق في التطبيقات الحديثة.</string>
|
||||
<string name="v4_3_improved_privacy_and_security">تحسن الخصوصية والأمان</string>
|
||||
<string name="if_you_cannot_meet_in_person_scan_QR_in_video_call_or_ask_for_invitation_link"><![CDATA[إذا لم تتمكن من الالتقاء شخصيًا، فيمكنك <b>مسح رمز QR في مكالمة الفيديو</b>، أو يمكن لجهة الاتصال مشاركة رابط الدعوة.]]></string>
|
||||
<string name="if_you_cannot_meet_in_person_scan_QR_in_video_call_or_ask_for_invitation_link">إذا لم تتمكن من الالتقاء شخصيًا، فيمكنك <b>مسح رمز QR في مكالمة الفيديو</b>، أو يمكن لجهة الاتصال مشاركة رابط الدعوة.</string>
|
||||
<string name="immune_to_spam_and_abuse">محصن ضد البريد العشوائي وسوء المعاملة</string>
|
||||
<string name="description_via_one_time_link_incognito">التخفي عبر رابط لمرة واحدة</string>
|
||||
<string name="icon_descr_image_snd_complete">أرسلت صورة</string>
|
||||
@@ -541,7 +541,7 @@
|
||||
<string name="onboarding_notifications_mode_service">فوري</string>
|
||||
<string name="host_verb">المضيف</string>
|
||||
<string name="hide_notification">إخفاء</string>
|
||||
<string name="turn_off_battery_optimization"><![CDATA[من أجل استخدامها، يرجى <b>تعطيل تحسين البطارية</b> لSimpleX في مربع الحوار التالي. وإلا، سيتم تعطيل الإخطارات.]]></string>
|
||||
<string name="turn_off_battery_optimization">من أجل استخدامها، يرجى <b>تعطيل تحسين البطارية</b> لSimpleX في مربع الحوار التالي. وإلا، سيتم تعطيل الإخطارات.</string>
|
||||
<string name="in_reply_to">ردًا على</string>
|
||||
<string name="icon_descr_instant_notifications">إشعارات فورية</string>
|
||||
<string name="enter_one_ICE_server_per_line">خوادم ICE (واحد لكل سطر)</string>
|
||||
@@ -716,7 +716,7 @@
|
||||
<string name="ensure_ICE_server_address_are_correct_format_and_unique">تأكد من أن عناوين خادم WebRTC ICE بالتنسيق الصحيح، وأن تكون مفصولة بأسطر وليست مكررة.</string>
|
||||
<string name="mark_code_verified">وضع علامة تَحقق منه</string>
|
||||
<string name="error_saving_user_password">خطأ في حفظ كلمة مرور المستخدم</string>
|
||||
<string name="many_people_asked_how_can_it_deliver"><![CDATA[سأل الكثير من الناس: <i>إذا SimpleX ليس لديه معرّفات مستخدم، كيف يمكنه توصيل الرسائل؟</i>]]></string>
|
||||
<string name="many_people_asked_how_can_it_deliver">سأل الكثير من الناس: <i>إذا SimpleX ليس لديه معرّفات مستخدم، كيف يمكنه توصيل الرسائل؟</i></string>
|
||||
<string name="error_saving_group_profile">خطأ في حفظ ملف تعريف المجموعة</string>
|
||||
<string name="notification_preview_mode_message">رسالة نصية</string>
|
||||
<string name="message_reactions">ردود فعل الرسائل</string>
|
||||
@@ -725,7 +725,7 @@
|
||||
<string name="message_delivery_error_title">خطأ في تسليم الرسالة</string>
|
||||
<string name="network_and_servers">الشبكة والخوادم</string>
|
||||
<string name="moderate_verb">إشراف</string>
|
||||
<string name="mobile_tap_open_in_mobile_app_then_tap_connect_in_app"><![CDATA[📱 للجوال: انقر فوق <b>فتح في تطبيق الجوال</b> ، ثم انقر فوق <b>اتصال</b> في التطبيق.]]></string>
|
||||
<string name="mobile_tap_open_in_mobile_app_then_tap_connect_in_app">📱 للجوال: انقر فوق <b>فتح في تطبيق الجوال</b> ، ثم انقر فوق <b>اتصال</b> في التطبيق.</string>
|
||||
<string name="share_text_moderated_at">تحت الإشراف في: %s</string>
|
||||
<string name="message_reactions_prohibited_in_this_chat">ردود الفعل الرسائل ممنوعة في هذه الدردشة.</string>
|
||||
<string name="moderated_item_description">مُشرف بواسطة %s</string>
|
||||
@@ -839,7 +839,7 @@
|
||||
<string name="call_connection_peer_to_peer">ند لند</string>
|
||||
<string name="people_can_connect_only_via_links_you_share">يمكن للناس التواصل معك فقط عبر الرابط الذي تقوم بمشاركته</string>
|
||||
<string name="icon_descr_call_pending_sent">مكالمة في الانتظار</string>
|
||||
<string name="only_client_devices_store_contacts_groups_e2e_encrypted_messages"><![CDATA[تقوم أجهزة العميل فقط بتخزين ملفات تعريف المستخدمين وجهات الاتصال والمجموعات والرسائل المرسلة باستخدام <b>تشفير ثنائي الطبقات من بين الطريفين</b>.]]></string>
|
||||
<string name="only_client_devices_store_contacts_groups_e2e_encrypted_messages">تقوم أجهزة العميل فقط بتخزين ملفات تعريف المستخدمين وجهات الاتصال والمجموعات والرسائل المرسلة باستخدام <b>تشفير ثنائي الطبقات من بين الطريفين</b>.</string>
|
||||
<string name="reset_color">إعادة تعيين الألوان</string>
|
||||
<string name="save_verb">حفظ</string>
|
||||
<string name="smp_servers_preset_address">عنوان الخادم المحدد مسبقًا</string>
|
||||
@@ -853,7 +853,7 @@
|
||||
<string name="onboarding_notifications_mode_title">الإشعارات خاصة</string>
|
||||
<string name="store_passphrase_securely_without_recover">يرجى تخزين عبارة المرور بشكل آمن، فلن تتمكن من الوصول إلى الدردشة إذا فقدتها.</string>
|
||||
<string name="contact_developers">يرجى تحديث التطبيق والاتصال بالمطورين.</string>
|
||||
<string name="read_more_in_user_guide_with_link"><![CDATA[اقرأ المزيد في <font color="#0088ff">دليل المستخدم</font>.]]></string>
|
||||
<string name="read_more_in_user_guide_with_link">اقرأ المزيد في <font color=#0088ff>دليل المستخدم</font>.</string>
|
||||
<string name="auth_open_chat_profiles">افتح ملفات تعريف الدردشة</string>
|
||||
<string name="revoke_file__confirm">اسحب الوصول</string>
|
||||
<string name="save_archive">حفظ الأرشيف</string>
|
||||
@@ -878,7 +878,7 @@
|
||||
<string name="saved_ICE_servers_will_be_removed">ستتم إزالة خوادم WebRTC ICE المحفوظة.</string>
|
||||
<string name="prohibit_sending_files">منع إرسال الملفات والوسائط.</string>
|
||||
<string name="callstate_received_answer">استلمت إجابة…</string>
|
||||
<string name="read_more_in_github_with_link"><![CDATA[اقرأ المزيد في <font color="#0088ff">مستودع GitHub</font>.]]></string>
|
||||
<string name="read_more_in_github_with_link">اقرأ المزيد في <font color=#0088ff>مستودع GitHub</font>.</string>
|
||||
<string name="reject">رفض</string>
|
||||
<string name="relay_server_protects_ip">يحمي خادم الترحيل عنوان IP الخاص بك، ولكن يمكنه مراقبة مدة المكالمة.</string>
|
||||
<string name="restore_database_alert_desc">الرجاء إدخال كلمة المرور السابقة بعد استعادة نسخة احتياطية لقاعدة البيانات. لا يمكن التراجع عن هذا الإجراء.</string>
|
||||
@@ -1090,7 +1090,7 @@
|
||||
<string name="stop_file__action">إيقاف الملف</string>
|
||||
<string name="stop_snd_file__title">التوقف عن استلام الملف؟</string>
|
||||
<string name="icon_descr_address">عنوان SimpleX</string>
|
||||
<string name="disable_onion_hosts_when_not_supported"><![CDATA[اضبط <i>استخدم مضيفي .onion</i> إلى \"لا\" إذا كان وكيل SOCKS لا يدعمها.]]></string>
|
||||
<string name="disable_onion_hosts_when_not_supported">اضبط <i>استخدم مضيفي .onion</i> إلى \"لا\" إذا كان وكيل SOCKS لا يدعمها.</string>
|
||||
<string name="share_with_contacts">مشاركة مع جهات الاتصال</string>
|
||||
<string name="shutdown_alert_question">إيقاف التشغيل؟</string>
|
||||
<string name="network_socks_proxy_settings">إعدادات وكيل SOCKS</string>
|
||||
@@ -1117,7 +1117,7 @@
|
||||
<string name="v4_4_french_interface_descr">بفضل المستخدمين - المساهمة عبر Weblate!</string>
|
||||
<string name="v4_6_audio_video_calls_descr">دعم البلوتوث وتحسينات أخرى.</string>
|
||||
<string name="v5_0_polish_interface_descr">بفضل المستخدمين - المساهمة عبر Weblate!</string>
|
||||
<string name="to_preserve_privacy_simplex_has_background_service_instead_of_push_notifications_it_uses_a_few_pc_battery"><![CDATA[للحفاظ على خصوصيتك، بدلاً من دفع الإشعارات، يحتوي التطبيق على <b>خدمة SimpleX تعمل في الخلفية</b> – يستخدم نسبة قليلة من البطارية يوميًا.]]></string>
|
||||
<string name="to_preserve_privacy_simplex_has_background_service_instead_of_push_notifications_it_uses_a_few_pc_battery">للحفاظ على خصوصيتك، بدلاً من دفع الإشعارات، يحتوي التطبيق على <b>خدمة SimpleX تعمل في الخلفية</b> – يستخدم نسبة قليلة من البطارية يوميًا.</string>
|
||||
<string name="tap_to_start_new_chat">انقر لبدء محادثة جديدة</string>
|
||||
<string name="to_share_with_your_contact">(للمشاركة مع جهة اتصالك)</string>
|
||||
<string name="to_connect_via_link_title">للتواصل عبر الرابط</string>
|
||||
@@ -1240,7 +1240,7 @@
|
||||
<string name="snd_group_event_user_left">غادرت</string>
|
||||
<string name="you_must_use_the_most_recent_version_of_database">يجب عليك استخدام أحدث إصدار من قاعدة بيانات الدردشة الخاصة بك على جهاز واحد فقط، وإلا فقد تتوقف عن تلقي الرسائل من بعض جهات الاتصال.</string>
|
||||
<string name="video_will_be_received_when_contact_is_online">سيتم استلام الفيديو عندما تكون جهة اتصالك متصلة بالإنترنت، يرجى الانتظار أو التحقق لاحقًا!</string>
|
||||
<string name="you_control_servers_to_receive_your_contacts_to_send"><![CDATA[يمكنك التحكم من خلال الخادم (الخوادم) <b>لتلقي</b> الرسائل وجهات اتصالك - الخوادم التي تستخدمها لمراسلتهم.]]></string>
|
||||
<string name="you_control_servers_to_receive_your_contacts_to_send">يمكنك التحكم من خلال الخادم (الخوادم) <b>لتلقي</b> الرسائل وجهات اتصالك - الخوادم التي تستخدمها لمراسلتهم.</string>
|
||||
<string name="you_can_share_this_address_with_your_contacts">يمكنك مشاركة هذا العنوان مع جهات اتصالك للسماح لهم بالاتصال بـ%s.</string>
|
||||
<string name="snd_group_event_member_deleted">أُزيلت %1$s</string>
|
||||
<string name="update_database">تحديث</string>
|
||||
@@ -1293,7 +1293,7 @@
|
||||
<string name="unhide_profile">إلغاء إخفاء ملف تعريف</string>
|
||||
<string name="alert_text_connection_pending_they_need_to_be_online_can_delete_and_retry">يجب أن تكون جهة الاتصال متصلة بالإنترنت حتى يكتمل الاتصال.
|
||||
\nيمكنك إلغاء هذا الاتصال وإزالة جهة الاتصال (والمحاولة لاحقًا باستخدام رابط جديد).</string>
|
||||
<string name="you_can_also_connect_by_clicking_the_link"><![CDATA[يمكنك أيضًا الاتصال بالضغط على الرابط. إذا تم فتحه في المتصفح، فانقر فوق الزر <b>فتح في تطبيق الجوال</b>.]]></string>
|
||||
<string name="you_can_also_connect_by_clicking_the_link">يمكنك أيضًا الاتصال بالضغط على الرابط. إذا تم فتحه في المتصفح، فانقر فوق الزر <b>فتح في تطبيق الجوال</b>.</string>
|
||||
<string name="smp_servers_use_server_for_new_conn">استخدم للاتصالات الجديدة</string>
|
||||
<string name="smp_servers_use_server">استخدم الخادم</string>
|
||||
<string name="smp_servers_your_server_address">عنوان خادمك</string>
|
||||
@@ -1335,7 +1335,7 @@
|
||||
<string name="observer_cant_send_message_title">لا يمكنك إرسال رسائل!</string>
|
||||
<string name="you_need_to_allow_to_send_voice">تحتاج إلى السماح لجهة الاتصال الخاصة بك بإرسال رسائل صوتية لتتمكن من إرسالها.</string>
|
||||
<string name="contact_sent_large_file">أرسلت جهة اتصالك ملفًا أكبر من الحجم الأقصى المعتمد حاليًا (%1$s).</string>
|
||||
<string name="you_can_connect_to_simplex_chat_founder"><![CDATA[يمكنك <font color=#0088ff>الاتصال بمطوري SimpleX Chat لطرح أي أسئلة وتلقي التحديثات</font>.]]></string>
|
||||
<string name="you_can_connect_to_simplex_chat_founder">يمكنك <font color=#0088ff>الاتصال بمطوري SimpleX Chat لطرح أي أسئلة وتلقي التحديثات</font>.</string>
|
||||
<string name="smp_servers_your_server">خادمك</string>
|
||||
<string name="your_profile_is_stored_on_device_and_shared_only_with_contacts_simplex_cannot_see_it">يُخزن ملف تعريفك على جهازك ومشاركته فقط مع جهات اتصالك. لا تستطيع خوادم SimpleX رؤية ملف تعريفك.</string>
|
||||
<string name="icon_descr_video_off">الفيديو مقفل</string>
|
||||
|
||||
@@ -140,11 +140,11 @@
|
||||
<string name="turn_off_battery_optimization_button">Allow</string>
|
||||
<string name="turn_off_system_restriction_button">Open app settings</string>
|
||||
<string name="disable_notifications_button">Disable notifications</string>
|
||||
<string name="system_restricted_background_desc">SimpleX can\'t run in background. You will receive the notifications only when the app is running.</string>
|
||||
<string name="system_restricted_background_desc"><![CDATA[SimpleX can\'t run in background. You will receive the notifications only when the app is running.]]></string>
|
||||
<string name="system_restricted_background_warn"><![CDATA[To enable notifications, please choose <b>App battery usage</b> / <b>Unrestricted</b> in the app settings.]]></string>
|
||||
<string name="system_restricted_background_in_call_title">No background calls</string>
|
||||
<string name="system_restricted_background_in_call_desc">The app may be closed after 1 minute in background.</string>
|
||||
<string name="system_restricted_background_in_call_warn"><![CDATA[To make calls in background, please choose <b>App battery usage</b> / <b>Unrestricted</b> in the app settings.]]></string>
|
||||
<string name="system_restricted_background_in_call_desc"><![CDATA[The app may be closed after 1 minute in background.]]></string>
|
||||
<string name="system_restricted_background_in_call_warn"><![CDATA[To make calls in background, please choose <b>App battery usage</b> / <b>Unrestricted</b> in the app settings]]>.</string>
|
||||
<string name="enter_passphrase_notification_title">Passphrase is needed</string>
|
||||
<string name="enter_passphrase_notification_desc">To receive notifications, please, enter the database passphrase</string>
|
||||
<string name="database_initialization_error_title">Can\'t initialize the database</string>
|
||||
@@ -1556,4 +1556,4 @@
|
||||
<!-- Under development -->
|
||||
<string name="in_developing_title">Coming soon!</string>
|
||||
<string name="in_developing_desc">This feature is not yet supported. Try the next release.</string>
|
||||
</resources>
|
||||
</resources>
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
<string name="accept_feature">Приеми</string>
|
||||
<string name="color_primary_variant">Допълнителен акцент</string>
|
||||
<string name="v4_2_group_links_desc">Админите могат да създадат линкове за присъединяване към групи.</string>
|
||||
<string name="if_you_cannot_meet_in_person_show_QR_in_video_call_or_via_another_channel"><![CDATA[Ако не можете да се срещнете лично, <b>покажете QR кода във видеоразговора</b> или споделете линка.]]></string>
|
||||
<string name="if_you_cannot_meet_in_person_show_QR_in_video_call_or_via_another_channel">Ако не можете да се срещнете лично, <b>покажете QR кода във видеоразговора</b> или споделете линка.</string>
|
||||
<string name="open_simplex_chat_to_accept_call">Отворете SimpleX Chat, за да приемете повикването</string>
|
||||
<string name="v4_6_audio_video_calls_descr">Поддръжка на bluetooth и други подобрения.</string>
|
||||
<string name="relay_server_protects_ip">Relay сървърът защитава вашия IP адрес, но може да наблюдава продължителността на разговора.</string>
|
||||
@@ -87,9 +87,9 @@
|
||||
<string name="incognito_random_profile_from_contact_description">Произволен профил ще бъде изпратен до контакта, от който сте получили тази връзка</string>
|
||||
<string name="la_authenticate">Идентифицирай</string>
|
||||
<string name="turning_off_service_and_periodic">Оптимизацията на батерията е активна, изключват се фоновата услуга и периодичните заявки за нови съобщения. Можете да ги активирате отново през настройките.</string>
|
||||
<string name="network_session_mode_user_description"><![CDATA[Ще се използва отделна TCP връзка (и идентификационни данни за SOCKS) <b>за всеки чат профил, който имате в приложението</b>.]]></string>
|
||||
<string name="network_session_mode_user_description">Ще се използва отделна TCP връзка (и идентификационни данни за SOCKS) <b>за всеки чат профил, който имате в приложението</b>.</string>
|
||||
<string name="icon_descr_audio_call">аудио разговор</string>
|
||||
<string name="onboarding_notifications_mode_off_desc"><![CDATA[<b>Най-добро за батерията</b>. Ще получавате известия само когато приложението работи (БЕЗ фонова услуга).]]></string>
|
||||
<string name="onboarding_notifications_mode_off_desc"><b>Най-добро за батерията</b>. Ще получавате известия само когато приложението работи (БЕЗ фонова услуга).</string>
|
||||
<string name="network_session_mode_entity_description">Ще се използва отделна TCP връзка (и идентификационни данни за SOCKS) <b>за всеки контакт и член на група</b>.
|
||||
\n<b>Моля, обърнете внимание</b>: ако имате много връзки, консумацията на батерията и трафика може да бъде значително по-висока и някои връзки може да се провалят.</string>
|
||||
<string name="icon_descr_asked_to_receive">Помолен да получи изображението</string>
|
||||
@@ -99,15 +99,15 @@
|
||||
<string name="both_you_and_your_contacts_can_delete">И вие, и вашият контакт можете да изтриете необратимо изпратените съобщения.</string>
|
||||
<string name="auth_unavailable">Идентификацията е недостъпна</string>
|
||||
<string name="both_you_and_your_contact_can_add_message_reactions">И вие, и вашият контакт можете да добавяте реакции към съобщението.</string>
|
||||
<string name="impossible_to_recover_passphrase"><![CDATA[<b>Моля, обърнете внимание</b>: НЯМА да можете да възстановите или промените паролата, ако я загубите.]]></string>
|
||||
<string name="onboarding_notifications_mode_service_desc"><![CDATA[<b>Използва повече батерия</b>! Услугата на заден план винаги работи – известията се показват веднага щом съобщенията са налични.]]></string>
|
||||
<string name="impossible_to_recover_passphrase"><b>Моля, обърнете внимание</b>: НЯМА да можете да възстановите или промените паролата, ако я загубите.</string>
|
||||
<string name="onboarding_notifications_mode_service_desc"><b>Използва повече батерия</b>! Услугата на заден план винаги работи – известията се показват веднага щом съобщенията са налични.</string>
|
||||
<string name="integrity_msg_bad_hash">лош хеш на съобщението</string>
|
||||
<string name="alert_title_msg_bad_hash">Лош хеш на съобщението</string>
|
||||
<string name="no_call_on_lock_screen">Деактивиране</string>
|
||||
<string name="callstatus_calling">повикване…</string>
|
||||
<string name="if_you_cannot_meet_in_person_scan_QR_in_video_call_or_ask_for_invitation_link"><![CDATA[Ако не можете да се срещнете лично, можете <b>да сканирате QR код във видеоразговора</b> или вашият контакт може да сподели линк за покана.]]></string>
|
||||
<string name="if_you_cannot_meet_in_person_scan_QR_in_video_call_or_ask_for_invitation_link">Ако не можете да се срещнете лично, можете <b>да сканирате QR код във видеоразговора</b> или вашият контакт може да сподели линк за покана.</string>
|
||||
<string name="notifications_mode_service_desc">Услугата във фонов режим винаги работи – известията ще се показват веднага щом съобщенията са налични.</string>
|
||||
<string name="it_can_disabled_via_settings_notifications_still_shown"><![CDATA[<b>Може да бъде деактивирано през настройките</b> – известията ще продължат да се показват, докато приложението работи.]]></string>
|
||||
<string name="it_can_disabled_via_settings_notifications_still_shown"><b>Може да бъде деактивирано през настройките</b> – известията ще продължат да се показват, докато приложението работи.</string>
|
||||
<string name="ntf_channel_calls">SimpleX Chat разговори</string>
|
||||
<string name="notifications_mode_periodic">Започва периодично</string>
|
||||
<string name="database_initialization_error_title">Базата данни не може да се стартира</string>
|
||||
@@ -120,8 +120,8 @@
|
||||
<string name="back">Назад</string>
|
||||
<string name="cancel_verb">Отказ</string>
|
||||
<string name="icon_descr_cancel_live_message">Спри живото съобщение</string>
|
||||
<string name="add_new_contact_to_create_one_time_QR_code"><![CDATA[<b>Добави нов контакт</b>: за да създадете своя еднократен QR код за вашия контакт.]]></string>
|
||||
<string name="scan_QR_code_to_connect_to_contact_who_shows_QR_code"><![CDATA[<b>Сканирай QR код</b>: за да се свържете с вашия контакт, който ви показва QR код.]]></string>
|
||||
<string name="add_new_contact_to_create_one_time_QR_code"><b>Добави нов контакт</b>: за да създадете своя еднократен QR код за вашия контакт.</string>
|
||||
<string name="scan_QR_code_to_connect_to_contact_who_shows_QR_code"><b>Сканирай QR код</b>: за да се свържете с вашия контакт, който ви показва QR код.</string>
|
||||
<string name="use_camera_button">Камера</string>
|
||||
<string name="if_you_cant_meet_in_person">Ако не можете да се срещнете лично, покажете QR код във видеоразговора или споделете линка.</string>
|
||||
<string name="icon_descr_cancel_link_preview">спри визуализацията на линка</string>
|
||||
@@ -140,7 +140,7 @@
|
||||
<string name="callstatus_missed">пропуснато повикване</string>
|
||||
<string name="callstatus_rejected">отхвърлено повикване</string>
|
||||
<string name="callstate_starting">стартиране…</string>
|
||||
<string name="onboarding_notifications_mode_periodic_desc"><![CDATA[<b>Добър за батерията</b>. Фоновата услуга проверява съобщенията на всеки 10 минути. Може да пропуснете обаждания или спешни съобщения.]]></string>
|
||||
<string name="onboarding_notifications_mode_periodic_desc"><b>Добър за батерията</b>. Фоновата услуга проверява съобщенията на всеки 10 минути. Може да пропуснете обаждания или спешни съобщения.</string>
|
||||
<string name="callstate_connected">свързан</string>
|
||||
<string name="callstate_connecting">свързване…</string>
|
||||
<string name="encrypted_audio_call">e2e криптиран аудио разговор</string>
|
||||
@@ -441,7 +441,7 @@
|
||||
<string name="custom_time_unit_days">дни</string>
|
||||
<string name="choose_file_title">Избери файл</string>
|
||||
<string name="if_you_received_simplex_invitation_link_you_can_open_in_browser">Ако сте получили линк за покана за SimpleX Chat, можете да го отворите във вашия браузър:</string>
|
||||
<string name="desktop_scan_QR_code_from_app_via_scan_QR_code"><![CDATA[💻 настолен компютър: сканирайте показания QR код от приложението чрез <b>Сканирай QR код</b>.]]></string>
|
||||
<string name="desktop_scan_QR_code_from_app_via_scan_QR_code">💻 настолен компютър: сканирайте показания QR код от приложението чрез <b>Сканирай QR код</b>.</string>
|
||||
<string name="delete_pending_connection__question">Изтрий предстоящата връзка\?</string>
|
||||
<string name="icon_descr_email">Електронна поща</string>
|
||||
<string name="share_invitation_link">Сподели еднократен линк</string>
|
||||
@@ -452,7 +452,7 @@
|
||||
<string name="smp_servers_delete_server">Изтрий сървър</string>
|
||||
<string name="dont_create_address">Не създавай адрес</string>
|
||||
<string name="display_name__field">Показвано име:</string>
|
||||
<string name="only_client_devices_store_contacts_groups_e2e_encrypted_messages"><![CDATA[Само потребителските устройства съхраняват потребителски профили, контакти, групи и съобщения, изпратени с <b>двуслойно криптиране от край до край</b>.]]></string>
|
||||
<string name="only_client_devices_store_contacts_groups_e2e_encrypted_messages">Само потребителските устройства съхраняват потребителски профили, контакти, групи и съобщения, изпратени с <b>двуслойно криптиране от край до край</b>.</string>
|
||||
<string name="receipts_contacts_title_disable">Деактивирай потвърждениeто\?</string>
|
||||
<string name="receipts_contacts_enable_keep_overrides">Активиране (запазване на промените)</string>
|
||||
<string name="receipts_contacts_title_enable">Активирай потвърждениeто\?</string>
|
||||
@@ -766,7 +766,7 @@
|
||||
<string name="invalid_message_format">невалиден формат на съобщението</string>
|
||||
<string name="invalid_connection_link">Невалиден линк за връзка</string>
|
||||
<string name="notification_display_mode_hidden_desc">Скриване на контакт и съобщение</string>
|
||||
<string name="turn_off_battery_optimization"><![CDATA[За да го използвате, моля, <b>деактивирайте оптимизирането на батерията</b> за SimpleX в следващия диалогов прозорец. В противен случай известията ще бъдат деактивирани.]]></string>
|
||||
<string name="turn_off_battery_optimization">За да го използвате, моля, <b>деактивирайте оптимизирането на батерията</b> за SimpleX в следващия диалогов прозорец. В противен случай известията ще бъдат деактивирани.</string>
|
||||
<string name="icon_descr_instant_notifications">Незабавни известия</string>
|
||||
<string name="service_notifications">Незабавни известия!</string>
|
||||
<string name="service_notifications_disabled">Незабавните известия са деактивирани!</string>
|
||||
@@ -791,14 +791,14 @@
|
||||
<string name="custom_time_unit_seconds">секунди</string>
|
||||
<string name="custom_time_unit_weeks">седмици</string>
|
||||
<string name="v5_1_japanese_portuguese_interface">Японски и португалски потребителски интерфейс</string>
|
||||
<string name="mobile_tap_open_in_mobile_app_then_tap_connect_in_app"><![CDATA[📱 мобилно: докоснете <b>Отваряне в мобилно приложение</b>, след което докоснете <b>Свързване</b> в приложението.]]></string>
|
||||
<string name="mobile_tap_open_in_mobile_app_then_tap_connect_in_app">📱 мобилно: докоснете <b>Отваряне в мобилно приложение</b>, след което докоснете <b>Свързване</b> в приложението.</string>
|
||||
<string name="reject_contact_button">Отхвърляне</string>
|
||||
<string name="mark_unread">Маркирай като непрочетено</string>
|
||||
<string name="mark_read">Маркирай като прочетено</string>
|
||||
<string name="mute_chat">Без звук</string>
|
||||
<string name="image_descr_qr_code">QR код</string>
|
||||
<string name="icon_descr_more_button">Повече</string>
|
||||
<string name="read_more_in_user_guide_with_link"><![CDATA[Прочетете повече в <font color=#0088ff>Ръководство за потребителя</font>.]]></string>
|
||||
<string name="read_more_in_user_guide_with_link">Прочетете повече в <font color=#0088ff>Ръководство за потребителя</font>.</string>
|
||||
<string name="mark_code_verified">Маркирай като проверено</string>
|
||||
<string name="is_not_verified">%s не е потвърдено</string>
|
||||
<string name="is_verified">%s е потвърдено</string>
|
||||
@@ -818,7 +818,7 @@
|
||||
<string name="email_invite_subject">Нека да поговорим в SimpleX Chat</string>
|
||||
<string name="password_to_show">Парола за показване</string>
|
||||
<string name="no_spaces">Без интервали!</string>
|
||||
<string name="read_more_in_github_with_link"><![CDATA[Прочетете повече в нашето <font color=#0088ff>GitHub хранилище</font>.]]></string>
|
||||
<string name="read_more_in_github_with_link">Прочетете повече в нашето <font color=#0088ff>GitHub хранилище</font>.</string>
|
||||
<string name="onboarding_notifications_mode_off">Когато приложението работи</string>
|
||||
<string name="onboarding_notifications_mode_periodic">Периодично</string>
|
||||
<string name="paste_the_link_you_received">Постави получения линк</string>
|
||||
@@ -973,7 +973,7 @@
|
||||
<string name="simplex_service_notification_text">Получаване на съобщения…</string>
|
||||
<string name="notifications_mode_off">Работи, когато приложението е отворено</string>
|
||||
<string name="simplex_service_notification_title">Simplex Chat услуга</string>
|
||||
<string name="to_preserve_privacy_simplex_has_background_service_instead_of_push_notifications_it_uses_a_few_pc_battery"><![CDATA[За да запази вашата поверителност, вместо да изпозлва push известия, приложението има <b> SimpleX фонова услуга </b> – използва няколко процента от батерията на ден.]]></string>
|
||||
<string name="to_preserve_privacy_simplex_has_background_service_instead_of_push_notifications_it_uses_a_few_pc_battery">За да запази вашата поверителност, вместо да изпозлва push известия, приложението има <b> SimpleX фонова услуга </b> – използва няколко процента от батерията на ден.</string>
|
||||
<string name="enter_passphrase_notification_desc">За да получавате известия, моля, въведете паролата на базата данни</string>
|
||||
<string name="auth_log_in_using_credential">Влезте с вашите идентификационни данни</string>
|
||||
<string name="message_delivery_error_title">Грешка при доставката на съобщението</string>
|
||||
@@ -1001,7 +1001,7 @@
|
||||
<string name="privacy_redefined">Поверителността преосмислена</string>
|
||||
<string name="read_more_in_github">Прочетете повече в нашето хранилище в GitHub.</string>
|
||||
<string name="make_private_connection">Добави поверителна връзка</string>
|
||||
<string name="many_people_asked_how_can_it_deliver"><![CDATA[Много хора попитаха: <i>ако SimpleX няма потребителски идентификатори, как може да доставя съобщения\?</i>]]></string>
|
||||
<string name="many_people_asked_how_can_it_deliver">Много хора попитаха: <i>ако SimpleX няма потребителски идентификатори, как може да доставя съобщения\?</i></string>
|
||||
<string name="open_verb">Отвори</string>
|
||||
<string name="relay_server_if_necessary">Реле сървър се използва само ако е необходимо. Друга страна може да наблюдава вашия IP адрес.</string>
|
||||
<string name="lock_after">Заключване след</string>
|
||||
@@ -1157,7 +1157,7 @@
|
||||
<string name="stop_file__action">Спри файл</string>
|
||||
<string name="icon_descr_settings">Настройки</string>
|
||||
<string name="star_on_github">Звезда в GitHub</string>
|
||||
<string name="disable_onion_hosts_when_not_supported"><![CDATA[Задайте <i>Използване на .onion хостове</i> на Не, ако SOCKS проксито не ги поддържа.]]></string>
|
||||
<string name="disable_onion_hosts_when_not_supported">Задайте <i>Използване на .onion хостове</i> на Не, ако SOCKS проксито не ги поддържа.</string>
|
||||
<string name="show_dev_options">Покажи:</string>
|
||||
<string name="core_simplexmq_version">simplexmq: v%s (%2s)</string>
|
||||
<string name="save_and_notify_contact">Запази и уведоми контакта</string>
|
||||
@@ -1257,7 +1257,7 @@
|
||||
\nМожете да го промените в Настройки.</string>
|
||||
<string name="your_profile_is_stored_on_your_device">Вашият профил, контакти и доставени съобщения се съхраняват на вашето устройство.</string>
|
||||
<string name="you_can_use_markdown_to_format_messages__prompt">Можете да използвате markdown за форматиране на съобщенията:</string>
|
||||
<string name="you_control_servers_to_receive_your_contacts_to_send"><![CDATA[Вие контролирате през кой сървър(и) <b>да получавате</b> съобщенията, вашите контакти – сървърите, които използвате, за да им изпращате съобщения.]]></string>
|
||||
<string name="you_control_servers_to_receive_your_contacts_to_send">Вие контролирате през кой сървър(и) <b>да получавате</b> съобщенията, вашите контакти – сървърите, които използвате, за да им изпращате съобщения.</string>
|
||||
<string name="use_chat">Използвай чата</string>
|
||||
<string name="update_database">Актуализация</string>
|
||||
<string name="you_have_to_enter_passphrase_every_time">Трябва да въвеждате парола при всяко стартиране на приложението - тя не се съхранява на устройството.</string>
|
||||
@@ -1351,9 +1351,9 @@
|
||||
<string name="auth_you_will_be_required_to_authenticate_when_you_start_or_resume">Ще трябва да се идентифицирате, когато стартирате или възобновите приложението след 30 секунди във фонов режим.</string>
|
||||
<string name="you_are_observer">вие сте наблюдател</string>
|
||||
<string name="gallery_video_button">Видео</string>
|
||||
<string name="you_can_connect_to_simplex_chat_founder"><![CDATA[Можете да <font color=#0088ff>се свържете с разработчиците на SimpleX Chat, за да задавате въпроси и да получавате актуализации</font>;.]]></string>
|
||||
<string name="you_can_connect_to_simplex_chat_founder">Можете да <font color=#0088ff>се свържете с разработчиците на SimpleX Chat, за да задавате въпроси и да получавате актуализации</font>.</string>
|
||||
<string name="contact_wants_to_connect_with_you">иска да се свърже с вас!</string>
|
||||
<string name="you_can_also_connect_by_clicking_the_link"><![CDATA[Можете също да се свържете, като натиснете върху линка. Ако се отвори в браузъра, натиснете върху бутона <b>Отваряне в мобилно приложение</b>.]]></string>
|
||||
<string name="you_can_also_connect_by_clicking_the_link">Можете също да се свържете, като натиснете върху линка. Ако се отвори в браузъра, натиснете върху бутона <b>Отваряне в мобилно приложение</b>.</string>
|
||||
<string name="xftp_servers">XFTP сървъри</string>
|
||||
<string name="update_network_session_mode_question">Актуализиране на режима на изолация на транспорта\?</string>
|
||||
<string name="your_current_profile">Вашият текущ профил</string>
|
||||
|
||||
@@ -762,7 +762,7 @@
|
||||
<string name="enable_automatic_deletion_message">Esta acción no se puede deshacer. Se eliminarán los mensajes enviados y recibidos anteriores a la selección. Puede tardar varios minutos.</string>
|
||||
<string name="messages_section_description">Esta configuración se aplica a los mensajes del perfil actual</string>
|
||||
<string name="this_string_is_not_a_connection_link">¡Esta cadena no es un enlace de conexión!</string>
|
||||
<string name="to_preserve_privacy_simplex_has_background_service_instead_of_push_notifications_it_uses_a_few_pc_battery"><![CDATA[Para preservar tu privacidad, en lugar de notificaciones automáticas la aplicación cuenta con un <b>servicio en segundo planoSimpleX</b>, usa un pequeño porcentaje de la batería al día.]]></string>
|
||||
<string name="to_preserve_privacy_simplex_has_background_service_instead_of_push_notifications_it_uses_a_few_pc_battery">Para preservar tu privacidad, en lugar de notificaciones automáticas la aplicación cuenta con un <b>servicio en segundo planoSimpleX</b>, usa un pequeño porcentaje de la batería al día.</string>
|
||||
<string name="icon_descr_settings">Configuración</string>
|
||||
<string name="icon_descr_speaker_off">Altavoz desactivado</string>
|
||||
<string name="add_contact_or_create_group">Inciar chat nuevo</string>
|
||||
|
||||
@@ -763,7 +763,7 @@
|
||||
<string name="wrong_passphrase">Password del database sbagliata</string>
|
||||
<string name="wrong_passphrase_title">Password sbagliata!</string>
|
||||
<string name="you_are_invited_to_group_join_to_connect_with_group_members">Sei stato/a invitato/a al gruppo. Entra per connetterti con i suoi membri.</string>
|
||||
<string name="you_can_start_chat_via_setting_or_by_restarting_the_app">Puoi avviare la chat tramite Impostazioni / Database o riavviando l\'app.</string>
|
||||
<string name="you_can_start_chat_via_setting_or_by_restarting_the_app">Puoi avviare la chat tramite Impostazioni -> Database o riavviando l\'app.</string>
|
||||
<string name="youve_accepted_group_invitation_connecting_to_inviting_group_member">Sei entrato/a in questo gruppo. Connessione al membro del gruppo invitante.</string>
|
||||
<string name="you_will_stop_receiving_messages_from_this_group_chat_history_will_be_preserved">Non riceverai più messaggi da questo gruppo. La cronologia della chat verrà conservata.</string>
|
||||
<string name="group_member_status_invited">ha invitato</string>
|
||||
|
||||
@@ -530,7 +530,7 @@
|
||||
<string name="v5_0_large_files_support">Vaizdo įrašai ir failai iki 1GB</string>
|
||||
<string name="search_verb">Ieškoti</string>
|
||||
<string name="la_mode_off">Išjungta</string>
|
||||
<string name="network_session_mode_user_description"><![CDATA[Atskiras TCP ryšys (ir SOCKS kredencialas) bus naudojamas <b>kiekvienam pokalbių profiliui, kurį turite programoje</b>.]]></string>
|
||||
<string name="network_session_mode_user_description">Atskiras TCP ryšys (ir SOCKS kredencialas) bus naudojamas <b>kiekvienam pokalbių profiliui, kurį turite programoje</b>.</string>
|
||||
<string name="alert_text_decryption_error_n_messages_failed_to_decrypt">Nepavyko iššifruoti %1$d pranešimų.</string>
|
||||
<string name="button_add_welcome_message">Pridėti sveikinimo pranešimą</string>
|
||||
<string name="v5_2_more_things">Dar keletas dalykų</string>
|
||||
@@ -539,7 +539,7 @@
|
||||
<string name="always_use_relay">Visada naudoti relę</string>
|
||||
<string name="icon_descr_asked_to_receive">Paprašė leidimo gauti nuotrauką</string>
|
||||
<string name="send_disappearing_message_5_minutes">5 minučių</string>
|
||||
<string name="onboarding_notifications_mode_off_desc"><![CDATA[<b>Mažiausiai bateriją eikvojantis variantas</b>. Jūs gausite sistemos pranešimus tik kai bus atidaryta programėlė (NEBUS fone veikiančios paslaugos).]]></string>
|
||||
<string name="onboarding_notifications_mode_off_desc"><b>Mažiausiai bateriją eikvojantis variantas</b>. Jūs gausite sistemos pranešimus tik kai bus atidaryta programėlė (NEBUS fone veikiančios paslaugos).</string>
|
||||
<string name="abort_switch_receiving_address">Atšaukti adreso keitimą</string>
|
||||
<string name="v4_2_auto_accept_contact_requests">Automatiškai priimti susisiekimo užklausas</string>
|
||||
<string name="v5_1_self_destruct_passcode_descr">Kai jį suvedate visi duomenys yra pašalinami.</string>
|
||||
@@ -603,19 +603,19 @@
|
||||
<string name="one_time_link_short">vienkartinė nuoroda</string>
|
||||
<string name="accept_call_on_lock_screen">Priimti</string>
|
||||
<string name="auto_accept_contact">Automatiškai priimti</string>
|
||||
<string name="onboarding_notifications_mode_periodic_desc"><![CDATA[<b>Geriau baterijai</b>. Fono paslauga tikrina pranešimus kas 10 minučių. Galite praleisti skambučius arba skubius pranešimus.]]></string>
|
||||
<string name="onboarding_notifications_mode_periodic_desc"><b>Geriau baterijai</b>. Fono paslauga tikrina pranešimus kas 10 minučių. Galite praleisti skambučius arba skubius pranešimus.</string>
|
||||
<string name="callstatus_in_progress">vyksta skambutis</string>
|
||||
<string name="icon_descr_cancel_live_message">Atšaukti tiesioginę žinutę</string>
|
||||
<string name="alert_title_cant_invite_contacts">Nepavyko pakviesti kontaktų!</string>
|
||||
<string name="icon_descr_call_progress">Vyksta skambutis</string>
|
||||
<string name="feature_cancelled_item">atšaukta %s</string>
|
||||
<string name="it_can_disabled_via_settings_notifications_still_shown"><![CDATA[<b>Galima išjungti nustatymuose</b> - pranešimai vis tiek bus rodomi kol programėlė veikia.]]></string>
|
||||
<string name="it_can_disabled_via_settings_notifications_still_shown"><b>Galima išjungti nustatymuose</b> - pranešimai vis tiek bus rodomi kol programėlė veikia.</string>
|
||||
<string name="icon_descr_cancel_link_preview">atšaukti nuorodos peržiūrą</string>
|
||||
<string name="both_you_and_your_contact_can_add_message_reactions">Jūs ir jūsų kontaktas galite pridėti reakcijas į žinutę.</string>
|
||||
<string name="call_on_lock_screen">Skambučiai užrakinimo ekrane:</string>
|
||||
<string name="invite_prohibited">Nepavyko pakviesti kontakto!</string>
|
||||
<string name="v4_5_transport_isolation_descr">Pagal pokalbių profilį (numatytieji nustatymai) arba pagal ryšį (BETA).</string>
|
||||
<string name="onboarding_notifications_mode_service_desc"><![CDATA[<b>Naudoja daugiau baterijos</b>! Fono paslauga veikia visada - pranešimai rodomi, kai tik atsiranda žinučių.]]></string>
|
||||
<string name="onboarding_notifications_mode_service_desc"><b>Naudoja daugiau baterijos</b>! Fono paslauga veikia visada - pranešimai rodomi, kai tik atsiranda žinučių.</string>
|
||||
<string name="cannot_access_keychain">Negalima pasiekti \"Keystore\", kad išsaugotumėte duomenų bazės slaptažodį</string>
|
||||
<string name="icon_descr_cancel_file_preview">Atšaukti failo peržiūrą</string>
|
||||
<string name="icon_descr_cancel_image_preview">Atšaukti vaizdo peržiūrą</string>
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
<string name="incognito_random_profile_from_contact_description">โปรไฟล์แบบสุ่มจะถูกส่งไปยังผู้ติดต่อที่คุณได้รับลิงก์นี้จาก</string>
|
||||
<string name="incognito_random_profile_description">โปรไฟล์แบบสุ่มจะถูกส่งไปยังผู้ติดต่อของคุณ</string>
|
||||
<string name="network_session_mode_user_description"><![CDATA[การเชื่อมต่อ TCP (และข้อมูลรับรอง SOCKS) แบบแยกต่างหาก จะถูกใช้ <b> สําหรับแต่ละโปรไฟล์แชทที่คุณมีในแอป </b>]]></string>
|
||||
<string name="network_session_mode_entity_description"><![CDATA[การเชื่อมต่อ TCP (และข้อมูลรับรอง SOCKS) แบบแยกต่างหาก จะถูกใช้ <b> สําหรับผู้ติดต่อแต่ละคนและสมาชิกกลุ่มแต่ละคน </b>\n<b>โปรดทราบ </b>: หากคุณมีการเชื่อมต่อจํานวนมากแบตเตอรี่และปริมาณการใช้การจราจรของคุณอาจสูงขึ้นอย่างมากและการเชื่อมต่อบางอย่างอาจล้มเหลว]]></string>
|
||||
<string name="network_session_mode_entity_description">การเชื่อมต่อ TCP (และข้อมูลรับรอง SOCKS) แบบแยกต่างหาก จะถูกใช้ <b> สําหรับผู้ติดต่อแต่ละคนและสมาชิกกลุ่มแต่ละคน </b>\n<b>โปรดทราบ </b>: หากคุณมีการเชื่อมต่อจํานวนมากแบตเตอรี่และปริมาณการใช้การจราจรของคุณอาจสูงขึ้นอย่างมากและการเชื่อมต่อบางอย่างอาจล้มเหลว</string>
|
||||
<string name="attach">แนบ</string>
|
||||
<string name="v4_6_audio_video_calls">การโทรด้วยเสียงและวิดีโอ</string>
|
||||
<string name="auto_accept_contact">ยอมรับอัตโนมัติ</string>
|
||||
@@ -530,7 +530,7 @@
|
||||
<string name="error_receiving_file">เกิดข้อผิดพลาดในการรับไฟล์</string>
|
||||
<string name="if_you_enter_passcode_data_removed">หากคุณใส่รหัสผ่านนี้เมื่อเปิดแอป ข้อมูลแอปทั้งหมดจะถูกลบอย่างถาวร!</string>
|
||||
<string name="if_you_choose_to_reject_the_sender_will_not_be_notified">หากคุณเลือกที่จะปฏิเสธ ผู้ส่งจะไม่ได้รับแจ้ง</string>
|
||||
<string name="if_you_cannot_meet_in_person_scan_QR_in_video_call_or_ask_for_invitation_link">หากคุณไม่สามารถพบกันในชีวิตจริงได้ คุณสามารถสแกนคิวอาร์โค้ดในวิดีโอคอล หรือผู้ติดต่อของคุณสามารถแชร์ลิงก์เชิญได้</string>
|
||||
<string name="if_you_cannot_meet_in_person_scan_QR_in_video_call_or_ask_for_invitation_link"><![CDATA[หากคุณไม่สามารถพบกันในชีวิตจริงได้ คุณสามารถสแกนคิวอาร์โค้ดในวิดีโอคอล </b> หรือผู้ติดต่อของคุณสามารถแชร์ลิงก์เชิญได้]]></string>
|
||||
<string name="if_you_cannot_meet_in_person_show_QR_in_video_call_or_via_another_channel"><![CDATA[หากคุณไม่สามารถพบกันในชีวิตจริงได้ <b>ให้แสดงคิวอาร์โค้ดในวิดีโอคอล</b> หรือแชร์ลิงก์]]></string>
|
||||
<string name="if_you_cant_meet_in_person">หากคุณไม่สามารถพบกันในชีวิตจริงได้ ให้แสดงคิวอาร์โค้ดในวิดีโอคอล หรือแชร์ลิงก์</string>
|
||||
<string name="network_disable_socks_info">หากคุณยืนยัน เซิร์ฟเวอร์การส่งข้อความจะสามารถเห็นที่อยู่ IP ของคุณและผู้ให้บริการของคุณ - ซึ่งคือเซิร์ฟเวอร์ใดที่คุณกำลังเชื่อมต่ออยู่</string>
|
||||
@@ -927,7 +927,7 @@
|
||||
<string name="smp_servers_scan_qr">สแกนคิวอาร์โค้ดของเซิร์ฟเวอร์</string>
|
||||
<string name="smp_save_servers_question">บันทึกเซิร์ฟเวอร์\?</string>
|
||||
<string name="saved_ICE_servers_will_be_removed">เซิร์ฟเวอร์ WebRTC ICE ที่บันทึกไว้จะถูกลบออก</string>
|
||||
<string name="disable_onion_hosts_when_not_supported"><![CDATA[ตั้ง <i>ใช้โฮสต์ .onion</i> เป็น ไม่ หากพร็อกซี SOCKS ไม่รองรับ]]></string>
|
||||
<string name="disable_onion_hosts_when_not_supported">ตั้ง <i>ใช้โฮสต์ .onion</i> เป็น ไม่ หากพร็อกซี SOCKS ไม่รองรับ</string>
|
||||
<string name="show_dev_options">แสดง:</string>
|
||||
<string name="show_developer_options">แสดงตัวเลือกสําหรับนักพัฒนาซอฟต์แวร์</string>
|
||||
<string name="share_link">แชร์ลิงก์</string>
|
||||
|
||||
@@ -73,7 +73,7 @@
|
||||
<string name="all_group_members_will_remain_connected">Konuşma üyelerinin tümü bağlı kalacaktır.</string>
|
||||
<string name="allow_verb">İzin ver</string>
|
||||
<string name="v5_0_app_passcode">Uygulama erişim kodu</string>
|
||||
<string name="network_session_mode_user_description"><![CDATA[<b>Uygulamadaki her konuşma profliniz için</b> ayrı bir TCP bağlantısı (ve SOCKS kimliği) kullanılacaktır.]]></string>
|
||||
<string name="network_session_mode_user_description"><b>Uygulamadaki her konuşma profliniz için</b> ayrı bir TCP bağlantısı (ve SOCKS kimliği) kullanılacaktır.</string>
|
||||
<string name="network_session_mode_entity_description"><b>Konuştuğun kişilerin ve grup üyelerinin tamamı için</b> ayrı bir TCP bağlantısı (ve SOCKS kimliği) kullanılacaktır.
|
||||
\n<b>Bilgin olsun</b>: Çok sayıda bağlantın varsa pilin ve veri kullanımın önemli ölçüde artabilir ve bazı bağlantılar başarısız olabilir.</string>
|
||||
<string name="save_and_notify_group_members">Kaydet ve grup üyelerini bilgilendir</string>
|
||||
@@ -391,7 +391,7 @@
|
||||
<string name="send_disappearing_message_custom_time">Kişiselleştirilmiş süre</string>
|
||||
<string name="copied">Panoya kopyalandı</string>
|
||||
<string name="share_one_time_link">Tek seferlik davet bağlantısı oluştur</string>
|
||||
<string name="desktop_scan_QR_code_from_app_via_scan_QR_code"><![CDATA[💻 masaüstü: uygulamadaki <b>Karekodu okut</b> ile karekodu okut]]></string>
|
||||
<string name="desktop_scan_QR_code_from_app_via_scan_QR_code">💻 masaüstü: uygulamadaki <b>Karekodu okut</b> ile karekodu okut</string>
|
||||
<string name="delete_pending_connection__question">Bekleyen bağlantıları sil\?</string>
|
||||
<string name="delete_contact_menu_action">Sil</string>
|
||||
<string name="delete_group_menu_action">Sil</string>
|
||||
@@ -625,8 +625,8 @@
|
||||
<string name="notification_display_mode_hidden_desc">Konuşulan kişileri ve mesajları gizle</string>
|
||||
<string name="v4_3_improved_privacy_and_security_desc">Uygulamayı, son kullanılanlar kısmından gizle.</string>
|
||||
<string name="how_simplex_works">SimpleX nasıl çalışıyor</string>
|
||||
<string name="if_you_cannot_meet_in_person_show_QR_in_video_call_or_via_another_channel"><![CDATA[Eğer yüz yüze görüşemiyorsanız <b>bir görüntülü aramada karşıdakine karekodunu gösterebilir</b> ya da konuştuğun kişiye bir katılım bağlantısı paylaşabilirsin.]]></string>
|
||||
<string name="if_you_cannot_meet_in_person_scan_QR_in_video_call_or_ask_for_invitation_link"><![CDATA[Eğer yüz yüze görüşemiyorsanız <b>bir görüntülü aramada karşıdakinin karekodunu okutabilirsin</b> ya da konuştuğun kişi seninle bir katılım bağlantısı paylaşabilir.]]></string>
|
||||
<string name="if_you_cannot_meet_in_person_show_QR_in_video_call_or_via_another_channel">Eğer yüz yüze görüşemiyorsanız <b>bir görüntülü aramada karşıdakine karekodunu gösterebilir</b> ya da konuştuğun kişiye bir katılım bağlantısı paylaşabilirsin.</string>
|
||||
<string name="if_you_cannot_meet_in_person_scan_QR_in_video_call_or_ask_for_invitation_link">Eğer yüz yüze görüşemiyorsanız <b>bir görüntülü aramada karşıdakinin karekodunu okutabilirsin</b> ya da konuştuğun kişi seninle bir katılım bağlantısı paylaşabilir.</string>
|
||||
<string name="if_you_cant_meet_in_person">Eğer yüz yüze görüşemiyorsanız bir görüntülü aramada karşıdakine karekodunu gösterebilir ya da konuştuğun kişiye bir katılım bağlantısı paylaşabilirsin.</string>
|
||||
<string name="if_you_choose_to_reject_the_sender_will_not_be_notified">Eğer geri çevirmeyi seçersen göndericiye bildirilmeyecek.</string>
|
||||
<string name="if_you_received_simplex_invitation_link_you_can_open_in_browser">Eğer SimplexX Chat katılım bağlantısı alırsan bu bağlantıyı tarayıcında açabilirsin:</string>
|
||||
@@ -717,7 +717,7 @@
|
||||
<string name="icon_descr_instant_notifications">Anlık bildirimler</string>
|
||||
<string name="service_notifications">Anlık bildirimler</string>
|
||||
<string name="service_notifications_disabled">Anlık bildirimler devre dışı!</string>
|
||||
<string name="turn_off_battery_optimization"><![CDATA[Bunu kullanmak için lütfen bir sonraki iletişim kutusunda SimpleX için <b>pil optimizasyonunu devre dışı bırakın</b>. Aksi takdirde, bildirimler devre dışı bırakılacaktır.]]></string>
|
||||
<string name="turn_off_battery_optimization">Bunu kullanmak için lütfen bir sonraki iletişim kutusunda SimpleX için <b>pil optimizasyonunu devre dışı bırakın</b>. Aksi takdirde, bildirimler devre dışı bırakılacaktır.</string>
|
||||
<string name="notification_preview_mode_contact">Kişi ismi</string>
|
||||
<string name="auth_device_authentication_is_disabled_turning_off">Cihaz doğrulaması devre dışı. SimpleX Kilidi Kapatılıyor.</string>
|
||||
<string name="auth_device_authentication_is_not_enabled_you_can_turn_on_in_settings_once_enabled">Cihaz doğrulaması etkin değil. Cihaz doğrulamasını etkinleştirdikten sonra SimpleX Kilidini Ayarlar üzerinden açabilirsiniz.</string>
|
||||
@@ -740,7 +740,7 @@
|
||||
<string name="v4_3_irreversible_message_deletion">Geri alınamaz mesaj silme</string>
|
||||
<string name="v4_5_italian_interface">İtalyanca arayüz</string>
|
||||
<string name="choose_file_title">Dosya seç</string>
|
||||
<string name="scan_QR_code_to_connect_to_contact_who_shows_QR_code"><![CDATA[<b>QR kodunu tara</b>: size QR kodunu gösteren kişiyle bağlantı kurmak için.]]></string>
|
||||
<string name="scan_QR_code_to_connect_to_contact_who_shows_QR_code"><b>QR kodunu tara</b>: size QR kodunu gösteren kişiyle bağlantı kurmak için.</string>
|
||||
<string name="invite_friends">Arkadaşlarınızı davet edin</string>
|
||||
<string name="bold_text">kalın</string>
|
||||
<string name="italic_text">İtalik</string>
|
||||
@@ -748,7 +748,7 @@
|
||||
<string name="status_contact_has_e2e_encryption">Kişi uçtan uca şifrelemeye sahiptir</string>
|
||||
<string name="status_contact_has_no_e2e_encryption">Kişi uçtan uca şifrelemeye sahip değildir</string>
|
||||
<string name="chat_is_stopped">Sohbet durduruldu</string>
|
||||
<string name="impossible_to_recover_passphrase"><![CDATA[<b>Aklınızda bulunsun</b>: kaybederseniz, parolayı kurtaramaz veya değiştiremezsiniz.]]></string>
|
||||
<string name="impossible_to_recover_passphrase"><b>Aklınızda bulunsun</b>: kaybederseniz, parolayı kurtaramaz veya değiştiremezsiniz.</string>
|
||||
<string name="chat_archive_header">Sohbet arşivi</string>
|
||||
<string name="chat_archive_section">SOHBET ARŞİVİ</string>
|
||||
<string name="group_invitation_item_description">1$s grubuna davet</string>
|
||||
@@ -767,7 +767,7 @@
|
||||
<string name="callstatus_connecting">Aramaya bağlanılıyor…</string>
|
||||
<string name="delivery_receipts_are_disabled">Gönderildi bilgisi kapalı!</string>
|
||||
<string name="v5_2_more_things">Birkaç şey daha</string>
|
||||
<string name="onboarding_notifications_mode_service_desc"><![CDATA[<b>Daha fazla pil kullanır</b>! Arka plan hizmeti her zaman çalışır - mesajlar gelir gelmez bildirim gönderilir.]]></string>
|
||||
<string name="onboarding_notifications_mode_service_desc"><b>Daha fazla pil kullanır</b>! Arka plan hizmeti her zaman çalışır - mesajlar gelir gelmez bildirim gönderilir.</string>
|
||||
<string name="in_developing_title">Çok yakında!</string>
|
||||
<string name="delete_contact_all_messages_deleted_cannot_undo_warning">Kişi ve tüm mesajlar silinecektir - bu geri alınamaz!</string>
|
||||
<string name="alert_title_contact_connection_pending">Kişi henüz bağlanmadı!</string>
|
||||
@@ -783,7 +783,7 @@
|
||||
<string name="description_via_contact_address_link_incognito">Bağlantı linki ile gizli</string>
|
||||
<string name="description_via_one_time_link_incognito">Tek seferlik bağlantı ile gizli</string>
|
||||
<string name="smp_server_test_compare_file">Dosyaları karşılaştır</string>
|
||||
<string name="it_can_disabled_via_settings_notifications_still_shown"><![CDATA[<b>ayarlardan devre dışı bırakılabilir</b> - uygulama çalışıyorken bildirimler gösterilmeye devam edilecektir.]]></string>
|
||||
<string name="it_can_disabled_via_settings_notifications_still_shown"><b>ayarlardan devre dışı bırakılabilir</b> - uygulama çalışıyorken bildirimler gösterilmeye devam edilecektir.</string>
|
||||
<string name="turning_off_service_and_periodic">Pil optimizasyonu etkin, arka plan hizmeti kapatılacak ve düzenli olarak yeni mesajlar kontrol edilmeyecek . Bunları ayarlardan yeniden etkinleştirebilirsiniz.</string>
|
||||
<string name="enter_passphrase_notification_title">Parola gerekli</string>
|
||||
<string name="notification_preview_mode_message">Mesaj metni</string>
|
||||
@@ -794,7 +794,7 @@
|
||||
<string name="delete_message_cannot_be_undone_warning">Mesajlar silinecek - bu geri alınamaz!</string>
|
||||
<string name="switch_receiving_address_question">Alıcı adresini değiştir\?</string>
|
||||
<string name="back">Geri</string>
|
||||
<string name="add_new_contact_to_create_one_time_QR_code"><![CDATA[<b>Yeni kişi ekle</b>: Kişiniz için tek seferlik QR Kodunuzu oluşturmak için.]]></string>
|
||||
<string name="add_new_contact_to_create_one_time_QR_code"><b>Yeni kişi ekle</b>: Kişiniz için tek seferlik QR Kodunuzu oluşturmak için.</string>
|
||||
<string name="you_will_be_connected_when_your_connection_request_is_accepted">Bağlantı isteğiniz kabul edildiğinde bağlanacaksınız, lütfen bekleyin veya daha sonra kontrol edin!</string>
|
||||
<string name="you_will_be_connected_when_your_contacts_device_is_online">Kişinizin cihazı çevrimiçi olduğunda bağlanacaksınız, lütfen bekleyin veya daha sonra kontrol edin!</string>
|
||||
<string name="learn_more">Daha fazla bilgi edinin</string>
|
||||
@@ -836,10 +836,10 @@
|
||||
<string name="mark_read">Okundu olarak işaretle</string>
|
||||
<string name="mark_unread">Okunmadı olarak işaretle</string>
|
||||
<string name="chat_console">Sohbet konsolu</string>
|
||||
<string name="onboarding_notifications_mode_periodic_desc"><![CDATA[<b>Pil için iyi</b>. Arka plan hizmeti mesajları 10 dakikada bir kontrol eder. Aramaları veya acil mesajları kaçırabilirsiniz.]]></string>
|
||||
<string name="onboarding_notifications_mode_periodic_desc"><b>Pil için iyi</b>. Arka plan hizmeti mesajları 10 dakikada bir kontrol eder. Aramaları veya acil mesajları kaçırabilirsiniz.</string>
|
||||
<string name="v4_4_verify_connection_security_desc">Güvenlik kodlarını kişilerinizle karşılaştırın.</string>
|
||||
<string name="notifications_mode_service_desc">Arka plan hizmeti her zaman çalışır - mesajlar gelir gelmez bildirim gönderilir.</string>
|
||||
<string name="onboarding_notifications_mode_off_desc"><![CDATA[<b>Pil için en iyisi</b>. Sadece uygulama çalışırken bildirim alırsınız (arka plan hizmeti YOK).]]></string>
|
||||
<string name="onboarding_notifications_mode_off_desc"><b>Pil için en iyisi</b>. Sadece uygulama çalışırken bildirim alırsınız (arka plan hizmeti YOK).</string>
|
||||
<string name="snd_conn_event_switch_queue_phase_changing_for_member">%s için adres değiştiriliyor.</string>
|
||||
<string name="large_file">Büyük dosya!</string>
|
||||
<string name="you_will_be_connected_when_group_host_device_is_online">Grup sahibinin cihazı çevrimiçi olduğunda gruba bağlanacaksınız, lütfen bekleyin veya daha sonra kontrol edin!</string>
|
||||
@@ -869,7 +869,7 @@
|
||||
<string name="your_ICE_servers">ICE sunucularınız</string>
|
||||
<string name="how_to">Nasıl</string>
|
||||
<string name="your_current_profile">Mevcut profiliniz</string>
|
||||
<string name="you_control_servers_to_receive_your_contacts_to_send"><![CDATA[Mesajların hangi sunucu(lar)dan <b>alınacağını</b> siz kontrol edersiniz, kişileriniz - onlara mesaj göndermek için kullandığınız sunucular.]]></string>
|
||||
<string name="you_control_servers_to_receive_your_contacts_to_send">Mesajların hangi sunucu(lar)dan <b>alınacağını</b> siz kontrol edersiniz, kişileriniz - onlara mesaj göndermek için kullandığınız sunucular.</string>
|
||||
<string name="video_call_no_encryption">video arama (uçtan uca şifreli değil)</string>
|
||||
<string name="your_ice_servers">ICE sunucularınız</string>
|
||||
<string name="icon_descr_video_off">Video kapalı</string>
|
||||
@@ -908,8 +908,8 @@
|
||||
\nBu bağlantıyı iptal edebilir ve kişiyi kaldırabilirsiniz (ve daha sonra yeni bir bağlantıyla deneyebilirsiniz).</string>
|
||||
<string name="contact_sent_large_file">Kişiniz desteklenen maksimum boyuttan (%1$s) daha büyük bir dosya gönderdi.</string>
|
||||
<string name="video_will_be_received_when_contact_completes_uploading">Kişiniz yüklemeyi tamamladığında video alınacaktır.</string>
|
||||
<string name="you_can_also_connect_by_clicking_the_link"><![CDATA[Ayrıca bağlantıya tıklayarak da bağlanabilirsiniz. Eğer bağlantı tarayıcda açılırsa, <b>mobil uygulamada aç</b> seçeneğine tıklayın.]]></string>
|
||||
<string name="you_can_connect_to_simplex_chat_founder"><![CDATA[Soru sormak ve güncellemeleri almak için <font color=#0088ff>SimpleX Chat geliştiricilerine bağlanabilirsiniz</font>.]]></string>
|
||||
<string name="you_can_also_connect_by_clicking_the_link">Ayrıca bağlantıya tıklayarak da bağlanabilirsiniz. Eğer bağlantı tarayıcda açılırsa, <b>mobil uygulamada aç</b> seçeneğine tıklayın.</string>
|
||||
<string name="you_can_connect_to_simplex_chat_founder">Soru sormak ve güncellemeleri almak için <font color=#0088ff>SimpleX Chat geliştiricilerine bağlanabilirsiniz</font>.</string>
|
||||
<string name="you_can_hide_or_mute_user_profile">Bir kullanıcının profilini gizleyebilir veya sessize alabilirsiniz - menü için basılı tutun.</string>
|
||||
<string name="you_invited_your_contact">Kişinizi davet ettiniz</string>
|
||||
<string name="you_must_use_the_most_recent_version_of_database">Sohbet veritabanınızın en son sürümünü SADECE bir cihazda kullanmalısınız, aksi takdirde bazı kişilerden daha fazla mesaj alamayabilirsiniz.</string>
|
||||
@@ -957,7 +957,7 @@
|
||||
\n- ve daha fazlası!</string>
|
||||
<string name="item_status_rcv_new_desc">Bu göndericiden yeni bir mesaj var.</string>
|
||||
<string name="item_status_snd_error_auth_desc">Mesaj teslim hatası. Büyük olasılıkla bu alıcı sizinle olan bağlantısını silmiştir.</string>
|
||||
<string name="only_client_devices_store_contacts_groups_e2e_encrypted_messages"><![CDATA[Sadece istemci cihazlar <b>2 katmanlı uçtan uca şifreleme</b> ile kullanıcı profillerini, kişileri, grupları ve gönderilen mesajları depolar.]]></string>
|
||||
<string name="only_client_devices_store_contacts_groups_e2e_encrypted_messages">Sadece istemci cihazlar <b>2 katmanlı uçtan uca şifreleme</b> ile kullanıcı profillerini, kişileri, grupları ve gönderilen mesajları depolar.</string>
|
||||
<string name="only_group_owners_can_change_prefs">Grup tercihlerini sadece grup sahipleri değiştirebilir.</string>
|
||||
<string name="item_info_no_text">metin yok</string>
|
||||
<string name="network_status">Ağ durumu</string>
|
||||
@@ -966,7 +966,7 @@
|
||||
<string name="change_lock_mode">Kilit modunu değiştir</string>
|
||||
<string name="trying_to_connect_to_server_to_receive_messages">Bu kişiden mesaj almak için kullanılan sunucuya bağlanılmaya çalışılıyor.</string>
|
||||
<string name="please_check_correct_link_and_maybe_ask_for_a_new_one">Lütfen doğru bağlantıyı kullandığınızı kontrol edin veya irtibat kişinizden size başka bir bağlantı göndermesini isteyin.</string>
|
||||
<string name="to_preserve_privacy_simplex_has_background_service_instead_of_push_notifications_it_uses_a_few_pc_battery"><![CDATA[Gizliliğinizi korumak için, anlık bildirimler yerine <b>SimpleX arka plan hizmeti</b> kullanılır - günde pilin yüzde birkaçını kullanır.]]></string>
|
||||
<string name="to_preserve_privacy_simplex_has_background_service_instead_of_push_notifications_it_uses_a_few_pc_battery">Gizliliğinizi korumak için, anlık bildirimler yerine <b>SimpleX arka plan hizmeti</b> kullanılır - günde pilin yüzde birkaçını kullanır.</string>
|
||||
<string name="periodic_notifications">Periyodik bildirimler</string>
|
||||
<string name="periodic_notifications_disabled">Periyodik bildirimler devre dışı</string>
|
||||
<string name="enter_passphrase_notification_desc">Bildirimleri almak için lütfen veri tabanı parolasını girin</string>
|
||||
@@ -988,7 +988,7 @@
|
||||
<string name="this_link_is_not_a_valid_connection_link">Bu geçerli bir bağlantı linki değil</string>
|
||||
<string name="this_QR_code_is_not_a_link">Bu QR kodu bir bağlantı değil!</string>
|
||||
<string name="paste_connection_link_below_to_connect">Kişinizle bağlantı kurmak için aldığınız bağlantıyı aşağıdaki kutuya yapıştırın.</string>
|
||||
<string name="read_more_in_user_guide_with_link"><![CDATA[Daha fazla bilgi için <font color=#0088ff>Kullanıcı Kılavuzu</font>.]]></string>
|
||||
<string name="read_more_in_user_guide_with_link">Daha fazla bilgi için <font color=#0088ff>Kullanıcı Kılavuzu</font>.</string>
|
||||
<string name="paste_button">Yapıştır</string>
|
||||
<string name="this_string_is_not_a_connection_link">Bu dize bir bağlantı linki değil!</string>
|
||||
<string name="rate_the_app">Uygulamaya puan verin</string>
|
||||
@@ -1033,7 +1033,7 @@
|
||||
<string name="unfavorite_chat">Favorilerden çıkar</string>
|
||||
<string name="make_profile_private">Sohbeti gizli yap!</string>
|
||||
<string name="profile_update_will_be_sent_to_contacts">Profil güncellemesi kişilerinize gönderilecektir.</string>
|
||||
<string name="read_more_in_github_with_link"><![CDATA[<font color=#0088ff>GitHub repomuzda</font> daha fazlasını okuyun.]]></string>
|
||||
<string name="read_more_in_github_with_link"><font color=#0088ff>GitHub repomuzda</font> daha fazlasını okuyun.</string>
|
||||
<string name="alert_text_fragment_please_report_to_developers">Lütfen geliştiricilere bildirin.</string>
|
||||
<string name="users_delete_with_connections">Profil ve sunucu bağlantıları</string>
|
||||
<string name="user_unhide">gizlemeyi kaldır</string>
|
||||
|
||||
@@ -74,7 +74,7 @@
|
||||
<string name="notifications_mode_off_desc">Додаток може отримувати сповіщення лише під час роботи, жодні фонові служби не запускаються</string>
|
||||
<string name="chat_preferences_always">завжди</string>
|
||||
<string name="allow_your_contacts_to_call">Дозвольте вашим контактам телефонувати вам.</string>
|
||||
<string name="network_session_mode_user_description"><![CDATA[<b>Для кожного профілю чату, який ви маєте в додатку</b>, буде використовуватися окреме TCP-з\'єднання (і SOCKS-обліковий запис).]]></string>
|
||||
<string name="network_session_mode_user_description"><![CDATA[Для кожного профілю чату, який ви маєте в додатку</b>, буде використовуватися окреме TCP-з\'єднання (і SOCKS-обліковий запис) <b>.]]></string>
|
||||
<string name="appearance_settings">Зовнішній вигляд</string>
|
||||
<string name="app_version_name">Версія програми: v%s</string>
|
||||
<string name="network_session_mode_entity_description"><b>Для кожного контакту і члена групи</b> буде використовуватися окреме TCP-з\'єднання (і SOCKS-обліковий запис).
|
||||
|
||||
+68
-76
@@ -14,7 +14,6 @@ import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.window.*
|
||||
import chat.simplex.common.model.ChatController
|
||||
import chat.simplex.common.model.ChatModel
|
||||
import chat.simplex.common.platform.defaultLocale
|
||||
import chat.simplex.common.platform.desktopPlatform
|
||||
import chat.simplex.common.ui.theme.SimpleXTheme
|
||||
import chat.simplex.common.views.helpers.FileDialogChooser
|
||||
@@ -26,96 +25,89 @@ import java.io.File
|
||||
val simplexWindowState = SimplexWindowState()
|
||||
|
||||
fun showApp() = application {
|
||||
// TODO: remove after update to compose 1.5.0+
|
||||
// See: https://github.com/JetBrains/compose-multiplatform/issues/3366#issuecomment-1643799976
|
||||
System.setProperty("compose.scrolling.smooth.enabled", "false")
|
||||
|
||||
// For some reason on Linux actual width will be 10.dp less after specifying it here. If we specify 1366,
|
||||
// it will show 1356. But after that we can still update it to 1366 by changing window state. Just making it +10 now here
|
||||
val width = if (desktopPlatform.isLinux()) 1376.dp else 1366.dp
|
||||
val windowState = rememberWindowState(placement = WindowPlacement.Floating, width = width, height = 768.dp)
|
||||
simplexWindowState.windowState = windowState
|
||||
// Reload all strings in all @Composable's after language change at runtime
|
||||
if (remember { ChatController.appPrefs.appLanguage.state }.value != "") {
|
||||
Window(state = windowState, onCloseRequest = ::exitApplication, onKeyEvent = {
|
||||
if (it.key == Key.Escape && it.type == KeyEventType.KeyUp) {
|
||||
simplexWindowState.backstack.lastOrNull()?.invoke() != null
|
||||
} else {
|
||||
false
|
||||
Window(state = windowState, onCloseRequest = ::exitApplication, onKeyEvent = {
|
||||
if (it.key == Key.Escape && it.type == KeyEventType.KeyUp) {
|
||||
simplexWindowState.backstack.lastOrNull()?.invoke() != null
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}, title = "SimpleX") {
|
||||
SimpleXTheme {
|
||||
AppScreen()
|
||||
if (simplexWindowState.openDialog.isAwaiting) {
|
||||
FileDialogChooser(
|
||||
title = "SimpleX",
|
||||
isLoad = true,
|
||||
params = simplexWindowState.openDialog.params,
|
||||
onResult = {
|
||||
simplexWindowState.openDialog.onResult(it.firstOrNull())
|
||||
}
|
||||
)
|
||||
}
|
||||
}, title = "SimpleX") {
|
||||
SimpleXTheme {
|
||||
AppScreen()
|
||||
if (simplexWindowState.openDialog.isAwaiting) {
|
||||
FileDialogChooser(
|
||||
title = "SimpleX",
|
||||
isLoad = true,
|
||||
params = simplexWindowState.openDialog.params,
|
||||
onResult = {
|
||||
simplexWindowState.openDialog.onResult(it.firstOrNull())
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
if (simplexWindowState.openMultipleDialog.isAwaiting) {
|
||||
FileDialogChooser(
|
||||
title = "SimpleX",
|
||||
isLoad = true,
|
||||
params = simplexWindowState.openMultipleDialog.params,
|
||||
onResult = {
|
||||
simplexWindowState.openMultipleDialog.onResult(it)
|
||||
}
|
||||
)
|
||||
}
|
||||
if (simplexWindowState.openMultipleDialog.isAwaiting) {
|
||||
FileDialogChooser(
|
||||
title = "SimpleX",
|
||||
isLoad = true,
|
||||
params = simplexWindowState.openMultipleDialog.params,
|
||||
onResult = {
|
||||
simplexWindowState.openMultipleDialog.onResult(it)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
if (simplexWindowState.saveDialog.isAwaiting) {
|
||||
FileDialogChooser(
|
||||
title = "SimpleX",
|
||||
isLoad = false,
|
||||
params = simplexWindowState.saveDialog.params,
|
||||
onResult = { simplexWindowState.saveDialog.onResult(it.firstOrNull()) }
|
||||
if (simplexWindowState.saveDialog.isAwaiting) {
|
||||
FileDialogChooser(
|
||||
title = "SimpleX",
|
||||
isLoad = false,
|
||||
params = simplexWindowState.saveDialog.params,
|
||||
onResult = { simplexWindowState.saveDialog.onResult(it.firstOrNull()) }
|
||||
)
|
||||
}
|
||||
val toasts = remember { simplexWindowState.toasts }
|
||||
val toast = toasts.firstOrNull()
|
||||
if (toast != null) {
|
||||
Box(Modifier.fillMaxSize().padding(bottom = 20.dp), contentAlignment = Alignment.BottomCenter) {
|
||||
Text(
|
||||
toast.first,
|
||||
Modifier.background(MaterialTheme.colors.primary, RoundedCornerShape(100)).padding(vertical = 5.dp, horizontal = 10.dp),
|
||||
color = MaterialTheme.colors.onPrimary,
|
||||
style = MaterialTheme.typography.body1
|
||||
)
|
||||
}
|
||||
val toasts = remember { simplexWindowState.toasts }
|
||||
val toast = toasts.firstOrNull()
|
||||
if (toast != null) {
|
||||
Box(Modifier.fillMaxSize().padding(bottom = 20.dp), contentAlignment = Alignment.BottomCenter) {
|
||||
Text(
|
||||
toast.first,
|
||||
Modifier.background(MaterialTheme.colors.primary, RoundedCornerShape(100)).padding(vertical = 5.dp, horizontal = 10.dp),
|
||||
color = MaterialTheme.colors.onPrimary,
|
||||
style = MaterialTheme.typography.body1
|
||||
)
|
||||
}
|
||||
// Shows toast in insertion order with preferred delay per toast. New one will be shown once previous one expires
|
||||
LaunchedEffect(toast, toasts.size) {
|
||||
delay(toast.second)
|
||||
simplexWindowState.toasts.removeFirst()
|
||||
}
|
||||
// Shows toast in insertion order with preferred delay per toast. New one will be shown once previous one expires
|
||||
LaunchedEffect(toast, toasts.size) {
|
||||
delay(toast.second)
|
||||
simplexWindowState.toasts.removeFirst()
|
||||
}
|
||||
}
|
||||
var windowFocused by remember { simplexWindowState.windowFocused }
|
||||
LaunchedEffect(windowFocused) {
|
||||
val delay = ChatController.appPrefs.laLockDelay.get()
|
||||
if (!windowFocused && ChatModel.performLA.value && delay > 0) {
|
||||
delay(delay * 1000L)
|
||||
// Trigger auth state check when delay ends (and if it ends)
|
||||
}
|
||||
var windowFocused by remember { simplexWindowState.windowFocused }
|
||||
LaunchedEffect(windowFocused) {
|
||||
val delay = ChatController.appPrefs.laLockDelay.get()
|
||||
if (!windowFocused && ChatModel.performLA.value && delay > 0) {
|
||||
delay(delay * 1000L)
|
||||
// Trigger auth state check when delay ends (and if it ends)
|
||||
AppLock.recheckAuthState()
|
||||
}
|
||||
}
|
||||
LaunchedEffect(Unit) {
|
||||
window.addWindowFocusListener(object : WindowFocusListener {
|
||||
override fun windowGainedFocus(p0: WindowEvent?) {
|
||||
windowFocused = true
|
||||
AppLock.recheckAuthState()
|
||||
}
|
||||
}
|
||||
LaunchedEffect(Unit) {
|
||||
window.addWindowFocusListener(object: WindowFocusListener {
|
||||
override fun windowGainedFocus(p0: WindowEvent?) {
|
||||
windowFocused = true
|
||||
AppLock.recheckAuthState()
|
||||
}
|
||||
|
||||
override fun windowLostFocus(p0: WindowEvent?) {
|
||||
windowFocused = false
|
||||
AppLock.appWasHidden()
|
||||
}
|
||||
})
|
||||
}
|
||||
override fun windowLostFocus(p0: WindowEvent?) {
|
||||
windowFocused = false
|
||||
AppLock.appWasHidden()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,11 +25,11 @@ android.nonTransitiveRClass=true
|
||||
android.enableJetifier=true
|
||||
kotlin.mpp.androidSourceSetLayoutVersion=2
|
||||
|
||||
android.version_name=5.3-beta.4
|
||||
android.version_code=146
|
||||
android.version_name=5.3-beta.3
|
||||
android.version_code=141
|
||||
|
||||
desktop.version_name=1.2.0
|
||||
desktop.version_code=4
|
||||
desktop.version_name=1.1.0
|
||||
desktop.version_code=3
|
||||
|
||||
kotlin.version=1.8.20
|
||||
gradle.plugin.version=7.4.2
|
||||
|
||||
@@ -19,7 +19,7 @@ import Control.Monad.Reader
|
||||
import qualified Data.ByteString.Char8 as B
|
||||
import Data.Time.Clock (getCurrentTime)
|
||||
import Data.Time.LocalTime (getCurrentTimeZone)
|
||||
import Data.Maybe (fromMaybe, maybeToList)
|
||||
import Data.Maybe (fromMaybe, isJust, maybeToList)
|
||||
import qualified Data.Set as S
|
||||
import Data.Text (Text)
|
||||
import qualified Data.Text as T
|
||||
@@ -134,7 +134,7 @@ directoryService st DirectoryOpts {superUsers, serviceName, testing} user@User {
|
||||
_ -> "Error joining group " <> displayName <> ", please re-send the invitation!"
|
||||
|
||||
deContactConnected :: Contact -> IO ()
|
||||
deContactConnected ct = when (contactDirect ct) $ do
|
||||
deContactConnected ct = unless (isJust $ viaGroup ct) $ do
|
||||
unless testing $ putStrLn $ T.unpack (localDisplayName' ct) <> " connected"
|
||||
sendMessage cc ct $
|
||||
"Welcome to " <> serviceName <> " service!\n\
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ constraints: zip +disable-bzip2 +disable-zstd
|
||||
source-repository-package
|
||||
type: git
|
||||
location: https://github.com/simplex-chat/simplexmq.git
|
||||
tag: e2065ab3525ca67e39700ee8040839d667f75ea2
|
||||
tag: 82aec2cd8f7b4033dbf08d5de33ced216f574bbb
|
||||
|
||||
source-repository-package
|
||||
type: git
|
||||
|
||||
+12
-102
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: Hosting your own SMP Server
|
||||
revision: 31.07.2023
|
||||
revision: 05.06.2023
|
||||
---
|
||||
|
||||
| Updated 05.06.2023 | Languages: EN, [FR](/docs/lang/fr/SERVER.md), [CZ](/docs/lang/cs/SERVER.md) |
|
||||
@@ -19,27 +19,17 @@ _Please note_: when you change the servers in the app configuration, it only aff
|
||||
|
||||
0. First, install `smp-server`:
|
||||
|
||||
- Manual deployment (see below)
|
||||
- Manual deployment:
|
||||
|
||||
- Semi-automatic deployment:
|
||||
- [Offical installation script](https://github.com/simplex-chat/simplexmq#using-installation-script)
|
||||
- [Docker container](https://github.com/simplex-chat/simplexmq#using-docker)
|
||||
- [Compiling from source](https://github.com/simplex-chat/simplexmq#using-your-distribution)
|
||||
- [Using pre-compiled binaries](https://github.com/simplex-chat/simplexmq#install-binaries)
|
||||
|
||||
- Alternatively, you can deploy `smp-server` using:
|
||||
- [Docker container](https://github.com/simplex-chat/simplexmq#using-docker-1)
|
||||
- [Linode StackScript](https://github.com/simplex-chat/simplexmq#deploy-smp-server-on-linode)
|
||||
|
||||
Manual installation requires some preliminary actions:
|
||||
|
||||
0. Install binary:
|
||||
|
||||
- Using offical binaries:
|
||||
|
||||
```sh
|
||||
curl -L https://github.com/simplex-chat/simplexmq/releases/latest/download/smp-server-ubuntu-20_04-x86-64 -o /usr/local/bin/smp-server
|
||||
```
|
||||
|
||||
- Compiling from source:
|
||||
|
||||
Please refer to [Build from source: Using your distribution](https://github.com/simplex-chat/simplexmq#using-your-distribution)
|
||||
|
||||
1. Create user and group for `smp-server`:
|
||||
|
||||
```sh
|
||||
@@ -67,104 +57,24 @@ Manual installation requires some preliminary actions:
|
||||
|
||||
```sh
|
||||
[Unit]
|
||||
Description=SMP server systemd service
|
||||
|
||||
Description=SMP server
|
||||
[Service]
|
||||
User=smp
|
||||
Group=smp
|
||||
Type=simple
|
||||
ExecStart=/usr/local/bin/smp-server start +RTS -N -RTS
|
||||
ExecStart=smp-server start
|
||||
ExecStopPost=/usr/bin/env sh -c '[ -e "/var/opt/simplex/smp-server-store.log" ] && cp "/var/opt/simplex/smp-server-store.log" "/var/opt/simplex/smp-server-store.log.bak"'
|
||||
LimitNOFILE=65535
|
||||
KillSignal=SIGINT
|
||||
TimeoutStopSec=infinity
|
||||
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
LimitNOFILE=65535
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
And execute `sudo systemctl daemon-reload`.
|
||||
|
||||
## Tor installation
|
||||
|
||||
smp-server can also be deployed to serve from [tor](https://www.torproject.org) network. Run the following commands as `root` user.
|
||||
|
||||
1. Install tor:
|
||||
|
||||
We're assuming you're using Ubuntu/Debian based distributions. If not, please refer to [offical tor documentation](https://community.torproject.org/onion-services/setup/install/) or your distribution guide.
|
||||
|
||||
- Configure offical Tor PPA repository:
|
||||
|
||||
```sh
|
||||
CODENAME="$(lsb_release -c | awk '{print $2}')"
|
||||
echo "deb [signed-by=/usr/share/keyrings/tor-archive-keyring.gpg] https://deb.torproject.org/torproject.org ${CODENAME} main
|
||||
deb-src [signed-by=/usr/share/keyrings/tor-archive-keyring.gpg] https://deb.torproject.org/torproject.org ${CODENAME} main" > /etc/apt/sources.list.d/tor.list
|
||||
```
|
||||
|
||||
- Import repository key:
|
||||
|
||||
```sh
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://deb.torproject.org/torproject.org/A3C4F0F979CAA22CDBA8F512EE8CBC9E886DDD89.asc | gpg --dearmor | tee /usr/share/keyrings/tor-archive-keyring.gpg >/dev/null
|
||||
```
|
||||
|
||||
- Update repository index:
|
||||
|
||||
```sh
|
||||
apt update
|
||||
```
|
||||
|
||||
- Install `tor` package:
|
||||
|
||||
```sh
|
||||
apt install -y tor deb.torproject.org-keyring
|
||||
```
|
||||
|
||||
2. Configure tor:
|
||||
|
||||
- File configuration:
|
||||
|
||||
Open tor configuration with your editor of choice (`nano`,`vim`,`emacs`,etc.):
|
||||
|
||||
```sh
|
||||
vim /etc/tor/torrc
|
||||
```
|
||||
|
||||
And insert the following lines to the bottom of configuration. Please note lines starting with `#`: this is comments about each individual options.
|
||||
|
||||
```sh
|
||||
# Enable log (otherwise, tor doesn't seemd to deploy onion address)
|
||||
Log notice file /var/log/tor/notices.log
|
||||
# Enable single hop routing (2 options below are dependencies of third). Will reduce latency in exchange of anonimity (since tor runs alongside smp-server and onion address will be displayed in clients, this is totally fine)
|
||||
SOCKSPort 0
|
||||
HiddenServiceNonAnonymousMode 1
|
||||
HiddenServiceSingleHopMode 1
|
||||
# smp-server hidden service host directory and port mappings
|
||||
HiddenServiceDir /var/lib/tor/simplex-smp/
|
||||
HiddenServicePort 5223 localhost:5223
|
||||
```
|
||||
|
||||
- Create directories:
|
||||
|
||||
```sh
|
||||
mkdir /var/lib/tor/simplex-smp/ && chown debian-tor:debian-tor /var/lib/tor/simplex-smp/ && chmod 700 /var/lib/tor/simplex-smp/
|
||||
```
|
||||
|
||||
3. Start tor:
|
||||
|
||||
Enable `systemd` service and start tor. Offical `tor` is a bit flunky on the first start and may not create onion host address, so we're restarting it just in case.
|
||||
|
||||
```sh
|
||||
systemctl enable tor && systemctl start tor && systemctl restart tor
|
||||
```
|
||||
|
||||
4. Display onion host:
|
||||
|
||||
Execute the following command to display your onion host address:
|
||||
|
||||
```sh
|
||||
cat /var/lib/tor/simplex-smp/hostname
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
To see which options are available, execute `smp-server` without flags:
|
||||
|
||||
+9
-106
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: Hosting your own XFTP Server
|
||||
revision: 31.07.2023
|
||||
revision: 21.04.2023
|
||||
---
|
||||
# Hosting your own XFTP Server
|
||||
|
||||
@@ -17,43 +17,26 @@ XFTP is a new file transfer protocol focussed on meta-data protection - it is ba
|
||||
|
||||
## Installation
|
||||
|
||||
0. First, install `xftp-server`:
|
||||
1. Download `xftp-server` binary:
|
||||
|
||||
- Manual deployment (see below)
|
||||
```sh
|
||||
sudo curl -L https://github.com/simplex-chat/simplexmq/releases/latest/download/xftp-server-ubuntu-20_04-x86-64 -o /usr/local/bin/xftp-server && sudo chmod +x /usr/local/bin/xftp-server
|
||||
```
|
||||
|
||||
- Semi-automatic deployment:
|
||||
- [Offical installation script](https://github.com/simplex-chat/simplexmq#using-installation-script)
|
||||
- [Docker container](https://github.com/simplex-chat/simplexmq#using-docker)
|
||||
|
||||
Manual installation requires some preliminary actions:
|
||||
|
||||
0. Install binary:
|
||||
|
||||
- Using offical binaries:
|
||||
|
||||
```sh
|
||||
curl -L https://github.com/simplex-chat/simplexmq/releases/latest/download/xftp-server-ubuntu-20_04-x86-64 -o /usr/local/bin/xftp-server
|
||||
```
|
||||
|
||||
- Compiling from source:
|
||||
|
||||
Please refer to [Build from source: Using your distribution](https://github.com/simplex-chat/simplexmq#using-your-distribution)
|
||||
|
||||
|
||||
1. Create user and group for `xftp-server`:
|
||||
2. Create user and group for `xftp-server`:
|
||||
|
||||
```sh
|
||||
sudo useradd -m xftp
|
||||
```
|
||||
|
||||
2. Create necessary directories and assign permissions:
|
||||
3. Create necessary directories and assign permissions:
|
||||
|
||||
```sh
|
||||
sudo mkdir -p /var/opt/simplex-xftp /etc/opt/simplex-xftp /srv/xftp
|
||||
sudo chown xftp:xftp /var/opt/simplex-xftp /etc/opt/simplex-xftp /srv/xftp
|
||||
```
|
||||
|
||||
3. Allow xftp-server port in firewall:
|
||||
4. Allow xftp-server port in firewall:
|
||||
|
||||
```sh
|
||||
# For Ubuntu
|
||||
@@ -63,7 +46,7 @@ Manual installation requires some preliminary actions:
|
||||
sudo firewall-cmd --reload
|
||||
```
|
||||
|
||||
4. **Optional** — If you're using distribution with `systemd`, create `/etc/systemd/system/xftp-server.service` file with the following content:
|
||||
5. **Optional** — If you're using distribution with `systemd`, create `/etc/systemd/system/xftp-server.service` file with the following content:
|
||||
|
||||
```sh
|
||||
[Unit]
|
||||
@@ -86,86 +69,6 @@ Manual installation requires some preliminary actions:
|
||||
|
||||
And execute `sudo systemctl daemon-reload`.
|
||||
|
||||
## Tor installation
|
||||
|
||||
xftp-server can also be deployed to serve from [tor](https://www.torproject.org) network. Run the following commands as `root` user.
|
||||
|
||||
1. Install tor:
|
||||
|
||||
We're assuming you're using Ubuntu/Debian based distributions. If not, please refer to [offical tor documentation](https://community.torproject.org/onion-services/setup/install/) or your distribution guide.
|
||||
|
||||
- Configure offical Tor PPA repository:
|
||||
|
||||
```sh
|
||||
CODENAME="$(lsb_release -c | awk '{print $2}')"
|
||||
echo "deb [signed-by=/usr/share/keyrings/tor-archive-keyring.gpg] https://deb.torproject.org/torproject.org ${CODENAME} main
|
||||
deb-src [signed-by=/usr/share/keyrings/tor-archive-keyring.gpg] https://deb.torproject.org/torproject.org ${CODENAME} main" > /etc/apt/sources.list.d/tor.list
|
||||
```
|
||||
|
||||
- Import repository key:
|
||||
|
||||
```sh
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://deb.torproject.org/torproject.org/A3C4F0F979CAA22CDBA8F512EE8CBC9E886DDD89.asc | gpg --dearmor | tee /usr/share/keyrings/tor-archive-keyring.gpg >/dev/null
|
||||
```
|
||||
|
||||
- Update repository index:
|
||||
|
||||
```sh
|
||||
apt update
|
||||
```
|
||||
|
||||
- Install `tor` package:
|
||||
|
||||
```sh
|
||||
apt install -y tor deb.torproject.org-keyring
|
||||
```
|
||||
|
||||
2. Configure tor:
|
||||
|
||||
- File configuration:
|
||||
|
||||
Open tor configuration with your editor of choice (`nano`,`vim`,`emacs`,etc.):
|
||||
|
||||
```sh
|
||||
vim /etc/tor/torrc
|
||||
```
|
||||
|
||||
And insert the following lines to the bottom of configuration. Please note lines starting with `#`: this is comments about each individual options.
|
||||
|
||||
```sh
|
||||
# Enable log (otherwise, tor doesn't seemd to deploy onion address)
|
||||
Log notice file /var/log/tor/notices.log
|
||||
# Enable single hop routing (2 options below are dependencies of third). Will reduce latency in exchange of anonimity (since tor runs alongside xftp-server and onion address will be displayed in clients, this is totally fine)
|
||||
SOCKSPort 0
|
||||
HiddenServiceNonAnonymousMode 1
|
||||
HiddenServiceSingleHopMode 1
|
||||
# xftp-server hidden service host directory and port mappings
|
||||
HiddenServiceDir /var/lib/tor/simplex-xftp/
|
||||
HiddenServicePort 443 localhost:443
|
||||
```
|
||||
|
||||
- Create directories:
|
||||
|
||||
```sh
|
||||
mkdir /var/lib/tor/simplex-xftp/ && chown debian-tor:debian-tor /var/lib/tor/simplex-xftp/ && chmod 700 /var/lib/tor/simplex-xftp/
|
||||
```
|
||||
|
||||
3. Start tor:
|
||||
|
||||
Enable `systemd` service and start tor. Offical `tor` is a bit flunky on the first start and may not create onion host address, so we're restarting it just in case.
|
||||
|
||||
```sh
|
||||
systemctl enable tor && systemctl start tor && systemctl restart tor
|
||||
```
|
||||
|
||||
4. Display onion host:
|
||||
|
||||
Execute the following command to display your onion host address:
|
||||
|
||||
```sh
|
||||
cat /var/lib/tor/simplex-xftp/hostname
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
To see which options are available, execute `xftp-server` without flags:
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
name: simplex-chat
|
||||
version: 5.3.0.4
|
||||
version: 5.3.0.2
|
||||
#synopsis:
|
||||
#description:
|
||||
homepage: https://github.com/simplex-chat/simplex-chat#readme
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"https://github.com/simplex-chat/simplexmq.git"."e2065ab3525ca67e39700ee8040839d667f75ea2" = "13rz58bdpkhfrp1d58ylpbazhzs26q5fjg0sclxgvdqnnmac5cgz";
|
||||
"https://github.com/simplex-chat/simplexmq.git"."82aec2cd8f7b4033dbf08d5de33ced216f574bbb" = "1x3rjq10d3c8qb6wf66a2j127xi9xdg21pyw5r4n124f8yvlb0nc";
|
||||
"https://github.com/simplex-chat/hs-socks.git"."a30cc7a79a08d8108316094f8f2f82a0c5e1ac51" = "0yasvnr7g91k76mjkamvzab2kvlb1g5pspjyjn2fr6v83swjhj38";
|
||||
"https://github.com/kazu-yamamoto/http2.git"."b5a1b7200cf5bc7044af34ba325284271f6dff25" = "0dqb50j57an64nf4qcf5vcz4xkd1vzvghvf8bk529c1k30r9nfzb";
|
||||
"https://github.com/simplex-chat/direct-sqlcipher.git"."34309410eb2069b029b8fc1872deb1e0db123294" = "0kwkmhyfsn2lixdlgl15smgr1h5gjk7fky6abzh8rng2h5ymnffd";
|
||||
|
||||
+2
-2
@@ -5,12 +5,12 @@ cabal-version: 1.12
|
||||
-- see: https://github.com/sol/hpack
|
||||
|
||||
name: simplex-chat
|
||||
version: 5.3.0.4
|
||||
version: 5.3.0.2
|
||||
category: Web, System, Services, Cryptography
|
||||
homepage: https://github.com/simplex-chat/simplex-chat#readme
|
||||
author: simplex.chat
|
||||
maintainer: chat@simplex.chat
|
||||
copyright: 2020-23 simplex.chat
|
||||
copyright: 2020-22 simplex.chat
|
||||
license: AGPL-3
|
||||
license-file: LICENSE
|
||||
build-type: Simple
|
||||
|
||||
+6
-15
@@ -48,7 +48,7 @@ import Data.Time (NominalDiffTime, addUTCTime, defaultTimeLocale, formatTime)
|
||||
import Data.Time.Clock (UTCTime, diffUTCTime, getCurrentTime, nominalDay, nominalDiffTimeToSeconds)
|
||||
import Data.Time.Clock.System (SystemTime, systemToUTCTime)
|
||||
import Data.Word (Word32)
|
||||
import qualified Database.SQLite.Simple as SQL
|
||||
import qualified Database.SQLite.Simple as DB
|
||||
import Simplex.Chat.Archive
|
||||
import Simplex.Chat.Call
|
||||
import Simplex.Chat.Controller
|
||||
@@ -74,12 +74,11 @@ import Simplex.FileTransfer.Client.Presets (defaultXFTPServers)
|
||||
import Simplex.FileTransfer.Description (ValidFileDescription, gb, kb, mb)
|
||||
import Simplex.FileTransfer.Protocol (FileParty (..), FilePartyI)
|
||||
import Simplex.Messaging.Agent as Agent
|
||||
import Simplex.Messaging.Agent.Client (AgentStatsKey (..), agentClientStore, temporaryAgentError)
|
||||
import Simplex.Messaging.Agent.Client (AgentStatsKey (..), temporaryAgentError)
|
||||
import Simplex.Messaging.Agent.Env.SQLite (AgentConfig (..), InitialAgentServers (..), createAgentStore, defaultAgentConfig)
|
||||
import Simplex.Messaging.Agent.Lock
|
||||
import Simplex.Messaging.Agent.Protocol
|
||||
import Simplex.Messaging.Agent.Store.SQLite (MigrationConfirmation (..), MigrationError, SQLiteStore (dbNew), execSQL, upMigration, withConnection)
|
||||
import qualified Simplex.Messaging.Agent.Store.SQLite.DB as DB
|
||||
import Simplex.Messaging.Agent.Store.SQLite (MigrationConfirmation (..), MigrationError, SQLiteStore (dbNew), execSQL, upMigration)
|
||||
import qualified Simplex.Messaging.Agent.Store.SQLite.Migrations as Migrations
|
||||
import Simplex.Messaging.Client (defaultNetworkConfig)
|
||||
import qualified Simplex.Messaging.Crypto as C
|
||||
@@ -398,7 +397,7 @@ processChatCommand = \case
|
||||
asks currentUser >>= atomically . (`writeTVar` Just user'')
|
||||
pure $ CRActiveUser user''
|
||||
SetActiveUser uName viewPwd_ -> do
|
||||
tryChatError (withStore (`getUserIdByName` uName)) >>= \case
|
||||
tryError (withStore (`getUserIdByName` uName)) >>= \case
|
||||
Left _ -> throwChatError CEUserUnknown
|
||||
Right userId -> processChatCommand $ APISetActiveUser userId viewPwd_
|
||||
SetAllContactReceipts onOff -> withUser $ \_ -> withStore' (`updateAllContactReceipts` onOff) >> ok_
|
||||
@@ -492,13 +491,6 @@ processChatCommand = \case
|
||||
APIStorageEncryption cfg -> withStoreChanged $ sqlCipherExport cfg
|
||||
ExecChatStoreSQL query -> CRSQLResult <$> withStore' (`execSQL` query)
|
||||
ExecAgentStoreSQL query -> CRSQLResult <$> withAgent (`execAgentStoreSQL` query)
|
||||
SlowSQLQueries -> do
|
||||
ChatController {chatStore, smpAgent} <- ask
|
||||
chatQueries <- slowQueries chatStore
|
||||
agentQueries <- slowQueries $ agentClientStore smpAgent
|
||||
pure CRSlowSQLQueries {chatQueries, agentQueries}
|
||||
where
|
||||
slowQueries st = liftIO $ map (uncurry SlowSQLQuery . first SQL.fromQuery) . sortOn snd . M.assocs <$> withConnection st (readTVarIO . DB.slow)
|
||||
APIGetChats userId withPCC -> withUserId userId $ \user ->
|
||||
CRApiChats user <$> withStoreCtx' (Just "APIGetChats, getChatPreviews") (\db -> getChatPreviews db user withPCC)
|
||||
APIGetChat (ChatRef cType cId) pagination search -> withUser $ \user -> case cType of
|
||||
@@ -1714,7 +1706,7 @@ processChatCommand = \case
|
||||
QuitChat -> liftIO exitSuccess
|
||||
ShowVersion -> do
|
||||
let versionInfo = coreVersionInfo $(simplexmqCommitQ)
|
||||
chatMigrations <- map upMigration <$> withStore' (Migrations.getCurrent . DB.conn)
|
||||
chatMigrations <- map upMigration <$> withStore' Migrations.getCurrent
|
||||
agentMigrations <- withAgent getAgentMigrations
|
||||
pure $ CRVersionInfo {versionInfo, chatMigrations, agentMigrations}
|
||||
DebugLocks -> do
|
||||
@@ -1967,7 +1959,7 @@ processChatCommand = \case
|
||||
drgRandomBytes n = asks idsDrg >>= liftIO . (`randomBytes` n)
|
||||
privateGetUser :: UserId -> m User
|
||||
privateGetUser userId =
|
||||
tryChatError (withStore (`getUser` userId)) >>= \case
|
||||
tryError (withStore (`getUser` userId)) >>= \case
|
||||
Left _ -> throwChatError CEUserUnknown
|
||||
Right user -> pure user
|
||||
validateUserPassword :: User -> User -> Maybe UserPwd -> m ()
|
||||
@@ -5048,7 +5040,6 @@ chatCommandP =
|
||||
"/db decrypt " *> (APIStorageEncryption . (`DBEncryptionConfig` "") <$> dbKeyP),
|
||||
"/sql chat " *> (ExecChatStoreSQL <$> textP),
|
||||
"/sql agent " *> (ExecAgentStoreSQL <$> textP),
|
||||
"/sql slow" $> SlowSQLQueries,
|
||||
"/_get chats " *> (APIGetChats <$> A.decimal <*> (" pcc=on" $> True <|> " pcc=off" $> False <|> pure False)),
|
||||
"/_get chat " *> (APIGetChat <$> chatRefP <* A.space <*> chatPaginationP <*> optional (" search=" *> stringP)),
|
||||
"/_get items " *> (APIGetChatItems <$> chatPaginationP <*> optional (" search=" *> stringP)),
|
||||
|
||||
@@ -229,7 +229,6 @@ data ChatCommand
|
||||
| APIStorageEncryption DBEncryptionConfig
|
||||
| ExecChatStoreSQL Text
|
||||
| ExecAgentStoreSQL Text
|
||||
| SlowSQLQueries
|
||||
| APIGetChats {userId :: UserId, pendingConnections :: Bool}
|
||||
| APIGetChat ChatRef ChatPagination (Maybe String)
|
||||
| APIGetChatItems ChatPagination (Maybe String)
|
||||
@@ -564,7 +563,6 @@ data ChatResponse
|
||||
| CRNewContactConnection {user :: User, connection :: PendingContactConnection}
|
||||
| CRContactConnectionDeleted {user :: User, connection :: PendingContactConnection}
|
||||
| CRSQLResult {rows :: [Text]}
|
||||
| CRSlowSQLQueries {chatQueries :: [SlowSQLQuery], agentQueries :: [SlowSQLQuery]}
|
||||
| CRDebugLocks {chatLockName :: Maybe String, agentLocks :: AgentLocks}
|
||||
| CRAgentStats {agentStats :: [[String]]}
|
||||
| CRConnectionDisabled {connectionEntity :: ConnectionEntity}
|
||||
@@ -803,14 +801,6 @@ data SendFileMode
|
||||
| SendFileXFTP
|
||||
deriving (Show, Generic)
|
||||
|
||||
data SlowSQLQuery = SlowSQLQuery
|
||||
{ query :: Text,
|
||||
duration :: Int64
|
||||
}
|
||||
deriving (Show, Generic)
|
||||
|
||||
instance ToJSON SlowSQLQuery where toEncoding = J.genericToEncoding J.defaultOptions
|
||||
|
||||
data ChatError
|
||||
= ChatError {errorType :: ChatErrorType}
|
||||
| ChatErrorAgent {agentError :: AgentErrorType, connectionEntity_ :: Maybe ConnectionEntity}
|
||||
|
||||
@@ -30,7 +30,6 @@ import Foreign.C.Types (CInt (..))
|
||||
import Foreign.Ptr
|
||||
import Foreign.StablePtr
|
||||
import Foreign.Storable (poke)
|
||||
import GHC.IO.Encoding (setLocaleEncoding, setFileSystemEncoding, setForeignEncoding)
|
||||
import GHC.Generics (Generic)
|
||||
import Simplex.Chat
|
||||
import Simplex.Chat.Controller
|
||||
@@ -48,7 +47,6 @@ import Simplex.Messaging.Encoding.String
|
||||
import Simplex.Messaging.Parsers (dropPrefix, sumTypeJSON)
|
||||
import Simplex.Messaging.Protocol (AProtoServerWithAuth (..), AProtocolType (..), BasicAuth (..), CorrId (..), ProtoServerWithAuth (..), ProtocolServer (..))
|
||||
import Simplex.Messaging.Util (catchAll, liftEitherWith, safeDecodeUtf8)
|
||||
import System.IO (utf8)
|
||||
import System.Timeout (timeout)
|
||||
|
||||
foreign export ccall "chat_migrate_init" cChatMigrateInit :: CString -> CString -> CString -> Ptr (StablePtr ChatController) -> IO CJSONString
|
||||
@@ -72,12 +70,6 @@ foreign export ccall "chat_decrypt_media" cChatDecryptMedia :: CString -> Ptr Wo
|
||||
-- | check / migrate database and initialize chat controller on success
|
||||
cChatMigrateInit :: CString -> CString -> CString -> Ptr (StablePtr ChatController) -> IO CJSONString
|
||||
cChatMigrateInit fp key conf ctrl = do
|
||||
-- ensure we are set to UTF-8; iOS does not have locale, and will default to
|
||||
-- US-ASCII all the time.
|
||||
setLocaleEncoding utf8
|
||||
setFileSystemEncoding utf8
|
||||
setForeignEncoding utf8
|
||||
|
||||
dbPath <- peekCAString fp
|
||||
dbKey <- peekCAString key
|
||||
confirm <- peekCAString conf
|
||||
|
||||
@@ -16,6 +16,7 @@ import Data.Maybe (fromMaybe)
|
||||
import Data.Text (Text)
|
||||
import Data.Time.Clock (UTCTime (..))
|
||||
import Database.SQLite.Simple ((:.) (..))
|
||||
import qualified Database.SQLite.Simple as DB
|
||||
import Database.SQLite.Simple.QQ (sql)
|
||||
import Simplex.Chat.Store.Files
|
||||
import Simplex.Chat.Store.Groups
|
||||
@@ -24,7 +25,6 @@ import Simplex.Chat.Protocol
|
||||
import Simplex.Chat.Types
|
||||
import Simplex.Chat.Types.Preferences
|
||||
import Simplex.Messaging.Agent.Store.SQLite (firstRow, firstRow')
|
||||
import qualified Simplex.Messaging.Agent.Store.SQLite.DB as DB
|
||||
|
||||
getConnectionEntity :: DB.Connection -> User -> AgentConnId -> ExceptT StoreError IO ConnectionEntity
|
||||
getConnectionEntity db user@User {userId, userContactId} agentConnId = do
|
||||
|
||||
@@ -68,13 +68,13 @@ import Data.Maybe (fromMaybe, isJust, isNothing)
|
||||
import Data.Text (Text)
|
||||
import Data.Time.Clock (UTCTime (..), getCurrentTime)
|
||||
import Database.SQLite.Simple (NamedParam (..), Only (..), (:.) (..))
|
||||
import qualified Database.SQLite.Simple as DB
|
||||
import Database.SQLite.Simple.QQ (sql)
|
||||
import Simplex.Chat.Store.Shared
|
||||
import Simplex.Chat.Types
|
||||
import Simplex.Chat.Types.Preferences
|
||||
import Simplex.Messaging.Agent.Protocol (ConnId, InvitationId, UserId)
|
||||
import Simplex.Messaging.Agent.Store.SQLite (firstRow, maybeFirstRow)
|
||||
import qualified Simplex.Messaging.Agent.Store.SQLite.DB as DB
|
||||
|
||||
getPendingContactConnection :: DB.Connection -> UserId -> Int64 -> ExceptT StoreError IO PendingContactConnection
|
||||
getPendingContactConnection db userId connId = do
|
||||
|
||||
@@ -83,6 +83,7 @@ import Data.Time (addUTCTime)
|
||||
import Data.Time.Clock (UTCTime (..), getCurrentTime, nominalDay)
|
||||
import Data.Type.Equality
|
||||
import Database.SQLite.Simple (Only (..), (:.) (..))
|
||||
import qualified Database.SQLite.Simple as DB
|
||||
import Database.SQLite.Simple.QQ (sql)
|
||||
import Simplex.Chat.Store.Direct
|
||||
import Simplex.Chat.Store.Messages
|
||||
@@ -95,7 +96,6 @@ import Simplex.Chat.Types
|
||||
import Simplex.Chat.Util (week)
|
||||
import Simplex.Messaging.Agent.Protocol (AgentMsgId, ConnId, UserId)
|
||||
import Simplex.Messaging.Agent.Store.SQLite (firstRow, maybeFirstRow)
|
||||
import qualified Simplex.Messaging.Agent.Store.SQLite.DB as DB
|
||||
|
||||
getLiveSndFileTransfers :: DB.Connection -> User -> IO [SndFileTransfer]
|
||||
getLiveSndFileTransfers db User {userId} = do
|
||||
|
||||
@@ -94,6 +94,7 @@ import Data.Maybe (fromMaybe, isNothing)
|
||||
import Data.Text (Text)
|
||||
import Data.Time.Clock (UTCTime (..), getCurrentTime)
|
||||
import Database.SQLite.Simple (NamedParam (..), Only (..), Query (..), (:.) (..))
|
||||
import qualified Database.SQLite.Simple as DB
|
||||
import Database.SQLite.Simple.QQ (sql)
|
||||
import Simplex.Chat.Messages
|
||||
import Simplex.Chat.Store.Direct
|
||||
@@ -102,7 +103,6 @@ import Simplex.Chat.Types
|
||||
import Simplex.Chat.Types.Preferences
|
||||
import Simplex.Messaging.Agent.Protocol (ConnId, UserId)
|
||||
import Simplex.Messaging.Agent.Store.SQLite (firstRow, maybeFirstRow)
|
||||
import qualified Simplex.Messaging.Agent.Store.SQLite.DB as DB
|
||||
import qualified Simplex.Messaging.Crypto as C
|
||||
import Simplex.Messaging.Util (eitherToMaybe)
|
||||
import UnliftIO.STM
|
||||
@@ -242,11 +242,11 @@ getGroupAndMember db User {userId, userContactId} groupMemberId =
|
||||
LEFT JOIN connections c ON c.connection_id = (
|
||||
SELECT max(cc.connection_id)
|
||||
FROM connections cc
|
||||
where cc.user_id = ? AND cc.group_member_id = m.group_member_id
|
||||
where cc.group_member_id = m.group_member_id
|
||||
)
|
||||
WHERE m.group_member_id = ? AND g.user_id = ? AND mu.contact_id = ?
|
||||
|]
|
||||
(userId, groupMemberId, userId, userContactId)
|
||||
(groupMemberId, userId, userContactId)
|
||||
where
|
||||
toGroupAndMember :: (GroupInfoRow :. GroupMemberRow :. MaybeConnectionRow) -> (GroupInfo, GroupMember)
|
||||
toGroupAndMember (groupInfoRow :. memberRow :. connRow) =
|
||||
@@ -530,7 +530,7 @@ groupMemberQuery =
|
||||
LEFT JOIN connections c ON c.connection_id = (
|
||||
SELECT max(cc.connection_id)
|
||||
FROM connections cc
|
||||
where cc.user_id = ? AND cc.group_member_id = m.group_member_id
|
||||
where cc.group_member_id = m.group_member_id
|
||||
)
|
||||
|]
|
||||
|
||||
@@ -540,7 +540,7 @@ getGroupMember db user@User {userId} groupId groupMemberId =
|
||||
DB.query
|
||||
db
|
||||
(groupMemberQuery <> " WHERE m.group_id = ? AND m.group_member_id = ? AND m.user_id = ?")
|
||||
(userId, groupId, groupMemberId, userId)
|
||||
(groupId, groupMemberId, userId)
|
||||
|
||||
getGroupMemberById :: DB.Connection -> User -> GroupMemberId -> ExceptT StoreError IO GroupMember
|
||||
getGroupMemberById db user@User {userId} groupMemberId =
|
||||
@@ -548,7 +548,7 @@ getGroupMemberById db user@User {userId} groupMemberId =
|
||||
DB.query
|
||||
db
|
||||
(groupMemberQuery <> " WHERE m.group_member_id = ? AND m.user_id = ?")
|
||||
(userId, groupMemberId, userId)
|
||||
(groupMemberId, userId)
|
||||
|
||||
getGroupMembers :: DB.Connection -> User -> GroupInfo -> IO [GroupMember]
|
||||
getGroupMembers db user@User {userId, userContactId} GroupInfo {groupId} = do
|
||||
@@ -556,7 +556,7 @@ getGroupMembers db user@User {userId, userContactId} GroupInfo {groupId} = do
|
||||
<$> DB.query
|
||||
db
|
||||
(groupMemberQuery <> " WHERE m.group_id = ? AND m.user_id = ? AND (m.contact_id IS NULL OR m.contact_id != ?)")
|
||||
(userId, groupId, userId, userContactId)
|
||||
(groupId, userId, userContactId)
|
||||
|
||||
getGroupMembersForExpiration :: DB.Connection -> User -> GroupInfo -> IO [GroupMember]
|
||||
getGroupMembersForExpiration db user@User {userId, userContactId} GroupInfo {groupId} = do
|
||||
@@ -572,7 +572,7 @@ getGroupMembersForExpiration db user@User {userId, userContactId} GroupInfo {gro
|
||||
)
|
||||
|]
|
||||
)
|
||||
(userId, groupId, userId, userContactId, GSMemRemoved, GSMemLeft, GSMemGroupDeleted)
|
||||
(groupId, userId, userContactId, GSMemRemoved, GSMemLeft, GSMemGroupDeleted)
|
||||
|
||||
toContactMember :: User -> (GroupMemberRow :. MaybeConnectionRow) -> GroupMember
|
||||
toContactMember User {userContactId} (memberRow :. connRow) =
|
||||
@@ -998,11 +998,11 @@ getViaGroupMember db User {userId, userContactId} Contact {contactId} =
|
||||
LEFT JOIN connections c ON c.connection_id = (
|
||||
SELECT max(cc.connection_id)
|
||||
FROM connections cc
|
||||
where cc.user_id = ? AND cc.group_member_id = m.group_member_id
|
||||
where cc.group_member_id = m.group_member_id
|
||||
)
|
||||
WHERE ct.user_id = ? AND ct.contact_id = ? AND mu.contact_id = ? AND ct.deleted = 0
|
||||
|]
|
||||
(userId, userId, contactId, userContactId)
|
||||
(userId, contactId, userContactId)
|
||||
where
|
||||
toGroupAndMember :: (GroupInfoRow :. GroupMemberRow :. MaybeConnectionRow) -> (GroupInfo, GroupMember)
|
||||
toGroupAndMember (groupInfoRow :. memberRow :. connRow) =
|
||||
@@ -1296,11 +1296,11 @@ getXGrpMemIntroContDirect db User {userId} Contact {contactId} = do
|
||||
LEFT JOIN connections ch ON ch.connection_id = (
|
||||
SELECT max(cc.connection_id)
|
||||
FROM connections cc
|
||||
where cc.user_id = ? AND cc.group_member_id = mh.group_member_id
|
||||
where cc.group_member_id = mh.group_member_id
|
||||
)
|
||||
WHERE ct.user_id = ? AND ct.contact_id = ? AND ct.deleted = 0 AND mh.member_category = ?
|
||||
|]
|
||||
(userId, userId, contactId, GCHostMember)
|
||||
(userId, contactId, GCHostMember)
|
||||
where
|
||||
toCont :: (Int64, GroupId, GroupMemberId, MemberId, Maybe ConnReqInvitation) -> Maybe (Int64, XGrpMemIntroCont)
|
||||
toCont (hostConnId, groupId, groupMemberId, memberId, connReq_) = case connReq_ of
|
||||
@@ -1326,11 +1326,11 @@ getXGrpMemIntroContGroup db User {userId} GroupMember {groupMemberId} = do
|
||||
LEFT JOIN connections ch ON ch.connection_id = (
|
||||
SELECT max(cc.connection_id)
|
||||
FROM connections cc
|
||||
where cc.user_id = ? AND cc.group_member_id = mh.group_member_id
|
||||
where cc.group_member_id = mh.group_member_id
|
||||
)
|
||||
WHERE m.user_id = ? AND m.group_member_id = ? AND mh.member_category = ? AND ct.deleted = 0
|
||||
|]
|
||||
(userId, userId, groupMemberId, GCHostMember)
|
||||
(userId, groupMemberId, GCHostMember)
|
||||
where
|
||||
toCont :: (Int64, Maybe ConnReqInvitation) -> Maybe (Int64, ConnReqInvitation)
|
||||
toCont (hostConnId, connReq_) = case connReq_ of
|
||||
|
||||
@@ -110,6 +110,7 @@ import Data.Text (Text)
|
||||
import Data.Time (addUTCTime)
|
||||
import Data.Time.Clock (UTCTime (..), getCurrentTime)
|
||||
import Database.SQLite.Simple (NamedParam (..), Only (..), (:.) (..))
|
||||
import qualified Database.SQLite.Simple as DB
|
||||
import Database.SQLite.Simple.QQ (sql)
|
||||
import Simplex.Chat.Markdown
|
||||
import Simplex.Chat.Messages
|
||||
@@ -121,7 +122,6 @@ import Simplex.Chat.Store.Shared
|
||||
import Simplex.Chat.Types
|
||||
import Simplex.Messaging.Agent.Protocol (AgentMsgId, ConnId, MsgMeta (..), UserId)
|
||||
import Simplex.Messaging.Agent.Store.SQLite (firstRow, firstRow', maybeFirstRow)
|
||||
import qualified Simplex.Messaging.Agent.Store.SQLite.DB as DB
|
||||
import Simplex.Messaging.Util (eitherToMaybe)
|
||||
import UnliftIO.STM
|
||||
|
||||
|
||||
@@ -66,6 +66,7 @@ import Data.Text (Text)
|
||||
import Data.Text.Encoding (decodeLatin1, encodeUtf8)
|
||||
import Data.Time.Clock (UTCTime (..), getCurrentTime)
|
||||
import Database.SQLite.Simple (NamedParam (..), Only (..), (:.) (..))
|
||||
import qualified Database.SQLite.Simple as DB
|
||||
import Database.SQLite.Simple.QQ (sql)
|
||||
import GHC.Generics (Generic)
|
||||
import Simplex.Chat.Call
|
||||
@@ -77,7 +78,6 @@ import Simplex.Chat.Types
|
||||
import Simplex.Chat.Types.Preferences
|
||||
import Simplex.Messaging.Agent.Protocol (ACorrId, ConnId, UserId)
|
||||
import Simplex.Messaging.Agent.Store.SQLite (firstRow, maybeFirstRow)
|
||||
import qualified Simplex.Messaging.Agent.Store.SQLite.DB as DB
|
||||
import qualified Simplex.Messaging.Crypto as C
|
||||
import Simplex.Messaging.Encoding.String
|
||||
import Simplex.Messaging.Protocol (BasicAuth (..), ProtoServerWithAuth (..), ProtocolServer (..), ProtocolTypeI (..))
|
||||
|
||||
@@ -25,7 +25,7 @@ import Data.Text (Text)
|
||||
import qualified Data.Text as T
|
||||
import Data.Time.Clock (UTCTime (..), getCurrentTime)
|
||||
import Database.SQLite.Simple (NamedParam (..), Only (..), Query, SQLError, (:.) (..))
|
||||
import qualified Database.SQLite.Simple as SQL
|
||||
import qualified Database.SQLite.Simple as DB
|
||||
import Database.SQLite.Simple.QQ (sql)
|
||||
import GHC.Generics (Generic)
|
||||
import Simplex.Chat.Messages
|
||||
@@ -34,7 +34,6 @@ import Simplex.Chat.Types
|
||||
import Simplex.Chat.Types.Preferences
|
||||
import Simplex.Messaging.Agent.Protocol (AgentMsgId, ConnId, UserId)
|
||||
import Simplex.Messaging.Agent.Store.SQLite (firstRow, maybeFirstRow)
|
||||
import qualified Simplex.Messaging.Agent.Store.SQLite.DB as DB
|
||||
import Simplex.Messaging.Parsers (dropPrefix, sumTypeJSON)
|
||||
import Simplex.Messaging.Util (allFinally)
|
||||
import UnliftIO.STM
|
||||
@@ -108,7 +107,7 @@ checkConstraint err action = ExceptT $ runExceptT action `E.catch` (pure . Left
|
||||
|
||||
handleSQLError :: StoreError -> SQLError -> StoreError
|
||||
handleSQLError err e
|
||||
| SQL.sqlError e == SQL.ErrorConstraint = err
|
||||
| DB.sqlError e == DB.ErrorConstraint = err
|
||||
| otherwise = SEInternalError $ show e
|
||||
|
||||
storeFinally :: ExceptT StoreError IO a -> ExceptT StoreError IO b -> ExceptT StoreError IO a
|
||||
@@ -310,7 +309,7 @@ withLocalDisplayName db userId displayName action = getLdnSuffix >>= (`tryCreate
|
||||
E.try (insertName ldn currentTs) >>= \case
|
||||
Right () -> action ldn
|
||||
Left e
|
||||
| SQL.sqlError e == SQL.ErrorConstraint -> tryCreateName (ldnSuffix + 1) (attempts - 1)
|
||||
| DB.sqlError e == DB.ErrorConstraint -> tryCreateName (ldnSuffix + 1) (attempts - 1)
|
||||
| otherwise -> E.throwIO e
|
||||
where
|
||||
insertName ldn ts =
|
||||
@@ -336,7 +335,7 @@ createWithRandomBytes size gVar create = tryCreate 3
|
||||
liftIO (E.try $ create id') >>= \case
|
||||
Right x -> pure x
|
||||
Left e
|
||||
| SQL.sqlError e == SQL.ErrorConstraint -> tryCreate (n - 1)
|
||||
| DB.sqlError e == DB.ErrorConstraint -> tryCreate (n - 1)
|
||||
| otherwise -> throwError . SEInternalError $ show e
|
||||
|
||||
encodedRandomBytes :: TVar ChaChaDRG -> Int -> IO ByteString
|
||||
|
||||
@@ -25,7 +25,7 @@ import Data.Text (Text)
|
||||
import qualified Data.Text as T
|
||||
import Data.Text.Encoding (encodeUtf8)
|
||||
import Database.SQLite.Simple (Only (..))
|
||||
import qualified Database.SQLite.Simple as SQL
|
||||
import qualified Database.SQLite.Simple as DB
|
||||
import Database.SQLite.Simple.QQ (sql)
|
||||
import GHC.Weak (deRefWeak)
|
||||
import Simplex.Chat
|
||||
@@ -36,7 +36,6 @@ import Simplex.Chat.Styled
|
||||
import Simplex.Chat.Terminal.Output
|
||||
import Simplex.Chat.Types (User (..))
|
||||
import Simplex.Messaging.Agent.Store.SQLite (SQLiteStore, withTransaction)
|
||||
import qualified Simplex.Messaging.Agent.Store.SQLite.DB as DB
|
||||
import Simplex.Messaging.Util (catchAll_, safeDecodeUtf8, whenM)
|
||||
import System.Exit (exitSuccess)
|
||||
import System.Terminal hiding (insertChars)
|
||||
@@ -300,7 +299,7 @@ updateTermState user_ st ac live tw (key, ms) ts@TerminalState {inputString = s,
|
||||
getNameSfxs table pfx =
|
||||
getNameSfxs_ pfx (userId, pfx <> "%") $
|
||||
"SELECT local_display_name FROM " <> table <> " WHERE user_id = ? AND local_display_name LIKE ?"
|
||||
getNameSfxs_ :: SQL.ToRow p => Text -> p -> SQL.Query -> IO [String]
|
||||
getNameSfxs_ :: DB.ToRow p => Text -> p -> DB.Query -> IO [String]
|
||||
getNameSfxs_ pfx ps q =
|
||||
withTransaction st (\db -> hasPfx pfx . map fromOnly <$> DB.query db q ps) `catchAll_` pure []
|
||||
commands =
|
||||
|
||||
@@ -247,9 +247,6 @@ responseToView user_ ChatConfig {logLevel, showReactions, showReceipts, testView
|
||||
CRNtfToken _ status mode -> ["device token status: " <> plain (smpEncode status) <> ", notifications mode: " <> plain (strEncode mode)]
|
||||
CRNtfMessages {} -> []
|
||||
CRSQLResult rows -> map plain rows
|
||||
CRSlowSQLQueries {chatQueries, agentQueries} ->
|
||||
let viewQuery SlowSQLQuery {query, duration} = sShow duration <> " ms: " <> plain (T.unwords $ T.lines query)
|
||||
in ("Chat queries" : map viewQuery chatQueries) <> [""] <> ("Agent queries" : map viewQuery agentQueries)
|
||||
CRDebugLocks {chatLockName, agentLocks} ->
|
||||
[ maybe "no chat lock" (("chat lock: " <>) . plain) chatLockName,
|
||||
plain $ "agent locks: " <> LB.unpack (J.encode agentLocks)
|
||||
|
||||
+1
-1
@@ -49,7 +49,7 @@ extra-deps:
|
||||
# - simplexmq-1.0.0@sha256:34b2004728ae396e3ae449cd090ba7410781e2b3cefc59259915f4ca5daa9ea8,8561
|
||||
# - ../simplexmq
|
||||
- github: simplex-chat/simplexmq
|
||||
commit: e2065ab3525ca67e39700ee8040839d667f75ea2
|
||||
commit: 82aec2cd8f7b4033dbf08d5de33ced216f574bbb
|
||||
- github: kazu-yamamoto/http2
|
||||
commit: b5a1b7200cf5bc7044af34ba325284271f6dff25
|
||||
# - ../direct-sqlcipher
|
||||
|
||||
@@ -25,7 +25,6 @@ directoryServiceTests :: SpecWith FilePath
|
||||
directoryServiceTests = do
|
||||
it "should register group" testDirectoryService
|
||||
it "should suspend and resume group" testSuspendResume
|
||||
it "should join found group via link" testJoinGroup
|
||||
describe "de-listing the group" $ do
|
||||
it "should de-list if owner leaves the group" testDelistedOwnerLeaves
|
||||
it "should de-list if owner is removed from the group" testDelistedOwnerRemoved
|
||||
@@ -191,56 +190,6 @@ testSuspendResume tmp =
|
||||
bob <# "SimpleX-Directory> The group ID 1 (privacy) is listed in the directory again!"
|
||||
groupFound bob "privacy"
|
||||
|
||||
testJoinGroup :: HasCallStack => FilePath -> IO ()
|
||||
testJoinGroup tmp =
|
||||
withDirectoryService tmp $ \superUser dsLink ->
|
||||
withNewTestChat tmp "bob" bobProfile $ \bob -> do
|
||||
withNewTestChat tmp "cath" cathProfile $ \cath ->
|
||||
withNewTestChat tmp "dan" danProfile $ \dan -> do
|
||||
bob `connectVia` dsLink
|
||||
registerGroup superUser bob "privacy" "Privacy"
|
||||
cath `connectVia` dsLink
|
||||
cath #> "@SimpleX-Directory privacy"
|
||||
cath <# "SimpleX-Directory> > privacy"
|
||||
cath <## " Found 1 group(s)"
|
||||
cath <# "SimpleX-Directory> privacy (Privacy)"
|
||||
cath <## "Welcome message:"
|
||||
welcomeMsg <- getTermLine cath
|
||||
let groupLink = dropStrPrefix "Link to join the group privacy: " welcomeMsg
|
||||
cath <## "2 members"
|
||||
cath ##> ("/c " <> groupLink)
|
||||
cath <## "connection request sent!"
|
||||
cath <## "SimpleX-Directory_1: contact is connected"
|
||||
cath <## "contact SimpleX-Directory_1 is merged into SimpleX-Directory"
|
||||
cath <## "use @SimpleX-Directory <message> to send messages"
|
||||
cath <## "#privacy: you joined the group"
|
||||
cath <# ("#privacy SimpleX-Directory> " <> welcomeMsg)
|
||||
cath <## "#privacy: member bob (Bob) is connected"
|
||||
bob <## "#privacy: SimpleX-Directory added cath (Catherine) to the group (connecting...)"
|
||||
bob <## "#privacy: new member cath is connected"
|
||||
bob ##> "/create link #privacy"
|
||||
bobLink <- getGroupLink bob "privacy" GRMember True
|
||||
dan ##> ("/c " <> bobLink)
|
||||
dan <## "connection request sent!"
|
||||
concurrentlyN_
|
||||
[ do
|
||||
bob <## "dan (Daniel): accepting request to join group #privacy..."
|
||||
bob <## "dan (Daniel): contact is connected"
|
||||
bob <## "dan invited to group #privacy via your group link"
|
||||
bob <## "#privacy: dan joined the group",
|
||||
do
|
||||
dan <## "bob (Bob): contact is connected"
|
||||
dan <## "#privacy: you joined the group"
|
||||
dan <# ("#privacy bob> " <> welcomeMsg)
|
||||
dan <###
|
||||
[ "#privacy: member SimpleX-Directory is connected",
|
||||
"#privacy: member cath (Catherine) is connected"
|
||||
],
|
||||
do
|
||||
cath <## "#privacy: bob added dan (Daniel) to the group (connecting...)"
|
||||
cath <## "#privacy: new member dan is connected"
|
||||
]
|
||||
|
||||
testDelistedOwnerLeaves :: HasCallStack => FilePath -> IO ()
|
||||
testDelistedOwnerLeaves tmp =
|
||||
withDirectoryService tmp $ \superUser dsLink ->
|
||||
|
||||
+4
-4
@@ -10,7 +10,7 @@ import Data.List (dropWhileEnd)
|
||||
import Data.Maybe (fromJust, isJust)
|
||||
import Simplex.Chat.Store (createChatStore)
|
||||
import qualified Simplex.Chat.Store as Store
|
||||
import Simplex.Messaging.Agent.Store.SQLite (MigrationConfirmation (..), closeSQLiteStore, createSQLiteStore, withConnection')
|
||||
import Simplex.Messaging.Agent.Store.SQLite (MigrationConfirmation (..), closeSQLiteStore, createSQLiteStore, withConnection)
|
||||
import Simplex.Messaging.Agent.Store.SQLite.Migrations (Migration (..), MigrationsToRun (..), toDownMigration)
|
||||
import qualified Simplex.Messaging.Agent.Store.SQLite.Migrations as Migrations
|
||||
import Simplex.Messaging.Util (ifM, whenM)
|
||||
@@ -53,14 +53,14 @@ testSchemaMigrations = withTmpFiles $ do
|
||||
putStrLn $ "down migration " <> name m
|
||||
let downMigr = fromJust $ toDownMigration m
|
||||
schema <- getSchema testDB testSchema
|
||||
withConnection' st (`Migrations.run` MTRUp [m])
|
||||
withConnection st (`Migrations.run` MTRUp [m])
|
||||
schema' <- getSchema testDB testSchema
|
||||
schema' `shouldNotBe` schema
|
||||
withConnection' st (`Migrations.run` MTRDown [downMigr])
|
||||
withConnection st (`Migrations.run` MTRDown [downMigr])
|
||||
unless (name m `elem` skipComparisonForDownMigrations) $ do
|
||||
schema'' <- getSchema testDB testSchema
|
||||
schema'' `shouldBe` schema
|
||||
withConnection' st (`Migrations.run` MTRUp [m])
|
||||
withConnection st (`Migrations.run` MTRUp [m])
|
||||
schema''' <- getSchema testDB testSchema
|
||||
schema''' `shouldBe` schema'
|
||||
|
||||
|
||||
@@ -120,7 +120,7 @@
|
||||
"simplex-unique-card-1-p-1": "يحمي SimpleX خصوصية ملف التعريف الخاص بك، جهات الاتصال والبيانات الوصفية، ويخفيه عن خوادم منصة SimpleX وأي مراقبين.",
|
||||
"privacy-matters-overlay-card-2-p-1": "منذ وقت ليس ببعيد، لاحظنا أن الانتخابات الرئيسية يتم التلاعب بها بواسطة <a href='https://en.wikipedia.org/wiki/Facebook–Cambridge_Analytica_data_scandal' target='_blank'> شركة استشارية ذات سمعة طيبة </a> التي استخدمت الرسوم البيانية الاجتماعية لتشويه نظرتنا للعالم الحقيقي والتلاعب بأصواتنا.",
|
||||
"privacy-matters-overlay-card-2-p-2": "لكي تكون موضوعيًا وتتخذ قرارات مستقلة، يجب أن تكون متحكمًا في مساحة المعلومات الخاصة بك. هذا ممكن فقط إذا كنت تستخدم منصة اتصالات خاصة لا يمكنها الوصول إلى الرسم البياني الاجتماعي الخاص بك.",
|
||||
"privacy-matters-overlay-card-2-p-3": "SimpleX هو النظام الأساسي الأول الذي لا يحتوي على أي معرفات مستخدم صمّم ليكون خاصًا، وبهذه الطريقة تحمي مخطط اتصالاتك بشكل أفضل من أي بديل معروف.",
|
||||
"privacy-matters-overlay-card-2-p-3": "SimpleX هو النظام الأساسي الأول الذي لا يحتوي على أي معرفات مستخدم حسب التصميم، وبهذه الطريقة تحمي مخطط اتصالاتك بشكل أفضل من أي بديل معروف.",
|
||||
"privacy-matters-overlay-card-3-p-2": "واحدة من أكثر القصص إثارة للصدمة هي تجربة <a href='https://en.wikipedia.org/wiki/Mohamedou_Ould_Slahi' target='_blank'> محمدو ولد صلاحي </a> الموصوفة في مذكراته والموضحة في فيلم موريتاني. تم وضعه في معتقل غوانتانامو بدون محاكمة، وتعرض للتعذيب هناك لمدة 15 عامًا بعد مكالمة هاتفية مع قريبه في أفغانستان، للاشتباه في تورطه في هجمات 11 سبتمبر، على الرغم من أنه عاش في ألمانيا طوال السنوات العشر الماضية.",
|
||||
"privacy-matters-overlay-card-3-p-3": "يتم القبض على الأشخاص العاديين بسبب ما يشاركونه عبر الإنترنت، حتى عبر حساباتهم \"المجهولة\"، <a href='https://www.dailymail.co.uk/news/article-11282263/Moment-police-swoop-house-devout-catholic-mother-malicious-online-posts.html' target='_blank'>وحتى في البلدان الديمقراطية</a>.",
|
||||
"simplex-unique-overlay-card-1-p-1": "على عكس أنظمة المراسلة الأخرى، <strong>لا يحتوي SimpleX على معرفات مخصصة للمستخدمين</strong>. لا يعتمد على أرقام الهواتف أو العناوين المستندة إلى النطاقات (مثل البريد الإلكتروني أو XMPP)، أسماء المستخدمين، المفاتيح العامة أو حتى الأرقام العشوائية لتحديد مستخدميها — لا نعرف عدد الأشخاص الذين يستخدمون خوادم SimpleX الخاصة بنا.",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"simplex-privacy": "Privatsphäre mit SimpleX",
|
||||
"simplex-network": "SimpleX-Netzwerk",
|
||||
"simplex-privacy": "SimpleX Privatsphäre",
|
||||
"simplex-network": "SimpleX Netzwerk",
|
||||
"home": "Startseite",
|
||||
"developers": "Entwickler",
|
||||
"reference": "Referenz",
|
||||
@@ -9,7 +9,7 @@
|
||||
"features": "Funktionen",
|
||||
"simplex-private-card-6-point-2": "Um das zu verhindern, werden von SimpleX Einmal-Schlüssel Out-of-Band weitergeleitet, wenn Sie eine Adresse als Link oder QR-Code teilen.",
|
||||
"simplex-explained": "SimpleX erklärt",
|
||||
"simplex-explained-tab-2-text": "2. Wie es funktioniert",
|
||||
"simplex-explained-tab-2-text": "2. Wie funktioniert es",
|
||||
"simplex-explained-tab-3-text": "3. Was die Server sehen",
|
||||
"simplex-explained-tab-1-text": "1. Wie es die Nutzer erleben",
|
||||
"simplex-explained-tab-1-p-1": "Sie können Kontakte und Gruppen erstellen und haben Zwei-Wege-Kommunikation wie in jedem anderen Messenger.",
|
||||
|
||||
@@ -95,7 +95,7 @@
|
||||
"simplex-unique-2-overlay-1-title": "La mejor protección contra el spam y el abuso",
|
||||
"simplex-unique-3-overlay-1-title": "Titularidad, control y seguridad de tus datos",
|
||||
"simplex-unique-4-overlay-1-title": "Totalmente descentralizado — los usuarios son dueños de la red SimpleX",
|
||||
"hero-overlay-card-1-p-2": "Para entregar los mensajes, en lugar de los identificadores de usuario utilizados por todas las demás plataformas, SimpleX emplea identificadores por pares temporales y anónimos de colas de mensajes, independientes para cada una de sus conexiones — no hay identificadores a largo plazo.",
|
||||
"hero-overlay-card-1-p-2": "Para entregar los mensajes, en lugar de los identificadores de usuario utilizados por todas las demás plataformas, SimpleX usa identificadores por pares anónimos y temporales de colas de mensajes, independientes para cada una de sus conexiones — no hay identificadores a largo plazo.",
|
||||
"hero-overlay-card-1-p-5": "Los perfiles de usuario, contactos y grupos sólo se almacenan en los dispositivos cliente; los mensajes se envían con cifrado de doble capa de extremo a extremo .",
|
||||
"hero-overlay-card-1-p-3": "Usted define qué servidor(es) se usan para recibir los mensajes; sus contactos — los servidores que se usan para enviar los mensajes. Es probable que cada conversación use dos servidores distintos.",
|
||||
"hero-overlay-card-2-p-4": "SimpleX protege frente estos ataques al no disponer de ID de usuario por diseño. Y si usa el modo incógnito, tendrá un nombre mostrado diferente por cada contacto, evitando cualquier dato compartido entre ellos.",
|
||||
|
||||
Reference in New Issue
Block a user