Merge branch 'master' into ep/debug-reconnect

This commit is contained in:
Evgeny Poberezkin
2023-12-30 21:26:31 +00:00
18 changed files with 129 additions and 91 deletions

View File

@@ -28,7 +28,9 @@ struct FramedItemView: View {
@State var metaColor = Color.secondary
@State var showFullScreenImage = false
@Binding var allowMenu: Bool
@State private var showSecrets = false
@State private var showQuoteSecrets = false
@Binding var audioPlayer: AudioPlayer?
@Binding var playbackState: VoiceMessagePlaybackState
@Binding var playbackTime: TimeInterval?
@@ -252,10 +254,12 @@ struct FramedItemView: View {
}
private func ciQuotedMsgTextView(_ qi: CIQuote, lines: Int) -> some View {
MsgContentView(chat: chat, text: qi.text, formattedText: qi.formattedText)
.lineLimit(lines)
.font(.subheadline)
.padding(.bottom, 6)
toggleSecrets(qi.formattedText, $showQuoteSecrets,
MsgContentView(chat: chat, text: qi.text, formattedText: qi.formattedText, showSecrets: showQuoteSecrets)
.lineLimit(lines)
.font(.subheadline)
.padding(.bottom, 6)
)
}
private func ciQuoteIconView(_ image: String) -> some View {
@@ -278,13 +282,15 @@ struct FramedItemView: View {
@ViewBuilder private func ciMsgContentView(_ ci: ChatItem) -> some View {
let text = ci.meta.isLive ? ci.content.msgContent?.text ?? ci.text : ci.text
let rtl = isRightToLeft(text)
let v = MsgContentView(
let ft = text == "" ? [] : ci.formattedText
let v = toggleSecrets(ft, $showSecrets, MsgContentView(
chat: chat,
text: text,
formattedText: text == "" ? [] : ci.formattedText,
formattedText: ft,
meta: ci.meta,
rightToLeft: rtl
)
rightToLeft: rtl,
showSecrets: showSecrets
))
.multilineTextAlignment(rtl ? .trailing : .leading)
.padding(.vertical, 6)
.padding(.horizontal, 12)
@@ -298,7 +304,7 @@ struct FramedItemView: View {
v
}
}
@ViewBuilder private func ciFileView(_ ci: ChatItem, _ text: String) -> some View {
CIFileView(file: chatItem.file, edited: chatItem.meta.itemEdited)
.overlay(DetermineWidth())
@@ -318,6 +324,14 @@ struct FramedItemView: View {
}
}
@ViewBuilder func toggleSecrets<V: View>(_ ft: [FormattedText]?, _ showSecrets: Binding<Bool>, _ v: V) -> some View {
if let ft = ft, ft.contains(where: { $0.isSecret }) {
v.onTapGesture { showSecrets.wrappedValue.toggle() }
} else {
v
}
}
func isRightToLeft(_ s: String) -> Bool {
if let lang = CFStringTokenizerCopyBestStringLanguage(s as CFString, CFRange(location: 0, length: min(s.count, 80))) {
return NSLocale.characterDirection(forLanguage: lang as String) == .rightToLeft

View File

@@ -31,6 +31,7 @@ struct MsgContentView: View {
var sender: String? = nil
var meta: CIMeta? = nil
var rightToLeft = false
var showSecrets: Bool
@State private var typingIdx = 0
@State private var timer: Timer?
@@ -62,7 +63,7 @@ struct MsgContentView: View {
}
private func msgContentView() -> Text {
var v = messageText(text, formattedText, sender)
var v = messageText(text, formattedText, sender, showSecrets: showSecrets)
if let mt = meta {
if mt.isLive {
v = v + typingIndicator(mt.recent)
@@ -84,14 +85,14 @@ struct MsgContentView: View {
}
}
func messageText(_ text: String, _ formattedText: [FormattedText]?, _ sender: String?, icon: String? = nil, preview: Bool = false) -> Text {
func messageText(_ text: String, _ formattedText: [FormattedText]?, _ sender: String?, icon: String? = nil, preview: Bool = false, showSecrets: Bool) -> Text {
let s = text
var res: Text
if let ft = formattedText, ft.count > 0 && ft.count <= 200 {
res = formatText(ft[0], preview)
res = formatText(ft[0], preview, showSecret: showSecrets)
var i = 1
while i < ft.count {
res = res + formatText(ft[i], preview)
res = res + formatText(ft[i], preview, showSecret: showSecrets)
i = i + 1
}
} else {
@@ -110,7 +111,7 @@ func messageText(_ text: String, _ formattedText: [FormattedText]?, _ sender: St
}
}
private func formatText(_ ft: FormattedText, _ preview: Bool) -> Text {
private func formatText(_ ft: FormattedText, _ preview: Bool, showSecret: Bool) -> Text {
let t = ft.text
if let f = ft.format {
switch (f) {
@@ -118,7 +119,13 @@ private func formatText(_ ft: FormattedText, _ preview: Bool) -> Text {
case .italic: return Text(t).italic()
case .strikeThrough: return Text(t).strikethrough()
case .snippet: return Text(t).font(.body.monospaced())
case .secret: return Text(t).foregroundColor(.clear).underline(color: .primary)
case .secret: return
showSecret
? Text(t)
: Text(AttributedString(t, attributes: AttributeContainer([
.foregroundColor: UIColor.clear as Any,
.backgroundColor: UIColor.secondarySystemFill as Any
])))
case let .colored(color): return Text(t).foregroundColor(color.uiColor)
case .uri: return linkText(t, t, preview, prefix: "")
case let .simplexLink(linkType, simplexUri, smpHosts):
@@ -156,7 +163,8 @@ struct MsgContentView_Previews: PreviewProvider {
text: chatItem.text,
formattedText: chatItem.formattedText,
sender: chatItem.memberDisplayName,
meta: chatItem.meta
meta: chatItem.meta,
showSecrets: false
)
.environmentObject(Chat.sampleData)
}

View File

@@ -168,7 +168,6 @@ struct ChatItemInfoView: View {
@ViewBuilder private func itemVersionView(_ itemVersion: ChatItemVersion, _ maxWidth: CGFloat, current: Bool) -> some View {
VStack(alignment: .leading, spacing: 4) {
textBubble(itemVersion.msgContent.text, itemVersion.formattedText, nil)
.allowsHitTesting(false)
.padding(.horizontal, 12)
.padding(.vertical, 6)
.background(chatItemFrameColor(ci, colorScheme))
@@ -198,7 +197,7 @@ struct ChatItemInfoView: View {
@ViewBuilder private func textBubble(_ text: String, _ formattedText: [FormattedText]?, _ sender: String? = nil) -> some View {
if text != "" {
messageText(text, formattedText, sender)
TextBubble(text: text, formattedText: formattedText, sender: sender)
} else {
Text("no text")
.italic()
@@ -206,6 +205,17 @@ struct ChatItemInfoView: View {
}
}
private struct TextBubble: View {
var text: String
var formattedText: [FormattedText]?
var sender: String? = nil
@State private var showSecrets = false
var body: some View {
toggleSecrets(formattedText, $showSecrets, messageText(text, formattedText, sender, showSecrets: showSecrets))
}
}
@ViewBuilder private func quoteTab(_ qi: CIQuote) -> some View {
GeometryReader { g in
let maxWidth = (g.size.width - 32) * 0.84
@@ -227,7 +237,6 @@ struct ChatItemInfoView: View {
@ViewBuilder private func quotedMsgView(_ qi: CIQuote, _ maxWidth: CGFloat) -> some View {
VStack(alignment: .leading, spacing: 4) {
textBubble(qi.text, qi.formattedText, qi.getSender(nil))
.allowsHitTesting(false)
.padding(.horizontal, 12)
.padding(.vertical, 6)
.background(quotedMsgFrameColor(qi, colorScheme))

View File

@@ -51,7 +51,8 @@ struct ContextItemView: View {
MsgContentView(
chat: chat,
text: contextItem.text,
formattedText: contextItem.formattedText
formattedText: contextItem.formattedText,
showSecrets: false
)
.multilineTextAlignment(isRightToLeft(contextItem.text) ? .trailing : .leading)
.lineLimit(lines)

View File

@@ -53,8 +53,7 @@ struct GroupWelcomeView: View {
}
private func textPreview() -> some View {
messageText(welcomeText, parseSimpleXMarkdown(welcomeText), nil)
.allowsHitTesting(false)
messageText(welcomeText, parseSimpleXMarkdown(welcomeText), nil, showSecrets: false)
.frame(minHeight: 140, alignment: .topLeading)
.frame(maxWidth: .infinity, alignment: .leading)
}

View File

@@ -150,7 +150,7 @@ struct ChatPreviewView: View {
let msg = draft.message
return image("rectangle.and.pencil.and.ellipsis", color: .accentColor)
+ attachment()
+ messageText(msg, parseSimpleXMarkdown(msg), nil, preview: true)
+ messageText(msg, parseSimpleXMarkdown(msg), nil, preview: true, showSecrets: false)
func image(_ s: String, color: Color = Color(uiColor: .tertiaryLabel)) -> Text {
Text(Image(systemName: s)).foregroundColor(color) + Text(" ")
@@ -169,7 +169,7 @@ struct ChatPreviewView: View {
func chatItemPreview(_ cItem: ChatItem) -> Text {
let itemText = cItem.meta.itemDeleted == nil ? cItem.text : NSLocalizedString("marked deleted", comment: "marked deleted chat item preview text")
let itemFormattedText = cItem.meta.itemDeleted == nil ? cItem.formattedText : nil
return messageText(itemText, itemFormattedText, cItem.memberDisplayName, icon: attachment(), preview: true)
return messageText(itemText, itemFormattedText, cItem.memberDisplayName, icon: attachment(), preview: true, showSecrets: false)
func attachment() -> String? {
switch cItem.content.msgContent {

View File

@@ -42,11 +42,11 @@
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 */; };
5C4E80DA2B3CCD090080FAE2 /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C4E80D52B3CCD090080FAE2 /* libgmp.a */; };
5C4E80DB2B3CCD090080FAE2 /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C4E80D62B3CCD090080FAE2 /* libffi.a */; };
5C4E80DC2B3CCD090080FAE2 /* libHSsimplex-chat-5.4.2.1-FP1oxJSttEYhorN1FRfI5.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C4E80D72B3CCD090080FAE2 /* libHSsimplex-chat-5.4.2.1-FP1oxJSttEYhorN1FRfI5.a */; };
5C4E80DD2B3CCD090080FAE2 /* libHSsimplex-chat-5.4.2.1-FP1oxJSttEYhorN1FRfI5-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C4E80D82B3CCD090080FAE2 /* libHSsimplex-chat-5.4.2.1-FP1oxJSttEYhorN1FRfI5-ghc9.6.3.a */; };
5C4E80DE2B3CCD090080FAE2 /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C4E80D92B3CCD090080FAE2 /* libgmpxx.a */; };
5C4E80E42B40A96C0080FAE2 /* libHSsimplex-chat-5.5.0.0-FwZXD1cMpkc1VLQMq43OyQ.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C4E80DF2B40A96C0080FAE2 /* libHSsimplex-chat-5.5.0.0-FwZXD1cMpkc1VLQMq43OyQ.a */; };
5C4E80E52B40A96C0080FAE2 /* libHSsimplex-chat-5.5.0.0-FwZXD1cMpkc1VLQMq43OyQ-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C4E80E02B40A96C0080FAE2 /* libHSsimplex-chat-5.5.0.0-FwZXD1cMpkc1VLQMq43OyQ-ghc9.6.3.a */; };
5C4E80E62B40A96C0080FAE2 /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C4E80E12B40A96C0080FAE2 /* libgmp.a */; };
5C4E80E72B40A96C0080FAE2 /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C4E80E22B40A96C0080FAE2 /* libgmpxx.a */; };
5C4E80E82B40A96C0080FAE2 /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C4E80E32B40A96C0080FAE2 /* libffi.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 */; };
@@ -173,11 +173,6 @@
646BB38E283FDB6D001CE359 /* LocalAuthenticationUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 646BB38D283FDB6D001CE359 /* LocalAuthenticationUtils.swift */; };
647F090E288EA27B00644C40 /* GroupMemberInfoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 647F090D288EA27B00644C40 /* GroupMemberInfoView.swift */; };
648010AB281ADD15009009B9 /* CIFileView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 648010AA281ADD15009009B9 /* CIFileView.swift */; };
64863B9B2B3C536500714A11 /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64863B962B3C536500714A11 /* libgmpxx.a */; };
64863B9C2B3C536500714A11 /* libHSsimplex-chat-5.4.2.0-1dXNnkvLJVS8FSAgswHDGD-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64863B972B3C536500714A11 /* libHSsimplex-chat-5.4.2.0-1dXNnkvLJVS8FSAgswHDGD-ghc9.6.3.a */; };
64863B9D2B3C536500714A11 /* libHSsimplex-chat-5.4.2.0-1dXNnkvLJVS8FSAgswHDGD.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64863B982B3C536500714A11 /* libHSsimplex-chat-5.4.2.0-1dXNnkvLJVS8FSAgswHDGD.a */; };
64863B9E2B3C536500714A11 /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64863B992B3C536500714A11 /* libgmp.a */; };
64863B9F2B3C536500714A11 /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64863B9A2B3C536500714A11 /* libffi.a */; };
649BCDA0280460FD00C3A862 /* ComposeImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 649BCD9F280460FD00C3A862 /* ComposeImageView.swift */; };
649BCDA22805D6EF00C3A862 /* CIImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 649BCDA12805D6EF00C3A862 /* CIImageView.swift */; };
64AA1C6927EE10C800AC7277 /* ContextItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64AA1C6827EE10C800AC7277 /* ContextItemView.swift */; };
@@ -294,11 +289,11 @@
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>"; };
5C4E80D52B3CCD090080FAE2 /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = "<group>"; };
5C4E80D62B3CCD090080FAE2 /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = "<group>"; };
5C4E80D72B3CCD090080FAE2 /* libHSsimplex-chat-5.4.2.1-FP1oxJSttEYhorN1FRfI5.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.4.2.1-FP1oxJSttEYhorN1FRfI5.a"; sourceTree = "<group>"; };
5C4E80D82B3CCD090080FAE2 /* libHSsimplex-chat-5.4.2.1-FP1oxJSttEYhorN1FRfI5-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.4.2.1-FP1oxJSttEYhorN1FRfI5-ghc9.6.3.a"; sourceTree = "<group>"; };
5C4E80D92B3CCD090080FAE2 /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = "<group>"; };
5C4E80DF2B40A96C0080FAE2 /* libHSsimplex-chat-5.5.0.0-FwZXD1cMpkc1VLQMq43OyQ.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.5.0.0-FwZXD1cMpkc1VLQMq43OyQ.a"; sourceTree = "<group>"; };
5C4E80E02B40A96C0080FAE2 /* libHSsimplex-chat-5.5.0.0-FwZXD1cMpkc1VLQMq43OyQ-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.5.0.0-FwZXD1cMpkc1VLQMq43OyQ-ghc9.6.3.a"; sourceTree = "<group>"; };
5C4E80E12B40A96C0080FAE2 /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = "<group>"; };
5C4E80E22B40A96C0080FAE2 /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = "<group>"; };
5C4E80E32B40A96C0080FAE2 /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.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>"; };
@@ -461,11 +456,6 @@
646BB38D283FDB6D001CE359 /* LocalAuthenticationUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalAuthenticationUtils.swift; sourceTree = "<group>"; };
647F090D288EA27B00644C40 /* GroupMemberInfoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupMemberInfoView.swift; sourceTree = "<group>"; };
648010AA281ADD15009009B9 /* CIFileView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CIFileView.swift; sourceTree = "<group>"; };
64863B962B3C536500714A11 /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = "<group>"; };
64863B972B3C536500714A11 /* libHSsimplex-chat-5.4.2.0-1dXNnkvLJVS8FSAgswHDGD-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.4.2.0-1dXNnkvLJVS8FSAgswHDGD-ghc9.6.3.a"; sourceTree = "<group>"; };
64863B982B3C536500714A11 /* libHSsimplex-chat-5.4.2.0-1dXNnkvLJVS8FSAgswHDGD.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.4.2.0-1dXNnkvLJVS8FSAgswHDGD.a"; sourceTree = "<group>"; };
64863B992B3C536500714A11 /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = "<group>"; };
64863B9A2B3C536500714A11 /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = "<group>"; };
6493D667280ED77F007A76FB /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
649BCD9F280460FD00C3A862 /* ComposeImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeImageView.swift; sourceTree = "<group>"; };
649BCDA12805D6EF00C3A862 /* CIImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CIImageView.swift; sourceTree = "<group>"; };
@@ -521,13 +511,13 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
5C4E80DD2B3CCD090080FAE2 /* libHSsimplex-chat-5.4.2.1-FP1oxJSttEYhorN1FRfI5-ghc9.6.3.a in Frameworks */,
5C4E80E72B40A96C0080FAE2 /* libgmpxx.a in Frameworks */,
5CE2BA93284534B000EC33A6 /* libiconv.tbd in Frameworks */,
5C4E80DA2B3CCD090080FAE2 /* libgmp.a in Frameworks */,
5C4E80DC2B3CCD090080FAE2 /* libHSsimplex-chat-5.4.2.1-FP1oxJSttEYhorN1FRfI5.a in Frameworks */,
5C4E80E62B40A96C0080FAE2 /* libgmp.a in Frameworks */,
5CE2BA94284534BB00EC33A6 /* libz.tbd in Frameworks */,
5C4E80DB2B3CCD090080FAE2 /* libffi.a in Frameworks */,
5C4E80DE2B3CCD090080FAE2 /* libgmpxx.a in Frameworks */,
5C4E80E82B40A96C0080FAE2 /* libffi.a in Frameworks */,
5C4E80E52B40A96C0080FAE2 /* libHSsimplex-chat-5.5.0.0-FwZXD1cMpkc1VLQMq43OyQ-ghc9.6.3.a in Frameworks */,
5C4E80E42B40A96C0080FAE2 /* libHSsimplex-chat-5.5.0.0-FwZXD1cMpkc1VLQMq43OyQ.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -589,11 +579,11 @@
5C764E5C279C70B7000C6508 /* Libraries */ = {
isa = PBXGroup;
children = (
5C4E80D62B3CCD090080FAE2 /* libffi.a */,
5C4E80D52B3CCD090080FAE2 /* libgmp.a */,
5C4E80D92B3CCD090080FAE2 /* libgmpxx.a */,
5C4E80D82B3CCD090080FAE2 /* libHSsimplex-chat-5.4.2.1-FP1oxJSttEYhorN1FRfI5-ghc9.6.3.a */,
5C4E80D72B3CCD090080FAE2 /* libHSsimplex-chat-5.4.2.1-FP1oxJSttEYhorN1FRfI5.a */,
5C4E80E32B40A96C0080FAE2 /* libffi.a */,
5C4E80E12B40A96C0080FAE2 /* libgmp.a */,
5C4E80E22B40A96C0080FAE2 /* libgmpxx.a */,
5C4E80E02B40A96C0080FAE2 /* libHSsimplex-chat-5.5.0.0-FwZXD1cMpkc1VLQMq43OyQ-ghc9.6.3.a */,
5C4E80DF2B40A96C0080FAE2 /* libHSsimplex-chat-5.5.0.0-FwZXD1cMpkc1VLQMq43OyQ.a */,
);
path = Libraries;
sourceTree = "<group>";
@@ -1512,7 +1502,7 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 186;
CURRENT_PROJECT_VERSION = 187;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_BITCODE = NO;
ENABLE_PREVIEWS = YES;
@@ -1534,7 +1524,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 5.4.2;
MARKETING_VERSION = 5.5;
PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.app;
PRODUCT_NAME = SimpleX;
SDKROOT = iphoneos;
@@ -1555,7 +1545,7 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 186;
CURRENT_PROJECT_VERSION = 187;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_BITCODE = NO;
ENABLE_PREVIEWS = YES;
@@ -1577,7 +1567,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 5.4.2;
MARKETING_VERSION = 5.5;
PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.app;
PRODUCT_NAME = SimpleX;
SDKROOT = iphoneos;
@@ -1636,7 +1626,7 @@
CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 186;
CURRENT_PROJECT_VERSION = 187;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_BITCODE = NO;
GENERATE_INFOPLIST_FILE = YES;
@@ -1649,7 +1639,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 5.4.2;
MARKETING_VERSION = 5.5;
PRODUCT_BUNDLE_IDENTIFIER = "chat.simplex.app.SimpleX-NSE";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
@@ -1668,7 +1658,7 @@
CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 186;
CURRENT_PROJECT_VERSION = 187;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_BITCODE = NO;
GENERATE_INFOPLIST_FILE = YES;
@@ -1681,7 +1671,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 5.4.2;
MARKETING_VERSION = 5.5;
PRODUCT_BUNDLE_IDENTIFIER = "chat.simplex.app.SimpleX-NSE";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
@@ -1700,7 +1690,7 @@
APPLICATION_EXTENSION_API_ONLY = YES;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 186;
CURRENT_PROJECT_VERSION = 187;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
DYLIB_COMPATIBILITY_VERSION = 1;
@@ -1724,7 +1714,7 @@
"$(inherited)",
"$(PROJECT_DIR)/Libraries/sim",
);
MARKETING_VERSION = 5.4.2;
MARKETING_VERSION = 5.5;
PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.SimpleXChat;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
SDKROOT = iphoneos;
@@ -1746,7 +1736,7 @@
APPLICATION_EXTENSION_API_ONLY = YES;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 186;
CURRENT_PROJECT_VERSION = 187;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
DYLIB_COMPATIBILITY_VERSION = 1;
@@ -1770,7 +1760,7 @@
"$(inherited)",
"$(PROJECT_DIR)/Libraries/sim",
);
MARKETING_VERSION = 5.4.2;
MARKETING_VERSION = 5.5;
PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.SimpleXChat;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
SDKROOT = iphoneos;

View File

@@ -3131,6 +3131,10 @@ extension MsgContent: Encodable {
public struct FormattedText: Decodable {
public var text: String
public var format: Format?
public var isSecret: Bool {
if case .secret = format { true } else { false }
}
}
public enum Format: Decodable, Equatable {

View File

@@ -53,6 +53,7 @@ fun ChatItemInfoView(chatModel: ChatModel, ci: ChatItem, ciInfo: ChatItemInfo, d
text, if (text.isEmpty()) emptyList() else formattedText,
sender = sender,
senderBold = true,
toggleSecrets = true,
linkMode = SimplexLinkMode.DESCRIPTION, uriHandler = uriHandler,
onLinkLongClick = { showMenu.value = true }
)

View File

@@ -34,6 +34,7 @@ fun ContextItemView(
fun msgContentView(lines: Int) {
MarkdownText(
contextItem.text, contextItem.formattedText,
toggleSecrets = false,
maxLines = lines,
linkMode = SimplexLinkMode.DESCRIPTION,
modifier = Modifier.fillMaxWidth(),

View File

@@ -15,6 +15,7 @@ import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.platform.LocalClipboardManager
import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.text.AnnotatedString
import dev.icerock.moko.resources.compose.painterResource
import dev.icerock.moko.resources.compose.stringResource
@@ -119,13 +120,15 @@ private fun GroupWelcomeLayout(
@Composable
private fun TextPreview(text: String, linkMode: SimplexLinkMode, markdown: Boolean = true) {
val uriHandler = LocalUriHandler.current
Column {
SelectionContainer(Modifier.fillMaxWidth()) {
MarkdownText(
text,
formattedText = if (markdown) remember(text) { parseToMarkdown(text) } else null,
toggleSecrets = false,
modifier = Modifier.fillMaxHeight().padding(horizontal = DEFAULT_PADDING),
linkMode = linkMode,
linkMode = linkMode, uriHandler = uriHandler,
style = MaterialTheme.typography.body1.copy(color = MaterialTheme.colors.onBackground, lineHeight = 22.sp)
)
}

View File

@@ -54,6 +54,7 @@ fun FramedItemView(
MarkdownText(
qi.text,
qi.formattedText,
toggleSecrets = true,
maxLines = lines,
overflow = TextOverflow.Ellipsis,
style = TextStyle(fontSize = 15.sp, color = MaterialTheme.colors.onSurface),
@@ -288,7 +289,7 @@ fun CIMarkdownText(
Box(Modifier.padding(vertical = 6.dp, horizontal = 12.dp)) {
val text = if (ci.meta.isLive) ci.content.msgContent?.text ?: ci.text else ci.text
MarkdownText(
text, if (text.isEmpty()) emptyList() else ci.formattedText,
text, if (text.isEmpty()) emptyList() else ci.formattedText, toggleSecrets = true,
meta = ci.meta, chatTTL = chatTTL, linkMode = linkMode,
uriHandler = uriHandler, senderBold = true, onLinkLongClick = onLinkLongClick
)

View File

@@ -60,6 +60,7 @@ fun MarkdownText (
sender: String? = null,
meta: CIMeta? = null,
chatTTL: Int? = null,
toggleSecrets: Boolean,
style: TextStyle = MaterialTheme.typography.body1.copy(color = MaterialTheme.colors.onSurface, lineHeight = 22.sp),
maxLines: Int = Int.MAX_VALUE,
overflow: TextOverflow = TextOverflow.Clip,
@@ -89,6 +90,7 @@ fun MarkdownText (
) {
var timer: Job? by remember { mutableStateOf(null) }
var typingIdx by rememberSaveable { mutableStateOf(0) }
val showSecrets = remember { mutableStateMapOf<String, Boolean>() }
fun stopTyping() {
timer?.cancel()
timer = null
@@ -127,15 +129,22 @@ fun MarkdownText (
}
Text(annotatedText, style = style, modifier = modifier, maxLines = maxLines, overflow = overflow, inlineContent = inlineContent ?: mapOf())
} else {
var hasLinks = false
var hasAnnotations = false
val annotatedText = buildAnnotatedString {
appendSender(this, sender, senderBold)
for (ft in formattedText) {
for ((i, ft) in formattedText.withIndex()) {
if (ft.format == null) append(ft.text)
else {
else if (toggleSecrets && ft.format is Format.Secret) {
val ftStyle = ft.format.style
hasAnnotations = true
val key = i.toString()
withAnnotation(tag = "SECRET", annotation = key) {
if (showSecrets[key] == true) append(ft.text) else withStyle(ftStyle) { append(ft.text) }
}
} else {
val link = ft.link(linkMode)
if (link != null) {
hasLinks = true
hasAnnotations = true
val ftStyle = ft.format.style
withAnnotation(tag = if (ft.format is Format.SimplexLink) "SIMPLEX_URL" else "URL", annotation = link) {
withStyle(ftStyle) { append(ft.viewText(linkMode)) }
@@ -153,7 +162,7 @@ fun MarkdownText (
withStyle(reserveTimestampStyle) { append("\n" + metaText) }
else */if (meta != null) withStyle(reserveTimestampStyle) { append(reserve) }
}
if (hasLinks && uriHandler != null) {
if (hasAnnotations && uriHandler != null) {
val icon = remember { mutableStateOf(PointerIcon.Default) }
ClickableText(annotatedText, style = style, modifier = modifier.pointerHoverIcon(icon.value), maxLines = maxLines, overflow = overflow,
onLongClick = { offset ->
@@ -177,12 +186,20 @@ fun MarkdownText (
.firstOrNull()?.let { annotation ->
uriHandler.openVerifiedSimplexUri(annotation.item)
}
annotatedText.getStringAnnotations(tag = "SECRET", start = offset, end = offset)
.firstOrNull()?.let { annotation ->
val key = annotation.item
showSecrets[key] = !(showSecrets[key] ?: false)
}
},
onHover = { offset ->
icon.value = annotatedText.getStringAnnotations(tag = "URL", start = offset, end = offset)
.firstOrNull()?.let {
PointerIcon.Hand
} ?: annotatedText.getStringAnnotations(tag = "SIMPLEX_URL", start = offset, end = offset)
.firstOrNull()?.let {
PointerIcon.Hand
} ?: annotatedText.getStringAnnotations(tag = "SECRET", start = offset, end = offset)
.firstOrNull()?.let {
PointerIcon.Hand
} ?: PointerIcon.Default

View File

@@ -173,6 +173,7 @@ fun ChatPreviewView(
cInfo is ChatInfo.Group && !ci.chatDir.sent -> ci.memberDisplayName
else -> null
},
toggleSecrets = false,
linkMode = linkMode,
senderBold = true,
maxLines = 2,

View File

@@ -78,17 +78,6 @@ fun ReadableText(text: String, textAlign: TextAlign = TextAlign.Start, padding:
Text(text, modifier = Modifier.padding(padding), textAlign = textAlign, lineHeight = 22.sp)
}
@Composable
fun ReadableMarkdownText(text: String, textAlign: TextAlign = TextAlign.Start, padding: PaddingValues = PaddingValues(bottom = 12.dp)) {
MarkdownText(
text,
formattedText = remember(text) { parseToMarkdown(text) },
modifier = Modifier.padding(padding),
style = TextStyle(textAlign = textAlign, lineHeight = 22.sp, fontSize = 16.sp),
linkMode = ChatController.appPrefs.simplexLinkMode.get(),
)
}
@Preview/*(
uiMode = Configuration.UI_MODE_NIGHT_YES,
showBackground = true,

View File

@@ -25,11 +25,11 @@ android.nonTransitiveRClass=true
android.enableJetifier=true
kotlin.mpp.androidSourceSetLayoutVersion=2
android.version_name=5.4.2
android.version_code=166
android.version_name=5.5-beta.0
android.version_code=168
desktop.version_name=5.4.2
desktop.version_code=20
desktop.version_name=5.5-beta.0
desktop.version_code=21
kotlin.version=1.8.20
gradle.plugin.version=7.4.2

View File

@@ -1,5 +1,5 @@
name: simplex-chat
version: 5.4.2.1
version: 5.5.0.0
#synopsis:
#description:
homepage: https://github.com/simplex-chat/simplex-chat#readme

View File

@@ -5,7 +5,7 @@ cabal-version: 1.12
-- see: https://github.com/sol/hpack
name: simplex-chat
version: 5.4.2.1
version: 5.5.0.0
category: Web, System, Services, Cryptography
homepage: https://github.com/simplex-chat/simplex-chat#readme
author: simplex.chat