mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2024-12-17 17:20:21 +01:00
Compare commits
20 Commits
ep/survey-bot
...
v5.2.3
| Author | SHA1 | Date | |
|---|---|---|---|
| 8f9134b494 | |||
| cee0dffd46 | |||
| a2fef15440 | |||
| 0176bc3b2c | |||
| fde3c4f4e0 | |||
| f17889b3e3 | |||
| 5a5876c258 | |||
| e30f7695ab | |||
| 920b56e3d8 | |||
| dd51f032d2 | |||
| 1bdbea4f6d | |||
| 90be54ff82 | |||
| bd4b445cbf | |||
| af98e703ec | |||
| fff8935b94 | |||
| 9e7a45c734 | |||
| af33f4e2d9 | |||
| 98e53fb35b | |||
| cb4aa29549 | |||
| 8fc3f5a0f7 |
@@ -62,6 +62,7 @@ struct CIFileView: View {
|
||||
case .rcvComplete: return true
|
||||
case .rcvCancelled: return false
|
||||
case .rcvError: return false
|
||||
case .invalid: return false
|
||||
}
|
||||
}
|
||||
return false
|
||||
@@ -149,6 +150,7 @@ struct CIFileView: View {
|
||||
case .rcvComplete: fileIcon("doc.fill")
|
||||
case .rcvCancelled: fileIcon("doc.fill", innerIcon: "xmark", innerIconSize: 10)
|
||||
case .rcvError: fileIcon("doc.fill", innerIcon: "xmark", innerIconSize: 10)
|
||||
case .invalid: fileIcon("doc.fill", innerIcon: "questionmark", innerIconSize: 10)
|
||||
}
|
||||
} else {
|
||||
fileIcon("doc.fill")
|
||||
|
||||
@@ -99,6 +99,7 @@ struct CIImageView: View {
|
||||
case .rcvTransfer: progressView()
|
||||
case .rcvCancelled: fileIcon("xmark", 10, 13)
|
||||
case .rcvError: fileIcon("xmark", 10, 13)
|
||||
case .invalid: fileIcon("questionmark", 10, 13)
|
||||
default: EmptyView()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -212,6 +212,7 @@ struct CIVideoView: View {
|
||||
}
|
||||
case .rcvCancelled: fileIcon("xmark", 10, 13)
|
||||
case .rcvError: fileIcon("xmark", 10, 13)
|
||||
case .invalid: fileIcon("questionmark", 10, 13)
|
||||
default: EmptyView()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -144,6 +144,7 @@ struct VoiceMessagePlayer: View {
|
||||
case .rcvComplete: playbackButton()
|
||||
case .rcvCancelled: playPauseIcon("play.fill", Color(uiColor: .tertiaryLabel))
|
||||
case .rcvError: playPauseIcon("play.fill", Color(uiColor: .tertiaryLabel))
|
||||
case .invalid: playPauseIcon("play.fill", Color(uiColor: .tertiaryLabel))
|
||||
}
|
||||
} else {
|
||||
playPauseIcon("play.fill", Color(uiColor: .tertiaryLabel))
|
||||
|
||||
@@ -87,7 +87,7 @@ struct MsgContentView: View {
|
||||
func messageText(_ text: String, _ formattedText: [FormattedText]?, _ sender: String?, icon: String? = nil, preview: Bool = false) -> Text {
|
||||
let s = text
|
||||
var res: Text
|
||||
if let ft = formattedText, ft.count > 0 {
|
||||
if let ft = formattedText, ft.count > 0 && ft.count <= 200 {
|
||||
res = formatText(ft[0], preview)
|
||||
var i = 1
|
||||
while i < ft.count {
|
||||
|
||||
@@ -51,9 +51,9 @@ struct AdvancedNetworkSettings: View {
|
||||
}
|
||||
.disabled(currentNetCfg == NetCfg.proxyDefaults)
|
||||
|
||||
timeoutSettingPicker("TCP connection timeout", selection: $netCfg.tcpConnectTimeout, values: [2_500000, 5_000000, 7_500000, 10_000000, 15_000000, 20_000000], label: secondsLabel)
|
||||
timeoutSettingPicker("Protocol timeout", selection: $netCfg.tcpTimeout, values: [1_500000, 3_000000, 5_000000, 7_000000, 10_000000, 15_000000], label: secondsLabel)
|
||||
timeoutSettingPicker("Protocol timeout per KB", selection: $netCfg.tcpTimeoutPerKb, values: [5_000, 10_000, 20_000, 40_000], label: secondsLabel)
|
||||
timeoutSettingPicker("TCP connection timeout", selection: $netCfg.tcpConnectTimeout, values: [5_000000, 7_500000, 10_000000, 15_000000, 20_000000, 30_000000, 45_000000], label: secondsLabel)
|
||||
timeoutSettingPicker("Protocol timeout", selection: $netCfg.tcpTimeout, values: [3_000000, 5_000000, 7_000000, 10_000000, 15_000000, 20_000000, 30_000000], label: secondsLabel)
|
||||
timeoutSettingPicker("Protocol timeout per KB", selection: $netCfg.tcpTimeoutPerKb, values: [10_000, 20_000, 40_000, 75_000, 100_000], label: secondsLabel)
|
||||
timeoutSettingPicker("PING interval", selection: $netCfg.smpPingInterval, values: [120_000000, 300_000000, 600_000000, 1200_000000, 2400_000000, 3600_000000], label: secondsLabel)
|
||||
intSettingPicker("PING count", selection: $netCfg.smpPingCount, values: [1, 2, 3, 5, 8], label: "")
|
||||
Toggle("Enable TCP keep-alive", isOn: $enableKeepAlive)
|
||||
@@ -153,7 +153,9 @@ struct AdvancedNetworkSettings: View {
|
||||
|
||||
private func timeoutSettingPicker(_ title: LocalizedStringKey, selection: Binding<Int>, values: [Int], label: String) -> some View {
|
||||
Picker(title, selection: selection) {
|
||||
ForEach(values, id: \.self) { value in
|
||||
let v = selection.wrappedValue
|
||||
let vs = values.contains(v) ? values : values + [v]
|
||||
ForEach(vs, id: \.self) { value in
|
||||
Text("\(String(format: "%g", (Double(value) / 1000000))) \(secondsLabel)")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,6 +84,11 @@
|
||||
5CA059ED279559F40002BEB4 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CA059C4279559F40002BEB4 /* ContentView.swift */; };
|
||||
5CA059EF279559F40002BEB4 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5CA059C5279559F40002BEB4 /* Assets.xcassets */; };
|
||||
5CA7DFC329302AF000F7FDDE /* AppSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CA7DFC229302AF000F7FDDE /* AppSheet.swift */; };
|
||||
5CA89A442A88020700021BE9 /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CA89A3F2A88020700021BE9 /* libffi.a */; };
|
||||
5CA89A452A88020700021BE9 /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CA89A402A88020700021BE9 /* libgmp.a */; };
|
||||
5CA89A462A88020700021BE9 /* libHSsimplex-chat-5.2.3.0-B6vDAdCeaTjEONCeTB2nA6.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CA89A412A88020700021BE9 /* libHSsimplex-chat-5.2.3.0-B6vDAdCeaTjEONCeTB2nA6.a */; };
|
||||
5CA89A472A88020700021BE9 /* libHSsimplex-chat-5.2.3.0-B6vDAdCeaTjEONCeTB2nA6-ghc8.10.7.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CA89A422A88020700021BE9 /* libHSsimplex-chat-5.2.3.0-B6vDAdCeaTjEONCeTB2nA6-ghc8.10.7.a */; };
|
||||
5CA89A482A88020700021BE9 /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CA89A432A88020700021BE9 /* libgmpxx.a */; };
|
||||
5CADE79A29211BB900072E13 /* PreferencesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CADE79929211BB900072E13 /* PreferencesView.swift */; };
|
||||
5CADE79C292131E900072E13 /* ContactPreferencesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CADE79B292131E900072E13 /* ContactPreferencesView.swift */; };
|
||||
5CB0BA882826CB3A00B3292C /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 5CB0BA862826CB3A00B3292C /* InfoPlist.strings */; };
|
||||
@@ -137,11 +142,6 @@
|
||||
5CE2BA97284537A800EC33A6 /* dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 5CE2BA96284537A800EC33A6 /* dummy.m */; };
|
||||
5CE2BA9D284555F500EC33A6 /* SimpleX NSE.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 5CDCAD452818589900503DA2 /* SimpleX NSE.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||
5CE2BAA62845617C00EC33A6 /* SimpleXChat.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CE2BA682845308900EC33A6 /* SimpleXChat.framework */; platformFilter = ios; };
|
||||
5CE381E12A6C103D004FB9E1 /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CE381DC2A6C103D004FB9E1 /* libffi.a */; };
|
||||
5CE381E22A6C103D004FB9E1 /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CE381DD2A6C103D004FB9E1 /* libgmpxx.a */; };
|
||||
5CE381E32A6C103D004FB9E1 /* libHSsimplex-chat-5.2.0.4-HUgQMHMGu1K8FDeUwC5hCd-ghc8.10.7.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CE381DE2A6C103D004FB9E1 /* libHSsimplex-chat-5.2.0.4-HUgQMHMGu1K8FDeUwC5hCd-ghc8.10.7.a */; };
|
||||
5CE381E42A6C103D004FB9E1 /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CE381DF2A6C103D004FB9E1 /* libgmp.a */; };
|
||||
5CE381E52A6C103D004FB9E1 /* libHSsimplex-chat-5.2.0.4-HUgQMHMGu1K8FDeUwC5hCd.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CE381E02A6C103D004FB9E1 /* libHSsimplex-chat-5.2.0.4-HUgQMHMGu1K8FDeUwC5hCd.a */; };
|
||||
5CE4407227ADB1D0007B033A /* Emoji.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CE4407127ADB1D0007B033A /* Emoji.swift */; };
|
||||
5CE4407927ADB701007B033A /* EmojiItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CE4407827ADB701007B033A /* EmojiItemView.swift */; };
|
||||
5CEACCE327DE9246000BD591 /* ComposeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CEACCE227DE9246000BD591 /* ComposeView.swift */; };
|
||||
@@ -351,6 +351,11 @@
|
||||
5CA85D0B297218AA0095AF72 /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
5CA85D0C297219EF0095AF72 /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = "it.lproj/SimpleX--iOS--InfoPlist.strings"; sourceTree = "<group>"; };
|
||||
5CA85D0D297219EF0095AF72 /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||
5CA89A3F2A88020700021BE9 /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = "<group>"; };
|
||||
5CA89A402A88020700021BE9 /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = "<group>"; };
|
||||
5CA89A412A88020700021BE9 /* libHSsimplex-chat-5.2.3.0-B6vDAdCeaTjEONCeTB2nA6.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.2.3.0-B6vDAdCeaTjEONCeTB2nA6.a"; sourceTree = "<group>"; };
|
||||
5CA89A422A88020700021BE9 /* libHSsimplex-chat-5.2.3.0-B6vDAdCeaTjEONCeTB2nA6-ghc8.10.7.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.2.3.0-B6vDAdCeaTjEONCeTB2nA6-ghc8.10.7.a"; sourceTree = "<group>"; };
|
||||
5CA89A432A88020700021BE9 /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = "<group>"; };
|
||||
5CAB912529E93F9400F34A95 /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = pl.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
5CAB912629E93F9400F34A95 /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = pl.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
5CAC41182A192D8400C331A2 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
@@ -415,11 +420,6 @@
|
||||
5CE2BA78284530CC00EC33A6 /* SimpleXChat.docc */ = {isa = PBXFileReference; lastKnownFileType = folder.documentationcatalog; path = SimpleXChat.docc; sourceTree = "<group>"; };
|
||||
5CE2BA8A2845332200EC33A6 /* SimpleX.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SimpleX.h; sourceTree = "<group>"; };
|
||||
5CE2BA96284537A800EC33A6 /* dummy.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = dummy.m; sourceTree = "<group>"; };
|
||||
5CE381DC2A6C103D004FB9E1 /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = "<group>"; };
|
||||
5CE381DD2A6C103D004FB9E1 /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = "<group>"; };
|
||||
5CE381DE2A6C103D004FB9E1 /* libHSsimplex-chat-5.2.0.4-HUgQMHMGu1K8FDeUwC5hCd-ghc8.10.7.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.2.0.4-HUgQMHMGu1K8FDeUwC5hCd-ghc8.10.7.a"; sourceTree = "<group>"; };
|
||||
5CE381DF2A6C103D004FB9E1 /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = "<group>"; };
|
||||
5CE381E02A6C103D004FB9E1 /* libHSsimplex-chat-5.2.0.4-HUgQMHMGu1K8FDeUwC5hCd.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.2.0.4-HUgQMHMGu1K8FDeUwC5hCd.a"; sourceTree = "<group>"; };
|
||||
5CE4407127ADB1D0007B033A /* Emoji.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Emoji.swift; sourceTree = "<group>"; };
|
||||
5CE4407827ADB701007B033A /* EmojiItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiItemView.swift; sourceTree = "<group>"; };
|
||||
5CEACCE227DE9246000BD591 /* ComposeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeView.swift; sourceTree = "<group>"; };
|
||||
@@ -501,13 +501,13 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
5CE381E22A6C103D004FB9E1 /* libgmpxx.a in Frameworks */,
|
||||
5CA89A472A88020700021BE9 /* libHSsimplex-chat-5.2.3.0-B6vDAdCeaTjEONCeTB2nA6-ghc8.10.7.a in Frameworks */,
|
||||
5CE2BA93284534B000EC33A6 /* libiconv.tbd in Frameworks */,
|
||||
5CE381E32A6C103D004FB9E1 /* libHSsimplex-chat-5.2.0.4-HUgQMHMGu1K8FDeUwC5hCd-ghc8.10.7.a in Frameworks */,
|
||||
5CE381E52A6C103D004FB9E1 /* libHSsimplex-chat-5.2.0.4-HUgQMHMGu1K8FDeUwC5hCd.a in Frameworks */,
|
||||
5CE381E12A6C103D004FB9E1 /* libffi.a in Frameworks */,
|
||||
5CE381E42A6C103D004FB9E1 /* libgmp.a in Frameworks */,
|
||||
5CA89A442A88020700021BE9 /* libffi.a in Frameworks */,
|
||||
5CA89A452A88020700021BE9 /* libgmp.a in Frameworks */,
|
||||
5CA89A462A88020700021BE9 /* libHSsimplex-chat-5.2.3.0-B6vDAdCeaTjEONCeTB2nA6.a in Frameworks */,
|
||||
5CE2BA94284534BB00EC33A6 /* libz.tbd in Frameworks */,
|
||||
5CA89A482A88020700021BE9 /* libgmpxx.a in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -568,11 +568,11 @@
|
||||
5C764E5C279C70B7000C6508 /* Libraries */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5CE381DC2A6C103D004FB9E1 /* libffi.a */,
|
||||
5CE381DF2A6C103D004FB9E1 /* libgmp.a */,
|
||||
5CE381DD2A6C103D004FB9E1 /* libgmpxx.a */,
|
||||
5CE381DE2A6C103D004FB9E1 /* libHSsimplex-chat-5.2.0.4-HUgQMHMGu1K8FDeUwC5hCd-ghc8.10.7.a */,
|
||||
5CE381E02A6C103D004FB9E1 /* libHSsimplex-chat-5.2.0.4-HUgQMHMGu1K8FDeUwC5hCd.a */,
|
||||
5CA89A3F2A88020700021BE9 /* libffi.a */,
|
||||
5CA89A402A88020700021BE9 /* libgmp.a */,
|
||||
5CA89A432A88020700021BE9 /* libgmpxx.a */,
|
||||
5CA89A422A88020700021BE9 /* libHSsimplex-chat-5.2.3.0-B6vDAdCeaTjEONCeTB2nA6-ghc8.10.7.a */,
|
||||
5CA89A412A88020700021BE9 /* libHSsimplex-chat-5.2.3.0-B6vDAdCeaTjEONCeTB2nA6.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 = 160;
|
||||
CURRENT_PROJECT_VERSION = 166;
|
||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||
ENABLE_BITCODE = NO;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
@@ -1499,7 +1499,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 5.2;
|
||||
MARKETING_VERSION = 5.2.3;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.app;
|
||||
PRODUCT_NAME = SimpleX;
|
||||
SDKROOT = iphoneos;
|
||||
@@ -1520,7 +1520,7 @@
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 160;
|
||||
CURRENT_PROJECT_VERSION = 166;
|
||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||
ENABLE_BITCODE = NO;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
@@ -1541,7 +1541,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 5.2;
|
||||
MARKETING_VERSION = 5.2.3;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.app;
|
||||
PRODUCT_NAME = SimpleX;
|
||||
SDKROOT = iphoneos;
|
||||
@@ -1600,7 +1600,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements";
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 160;
|
||||
CURRENT_PROJECT_VERSION = 166;
|
||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||
ENABLE_BITCODE = NO;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
@@ -1613,7 +1613,7 @@
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 5.2;
|
||||
MARKETING_VERSION = 5.2.3;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "chat.simplex.app.SimpleX-NSE";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
@@ -1632,7 +1632,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements";
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 160;
|
||||
CURRENT_PROJECT_VERSION = 166;
|
||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||
ENABLE_BITCODE = NO;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
@@ -1645,7 +1645,7 @@
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 5.2;
|
||||
MARKETING_VERSION = 5.2.3;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "chat.simplex.app.SimpleX-NSE";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
@@ -1664,7 +1664,7 @@
|
||||
APPLICATION_EXTENSION_API_ONLY = YES;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 160;
|
||||
CURRENT_PROJECT_VERSION = 166;
|
||||
DEFINES_MODULE = YES;
|
||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
@@ -1688,7 +1688,7 @@
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/Libraries/sim",
|
||||
);
|
||||
MARKETING_VERSION = 5.2;
|
||||
MARKETING_VERSION = 5.2.3;
|
||||
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 = 160;
|
||||
CURRENT_PROJECT_VERSION = 166;
|
||||
DEFINES_MODULE = YES;
|
||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
@@ -1734,7 +1734,7 @@
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/Libraries/sim",
|
||||
);
|
||||
MARKETING_VERSION = 5.2;
|
||||
MARKETING_VERSION = 5.2.3;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.SimpleXChat;
|
||||
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
|
||||
SDKROOT = iphoneos;
|
||||
|
||||
@@ -1052,9 +1052,9 @@ public struct NetCfg: Codable, Equatable {
|
||||
public static let defaults: NetCfg = NetCfg(
|
||||
socksProxy: nil,
|
||||
sessionMode: TransportSessionMode.user,
|
||||
tcpConnectTimeout: 10_000_000,
|
||||
tcpTimeout: 7_000_000,
|
||||
tcpTimeoutPerKb: 10_000,
|
||||
tcpConnectTimeout: 15_000_000,
|
||||
tcpTimeout: 10_000_000,
|
||||
tcpTimeoutPerKb: 20_000,
|
||||
tcpKeepAlive: KeepAliveOpts.defaults,
|
||||
smpPingInterval: 1200_000_000,
|
||||
smpPingCount: 3,
|
||||
@@ -1064,9 +1064,9 @@ public struct NetCfg: Codable, Equatable {
|
||||
public static let proxyDefaults: NetCfg = NetCfg(
|
||||
socksProxy: nil,
|
||||
sessionMode: TransportSessionMode.user,
|
||||
tcpConnectTimeout: 20_000_000,
|
||||
tcpTimeout: 15_000_000,
|
||||
tcpTimeoutPerKb: 20_000,
|
||||
tcpConnectTimeout: 30_000_000,
|
||||
tcpTimeout: 20_000_000,
|
||||
tcpTimeoutPerKb: 40_000,
|
||||
tcpKeepAlive: KeepAliveOpts.defaults,
|
||||
smpPingInterval: 1200_000_000,
|
||||
smpPingCount: 3,
|
||||
|
||||
@@ -2273,6 +2273,7 @@ public struct CIMeta: Decodable {
|
||||
case .sndErrorAuth: return ("multiply", .red)
|
||||
case .sndError: return ("exclamationmark.triangle.fill", .yellow)
|
||||
case .rcvNew: return ("circlebadge.fill", Color.accentColor)
|
||||
case .invalid: return ("questionmark", metaColor)
|
||||
default: return nil
|
||||
}
|
||||
}
|
||||
@@ -2343,6 +2344,7 @@ public enum CIStatus: Decodable {
|
||||
case sndError(agentError: String)
|
||||
case rcvNew
|
||||
case rcvRead
|
||||
case invalid(text: String)
|
||||
|
||||
var id: String {
|
||||
switch self {
|
||||
@@ -2353,6 +2355,7 @@ public enum CIStatus: Decodable {
|
||||
case .sndError: return "sndError"
|
||||
case .rcvNew: return "rcvNew"
|
||||
case .rcvRead: return "rcvRead"
|
||||
case .invalid: return "invalid"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2615,6 +2618,7 @@ public struct CIFile: Decodable {
|
||||
case .rcvCancelled: return false
|
||||
case .rcvComplete: return true
|
||||
case .rcvError: return false
|
||||
case .invalid: return false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2638,6 +2642,7 @@ public struct CIFile: Decodable {
|
||||
case .rcvCancelled: return nil
|
||||
case .rcvComplete: return nil
|
||||
case .rcvError: return nil
|
||||
case .invalid: return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2698,6 +2703,7 @@ public enum CIFileStatus: Decodable, Equatable {
|
||||
case rcvComplete
|
||||
case rcvCancelled
|
||||
case rcvError
|
||||
case invalid(text: String)
|
||||
|
||||
var id: String {
|
||||
switch self {
|
||||
@@ -2712,6 +2718,7 @@ public enum CIFileStatus: Decodable, Equatable {
|
||||
case .rcvComplete: return "rcvComplete"
|
||||
case .rcvCancelled: return "rcvCancelled"
|
||||
case .rcvError: return "rcvError"
|
||||
case .invalid: return "invalid"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ android {
|
||||
defaultConfig {
|
||||
applicationId = "chat.simplex.app"
|
||||
minSdkVersion(26)
|
||||
targetSdkVersion(33)
|
||||
targetSdkVersion(32)
|
||||
// !!!
|
||||
// skip version code after release to F-Droid, as it uses two version codes
|
||||
versionCode = (extra["android.version_code"] as String).toInt()
|
||||
|
||||
@@ -24,9 +24,8 @@
|
||||
|
||||
<application
|
||||
android:name="SimplexApp"
|
||||
android:allowBackup="true"
|
||||
android:fullBackupOnly="true"
|
||||
android:backupAgent="BackupAgent"
|
||||
android:allowBackup="false"
|
||||
android:fullBackupOnly="false"
|
||||
android:icon="@mipmap/icon"
|
||||
android:label="${app_name}"
|
||||
android:extractNativeLibs="${extract_native_libs}"
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
package chat.simplex.app
|
||||
|
||||
import android.app.backup.BackupAgentHelper
|
||||
import android.app.backup.FullBackupDataOutput
|
||||
import android.content.Context
|
||||
import chat.simplex.app.model.AppPreferences
|
||||
import chat.simplex.app.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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1626,6 +1626,7 @@ data class CIMeta (
|
||||
is CIStatus.SndErrorAuth -> MR.images.ic_close to Color.Red
|
||||
is CIStatus.SndError -> MR.images.ic_warning_filled to WarningYellow
|
||||
is CIStatus.RcvNew -> MR.images.ic_circle_filled to primaryColor
|
||||
is CIStatus.Invalid -> MR.images.ic_question_mark to metaColor
|
||||
else -> null
|
||||
}
|
||||
|
||||
@@ -1712,6 +1713,7 @@ sealed class CIStatus {
|
||||
@Serializable @SerialName("sndError") class SndError(val agentError: String): CIStatus()
|
||||
@Serializable @SerialName("rcvNew") class RcvNew: CIStatus()
|
||||
@Serializable @SerialName("rcvRead") class RcvRead: CIStatus()
|
||||
@Serializable @SerialName("invalid") class Invalid(val text: String): CIStatus()
|
||||
}
|
||||
|
||||
@Serializable
|
||||
@@ -1949,6 +1951,7 @@ class CIFile(
|
||||
is CIFileStatus.RcvCancelled -> false
|
||||
is CIFileStatus.RcvComplete -> true
|
||||
is CIFileStatus.RcvError -> false
|
||||
is CIFileStatus.Invalid -> false
|
||||
}
|
||||
|
||||
@Transient
|
||||
@@ -1969,6 +1972,7 @@ class CIFile(
|
||||
is CIFileStatus.RcvCancelled -> null
|
||||
is CIFileStatus.RcvComplete -> null
|
||||
is CIFileStatus.RcvError -> null
|
||||
is CIFileStatus.Invalid -> null
|
||||
}
|
||||
|
||||
companion object {
|
||||
@@ -2038,6 +2042,7 @@ sealed class CIFileStatus {
|
||||
@Serializable @SerialName("rcvComplete") object RcvComplete: CIFileStatus()
|
||||
@Serializable @SerialName("rcvCancelled") object RcvCancelled: CIFileStatus()
|
||||
@Serializable @SerialName("rcvError") object RcvError: CIFileStatus()
|
||||
@Serializable @SerialName("invalid") class Invalid(val text: String): CIFileStatus()
|
||||
}
|
||||
|
||||
@Suppress("SERIALIZER_TYPE_INCOMPATIBLE")
|
||||
|
||||
@@ -94,7 +94,6 @@ 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)
|
||||
@@ -2336,9 +2335,9 @@ data class NetCfg(
|
||||
hostMode = HostMode.OnionViaSocks,
|
||||
requiredHostMode = false,
|
||||
sessionMode = TransportSessionMode.User,
|
||||
tcpConnectTimeout = 10_000_000,
|
||||
tcpTimeout = 7_000_000,
|
||||
tcpTimeoutPerKb = 10_000,
|
||||
tcpConnectTimeout = 15_000_000,
|
||||
tcpTimeout = 10_000_000,
|
||||
tcpTimeoutPerKb = 20_000,
|
||||
tcpKeepAlive = KeepAliveOpts.defaults,
|
||||
smpPingInterval = 1200_000_000,
|
||||
smpPingCount = 3
|
||||
@@ -2350,9 +2349,9 @@ data class NetCfg(
|
||||
hostMode = HostMode.OnionViaSocks,
|
||||
requiredHostMode = false,
|
||||
sessionMode = TransportSessionMode.User,
|
||||
tcpConnectTimeout = 20_000_000,
|
||||
tcpTimeout = 15_000_000,
|
||||
tcpTimeoutPerKb = 20_000,
|
||||
tcpConnectTimeout = 30_000_000,
|
||||
tcpTimeout = 20_000_000,
|
||||
tcpTimeoutPerKb = 40_000,
|
||||
tcpKeepAlive = KeepAliveOpts.defaults,
|
||||
smpPingInterval = 1200_000_000,
|
||||
smpPingCount = 3
|
||||
|
||||
+1
@@ -170,6 +170,7 @@ fun CIFileView(
|
||||
is CIFileStatus.RcvComplete -> fileIcon()
|
||||
is CIFileStatus.RcvCancelled -> fileIcon(innerIcon = painterResource(MR.images.ic_close))
|
||||
is CIFileStatus.RcvError -> fileIcon(innerIcon = painterResource(MR.images.ic_close))
|
||||
is CIFileStatus.Invalid -> fileIcon(innerIcon = painterResource(MR.images.ic_question_mark))
|
||||
}
|
||||
} else {
|
||||
fileIcon()
|
||||
|
||||
+1
@@ -86,6 +86,7 @@ fun CIImageView(
|
||||
is CIFileStatus.RcvTransfer -> progressIndicator()
|
||||
is CIFileStatus.RcvCancelled -> fileIcon(painterResource(MR.images.ic_close), MR.strings.icon_descr_file)
|
||||
is CIFileStatus.RcvError -> fileIcon(painterResource(MR.images.ic_close), MR.strings.icon_descr_file)
|
||||
is CIFileStatus.Invalid -> fileIcon(painterResource(MR.images.ic_question_mark), MR.strings.icon_descr_file)
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
|
||||
+1
@@ -309,6 +309,7 @@ private fun loadingIndicator(file: CIFile?) {
|
||||
}
|
||||
is CIFileStatus.RcvCancelled -> fileIcon(painterResource(MR.images.ic_close), MR.strings.icon_descr_file)
|
||||
is CIFileStatus.RcvError -> fileIcon(painterResource(MR.images.ic_close), MR.strings.icon_descr_file)
|
||||
is CIFileStatus.Invalid -> fileIcon(painterResource(MR.images.ic_question_mark), MR.strings.icon_descr_file)
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
|
||||
+7
-29
@@ -83,7 +83,6 @@ fun DatabaseView(
|
||||
chatArchiveName,
|
||||
chatArchiveTime,
|
||||
chatLastStart,
|
||||
m.controller.appPrefs.privacyFullBackup,
|
||||
appFilesCountAndSize,
|
||||
chatItemTTL,
|
||||
m.currentUser.value,
|
||||
@@ -133,7 +132,6 @@ fun DatabaseLayout(
|
||||
chatArchiveName: MutableState<String?>,
|
||||
chatArchiveTime: MutableState<Instant?>,
|
||||
chatLastStart: MutableState<Instant?>,
|
||||
privacyFullBackup: SharedPreference<Boolean>,
|
||||
appFilesCountAndSize: MutableState<Pair<Int, Long>>,
|
||||
chatItemTTL: MutableState<ChatItemTTL>,
|
||||
currentUser: User?,
|
||||
@@ -173,6 +171,13 @@ 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,8 +190,6 @@ 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),
|
||||
@@ -230,13 +233,6 @@ 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()) {
|
||||
@@ -263,23 +259,6 @@ 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>,
|
||||
@@ -723,7 +702,6 @@ 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
-1
@@ -58,7 +58,8 @@ fun SetNotificationsMode(m: ChatModel) {
|
||||
|
||||
@Composable
|
||||
fun SetNotificationsModeAdditions() {
|
||||
if (Build.VERSION.SDK_INT >= 33) {
|
||||
// When target and compile SDK are different
|
||||
if (Build.VERSION.SDK_INT >= 33 && SimplexApp.context.applicationInfo.targetSdkVersion >= 33) {
|
||||
val notificationsPermissionState = rememberPermissionState(Manifest.permission.POST_NOTIFICATIONS)
|
||||
LaunchedEffect(notificationsPermissionState.hasPermission) {
|
||||
if (notificationsPermissionState.hasPermission) {
|
||||
|
||||
+6
-4
@@ -155,19 +155,19 @@ fun AdvancedNetworkSettingsView(chatModel: ChatModel) {
|
||||
SectionItemView {
|
||||
TimeoutSettingRow(
|
||||
stringResource(MR.strings.network_option_tcp_connection_timeout), networkTCPConnectTimeout,
|
||||
listOf(2_500000, 5_000000, 7_500000, 10_000000, 15_000000, 20_000000), secondsLabel
|
||||
listOf(5_000000, 7_500000, 10_000000, 15_000000, 20_000000, 30_000_000, 45_000_000), secondsLabel
|
||||
)
|
||||
}
|
||||
SectionItemView {
|
||||
TimeoutSettingRow(
|
||||
stringResource(MR.strings.network_option_protocol_timeout), networkTCPTimeout,
|
||||
listOf(1_500000, 3_000000, 5_000000, 7_000000, 10_000000, 15_000000), secondsLabel
|
||||
listOf(3_000000, 5_000000, 7_000000, 10_000000, 15_000000, 20_000_000, 30_000_000), secondsLabel
|
||||
)
|
||||
}
|
||||
SectionItemView {
|
||||
TimeoutSettingRow(
|
||||
stringResource(MR.strings.network_option_protocol_timeout_per_kb), networkTCPTimeoutPerKb,
|
||||
listOf(5_000, 10_000, 20_000, 40_000), secondsLabel
|
||||
listOf(10_000, 20_000, 40_000, 75_000, 100_000), secondsLabel
|
||||
)
|
||||
}
|
||||
SectionItemView {
|
||||
@@ -342,7 +342,9 @@ fun TimeoutSettingRow(title: String, selection: MutableState<Long>, values: List
|
||||
DefaultExposedDropdownMenu(
|
||||
expanded = expanded
|
||||
) {
|
||||
values.forEach { selectionOption ->
|
||||
val v = selection.value
|
||||
val vs = if (values.contains(v)) values else values + v
|
||||
vs.forEach { selectionOption ->
|
||||
DropdownMenuItem(
|
||||
onClick = {
|
||||
selection.value = selectionOption
|
||||
|
||||
@@ -116,7 +116,7 @@ android {
|
||||
sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml")
|
||||
defaultConfig {
|
||||
minSdkVersion(26)
|
||||
targetSdkVersion(33)
|
||||
targetSdkVersion(32)
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M432-332.5q1-70 17.75-104.25T511-509q40.5-35 62.25-68.25T595-648q0-46.5-30.5-76.5t-86-30q-52 0-80.5 29t-42 61l-81.5-36q23-59 75.25-99.25T478.5-840q100.5 0 154.25 55t53.75 134q0 47-21.25 88.5t-66.25 83q-48.5 45.5-58.5 70t-11 77H432Zm46.5 250q-27.5 0-47.5-20T411-150q0-28.5 20-48t47.5-19.5q28.5 0 48 19.5t19.5 48q0 27.5-19.5 47.5t-48 20Z"/></svg>
|
||||
|
After Width: | Height: | Size: 441 B |
@@ -25,8 +25,8 @@ android.nonTransitiveRClass=true
|
||||
android.enableJetifier=true
|
||||
kotlin.mpp.androidSourceSetLayoutVersion=2
|
||||
|
||||
android.version_name=5.2
|
||||
android.version_code=134
|
||||
android.version_name=5.2.3
|
||||
android.version_code=144
|
||||
|
||||
desktop.version_name=1.0
|
||||
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
name: simplex-chat
|
||||
version: 5.2.0.4
|
||||
version: 5.2.3.0
|
||||
#synopsis:
|
||||
#description:
|
||||
homepage: https://github.com/simplex-chat/simplex-chat#readme
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ cabal-version: 1.12
|
||||
-- see: https://github.com/sol/hpack
|
||||
|
||||
name: simplex-chat
|
||||
version: 5.2.0.4
|
||||
version: 5.2.3.0
|
||||
category: Web, System, Services, Cryptography
|
||||
homepage: https://github.com/simplex-chat/simplex-chat#readme
|
||||
author: simplex.chat
|
||||
|
||||
+5
-3
@@ -139,9 +139,11 @@ defaultChatConfig =
|
||||
_defaultSMPServers :: NonEmpty SMPServerWithAuth
|
||||
_defaultSMPServers =
|
||||
L.fromList
|
||||
[ "smp://1OwYGt-yqOfe2IyVHhxz3ohqo3aCCMjtB-8wn4X_aoY=@smp11.simplex.im,6ioorbm6i3yxmuoezrhjk6f6qgkc4syabh7m3so74xunb5nzr4pwgfqd.onion",
|
||||
"smp://UkMFNAXLXeAAe0beCa4w6X_zp18PwxSaSjY17BKUGXQ=@smp12.simplex.im,ie42b5weq7zdkghocs3mgxdjeuycheeqqmksntj57rmejagmg4eor5yd.onion",
|
||||
"smp://enEkec4hlR3UtKx2NMpOUK_K4ZuDxjWBO1d9Y4YXVaA=@smp14.simplex.im,aspkyu2sopsnizbyfabtsicikr2s4r3ti35jogbcekhm3fsoeyjvgrid.onion"
|
||||
[ "smp://h--vW7ZSkXPeOUpfxlFGgauQmXNFOzGoizak7Ult7cw=@smp15.simplex.im,oauu4bgijybyhczbnxtlggo6hiubahmeutaqineuyy23aojpih3dajad.onion",
|
||||
"smp://hejn2gVIqNU6xjtGM3OwQeuk8ZEbDXVJXAlnSBJBWUA=@smp16.simplex.im,p3ktngodzi6qrf7w64mmde3syuzrv57y55hxabqcq3l5p6oi7yzze6qd.onion",
|
||||
"smp://ZKe4uxF4Z_aLJJOEsC-Y6hSkXgQS5-oc442JQGkyP8M=@smp17.simplex.im,ogtwfxyi3h2h5weftjjpjmxclhb5ugufa5rcyrmg7j4xlch7qsr5nuqd.onion",
|
||||
"smp://PtsqghzQKU83kYTlQ1VKg996dW4Cw4x_bvpKmiv8uns=@smp18.simplex.im,lyqpnwbs2zqfr45jqkncwpywpbtq7jrhxnib5qddtr6npjyezuwd3nqd.onion",
|
||||
"smp://N_McQS3F9TGoh4ER0QstUf55kGnNSd-wXfNPZ7HukcM=@smp19.simplex.im,i53bbtoqhlc365k6kxzwdp5w3cdt433s7bwh3y32rcbml2vztiyyz5id.onion"
|
||||
]
|
||||
|
||||
_defaultNtfServers :: [NtfServer]
|
||||
|
||||
@@ -17,7 +17,7 @@ import qualified Data.Attoparsec.Text as A
|
||||
import Data.Char (isDigit)
|
||||
import Data.Either (fromRight)
|
||||
import Data.Functor (($>))
|
||||
import Data.List (intercalate)
|
||||
import Data.List (intercalate, foldl')
|
||||
import Data.List.NonEmpty (NonEmpty)
|
||||
import qualified Data.List.NonEmpty as L
|
||||
import Data.Maybe (fromMaybe, isNothing)
|
||||
@@ -124,9 +124,15 @@ unmarked :: Text -> Markdown
|
||||
unmarked = Markdown Nothing
|
||||
|
||||
parseMaybeMarkdownList :: Text -> Maybe MarkdownList
|
||||
parseMaybeMarkdownList s =
|
||||
let m = intercalate ["\n"] . map (markdownToList . parseMarkdown) $ T.lines s
|
||||
in if all (isNothing . format) m then Nothing else Just m
|
||||
parseMaybeMarkdownList s
|
||||
| all (isNothing . format) ml = Nothing
|
||||
| otherwise = Just . reverse $ foldl' acc [] ml
|
||||
where
|
||||
ml = intercalate ["\n"] . map (markdownToList . parseMarkdown) $ T.lines s
|
||||
acc [] m = [m]
|
||||
acc ms@(FormattedText f t : ms') ft@(FormattedText f' t')
|
||||
| f == f' = FormattedText f (t <> t') : ms'
|
||||
| otherwise = ft : ms
|
||||
|
||||
parseMarkdownList :: Text -> MarkdownList
|
||||
parseMarkdownList = markdownToList . parseMarkdown
|
||||
|
||||
@@ -501,6 +501,7 @@ data CIFileStatus (d :: MsgDirection) where
|
||||
CIFSRcvComplete :: CIFileStatus 'MDRcv
|
||||
CIFSRcvCancelled :: CIFileStatus 'MDRcv
|
||||
CIFSRcvError :: CIFileStatus 'MDRcv
|
||||
CIFSInvalid :: {text :: Text} -> CIFileStatus 'MDSnd
|
||||
|
||||
deriving instance Eq (CIFileStatus d)
|
||||
|
||||
@@ -519,6 +520,7 @@ ciFileEnded = \case
|
||||
CIFSRcvCancelled -> True
|
||||
CIFSRcvComplete -> True
|
||||
CIFSRcvError -> True
|
||||
CIFSInvalid {} -> True
|
||||
|
||||
instance ToJSON (CIFileStatus d) where
|
||||
toJSON = J.toJSON . jsonCIFileStatus
|
||||
@@ -545,25 +547,29 @@ instance MsgDirectionI d => StrEncoding (CIFileStatus d) where
|
||||
CIFSRcvComplete -> "rcv_complete"
|
||||
CIFSRcvCancelled -> "rcv_cancelled"
|
||||
CIFSRcvError -> "rcv_error"
|
||||
CIFSInvalid {} -> "invalid"
|
||||
strP = (\(AFS _ st) -> checkDirection st) <$?> strP
|
||||
|
||||
instance StrEncoding ACIFileStatus where
|
||||
strEncode (AFS _ s) = strEncode s
|
||||
strP =
|
||||
A.takeTill (== ' ') >>= \case
|
||||
"snd_stored" -> pure $ AFS SMDSnd CIFSSndStored
|
||||
"snd_transfer" -> AFS SMDSnd <$> progress CIFSSndTransfer
|
||||
"snd_cancelled" -> pure $ AFS SMDSnd CIFSSndCancelled
|
||||
"snd_complete" -> pure $ AFS SMDSnd CIFSSndComplete
|
||||
"snd_error" -> pure $ AFS SMDSnd CIFSSndError
|
||||
"rcv_invitation" -> pure $ AFS SMDRcv CIFSRcvInvitation
|
||||
"rcv_accepted" -> pure $ AFS SMDRcv CIFSRcvAccepted
|
||||
"rcv_transfer" -> AFS SMDRcv <$> progress CIFSRcvTransfer
|
||||
"rcv_complete" -> pure $ AFS SMDRcv CIFSRcvComplete
|
||||
"rcv_cancelled" -> pure $ AFS SMDRcv CIFSRcvCancelled
|
||||
"rcv_error" -> pure $ AFS SMDRcv CIFSRcvError
|
||||
_ -> fail "bad file status"
|
||||
(statusP <* A.endOfInput) -- endOfInput to make it fail on partial correct parse
|
||||
<|> (AFS SMDSnd . CIFSInvalid . safeDecodeUtf8 <$> A.takeByteString)
|
||||
where
|
||||
statusP =
|
||||
A.takeTill (== ' ') >>= \case
|
||||
"snd_stored" -> pure $ AFS SMDSnd CIFSSndStored
|
||||
"snd_transfer" -> AFS SMDSnd <$> progress CIFSSndTransfer
|
||||
"snd_cancelled" -> pure $ AFS SMDSnd CIFSSndCancelled
|
||||
"snd_complete" -> pure $ AFS SMDSnd CIFSSndComplete
|
||||
"snd_error" -> pure $ AFS SMDSnd CIFSSndError
|
||||
"rcv_invitation" -> pure $ AFS SMDRcv CIFSRcvInvitation
|
||||
"rcv_accepted" -> pure $ AFS SMDRcv CIFSRcvAccepted
|
||||
"rcv_transfer" -> AFS SMDRcv <$> progress CIFSRcvTransfer
|
||||
"rcv_complete" -> pure $ AFS SMDRcv CIFSRcvComplete
|
||||
"rcv_cancelled" -> pure $ AFS SMDRcv CIFSRcvCancelled
|
||||
"rcv_error" -> pure $ AFS SMDRcv CIFSRcvError
|
||||
_ -> fail "bad file status"
|
||||
progress :: (Int64 -> Int64 -> a) -> A.Parser a
|
||||
progress f = f <$> num <*> num <|> pure (f 0 1)
|
||||
num = A.space *> A.decimal
|
||||
@@ -580,6 +586,7 @@ data JSONCIFileStatus
|
||||
| JCIFSRcvComplete
|
||||
| JCIFSRcvCancelled
|
||||
| JCIFSRcvError
|
||||
| JCIFSInvalid {text :: Text}
|
||||
deriving (Generic)
|
||||
|
||||
instance ToJSON JSONCIFileStatus where
|
||||
@@ -599,6 +606,7 @@ jsonCIFileStatus = \case
|
||||
CIFSRcvComplete -> JCIFSRcvComplete
|
||||
CIFSRcvCancelled -> JCIFSRcvCancelled
|
||||
CIFSRcvError -> JCIFSRcvError
|
||||
CIFSInvalid text -> JCIFSInvalid text
|
||||
|
||||
aciFileStatusJSON :: JSONCIFileStatus -> ACIFileStatus
|
||||
aciFileStatusJSON = \case
|
||||
@@ -613,6 +621,7 @@ aciFileStatusJSON = \case
|
||||
JCIFSRcvComplete -> AFS SMDRcv CIFSRcvComplete
|
||||
JCIFSRcvCancelled -> AFS SMDRcv CIFSRcvCancelled
|
||||
JCIFSRcvError -> AFS SMDRcv CIFSRcvError
|
||||
JCIFSInvalid text -> AFS SMDSnd $ CIFSInvalid text
|
||||
|
||||
-- to conveniently read file data from db
|
||||
data CIFileInfo = CIFileInfo
|
||||
@@ -630,6 +639,7 @@ data CIStatus (d :: MsgDirection) where
|
||||
CISSndError :: String -> CIStatus 'MDSnd
|
||||
CISRcvNew :: CIStatus 'MDRcv
|
||||
CISRcvRead :: CIStatus 'MDRcv
|
||||
CISInvalid :: Text -> CIStatus 'MDSnd
|
||||
|
||||
deriving instance Show (CIStatus d)
|
||||
|
||||
@@ -654,20 +664,25 @@ instance MsgDirectionI d => StrEncoding (CIStatus d) where
|
||||
CISSndError e -> "snd_error " <> encodeUtf8 (T.pack e)
|
||||
CISRcvNew -> "rcv_new"
|
||||
CISRcvRead -> "rcv_read"
|
||||
CISInvalid {} -> "invalid"
|
||||
strP = (\(ACIStatus _ st) -> checkDirection st) <$?> strP
|
||||
|
||||
instance StrEncoding ACIStatus where
|
||||
strEncode (ACIStatus _ s) = strEncode s
|
||||
strP =
|
||||
A.takeTill (== ' ') >>= \case
|
||||
"snd_new" -> pure $ ACIStatus SMDSnd CISSndNew
|
||||
"snd_sent" -> pure $ ACIStatus SMDSnd CISSndSent
|
||||
"snd_rcvd" -> ACIStatus SMDSnd . CISSndRcvd <$> (A.space *> strP)
|
||||
"snd_error_auth" -> pure $ ACIStatus SMDSnd CISSndErrorAuth
|
||||
"snd_error" -> ACIStatus SMDSnd . CISSndError . T.unpack . safeDecodeUtf8 <$> (A.space *> A.takeByteString)
|
||||
"rcv_new" -> pure $ ACIStatus SMDRcv CISRcvNew
|
||||
"rcv_read" -> pure $ ACIStatus SMDRcv CISRcvRead
|
||||
_ -> fail "bad status"
|
||||
(statusP <* A.endOfInput) -- endOfInput to make it fail on partial correct parse, e.g. "snd_rcvd ok complete"
|
||||
<|> (ACIStatus SMDSnd . CISInvalid . safeDecodeUtf8 <$> A.takeByteString)
|
||||
where
|
||||
statusP =
|
||||
A.takeTill (== ' ') >>= \case
|
||||
"snd_new" -> pure $ ACIStatus SMDSnd CISSndNew
|
||||
"snd_sent" -> pure $ ACIStatus SMDSnd CISSndSent
|
||||
"snd_rcvd" -> ACIStatus SMDSnd . CISSndRcvd <$> (A.space *> strP)
|
||||
"snd_error_auth" -> pure $ ACIStatus SMDSnd CISSndErrorAuth
|
||||
"snd_error" -> ACIStatus SMDSnd . CISSndError . T.unpack . safeDecodeUtf8 <$> (A.space *> A.takeByteString)
|
||||
"rcv_new" -> pure $ ACIStatus SMDRcv CISRcvNew
|
||||
"rcv_read" -> pure $ ACIStatus SMDRcv CISRcvRead
|
||||
_ -> fail "bad status"
|
||||
|
||||
data JSONCIStatus
|
||||
= JCISSndNew
|
||||
@@ -677,6 +692,7 @@ data JSONCIStatus
|
||||
| JCISSndError {agentError :: String}
|
||||
| JCISRcvNew
|
||||
| JCISRcvRead
|
||||
| JCISInvalid {text :: Text}
|
||||
deriving (Show, Generic)
|
||||
|
||||
instance ToJSON JSONCIStatus where
|
||||
@@ -692,6 +708,7 @@ jsonCIStatus = \case
|
||||
CISSndError e -> JCISSndError e
|
||||
CISRcvNew -> JCISRcvNew
|
||||
CISRcvRead -> JCISRcvRead
|
||||
CISInvalid text -> JCISInvalid text
|
||||
|
||||
ciStatusNew :: forall d. MsgDirectionI d => CIStatus d
|
||||
ciStatusNew = case msgDirection @d of
|
||||
|
||||
@@ -239,11 +239,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.group_member_id = m.group_member_id
|
||||
where cc.user_id = ? AND cc.group_member_id = m.group_member_id
|
||||
)
|
||||
WHERE m.group_member_id = ? AND g.user_id = ? AND mu.contact_id = ?
|
||||
|]
|
||||
(groupMemberId, userId, userContactId)
|
||||
(userId, groupMemberId, userId, userContactId)
|
||||
where
|
||||
toGroupAndMember :: (GroupInfoRow :. GroupMemberRow :. MaybeConnectionRow) -> (GroupInfo, GroupMember)
|
||||
toGroupAndMember (groupInfoRow :. memberRow :. connRow) =
|
||||
@@ -500,7 +500,7 @@ groupMemberQuery =
|
||||
LEFT JOIN connections c ON c.connection_id = (
|
||||
SELECT max(cc.connection_id)
|
||||
FROM connections cc
|
||||
where cc.group_member_id = m.group_member_id
|
||||
where cc.user_id = ? AND cc.group_member_id = m.group_member_id
|
||||
)
|
||||
|]
|
||||
|
||||
@@ -510,7 +510,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 = ?")
|
||||
(groupId, groupMemberId, userId)
|
||||
(userId, groupId, groupMemberId, userId)
|
||||
|
||||
getGroupMemberById :: DB.Connection -> User -> GroupMemberId -> ExceptT StoreError IO GroupMember
|
||||
getGroupMemberById db user@User {userId} groupMemberId =
|
||||
@@ -518,7 +518,7 @@ getGroupMemberById db user@User {userId} groupMemberId =
|
||||
DB.query
|
||||
db
|
||||
(groupMemberQuery <> " WHERE m.group_member_id = ? AND m.user_id = ?")
|
||||
(groupMemberId, userId)
|
||||
(userId, groupMemberId, userId)
|
||||
|
||||
getGroupMembers :: DB.Connection -> User -> GroupInfo -> IO [GroupMember]
|
||||
getGroupMembers db user@User {userId, userContactId} GroupInfo {groupId} = do
|
||||
@@ -526,7 +526,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 != ?)")
|
||||
(groupId, userId, userContactId)
|
||||
(userId, groupId, userId, userContactId)
|
||||
|
||||
getGroupMembersForExpiration :: DB.Connection -> User -> GroupInfo -> IO [GroupMember]
|
||||
getGroupMembersForExpiration db user@User {userId, userContactId} GroupInfo {groupId} = do
|
||||
@@ -542,7 +542,7 @@ getGroupMembersForExpiration db user@User {userId, userContactId} GroupInfo {gro
|
||||
)
|
||||
|]
|
||||
)
|
||||
(groupId, userId, userContactId, GSMemRemoved, GSMemLeft, GSMemGroupDeleted)
|
||||
(userId, groupId, userId, userContactId, GSMemRemoved, GSMemLeft, GSMemGroupDeleted)
|
||||
|
||||
toContactMember :: User -> (GroupMemberRow :. MaybeConnectionRow) -> GroupMember
|
||||
toContactMember User {userContactId} (memberRow :. connRow) =
|
||||
@@ -954,11 +954,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.group_member_id = m.group_member_id
|
||||
where cc.user_id = ? AND 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, contactId, userContactId)
|
||||
(userId, userId, contactId, userContactId)
|
||||
where
|
||||
toGroupAndMember :: (GroupInfoRow :. GroupMemberRow :. MaybeConnectionRow) -> (GroupInfo, GroupMember)
|
||||
toGroupAndMember (groupInfoRow :. memberRow :. connRow) =
|
||||
@@ -1252,11 +1252,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.group_member_id = mh.group_member_id
|
||||
where cc.user_id = ? AND 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, contactId, GCHostMember)
|
||||
(userId, userId, contactId, GCHostMember)
|
||||
where
|
||||
toCont :: (Int64, GroupId, GroupMemberId, MemberId, Maybe ConnReqInvitation) -> Maybe (Int64, XGrpMemIntroCont)
|
||||
toCont (hostConnId, groupId, groupMemberId, memberId, connReq_) = case connReq_ of
|
||||
@@ -1282,11 +1282,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.group_member_id = mh.group_member_id
|
||||
where cc.user_id = ? AND 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, groupMemberId, GCHostMember)
|
||||
(userId, userId, groupMemberId, GCHostMember)
|
||||
where
|
||||
toCont :: (Int64, Maybe ConnReqInvitation) -> Maybe (Int64, ConnReqInvitation)
|
||||
toCont (hostConnId, connReq_) = case connReq_ of
|
||||
|
||||
@@ -1360,6 +1360,7 @@ viewFileTransferStatusXFTP (AChatItem _ _ _ ChatItem {file = Just CIFile {fileId
|
||||
CIFSRcvComplete -> ["receiving " <> fstr <> " complete" <> maybe "" (\fp -> ", path: " <> plain fp) filePath]
|
||||
CIFSRcvCancelled -> ["receiving " <> fstr <> " cancelled"]
|
||||
CIFSRcvError -> ["receiving " <> fstr <> " error"]
|
||||
CIFSInvalid text -> [fstr <> " invalid status: " <> plain text]
|
||||
where
|
||||
fstr = fileTransferStr fileId fileName
|
||||
viewFileTransferStatusXFTP _ = ["no file status"]
|
||||
|
||||
@@ -204,5 +204,7 @@ multilineMarkdownList :: Spec
|
||||
multilineMarkdownList = describe "multiline markdown" do
|
||||
it "correct markdown" do
|
||||
parseMaybeMarkdownList "http://simplex.chat\nhttp://app.simplex.chat" `shouldBe` Just [uri' "http://simplex.chat", "\n", uri' "http://app.simplex.chat"]
|
||||
it "combines the same formats" do
|
||||
parseMaybeMarkdownList "http://simplex.chat\ntext 1\ntext 2\nhttp://app.simplex.chat" `shouldBe` Just [uri' "http://simplex.chat", "\ntext 1\ntext 2\n", uri' "http://app.simplex.chat"]
|
||||
it "no markdown" do
|
||||
parseMaybeMarkdownList "not a\nmarkdown" `shouldBe` Nothing
|
||||
|
||||
@@ -90,7 +90,7 @@
|
||||
"simplex-unique-4-title": "You own SimpleX network",
|
||||
"simplex-unique-4-overlay-1-title": "Fully decentralised — users own the SimpleX network",
|
||||
"hero-overlay-card-1-p-1": "Many users asked: <em>if SimpleX has no user identifiers, how can it know where to deliver messages?</em>",
|
||||
"hero-overlay-card-1-p-2": "To deliver mesages, instead of user IDs used by all other platforms, SimpleX uses temporary anonymous pairwise identifiers of message queues, separate for each of your connections — there are no long term identifiers.",
|
||||
"hero-overlay-card-1-p-2": "To deliver messages, instead of user IDs used by all other platforms, SimpleX uses temporary anonymous pairwise identifiers of message queues, separate for each of your connections — there are no long term identifiers.",
|
||||
"hero-overlay-card-1-p-3": "You define which server(s) to use to receive the messages, your contacts — the servers you use to send the messages to them. Every conversation is likely to use two different servers.",
|
||||
"hero-overlay-card-1-p-4": "This design prevents leaking any users' metadata on the application level. To further improve privacy and protect your IP address you can connect to messaging servers via Tor.",
|
||||
"hero-overlay-card-1-p-5": "Only client devices store user profiles, contacts and groups; the messages are sent with 2-layer end-to-end encryption.",
|
||||
@@ -233,4 +233,4 @@
|
||||
"on-this-page": "On this page",
|
||||
"back-to-top": "Back to top",
|
||||
"glossary": "Glossary"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user