From 043a4ed9159a89f7e12026348d2bed8a8ccceb24 Mon Sep 17 00:00:00 2001 From: Arturs Krumins Date: Tue, 27 Aug 2024 16:30:07 +0300 Subject: [PATCH 1/4] ios: add chat message tail and roundness settings; date separators (#4764) * ios: add chat message tail and roundness settings * cleanup * minor * rename * date separator * revert max roundness to pills * increase default roundness to 1 * minor * out of bounds tails, style date separator * formatting * hardcode tail growth * revert * different shape (WIP) * tail * rename * square * only show tail for the last message * remove func * capture less * variable tail height * export localizations --------- Co-authored-by: Evgeny Poberezkin --- .../Chat/ChatItem/CIGroupInvitationView.swift | 2 +- .../Chat/ChatItem/CIRcvDecryptionError.swift | 55 +++--- .../Views/Chat/ChatItem/FramedItemView.swift | 4 +- .../ChatItem/IntegrityErrorItemView.swift | 2 +- .../Chat/ChatItem/MarkedDeletedItemView.swift | 2 +- apps/ios/Shared/Views/Chat/ChatView.swift | 32 +++- .../Views/Helpers/ChatItemClipShape.swift | 174 ++++++++++++++---- .../UserSettings/AppearanceSettings.swift | 17 +- .../Views/UserSettings/SettingsView.swift | 6 + .../bg.xcloc/Localized Contents/bg.xliff | 40 ++++ .../cs.xcloc/Localized Contents/cs.xliff | 40 ++++ .../de.xcloc/Localized Contents/de.xliff | 40 ++++ .../en.xcloc/Localized Contents/en.xliff | 50 +++++ .../es.xcloc/Localized Contents/es.xliff | 40 ++++ .../fi.xcloc/Localized Contents/fi.xliff | 40 ++++ .../fr.xcloc/Localized Contents/fr.xliff | 40 ++++ .../hu.xcloc/Localized Contents/hu.xliff | 40 ++++ .../it.xcloc/Localized Contents/it.xliff | 40 ++++ .../ja.xcloc/Localized Contents/ja.xliff | 40 ++++ .../nl.xcloc/Localized Contents/nl.xliff | 40 ++++ .../pl.xcloc/Localized Contents/pl.xliff | 40 ++++ .../ru.xcloc/Localized Contents/ru.xliff | 40 ++++ .../th.xcloc/Localized Contents/th.xliff | 40 ++++ .../tr.xcloc/Localized Contents/tr.xliff | 40 ++++ .../uk.xcloc/Localized Contents/uk.xliff | 40 ++++ .../Localized Contents/zh-Hans.xliff | 40 ++++ 26 files changed, 909 insertions(+), 75 deletions(-) diff --git a/apps/ios/Shared/Views/Chat/ChatItem/CIGroupInvitationView.swift b/apps/ios/Shared/Views/Chat/ChatItem/CIGroupInvitationView.swift index 3c6da34ae5..da859c1606 100644 --- a/apps/ios/Shared/Views/Chat/ChatItem/CIGroupInvitationView.swift +++ b/apps/ios/Shared/Views/Chat/ChatItem/CIGroupInvitationView.swift @@ -70,7 +70,7 @@ struct CIGroupInvitationView: View { } .padding(.horizontal, 12) .padding(.vertical, 6) - .background(chatItemFrameColor(chatItem, theme)) + .background { chatItemFrameColor(chatItem, theme).modifier(ChatTailPadding()) } .textSelection(.disabled) .onPreferenceChange(DetermineWidth.Key.self) { frameWidth = $0 } .onChange(of: inProgress) { inProgress in diff --git a/apps/ios/Shared/Views/Chat/ChatItem/CIRcvDecryptionError.swift b/apps/ios/Shared/Views/Chat/ChatItem/CIRcvDecryptionError.swift index 915af3f479..9f721f83b7 100644 --- a/apps/ios/Shared/Views/Chat/ChatItem/CIRcvDecryptionError.swift +++ b/apps/ios/Shared/Views/Chat/ChatItem/CIRcvDecryptionError.swift @@ -69,37 +69,40 @@ struct CIRcvDecryptionError: View { } @ViewBuilder private func viewBody() -> some View { - if case let .direct(contact) = chat.chatInfo, - let contactStats = contact.activeConn?.connectionStats { - if contactStats.ratchetSyncAllowed { - decryptionErrorItemFixButton(syncSupported: true) { - alert = .syncAllowedAlert { syncContactConnection(contact) } + Group { + if case let .direct(contact) = chat.chatInfo, + let contactStats = contact.activeConn?.connectionStats { + if contactStats.ratchetSyncAllowed { + decryptionErrorItemFixButton(syncSupported: true) { + alert = .syncAllowedAlert { syncContactConnection(contact) } + } + } else if !contactStats.ratchetSyncSupported { + decryptionErrorItemFixButton(syncSupported: false) { + alert = .syncNotSupportedContactAlert + } + } else { + basicDecryptionErrorItem() } - } else if !contactStats.ratchetSyncSupported { - decryptionErrorItemFixButton(syncSupported: false) { - alert = .syncNotSupportedContactAlert + } else if case let .group(groupInfo) = chat.chatInfo, + case let .groupRcv(groupMember) = chatItem.chatDir, + let mem = m.getGroupMember(groupMember.groupMemberId), + let memberStats = mem.wrapped.activeConn?.connectionStats { + if memberStats.ratchetSyncAllowed { + decryptionErrorItemFixButton(syncSupported: true) { + alert = .syncAllowedAlert { syncMemberConnection(groupInfo, groupMember) } + } + } else if !memberStats.ratchetSyncSupported { + decryptionErrorItemFixButton(syncSupported: false) { + alert = .syncNotSupportedMemberAlert + } + } else { + basicDecryptionErrorItem() } } else { basicDecryptionErrorItem() } - } else if case let .group(groupInfo) = chat.chatInfo, - case let .groupRcv(groupMember) = chatItem.chatDir, - let mem = m.getGroupMember(groupMember.groupMemberId), - let memberStats = mem.wrapped.activeConn?.connectionStats { - if memberStats.ratchetSyncAllowed { - decryptionErrorItemFixButton(syncSupported: true) { - alert = .syncAllowedAlert { syncMemberConnection(groupInfo, groupMember) } - } - } else if !memberStats.ratchetSyncSupported { - decryptionErrorItemFixButton(syncSupported: false) { - alert = .syncNotSupportedMemberAlert - } - } else { - basicDecryptionErrorItem() - } - } else { - basicDecryptionErrorItem() } + .background { chatItemFrameColor(chatItem, theme).modifier(ChatTailPadding()) } } private func basicDecryptionErrorItem() -> some View { @@ -132,7 +135,6 @@ struct CIRcvDecryptionError: View { } .onTapGesture(perform: { onClick() }) .padding(.vertical, 6) - .background(Color(uiColor: .tertiarySystemGroupedBackground)) .textSelection(.disabled) } @@ -151,7 +153,6 @@ struct CIRcvDecryptionError: View { } .onTapGesture(perform: { onClick() }) .padding(.vertical, 6) - .background(Color(uiColor: .tertiarySystemGroupedBackground)) .textSelection(.disabled) } diff --git a/apps/ios/Shared/Views/Chat/ChatItem/FramedItemView.swift b/apps/ios/Shared/Views/Chat/ChatItem/FramedItemView.swift index 313ec0d419..e70f891302 100644 --- a/apps/ios/Shared/Views/Chat/ChatItem/FramedItemView.swift +++ b/apps/ios/Shared/Views/Chat/ChatItem/FramedItemView.swift @@ -71,8 +71,8 @@ struct FramedItemView: View { .overlay(DetermineWidth()) .accessibilityLabel("") } - } - .background(chatItemFrameColorMaybeImageOrVideo(chatItem, theme)) + } + .background { chatItemFrameColorMaybeImageOrVideo(chatItem, theme).modifier(ChatTailPadding()) } .onPreferenceChange(DetermineWidth.Key.self) { msgWidth = $0 } if let (title, text) = chatItem.meta.itemStatus.statusInfo { diff --git a/apps/ios/Shared/Views/Chat/ChatItem/IntegrityErrorItemView.swift b/apps/ios/Shared/Views/Chat/ChatItem/IntegrityErrorItemView.swift index 822dda4d06..afeb88b05d 100644 --- a/apps/ios/Shared/Views/Chat/ChatItem/IntegrityErrorItemView.swift +++ b/apps/ios/Shared/Views/Chat/ChatItem/IntegrityErrorItemView.swift @@ -69,7 +69,7 @@ struct CIMsgError: View { } .padding(.leading, 12) .padding(.vertical, 6) - .background(Color(uiColor: .tertiarySystemGroupedBackground)) + .background { chatItemFrameColor(chatItem, theme).modifier(ChatTailPadding()) } .textSelection(.disabled) .onTapGesture(perform: onTap) } diff --git a/apps/ios/Shared/Views/Chat/ChatItem/MarkedDeletedItemView.swift b/apps/ios/Shared/Views/Chat/ChatItem/MarkedDeletedItemView.swift index 25e06b9ea4..afd817357c 100644 --- a/apps/ios/Shared/Views/Chat/ChatItem/MarkedDeletedItemView.swift +++ b/apps/ios/Shared/Views/Chat/ChatItem/MarkedDeletedItemView.swift @@ -22,7 +22,7 @@ struct MarkedDeletedItemView: View { .foregroundColor(theme.colors.secondary) .padding(.horizontal, 12) .padding(.vertical, 6) - .background(chatItemFrameColor(chatItem, theme)) + .background { chatItemFrameColor(chatItem, theme).modifier(ChatTailPadding()) } .textSelection(.disabled) } diff --git a/apps/ios/Shared/Views/Chat/ChatView.swift b/apps/ios/Shared/Views/Chat/ChatView.swift index e9e86c31d7..d94be2bb81 100644 --- a/apps/ios/Shared/Views/Chat/ChatView.swift +++ b/apps/ios/Shared/Views/Chat/ChatView.swift @@ -717,8 +717,8 @@ struct ChatView: View { var revealed: Bool { chatItem == revealedChatItem } - typealias ItemSeparation = (timestamp: Bool, largeGap: Bool) - + typealias ItemSeparation = (timestamp: Bool, largeGap: Bool, date: Date?) + func getItemSeparation(_ chatItem: ChatItem, at i: Int?) -> ItemSeparation { let im = ItemsModel.shared if let i, i > 0 && im.reversedChatItems.count >= i { @@ -726,10 +726,11 @@ struct ChatView: View { let largeGap = !nextItem.chatDir.sameDirection(chatItem.chatDir) || nextItem.meta.createdAt.timeIntervalSince(chatItem.meta.createdAt) > 60 return ( timestamp: largeGap || formatTimestampText(chatItem.meta.createdAt) != formatTimestampText(nextItem.meta.createdAt), - largeGap: largeGap + largeGap: largeGap, + date: Calendar.current.isDate(chatItem.meta.createdAt, inSameDayAs: nextItem.meta.createdAt) ? nil : nextItem.meta.createdAt ) } else { - return (timestamp: true, largeGap: true) + return (timestamp: true, largeGap: true, date: nil) } } @@ -760,7 +761,20 @@ struct ChatView: View { } } } else { - chatItemView(chatItem, range, prevItem, timeSeparation) + VStack(spacing: 0) { + chatItemView(chatItem, range, prevItem, timeSeparation) + if let date = timeSeparation.date { + Text(String.localizedStringWithFormat( + NSLocalizedString("%@, %@", comment: "format for date separator in chat"), + date.formatted(.dateTime.weekday(.abbreviated)), + date.formatted(.dateTime.day().month(.abbreviated)) + )) + .font(.callout) + .fontWeight(.medium) + .foregroundStyle(.secondary) + .padding(8) + } + } .overlay { if let selected = selectedChatItems, chatItem.canBeDeletedForSelf { Color.clear @@ -834,14 +848,14 @@ struct ChatView: View { .foregroundStyle(.secondary) .lineLimit(2) .padding(.leading, memberImageSize + 14 + (selectedChatItems != nil && ci.canBeDeletedForSelf ? 12 + 24 : 0)) - .padding(.top, 7) + .padding(.top, 3) // this is in addition to message sequence gap } HStack(alignment: .center, spacing: 0) { if selectedChatItems != nil && ci.canBeDeletedForSelf { SelectedChatItem(ciId: ci.id, selectedChatItems: $selectedChatItems) .padding(.trailing, 12) } - HStack(alignment: .top, spacing: 8) { + HStack(alignment: .top, spacing: 10) { MemberProfileImage(member, size: memberImageSize, backgroundColor: theme.colors.background) .onTapGesture { if let member = m.getGroupMember(member.groupMemberId) { @@ -869,7 +883,7 @@ struct ChatView: View { } chatItemWithMenu(ci, range, maxWidth, itemSeparation) .padding(.trailing) - .padding(.leading, memberImageSize + 8 + 12) + .padding(.leading, 10 + memberImageSize + 12) } .padding(.bottom, bottomPadding) } @@ -913,7 +927,7 @@ struct ChatView: View { allowMenu: $allowMenu ) .environment(\.showTimestamp, itemSeparation.timestamp) - .modifier(ChatItemClipped(ci)) + .modifier(ChatItemClipped(ci, tailVisible: itemSeparation.largeGap)) .contextMenu { menu(ci, range, live: composeState.liveMessage != nil) } .accessibilityLabel("") if ci.content.msgContent != nil && (ci.meta.itemDeleted == nil || revealed) && ci.reactions.count > 0 { diff --git a/apps/ios/Shared/Views/Helpers/ChatItemClipShape.swift b/apps/ios/Shared/Views/Helpers/ChatItemClipShape.swift index 477dc567eb..ddae6a5f6d 100644 --- a/apps/ios/Shared/Views/Helpers/ChatItemClipShape.swift +++ b/apps/ios/Shared/Views/Helpers/ChatItemClipShape.swift @@ -14,50 +14,60 @@ import SimpleXChat /// Supports [Dynamic Type](https://developer.apple.com/documentation/uikit/uifont/scaling_fonts_automatically) /// by retaining pill shape, even when ``ChatItem``'s height is less that twice its corner radius struct ChatItemClipped: ViewModifier { - struct ClipShape: Shape { - let maxCornerRadius: Double - - func path(in rect: CGRect) -> Path { - Path( - roundedRect: rect, - cornerRadius: min((rect.height / 2), maxCornerRadius), - style: .circular - ) - } - } - + @AppStorage(DEFAULT_CHAT_ITEM_ROUNDNESS) private var roundness = defaultChatItemRoundness + @AppStorage(DEFAULT_CHAT_ITEM_TAIL) private var tailEnabled = true + private let chatItem: (content: CIContent, chatDir: CIDirection)? + private let tailVisible: Bool + init() { - clipShape = ClipShape( - maxCornerRadius: 18 - ) + self.chatItem = nil + self.tailVisible = false + } + + init(_ ci: ChatItem, tailVisible: Bool) { + self.chatItem = (ci.content, ci.chatDir) + self.tailVisible = tailVisible } - init(_ chatItem: ChatItem) { - clipShape = ClipShape( - maxCornerRadius: { - switch chatItem.content { - case - .sndMsgContent, + private func shapeStyle() -> ChatItemShape.Style { + if let ci = chatItem { + switch ci.content { + case + .sndMsgContent, .rcvMsgContent, .rcvDecryptionError, .rcvGroupInvitation, .sndGroupInvitation, - .sndDeleted, + .sndDeleted, .rcvDeleted, .rcvIntegrityError, - .sndModerated, - .rcvModerated, + .sndModerated, + .rcvModerated, .rcvBlocked, - .invalidJSON: 18 - default: 8 + .invalidJSON: + let tail = if let mc = ci.content.msgContent, mc.isImageOrVideo && mc.text.isEmpty { + false + } else { + tailVisible } - }() - ) + return tailEnabled + ? .bubble( + padding: ci.chatDir.sent ? .trailing : .leading, + tailVisible: tail + ) + : .roundRect(radius: msgRectMaxRadius) + default: return .roundRect(radius: 8) + } + } else { + return.roundRect(radius: msgRectMaxRadius) + } } - - private let clipShape: ClipShape - + func body(content: Content) -> some View { + let clipShape = ChatItemShape( + roundness: roundness, + style: shapeStyle() + ) content .contentShape(.dragPreview, clipShape) .contentShape(.contextMenuPreview, clipShape) @@ -65,4 +75,106 @@ struct ChatItemClipped: ViewModifier { } } +struct ChatTailPadding: ViewModifier { + func body(content: Content) -> some View { + content.padding(.horizontal, -msgTailWidth) + } +} +private let msgRectMaxRadius: Double = 18 +private let msgBubbleMaxRadius: Double = msgRectMaxRadius * 1.2 +private let msgTailWidth: Double = 9 +private let msgTailMinHeight: Double = msgTailWidth * 1.254 // ~56deg +private let msgTailMaxHeight: Double = msgTailWidth * 1.732 // 60deg + +struct ChatItemShape: Shape { + fileprivate enum Style { + case bubble(padding: HorizontalEdge, tailVisible: Bool) + case roundRect(radius: Double) + } + + fileprivate let roundness: Double + fileprivate let style: Style + + func path(in rect: CGRect) -> Path { + switch style { + case let .bubble(padding, tailVisible): + let w = rect.width + let h = rect.height + let rxMax = min(msgBubbleMaxRadius, w / 2) + let ryMax = min(msgBubbleMaxRadius, h / 2) + let rx = roundness * rxMax + let ry = roundness * ryMax + let tailHeight = min(msgTailMinHeight + roundness * (msgTailMaxHeight - msgTailMinHeight), h / 2) + var path = Path() + // top side + path.move(to: CGPoint(x: rx, y: 0)) + path.addLine(to: CGPoint(x: w - rx, y: 0)) + if roundness > 0 { + // top-right corner + path.addQuadCurve(to: CGPoint(x: w, y: ry), control: CGPoint(x: w, y: 0)) + } + if rect.height > 2 * ry { + // right side + path.addLine(to: CGPoint(x: w, y: h - ry)) + } + if roundness > 0 { + // bottom-right corner + path.addQuadCurve(to: CGPoint(x: w - rx, y: h), control: CGPoint(x: w, y: h)) + } + // bottom side + if tailVisible { + path.addLine(to: CGPoint(x: -msgTailWidth, y: h)) + if roundness > 0 { + // bottom-left tail + // distance of control point from touch point, calculated via ratios + let d = tailHeight - msgTailWidth * msgTailWidth / tailHeight + // tail control point + let tc = CGPoint(x: 0, y: h - tailHeight + d * sqrt(roundness)) + // bottom-left tail curve + path.addQuadCurve(to: CGPoint(x: 0, y: h - tailHeight), control: tc) + } else { + path.addLine(to: CGPoint(x: 0, y: h - tailHeight)) + } + if rect.height > ry + tailHeight { + // left side + path.addLine(to: CGPoint(x: 0, y: ry)) + } + } else { + path.addLine(to: CGPoint(x: rx, y: h)) + path.addQuadCurve(to: CGPoint(x: 0, y: h - ry), control: CGPoint(x: 0 , y: h)) + if rect.height > 2 * ry { + // left side + path.addLine(to: CGPoint(x: 0, y: ry)) + } + } + if roundness > 0 { + // top-left corner + path.addQuadCurve(to: CGPoint(x: rx, y: 0), control: CGPoint(x: 0, y: 0)) + } + path.closeSubpath() + return switch padding { + case .leading: path + case .trailing: path + .scale(x: -1, y: 1, anchor: .center) + .path(in: rect) + } + case let .roundRect(radius): + return Path(roundedRect: rect, cornerRadius: radius * roundness) + } + } + + var offset: Double? { + switch style { + case let .bubble(padding, isTailVisible): + if isTailVisible { + switch padding { + case .leading: -msgTailWidth + case .trailing: msgTailWidth + } + } else { 0 } + case .roundRect: 0 + } + } + +} diff --git a/apps/ios/Shared/Views/UserSettings/AppearanceSettings.swift b/apps/ios/Shared/Views/UserSettings/AppearanceSettings.swift index 73a789f108..70c33329b1 100644 --- a/apps/ios/Shared/Views/UserSettings/AppearanceSettings.swift +++ b/apps/ios/Shared/Views/UserSettings/AppearanceSettings.swift @@ -33,6 +33,8 @@ struct AppearanceSettings: View { }() @State private var darkModeTheme: String = UserDefaults.standard.string(forKey: DEFAULT_SYSTEM_DARK_THEME) ?? DefaultTheme.DARK.themeName @AppStorage(DEFAULT_PROFILE_IMAGE_CORNER_RADIUS) private var profileImageCornerRadius = defaultProfileImageCorner + @AppStorage(DEFAULT_CHAT_ITEM_ROUNDNESS) private var chatItemRoundness = defaultChatItemRoundness + @AppStorage(DEFAULT_CHAT_ITEM_TAIL) private var chatItemTail = true @AppStorage(GROUP_DEFAULT_ONE_HAND_UI, store: groupDefaults) private var oneHandUI = true @AppStorage(DEFAULT_TOOLBAR_MATERIAL) private var toolbarMaterial = ToolbarMaterial.defaultMaterial @@ -179,6 +181,14 @@ struct AppearanceSettings: View { } } + Section(header: Text("Message shape").foregroundColor(theme.colors.secondary)) { + HStack { + Text("Corner") + Slider(value: $chatItemRoundness, in: 0...1, step: 0.05) + } + Toggle("Tail", isOn: $chatItemTail) + } + Section(header: Text("Profile images").foregroundColor(theme.colors.secondary)) { HStack(spacing: 16) { if let img = m.currentUser?.image, img != "" { @@ -358,20 +368,21 @@ struct ChatThemePreview: View { let bob = ChatItem.getSample(2, CIDirection.directSnd, Date.now, NSLocalizedString("Good morning!", comment: "message preview"), quotedItem: CIQuote.getSample(alice.id, alice.meta.itemTs, alice.content.text, chatDir: alice.chatDir)) HStack { ChatItemView(chat: Chat.sampleData, chatItem: alice, revealed: Binding.constant(false)) - .modifier(ChatItemClipped()) + .modifier(ChatItemClipped(alice, tailVisible: true)) Spacer() } HStack { Spacer() ChatItemView(chat: Chat.sampleData, chatItem: bob, revealed: Binding.constant(false)) - .modifier(ChatItemClipped()) + .modifier(ChatItemClipped(bob, tailVisible: true)) .frame(alignment: .trailing) } } else { Rectangle().fill(.clear) } } - .padding(10) + .padding(.vertical, 10) + .padding(.horizontal, 16) .frame(maxWidth: .infinity) if let wallpaperType, let wallpaperImage = wallpaperType.image, let backgroundColor, let tintColor { diff --git a/apps/ios/Shared/Views/UserSettings/SettingsView.swift b/apps/ios/Shared/Views/UserSettings/SettingsView.swift index a4908f628f..d9c83803dd 100644 --- a/apps/ios/Shared/Views/UserSettings/SettingsView.swift +++ b/apps/ios/Shared/Views/UserSettings/SettingsView.swift @@ -47,6 +47,8 @@ let DEFAULT_ACCENT_COLOR_GREEN = "accentColorGreen" // deprecated, only used for let DEFAULT_ACCENT_COLOR_BLUE = "accentColorBlue" // deprecated, only used for migration let DEFAULT_USER_INTERFACE_STYLE = "userInterfaceStyle" // deprecated, only used for migration let DEFAULT_PROFILE_IMAGE_CORNER_RADIUS = "profileImageCornerRadius" +let DEFAULT_CHAT_ITEM_ROUNDNESS = "chatItemRoundness" +let DEFAULT_CHAT_ITEM_TAIL = "chatItemTail" let DEFAULT_ONE_HAND_UI_CARD_SHOWN = "oneHandUICardShown" let DEFAULT_TOOLBAR_MATERIAL = "toolbarMaterial" let DEFAULT_CONNECT_VIA_LINK_TAB = "connectViaLinkTab" @@ -75,6 +77,8 @@ let DEFAULT_THEME_OVERRIDES = "themeOverrides" let ANDROID_DEFAULT_CALL_ON_LOCK_SCREEN = "androidCallOnLockScreen" +let defaultChatItemRoundness: Double = 0.75 + let appDefaults: [String: Any] = [ DEFAULT_SHOW_LA_NOTICE: false, DEFAULT_LA_NOTICE_SHOWN: false, @@ -98,6 +102,8 @@ let appDefaults: [String: Any] = [ DEFAULT_DEVELOPER_TOOLS: false, DEFAULT_ENCRYPTION_STARTED: false, DEFAULT_PROFILE_IMAGE_CORNER_RADIUS: defaultProfileImageCorner, + DEFAULT_CHAT_ITEM_ROUNDNESS: defaultChatItemRoundness, + DEFAULT_CHAT_ITEM_TAIL: true, DEFAULT_ONE_HAND_UI_CARD_SHOWN: false, DEFAULT_TOOLBAR_MATERIAL: ToolbarMaterial.defaultMaterial, DEFAULT_CONNECT_VIA_LINK_TAB: ConnectViaLinkTab.scan.rawValue, diff --git a/apps/ios/SimpleX Localizations/bg.xcloc/Localized Contents/bg.xliff b/apps/ios/SimpleX Localizations/bg.xcloc/Localized Contents/bg.xliff index 419f0ae864..89e628e2b6 100644 --- a/apps/ios/SimpleX Localizations/bg.xcloc/Localized Contents/bg.xliff +++ b/apps/ios/SimpleX Localizations/bg.xcloc/Localized Contents/bg.xliff @@ -137,6 +137,10 @@ %@ иска да се свърже! notification title + + %1$@, %2$@ + format for date separator in chat + %@, %@ and %lld members %@, %@ и %lld членове @@ -1685,6 +1689,10 @@ This is your own one-time link! Версия на ядрото: v%@ No comment provided by engineer. + + Corner + No comment provided by engineer. + Correct name to %@? Поправи име на %@? @@ -2645,6 +2653,10 @@ This is your own one-time link! Грешка при промяна на адреса No comment provided by engineer. + + Error changing connection profile + No comment provided by engineer. + Error changing role Грешка при промяна на ролята @@ -2655,6 +2667,10 @@ This is your own one-time link! Грешка при промяна на настройката No comment provided by engineer. + + Error changing to incognito! + No comment provided by engineer. + Error connecting to forwarding server %@. Please try later. No comment provided by engineer. @@ -2870,6 +2886,10 @@ This is your own one-time link! Грешка при спиране на чата No comment provided by engineer. + + Error switching profile + No comment provided by engineer. + Error switching profile! Грешка при смяна на профил! @@ -4069,6 +4089,10 @@ This is your link for group %@! Message servers No comment provided by engineer. + + Message shape + No comment provided by engineer. + Message source remains private. Източникът на съобщението остава скрит. @@ -5562,6 +5586,10 @@ Enable in *Network & servers* settings. Избери chat item action + + Select chat profile + No comment provided by engineer. + Selected %lld No comment provided by engineer. @@ -5911,6 +5939,10 @@ Enable in *Network & servers* settings. Сподели линк No comment provided by engineer. + + Share profile + No comment provided by engineer. + Share this 1-time invite link Сподели този еднократен линк за връзка @@ -6235,6 +6267,10 @@ Enable in *Network & servers* settings. TCP_KEEPINTVL No comment provided by engineer. + + Tail + No comment provided by engineer. + Take picture Направи снимка @@ -7480,6 +7516,10 @@ Repeat connection request? Вашите чат профили No comment provided by engineer. + + Your connection was moved to %@ but an unexpected error occurred while redirecting you to the profile. + No comment provided by engineer. + Your contact sent a file that is larger than currently supported maximum size (%@). Вашият контакт изпрати файл, който е по-голям от поддържания в момента максимален размер (%@). diff --git a/apps/ios/SimpleX Localizations/cs.xcloc/Localized Contents/cs.xliff b/apps/ios/SimpleX Localizations/cs.xcloc/Localized Contents/cs.xliff index a02203e630..65bc83d096 100644 --- a/apps/ios/SimpleX Localizations/cs.xcloc/Localized Contents/cs.xliff +++ b/apps/ios/SimpleX Localizations/cs.xcloc/Localized Contents/cs.xliff @@ -135,6 +135,10 @@ %@ se chce připojit! notification title + + %1$@, %2$@ + format for date separator in chat + %@, %@ and %lld members No comment provided by engineer. @@ -1623,6 +1627,10 @@ This is your own one-time link! Verze jádra: v%@ No comment provided by engineer. + + Corner + No comment provided by engineer. + Correct name to %@? No comment provided by engineer. @@ -2552,6 +2560,10 @@ This is your own one-time link! Chuba změny adresy No comment provided by engineer. + + Error changing connection profile + No comment provided by engineer. + Error changing role Chyba při změně role @@ -2562,6 +2574,10 @@ This is your own one-time link! Chyba změny nastavení No comment provided by engineer. + + Error changing to incognito! + No comment provided by engineer. + Error connecting to forwarding server %@. Please try later. No comment provided by engineer. @@ -2772,6 +2788,10 @@ This is your own one-time link! Chyba při zastavení chatu No comment provided by engineer. + + Error switching profile + No comment provided by engineer. + Error switching profile! Chyba při přepínání profilu! @@ -3928,6 +3948,10 @@ This is your link for group %@! Message servers No comment provided by engineer. + + Message shape + No comment provided by engineer. + Message source remains private. No comment provided by engineer. @@ -5363,6 +5387,10 @@ Enable in *Network & servers* settings. Vybrat chat item action + + Select chat profile + No comment provided by engineer. + Selected %lld No comment provided by engineer. @@ -5708,6 +5736,10 @@ Enable in *Network & servers* settings. Sdílet odkaz No comment provided by engineer. + + Share profile + No comment provided by engineer. + Share this 1-time invite link No comment provided by engineer. @@ -6024,6 +6056,10 @@ Enable in *Network & servers* settings. TCP_KEEPINTVL No comment provided by engineer. + + Tail + No comment provided by engineer. + Take picture Vyfotit @@ -7209,6 +7245,10 @@ Repeat connection request? Vaše chat profily No comment provided by engineer. + + Your connection was moved to %@ but an unexpected error occurred while redirecting you to the profile. + No comment provided by engineer. + Your contact sent a file that is larger than currently supported maximum size (%@). Kontakt odeslal soubor, který je větší než aktuálně podporovaná maximální velikost (%@). diff --git a/apps/ios/SimpleX Localizations/de.xcloc/Localized Contents/de.xliff b/apps/ios/SimpleX Localizations/de.xcloc/Localized Contents/de.xliff index 29adfbabf0..357b1c3c47 100644 --- a/apps/ios/SimpleX Localizations/de.xcloc/Localized Contents/de.xliff +++ b/apps/ios/SimpleX Localizations/de.xcloc/Localized Contents/de.xliff @@ -137,6 +137,10 @@ %@ will sich mit Ihnen verbinden! notification title + + %1$@, %2$@ + format for date separator in chat + %@, %@ and %lld members %@, %@ und %lld Mitglieder @@ -1740,6 +1744,10 @@ Das ist Ihr eigener Einmal-Link! Core Version: v%@ No comment provided by engineer. + + Corner + No comment provided by engineer. + Correct name to %@? Richtiger Name für %@? @@ -2724,6 +2732,10 @@ Das ist Ihr eigener Einmal-Link! Fehler beim Wechseln der Empfängeradresse No comment provided by engineer. + + Error changing connection profile + No comment provided by engineer. + Error changing role Fehler beim Ändern der Rolle @@ -2734,6 +2746,10 @@ Das ist Ihr eigener Einmal-Link! Fehler beim Ändern der Einstellung No comment provided by engineer. + + Error changing to incognito! + No comment provided by engineer. + Error connecting to forwarding server %@. Please try later. Fehler beim Verbinden mit dem Weiterleitungsserver %@. Bitte versuchen Sie es später erneut. @@ -2954,6 +2970,10 @@ Das ist Ihr eigener Einmal-Link! Fehler beim Beenden des Chats No comment provided by engineer. + + Error switching profile + No comment provided by engineer. + Error switching profile! Fehler beim Umschalten des Profils! @@ -4184,6 +4204,10 @@ Das ist Ihr Link für die Gruppe %@! Nachrichten-Server No comment provided by engineer. + + Message shape + No comment provided by engineer. + Message source remains private. Die Nachrichtenquelle bleibt privat. @@ -5729,6 +5753,10 @@ Aktivieren Sie es in den *Netzwerk & Server* Einstellungen. Auswählen chat item action + + Select chat profile + No comment provided by engineer. + Selected %lld %lld ausgewählt @@ -6099,6 +6127,10 @@ Aktivieren Sie es in den *Netzwerk & Server* Einstellungen. Link teilen No comment provided by engineer. + + Share profile + No comment provided by engineer. + Share this 1-time invite link Teilen Sie diesen Einmal-Einladungslink @@ -6439,6 +6471,10 @@ Aktivieren Sie es in den *Netzwerk & Server* Einstellungen. TCP_KEEPINTVL No comment provided by engineer. + + Tail + No comment provided by engineer. + Take picture Machen Sie ein Foto @@ -7719,6 +7755,10 @@ Verbindungsanfrage wiederholen? Ihre Chat-Profile No comment provided by engineer. + + Your connection was moved to %@ but an unexpected error occurred while redirecting you to the profile. + No comment provided by engineer. + Your contact sent a file that is larger than currently supported maximum size (%@). Ihr Kontakt hat eine Datei gesendet, die größer ist als die derzeit unterstützte maximale Größe (%@). diff --git a/apps/ios/SimpleX Localizations/en.xcloc/Localized Contents/en.xliff b/apps/ios/SimpleX Localizations/en.xcloc/Localized Contents/en.xliff index c217793f03..006996c8d9 100644 --- a/apps/ios/SimpleX Localizations/en.xcloc/Localized Contents/en.xliff +++ b/apps/ios/SimpleX Localizations/en.xcloc/Localized Contents/en.xliff @@ -137,6 +137,11 @@ %@ wants to connect! notification title + + %1$@, %2$@ + %1$@, %2$@ + format for date separator in chat + %@, %@ and %lld members %@, %@ and %lld members @@ -1740,6 +1745,11 @@ This is your own one-time link! Core version: v%@ No comment provided by engineer. + + Corner + Corner + No comment provided by engineer. + Correct name to %@? Correct name to %@? @@ -2724,6 +2734,11 @@ This is your own one-time link! Error changing address No comment provided by engineer. + + Error changing connection profile + Error changing connection profile + No comment provided by engineer. + Error changing role Error changing role @@ -2734,6 +2749,11 @@ This is your own one-time link! Error changing setting No comment provided by engineer. + + Error changing to incognito! + Error changing to incognito! + No comment provided by engineer. + Error connecting to forwarding server %@. Please try later. Error connecting to forwarding server %@. Please try later. @@ -2954,6 +2974,11 @@ This is your own one-time link! Error stopping chat No comment provided by engineer. + + Error switching profile + Error switching profile + No comment provided by engineer. + Error switching profile! Error switching profile! @@ -4184,6 +4209,11 @@ This is your link for group %@! Message servers No comment provided by engineer. + + Message shape + Message shape + No comment provided by engineer. + Message source remains private. Message source remains private. @@ -5729,6 +5759,11 @@ Enable in *Network & servers* settings. Select chat item action + + Select chat profile + Select chat profile + No comment provided by engineer. + Selected %lld Selected %lld @@ -6099,6 +6134,11 @@ Enable in *Network & servers* settings. Share link No comment provided by engineer. + + Share profile + Share profile + No comment provided by engineer. + Share this 1-time invite link Share this 1-time invite link @@ -6439,6 +6479,11 @@ Enable in *Network & servers* settings. TCP_KEEPINTVL No comment provided by engineer. + + Tail + Tail + No comment provided by engineer. + Take picture Take picture @@ -7719,6 +7764,11 @@ Repeat connection request? Your chat profiles No comment provided by engineer. + + Your connection was moved to %@ but an unexpected error occurred while redirecting you to the profile. + Your connection was moved to %@ but an unexpected error occurred while redirecting you to the profile. + No comment provided by engineer. + Your contact sent a file that is larger than currently supported maximum size (%@). Your contact sent a file that is larger than currently supported maximum size (%@). diff --git a/apps/ios/SimpleX Localizations/es.xcloc/Localized Contents/es.xliff b/apps/ios/SimpleX Localizations/es.xcloc/Localized Contents/es.xliff index 6e5ec0e85a..529b185e25 100644 --- a/apps/ios/SimpleX Localizations/es.xcloc/Localized Contents/es.xliff +++ b/apps/ios/SimpleX Localizations/es.xcloc/Localized Contents/es.xliff @@ -137,6 +137,10 @@ ¡ %@ quiere contactar! notification title + + %1$@, %2$@ + format for date separator in chat + %@, %@ and %lld members %@, %@ y %lld miembro(s) más @@ -1740,6 +1744,10 @@ This is your own one-time link! Versión Core: v%@ No comment provided by engineer. + + Corner + No comment provided by engineer. + Correct name to %@? ¿Corregir el nombre a %@? @@ -2724,6 +2732,10 @@ This is your own one-time link! Error al cambiar servidor No comment provided by engineer. + + Error changing connection profile + No comment provided by engineer. + Error changing role Error al cambiar rol @@ -2734,6 +2746,10 @@ This is your own one-time link! Error cambiando configuración No comment provided by engineer. + + Error changing to incognito! + No comment provided by engineer. + Error connecting to forwarding server %@. Please try later. Error al conectar con el servidor de reenvío %@. Por favor, inténtalo más tarde. @@ -2954,6 +2970,10 @@ This is your own one-time link! Error al parar SimpleX No comment provided by engineer. + + Error switching profile + No comment provided by engineer. + Error switching profile! ¡Error al cambiar perfil! @@ -4184,6 +4204,10 @@ This is your link for group %@! Servidores de mensajes No comment provided by engineer. + + Message shape + No comment provided by engineer. + Message source remains private. El autor del mensaje se mantiene privado. @@ -5729,6 +5753,10 @@ Actívalo en ajustes de *Servidores y Redes*. Seleccionar chat item action + + Select chat profile + No comment provided by engineer. + Selected %lld Seleccionados %lld @@ -6099,6 +6127,10 @@ Actívalo en ajustes de *Servidores y Redes*. Compartir enlace No comment provided by engineer. + + Share profile + No comment provided by engineer. + Share this 1-time invite link Comparte este enlace de un solo uso @@ -6439,6 +6471,10 @@ Actívalo en ajustes de *Servidores y Redes*. TCP_KEEPINTVL No comment provided by engineer. + + Tail + No comment provided by engineer. + Take picture Tomar foto @@ -7719,6 +7755,10 @@ Repeat connection request? Mis perfiles No comment provided by engineer. + + Your connection was moved to %@ but an unexpected error occurred while redirecting you to the profile. + No comment provided by engineer. + Your contact sent a file that is larger than currently supported maximum size (%@). El contacto ha enviado un archivo mayor al máximo admitido (%@). diff --git a/apps/ios/SimpleX Localizations/fi.xcloc/Localized Contents/fi.xliff b/apps/ios/SimpleX Localizations/fi.xcloc/Localized Contents/fi.xliff index 211e512a1e..fc31e4f2df 100644 --- a/apps/ios/SimpleX Localizations/fi.xcloc/Localized Contents/fi.xliff +++ b/apps/ios/SimpleX Localizations/fi.xcloc/Localized Contents/fi.xliff @@ -133,6 +133,10 @@ %@ haluaa muodostaa yhteyden! notification title + + %1$@, %2$@ + format for date separator in chat + %@, %@ and %lld members No comment provided by engineer. @@ -1616,6 +1620,10 @@ This is your own one-time link! Ydinversio: v%@ No comment provided by engineer. + + Corner + No comment provided by engineer. + Correct name to %@? No comment provided by engineer. @@ -2544,6 +2552,10 @@ This is your own one-time link! Virhe osoitteenvaihdossa No comment provided by engineer. + + Error changing connection profile + No comment provided by engineer. + Error changing role Virhe roolin vaihdossa @@ -2554,6 +2566,10 @@ This is your own one-time link! Virhe asetuksen muuttamisessa No comment provided by engineer. + + Error changing to incognito! + No comment provided by engineer. + Error connecting to forwarding server %@. Please try later. No comment provided by engineer. @@ -2762,6 +2778,10 @@ This is your own one-time link! Virhe keskustelun lopettamisessa No comment provided by engineer. + + Error switching profile + No comment provided by engineer. + Error switching profile! Virhe profiilin vaihdossa! @@ -3918,6 +3938,10 @@ This is your link for group %@! Message servers No comment provided by engineer. + + Message shape + No comment provided by engineer. + Message source remains private. No comment provided by engineer. @@ -5351,6 +5375,10 @@ Enable in *Network & servers* settings. Valitse chat item action + + Select chat profile + No comment provided by engineer. + Selected %lld No comment provided by engineer. @@ -5695,6 +5723,10 @@ Enable in *Network & servers* settings. Jaa linkki No comment provided by engineer. + + Share profile + No comment provided by engineer. + Share this 1-time invite link No comment provided by engineer. @@ -6010,6 +6042,10 @@ Enable in *Network & servers* settings. TCP_KEEPINTVL No comment provided by engineer. + + Tail + No comment provided by engineer. + Take picture Ota kuva @@ -7194,6 +7230,10 @@ Repeat connection request? Keskusteluprofiilisi No comment provided by engineer. + + Your connection was moved to %@ but an unexpected error occurred while redirecting you to the profile. + No comment provided by engineer. + Your contact sent a file that is larger than currently supported maximum size (%@). Yhteyshenkilösi lähetti tiedoston, joka on suurempi kuin tällä hetkellä tuettu enimmäiskoko (%@). diff --git a/apps/ios/SimpleX Localizations/fr.xcloc/Localized Contents/fr.xliff b/apps/ios/SimpleX Localizations/fr.xcloc/Localized Contents/fr.xliff index c05098980e..6970039315 100644 --- a/apps/ios/SimpleX Localizations/fr.xcloc/Localized Contents/fr.xliff +++ b/apps/ios/SimpleX Localizations/fr.xcloc/Localized Contents/fr.xliff @@ -137,6 +137,10 @@ %@ veut se connecter ! notification title + + %1$@, %2$@ + format for date separator in chat + %@, %@ and %lld members %@, %@ et %lld membres @@ -1740,6 +1744,10 @@ Il s'agit de votre propre lien unique ! Version du cœur : v%@ No comment provided by engineer. + + Corner + No comment provided by engineer. + Correct name to %@? Corriger le nom pour %@ ? @@ -2724,6 +2732,10 @@ Il s'agit de votre propre lien unique ! Erreur de changement d'adresse No comment provided by engineer. + + Error changing connection profile + No comment provided by engineer. + Error changing role Erreur lors du changement de rôle @@ -2734,6 +2746,10 @@ Il s'agit de votre propre lien unique ! Erreur de changement de paramètre No comment provided by engineer. + + Error changing to incognito! + No comment provided by engineer. + Error connecting to forwarding server %@. Please try later. Erreur de connexion au serveur de redirection %@. Veuillez réessayer plus tard. @@ -2954,6 +2970,10 @@ Il s'agit de votre propre lien unique ! Erreur lors de l'arrêt du chat No comment provided by engineer. + + Error switching profile + No comment provided by engineer. + Error switching profile! Erreur lors du changement de profil ! @@ -4184,6 +4204,10 @@ Voici votre lien pour le groupe %@ ! Serveurs de messages No comment provided by engineer. + + Message shape + No comment provided by engineer. + Message source remains private. La source du message reste privée. @@ -5729,6 +5753,10 @@ Activez-le dans les paramètres *Réseau et serveurs*. Choisir chat item action + + Select chat profile + No comment provided by engineer. + Selected %lld %lld sélectionné(s) @@ -6099,6 +6127,10 @@ Activez-le dans les paramètres *Réseau et serveurs*. Partager le lien No comment provided by engineer. + + Share profile + No comment provided by engineer. + Share this 1-time invite link Partager ce lien d'invitation unique @@ -6439,6 +6471,10 @@ Activez-le dans les paramètres *Réseau et serveurs*. TCP_KEEPINTVL No comment provided by engineer. + + Tail + No comment provided by engineer. + Take picture Prendre une photo @@ -7719,6 +7755,10 @@ Répéter la demande de connexion ? Vos profils de chat No comment provided by engineer. + + Your connection was moved to %@ but an unexpected error occurred while redirecting you to the profile. + No comment provided by engineer. + Your contact sent a file that is larger than currently supported maximum size (%@). Votre contact a envoyé un fichier plus grand que la taille maximale supportée actuellement(%@). diff --git a/apps/ios/SimpleX Localizations/hu.xcloc/Localized Contents/hu.xliff b/apps/ios/SimpleX Localizations/hu.xcloc/Localized Contents/hu.xliff index f7328eed91..de95de3421 100644 --- a/apps/ios/SimpleX Localizations/hu.xcloc/Localized Contents/hu.xliff +++ b/apps/ios/SimpleX Localizations/hu.xcloc/Localized Contents/hu.xliff @@ -137,6 +137,10 @@ %@ kapcsolódni szeretne! notification title + + %1$@, %2$@ + format for date separator in chat + %@, %@ and %lld members %@, %@ és további %lld tag @@ -1740,6 +1744,10 @@ Ez az egyszer használatos hivatkozása! Alapverziószám: v%@ No comment provided by engineer. + + Corner + No comment provided by engineer. + Correct name to %@? Név javítása erre: %@? @@ -2724,6 +2732,10 @@ Ez az egyszer használatos hivatkozása! Hiba a cím megváltoztatásakor No comment provided by engineer. + + Error changing connection profile + No comment provided by engineer. + Error changing role Hiba a szerepkör megváltoztatásakor @@ -2734,6 +2746,10 @@ Ez az egyszer használatos hivatkozása! Hiba a beállítás megváltoztatásakor No comment provided by engineer. + + Error changing to incognito! + No comment provided by engineer. + Error connecting to forwarding server %@. Please try later. Hiba a(z) %@ továbbító kiszolgálóhoz való kapcsolódáskor. Próbálja meg később. @@ -2954,6 +2970,10 @@ Ez az egyszer használatos hivatkozása! Hiba a csevegés megállításakor No comment provided by engineer. + + Error switching profile + No comment provided by engineer. + Error switching profile! Hiba a profil váltásakor! @@ -4184,6 +4204,10 @@ Ez az ön hivatkozása a(z) %@ csoporthoz! Üzenetkiszolgálók No comment provided by engineer. + + Message shape + No comment provided by engineer. + Message source remains private. Az üzenet forrása titokban marad. @@ -5729,6 +5753,10 @@ Engedélyezze a Beállítások / Hálózat és kiszolgálók menüben. Választás chat item action + + Select chat profile + No comment provided by engineer. + Selected %lld %lld kiválasztva @@ -6099,6 +6127,10 @@ Engedélyezze a Beállítások / Hálózat és kiszolgálók menüben. Hivatkozás megosztása No comment provided by engineer. + + Share profile + No comment provided by engineer. + Share this 1-time invite link Egyszer használatos meghívó hivatkozás megosztása @@ -6439,6 +6471,10 @@ Engedélyezze a Beállítások / Hálózat és kiszolgálók menüben. TCP_KEEPINTVL No comment provided by engineer. + + Tail + No comment provided by engineer. + Take picture Kép készítése @@ -7719,6 +7755,10 @@ Kapcsolódási kérés megismétlése? Csevegési profilok No comment provided by engineer. + + Your connection was moved to %@ but an unexpected error occurred while redirecting you to the profile. + No comment provided by engineer. + Your contact sent a file that is larger than currently supported maximum size (%@). Ismerőse olyan fájlt küldött, amely meghaladja a jelenleg támogatott maximális méretet (%@). diff --git a/apps/ios/SimpleX Localizations/it.xcloc/Localized Contents/it.xliff b/apps/ios/SimpleX Localizations/it.xcloc/Localized Contents/it.xliff index 72eb3561e3..700d181aab 100644 --- a/apps/ios/SimpleX Localizations/it.xcloc/Localized Contents/it.xliff +++ b/apps/ios/SimpleX Localizations/it.xcloc/Localized Contents/it.xliff @@ -137,6 +137,10 @@ %@ si vuole connettere! notification title + + %1$@, %2$@ + format for date separator in chat + %@, %@ and %lld members %@, %@ e %lld membri @@ -1740,6 +1744,10 @@ Questo è il tuo link una tantum! Versione core: v%@ No comment provided by engineer. + + Corner + No comment provided by engineer. + Correct name to %@? Correggere il nome a %@? @@ -2724,6 +2732,10 @@ Questo è il tuo link una tantum! Errore nella modifica dell'indirizzo No comment provided by engineer. + + Error changing connection profile + No comment provided by engineer. + Error changing role Errore nel cambio di ruolo @@ -2734,6 +2746,10 @@ Questo è il tuo link una tantum! Errore nella modifica dell'impostazione No comment provided by engineer. + + Error changing to incognito! + No comment provided by engineer. + Error connecting to forwarding server %@. Please try later. Errore di connessione al server di inoltro %@. Riprova più tardi. @@ -2954,6 +2970,10 @@ Questo è il tuo link una tantum! Errore nell'interruzione della chat No comment provided by engineer. + + Error switching profile + No comment provided by engineer. + Error switching profile! Errore nel cambio di profilo! @@ -4184,6 +4204,10 @@ Questo è il tuo link per il gruppo %@! Server dei messaggi No comment provided by engineer. + + Message shape + No comment provided by engineer. + Message source remains private. La fonte del messaggio resta privata. @@ -5729,6 +5753,10 @@ Attivalo nelle impostazioni *Rete e server*. Seleziona chat item action + + Select chat profile + No comment provided by engineer. + Selected %lld %lld selezionato @@ -6099,6 +6127,10 @@ Attivalo nelle impostazioni *Rete e server*. Condividi link No comment provided by engineer. + + Share profile + No comment provided by engineer. + Share this 1-time invite link Condividi questo link di invito una tantum @@ -6439,6 +6471,10 @@ Attivalo nelle impostazioni *Rete e server*. TCP_KEEPINTVL No comment provided by engineer. + + Tail + No comment provided by engineer. + Take picture Scatta foto @@ -7719,6 +7755,10 @@ Ripetere la richiesta di connessione? I tuoi profili di chat No comment provided by engineer. + + Your connection was moved to %@ but an unexpected error occurred while redirecting you to the profile. + No comment provided by engineer. + Your contact sent a file that is larger than currently supported maximum size (%@). Il tuo contatto ha inviato un file più grande della dimensione massima attualmente supportata (%@). diff --git a/apps/ios/SimpleX Localizations/ja.xcloc/Localized Contents/ja.xliff b/apps/ios/SimpleX Localizations/ja.xcloc/Localized Contents/ja.xliff index a545f3ba05..0b9b431c8b 100644 --- a/apps/ios/SimpleX Localizations/ja.xcloc/Localized Contents/ja.xliff +++ b/apps/ios/SimpleX Localizations/ja.xcloc/Localized Contents/ja.xliff @@ -137,6 +137,10 @@ %@ が接続を希望しています! notification title + + %1$@, %2$@ + format for date separator in chat + %@, %@ and %lld members %@や%@など%lld人のメンバー @@ -1640,6 +1644,10 @@ This is your own one-time link! コアのバージョン: v%@ No comment provided by engineer. + + Corner + No comment provided by engineer. + Correct name to %@? No comment provided by engineer. @@ -2569,6 +2577,10 @@ This is your own one-time link! アドレス変更にエラー発生 No comment provided by engineer. + + Error changing connection profile + No comment provided by engineer. + Error changing role 役割変更にエラー発生 @@ -2579,6 +2591,10 @@ This is your own one-time link! 設定変更にエラー発生 No comment provided by engineer. + + Error changing to incognito! + No comment provided by engineer. + Error connecting to forwarding server %@. Please try later. No comment provided by engineer. @@ -2787,6 +2803,10 @@ This is your own one-time link! チャット停止にエラー発生 No comment provided by engineer. + + Error switching profile + No comment provided by engineer. + Error switching profile! プロフィール切り替えにエラー発生! @@ -3942,6 +3962,10 @@ This is your link for group %@! Message servers No comment provided by engineer. + + Message shape + No comment provided by engineer. + Message source remains private. No comment provided by engineer. @@ -5376,6 +5400,10 @@ Enable in *Network & servers* settings. 選択 chat item action + + Select chat profile + No comment provided by engineer. + Selected %lld No comment provided by engineer. @@ -5713,6 +5741,10 @@ Enable in *Network & servers* settings. リンクを送る No comment provided by engineer. + + Share profile + No comment provided by engineer. + Share this 1-time invite link No comment provided by engineer. @@ -6029,6 +6061,10 @@ Enable in *Network & servers* settings. TCP_KEEPINTVL No comment provided by engineer. + + Tail + No comment provided by engineer. + Take picture 写真を撮影 @@ -7212,6 +7248,10 @@ Repeat connection request? あなたのチャットプロフィール No comment provided by engineer. + + Your connection was moved to %@ but an unexpected error occurred while redirecting you to the profile. + No comment provided by engineer. + Your contact sent a file that is larger than currently supported maximum size (%@). 連絡先が現在サポートされている最大サイズ (%@) より大きいファイルを送信しました。 diff --git a/apps/ios/SimpleX Localizations/nl.xcloc/Localized Contents/nl.xliff b/apps/ios/SimpleX Localizations/nl.xcloc/Localized Contents/nl.xliff index 15a8c01a64..cd52825882 100644 --- a/apps/ios/SimpleX Localizations/nl.xcloc/Localized Contents/nl.xliff +++ b/apps/ios/SimpleX Localizations/nl.xcloc/Localized Contents/nl.xliff @@ -137,6 +137,10 @@ %@ wil verbinding maken! notification title + + %1$@, %2$@ + format for date separator in chat + %@, %@ and %lld members %@, %@ en %lld leden @@ -1740,6 +1744,10 @@ Dit is uw eigen eenmalige link! Core versie: v% @ No comment provided by engineer. + + Corner + No comment provided by engineer. + Correct name to %@? Juiste naam voor %@? @@ -2724,6 +2732,10 @@ Dit is uw eigen eenmalige link! Fout bij wijzigen van adres No comment provided by engineer. + + Error changing connection profile + No comment provided by engineer. + Error changing role Fout bij wisselen van rol @@ -2734,6 +2746,10 @@ Dit is uw eigen eenmalige link! Fout bij wijzigen van instelling No comment provided by engineer. + + Error changing to incognito! + No comment provided by engineer. + Error connecting to forwarding server %@. Please try later. Fout bij het verbinden met doorstuurserver %@. Probeer het later opnieuw. @@ -2954,6 +2970,10 @@ Dit is uw eigen eenmalige link! Fout bij het stoppen van de chat No comment provided by engineer. + + Error switching profile + No comment provided by engineer. + Error switching profile! Fout bij wisselen van profiel! @@ -4184,6 +4204,10 @@ Dit is jouw link voor groep %@! Berichtservers No comment provided by engineer. + + Message shape + No comment provided by engineer. + Message source remains private. Berichtbron blijft privé. @@ -5729,6 +5753,10 @@ Schakel dit in in *Netwerk en servers*-instellingen. Selecteer chat item action + + Select chat profile + No comment provided by engineer. + Selected %lld %lld geselecteerd @@ -6099,6 +6127,10 @@ Schakel dit in in *Netwerk en servers*-instellingen. Deel link No comment provided by engineer. + + Share profile + No comment provided by engineer. + Share this 1-time invite link Deel deze eenmalige uitnodigingslink @@ -6439,6 +6471,10 @@ Schakel dit in in *Netwerk en servers*-instellingen. TCP_KEEPINTVL No comment provided by engineer. + + Tail + No comment provided by engineer. + Take picture Foto nemen @@ -7719,6 +7755,10 @@ Verbindingsverzoek herhalen? Uw chat profielen No comment provided by engineer. + + Your connection was moved to %@ but an unexpected error occurred while redirecting you to the profile. + No comment provided by engineer. + Your contact sent a file that is larger than currently supported maximum size (%@). Uw contact heeft een bestand verzonden dat groter is dan de momenteel ondersteunde maximale grootte (%@). diff --git a/apps/ios/SimpleX Localizations/pl.xcloc/Localized Contents/pl.xliff b/apps/ios/SimpleX Localizations/pl.xcloc/Localized Contents/pl.xliff index 525d30daa6..a474f30768 100644 --- a/apps/ios/SimpleX Localizations/pl.xcloc/Localized Contents/pl.xliff +++ b/apps/ios/SimpleX Localizations/pl.xcloc/Localized Contents/pl.xliff @@ -137,6 +137,10 @@ %@ chce się połączyć! notification title + + %1$@, %2$@ + format for date separator in chat + %@, %@ and %lld members %@, %@ i %lld członków @@ -1740,6 +1744,10 @@ To jest twój jednorazowy link! Wersja rdzenia: v%@ No comment provided by engineer. + + Corner + No comment provided by engineer. + Correct name to %@? Poprawić imię na %@? @@ -2724,6 +2732,10 @@ To jest twój jednorazowy link! Błąd zmiany adresu No comment provided by engineer. + + Error changing connection profile + No comment provided by engineer. + Error changing role Błąd zmiany roli @@ -2734,6 +2746,10 @@ To jest twój jednorazowy link! Błąd zmiany ustawienia No comment provided by engineer. + + Error changing to incognito! + No comment provided by engineer. + Error connecting to forwarding server %@. Please try later. Błąd połączenia z serwerem przekierowania %@. Spróbuj ponownie później. @@ -2954,6 +2970,10 @@ To jest twój jednorazowy link! Błąd zatrzymania czatu No comment provided by engineer. + + Error switching profile + No comment provided by engineer. + Error switching profile! Błąd przełączania profilu! @@ -4184,6 +4204,10 @@ To jest twój link do grupy %@! Serwery wiadomości No comment provided by engineer. + + Message shape + No comment provided by engineer. + Message source remains private. Źródło wiadomości pozostaje prywatne. @@ -5729,6 +5753,10 @@ Włącz w ustawianiach *Sieć i serwery* . Wybierz chat item action + + Select chat profile + No comment provided by engineer. + Selected %lld Zaznaczono %lld @@ -6099,6 +6127,10 @@ Włącz w ustawianiach *Sieć i serwery* . Udostępnij link No comment provided by engineer. + + Share profile + No comment provided by engineer. + Share this 1-time invite link Udostępnij ten jednorazowy link @@ -6439,6 +6471,10 @@ Włącz w ustawianiach *Sieć i serwery* . TCP_KEEPINTVL No comment provided by engineer. + + Tail + No comment provided by engineer. + Take picture Zrób zdjęcie @@ -7719,6 +7755,10 @@ Powtórzyć prośbę połączenia? Twoje profile czatu No comment provided by engineer. + + Your connection was moved to %@ but an unexpected error occurred while redirecting you to the profile. + No comment provided by engineer. + Your contact sent a file that is larger than currently supported maximum size (%@). Twój kontakt wysłał plik, który jest większy niż obecnie obsługiwany maksymalny rozmiar (%@). diff --git a/apps/ios/SimpleX Localizations/ru.xcloc/Localized Contents/ru.xliff b/apps/ios/SimpleX Localizations/ru.xcloc/Localized Contents/ru.xliff index 969a7d68e0..957e599e85 100644 --- a/apps/ios/SimpleX Localizations/ru.xcloc/Localized Contents/ru.xliff +++ b/apps/ios/SimpleX Localizations/ru.xcloc/Localized Contents/ru.xliff @@ -137,6 +137,10 @@ %@ хочет соединиться! notification title + + %1$@, %2$@ + format for date separator in chat + %@, %@ and %lld members %@, %@ и %lld членов группы @@ -1740,6 +1744,10 @@ This is your own one-time link! Версия ядра: v%@ No comment provided by engineer. + + Corner + No comment provided by engineer. + Correct name to %@? Исправить имя на %@? @@ -2724,6 +2732,10 @@ This is your own one-time link! Ошибка при изменении адреса No comment provided by engineer. + + Error changing connection profile + No comment provided by engineer. + Error changing role Ошибка при изменении роли @@ -2734,6 +2746,10 @@ This is your own one-time link! Ошибка при изменении настройки No comment provided by engineer. + + Error changing to incognito! + No comment provided by engineer. + Error connecting to forwarding server %@. Please try later. Ошибка подключения к пересылающему серверу %@. Попробуйте позже. @@ -2954,6 +2970,10 @@ This is your own one-time link! Ошибка при остановке чата No comment provided by engineer. + + Error switching profile + No comment provided by engineer. + Error switching profile! Ошибка выбора профиля! @@ -4184,6 +4204,10 @@ This is your link for group %@! Серверы сообщений No comment provided by engineer. + + Message shape + No comment provided by engineer. + Message source remains private. Источник сообщения остаётся конфиденциальным. @@ -5729,6 +5753,10 @@ Enable in *Network & servers* settings. Выбрать chat item action + + Select chat profile + No comment provided by engineer. + Selected %lld Выбрано %lld @@ -6099,6 +6127,10 @@ Enable in *Network & servers* settings. Поделиться ссылкой No comment provided by engineer. + + Share profile + No comment provided by engineer. + Share this 1-time invite link Поделиться одноразовой ссылкой-приглашением @@ -6439,6 +6471,10 @@ Enable in *Network & servers* settings. TCP_KEEPINTVL No comment provided by engineer. + + Tail + No comment provided by engineer. + Take picture Сделать фото @@ -7719,6 +7755,10 @@ Repeat connection request? Ваши профили чата No comment provided by engineer. + + Your connection was moved to %@ but an unexpected error occurred while redirecting you to the profile. + No comment provided by engineer. + Your contact sent a file that is larger than currently supported maximum size (%@). Ваш контакт отправил файл, размер которого превышает максимальный размер (%@). diff --git a/apps/ios/SimpleX Localizations/th.xcloc/Localized Contents/th.xliff b/apps/ios/SimpleX Localizations/th.xcloc/Localized Contents/th.xliff index 646a94a337..366f67d0cd 100644 --- a/apps/ios/SimpleX Localizations/th.xcloc/Localized Contents/th.xliff +++ b/apps/ios/SimpleX Localizations/th.xcloc/Localized Contents/th.xliff @@ -129,6 +129,10 @@ %@ อยากเชื่อมต่อ! notification title + + %1$@, %2$@ + format for date separator in chat + %@, %@ and %lld members No comment provided by engineer. @@ -1606,6 +1610,10 @@ This is your own one-time link! รุ่นหลัก: v%@ No comment provided by engineer. + + Corner + No comment provided by engineer. + Correct name to %@? No comment provided by engineer. @@ -2530,6 +2538,10 @@ This is your own one-time link! เกิดข้อผิดพลาดในการเปลี่ยนที่อยู่ No comment provided by engineer. + + Error changing connection profile + No comment provided by engineer. + Error changing role เกิดข้อผิดพลาดในการเปลี่ยนบทบาท @@ -2540,6 +2552,10 @@ This is your own one-time link! เกิดข้อผิดพลาดในการเปลี่ยนการตั้งค่า No comment provided by engineer. + + Error changing to incognito! + No comment provided by engineer. + Error connecting to forwarding server %@. Please try later. No comment provided by engineer. @@ -2747,6 +2763,10 @@ This is your own one-time link! เกิดข้อผิดพลาดในการหยุดแชท No comment provided by engineer. + + Error switching profile + No comment provided by engineer. + Error switching profile! เกิดข้อผิดพลาดในการเปลี่ยนโปรไฟล์! @@ -3901,6 +3921,10 @@ This is your link for group %@! Message servers No comment provided by engineer. + + Message shape + No comment provided by engineer. + Message source remains private. No comment provided by engineer. @@ -5328,6 +5352,10 @@ Enable in *Network & servers* settings. เลือก chat item action + + Select chat profile + No comment provided by engineer. + Selected %lld No comment provided by engineer. @@ -5670,6 +5698,10 @@ Enable in *Network & servers* settings. แชร์ลิงก์ No comment provided by engineer. + + Share profile + No comment provided by engineer. + Share this 1-time invite link No comment provided by engineer. @@ -5983,6 +6015,10 @@ Enable in *Network & servers* settings. TCP_KEEPINTVL No comment provided by engineer. + + Tail + No comment provided by engineer. + Take picture ถ่ายภาพ @@ -7163,6 +7199,10 @@ Repeat connection request? โปรไฟล์แชทของคุณ No comment provided by engineer. + + Your connection was moved to %@ but an unexpected error occurred while redirecting you to the profile. + No comment provided by engineer. + Your contact sent a file that is larger than currently supported maximum size (%@). ผู้ติดต่อของคุณส่งไฟล์ที่ใหญ่กว่าขนาดสูงสุดที่รองรับในปัจจุบัน (%@) diff --git a/apps/ios/SimpleX Localizations/tr.xcloc/Localized Contents/tr.xliff b/apps/ios/SimpleX Localizations/tr.xcloc/Localized Contents/tr.xliff index 054f65110f..13fa3c8a84 100644 --- a/apps/ios/SimpleX Localizations/tr.xcloc/Localized Contents/tr.xliff +++ b/apps/ios/SimpleX Localizations/tr.xcloc/Localized Contents/tr.xliff @@ -137,6 +137,10 @@ %@ bağlanmak istiyor! notification title + + %1$@, %2$@ + format for date separator in chat + %@, %@ and %lld members %@, %@ ve %lld üyeleri @@ -1689,6 +1693,10 @@ Bu senin kendi tek kullanımlık bağlantın! Çekirdek sürümü: v%@ No comment provided by engineer. + + Corner + No comment provided by engineer. + Correct name to %@? İsim %@ olarak düzeltilsin mi? @@ -2653,6 +2661,10 @@ Bu senin kendi tek kullanımlık bağlantın! Adres değiştirilirken hata oluştu No comment provided by engineer. + + Error changing connection profile + No comment provided by engineer. + Error changing role Rol değiştirilirken hata oluştu @@ -2663,6 +2675,10 @@ Bu senin kendi tek kullanımlık bağlantın! Ayar değiştirilirken hata oluştu No comment provided by engineer. + + Error changing to incognito! + No comment provided by engineer. + Error connecting to forwarding server %@. Please try later. No comment provided by engineer. @@ -2878,6 +2894,10 @@ Bu senin kendi tek kullanımlık bağlantın! Sohbet durdurulurken hata oluştu No comment provided by engineer. + + Error switching profile + No comment provided by engineer. + Error switching profile! Profil değiştirilirken hata oluştu! @@ -4084,6 +4104,10 @@ Bu senin grup için bağlantın %@! Message servers No comment provided by engineer. + + Message shape + No comment provided by engineer. + Message source remains private. Mesaj kaynağı gizli kalır. @@ -5585,6 +5609,10 @@ Enable in *Network & servers* settings. Seç chat item action + + Select chat profile + No comment provided by engineer. + Selected %lld No comment provided by engineer. @@ -5938,6 +5966,10 @@ Enable in *Network & servers* settings. Bağlantıyı paylaş No comment provided by engineer. + + Share profile + No comment provided by engineer. + Share this 1-time invite link Bu tek kullanımlık bağlantı davetini paylaş @@ -6264,6 +6296,10 @@ Enable in *Network & servers* settings. TCP_TVLDEKAL No comment provided by engineer. + + Tail + No comment provided by engineer. + Take picture Fotoğraf çek @@ -7517,6 +7553,10 @@ Bağlantı isteği tekrarlansın mı? Sohbet profillerin No comment provided by engineer. + + Your connection was moved to %@ but an unexpected error occurred while redirecting you to the profile. + No comment provided by engineer. + Your contact sent a file that is larger than currently supported maximum size (%@). Kişiniz şu anda desteklenen maksimum boyuttan (%@) daha büyük bir dosya gönderdi. diff --git a/apps/ios/SimpleX Localizations/uk.xcloc/Localized Contents/uk.xliff b/apps/ios/SimpleX Localizations/uk.xcloc/Localized Contents/uk.xliff index 7bcb30c1db..69685620ba 100644 --- a/apps/ios/SimpleX Localizations/uk.xcloc/Localized Contents/uk.xliff +++ b/apps/ios/SimpleX Localizations/uk.xcloc/Localized Contents/uk.xliff @@ -137,6 +137,10 @@ %@ хоче підключитися! notification title + + %1$@, %2$@ + format for date separator in chat + %@, %@ and %lld members %@, %@ та %lld учасників @@ -1740,6 +1744,10 @@ This is your own one-time link! Основна версія: v%@ No comment provided by engineer. + + Corner + No comment provided by engineer. + Correct name to %@? Виправити ім'я на %@? @@ -2724,6 +2732,10 @@ This is your own one-time link! Помилка зміни адреси No comment provided by engineer. + + Error changing connection profile + No comment provided by engineer. + Error changing role Помилка зміни ролі @@ -2734,6 +2746,10 @@ This is your own one-time link! Помилка зміни налаштування No comment provided by engineer. + + Error changing to incognito! + No comment provided by engineer. + Error connecting to forwarding server %@. Please try later. Помилка підключення до сервера переадресації %@. Спробуйте пізніше. @@ -2954,6 +2970,10 @@ This is your own one-time link! Помилка зупинки чату No comment provided by engineer. + + Error switching profile + No comment provided by engineer. + Error switching profile! Помилка перемикання профілю! @@ -4184,6 +4204,10 @@ This is your link for group %@! Сервери повідомлень No comment provided by engineer. + + Message shape + No comment provided by engineer. + Message source remains private. Джерело повідомлення залишається приватним. @@ -5729,6 +5753,10 @@ Enable in *Network & servers* settings. Виберіть chat item action + + Select chat profile + No comment provided by engineer. + Selected %lld Вибрано %lld @@ -6099,6 +6127,10 @@ Enable in *Network & servers* settings. Поділіться посиланням No comment provided by engineer. + + Share profile + No comment provided by engineer. + Share this 1-time invite link Поділіться цим одноразовим посиланням-запрошенням @@ -6439,6 +6471,10 @@ Enable in *Network & servers* settings. TCP_KEEPINTVL No comment provided by engineer. + + Tail + No comment provided by engineer. + Take picture Сфотографуйте @@ -7719,6 +7755,10 @@ Repeat connection request? Ваші профілі чату No comment provided by engineer. + + Your connection was moved to %@ but an unexpected error occurred while redirecting you to the profile. + No comment provided by engineer. + Your contact sent a file that is larger than currently supported maximum size (%@). Ваш контакт надіслав файл, розмір якого перевищує підтримуваний на цей момент максимальний розмір (%@). diff --git a/apps/ios/SimpleX Localizations/zh-Hans.xcloc/Localized Contents/zh-Hans.xliff b/apps/ios/SimpleX Localizations/zh-Hans.xcloc/Localized Contents/zh-Hans.xliff index 8c3641549d..b524846ffd 100644 --- a/apps/ios/SimpleX Localizations/zh-Hans.xcloc/Localized Contents/zh-Hans.xliff +++ b/apps/ios/SimpleX Localizations/zh-Hans.xcloc/Localized Contents/zh-Hans.xliff @@ -135,6 +135,10 @@ %@ 要连接! notification title + + %1$@, %2$@ + format for date separator in chat + %@, %@ and %lld members %@, %@ 和 %lld 成员 @@ -1665,6 +1669,10 @@ This is your own one-time link! 核心版本: v%@ No comment provided by engineer. + + Corner + No comment provided by engineer. + Correct name to %@? No comment provided by engineer. @@ -2618,6 +2626,10 @@ This is your own one-time link! 更改地址错误 No comment provided by engineer. + + Error changing connection profile + No comment provided by engineer. + Error changing role 更改角色错误 @@ -2628,6 +2640,10 @@ This is your own one-time link! 更改设置错误 No comment provided by engineer. + + Error changing to incognito! + No comment provided by engineer. + Error connecting to forwarding server %@. Please try later. No comment provided by engineer. @@ -2841,6 +2857,10 @@ This is your own one-time link! 停止聊天错误 No comment provided by engineer. + + Error switching profile + No comment provided by engineer. + Error switching profile! 切换资料错误! @@ -4033,6 +4053,10 @@ This is your link for group %@! Message servers No comment provided by engineer. + + Message shape + No comment provided by engineer. + Message source remains private. 消息来源保持私密。 @@ -5512,6 +5536,10 @@ Enable in *Network & servers* settings. 选择 chat item action + + Select chat profile + No comment provided by engineer. + Selected %lld No comment provided by engineer. @@ -5861,6 +5889,10 @@ Enable in *Network & servers* settings. 分享链接 No comment provided by engineer. + + Share profile + No comment provided by engineer. + Share this 1-time invite link 分享此一次性邀请链接 @@ -6185,6 +6217,10 @@ Enable in *Network & servers* settings. TCP_KEEPINTVL No comment provided by engineer. + + Tail + No comment provided by engineer. + Take picture 拍照 @@ -7417,6 +7453,10 @@ Repeat connection request? 您的聊天资料 No comment provided by engineer. + + Your connection was moved to %@ but an unexpected error occurred while redirecting you to the profile. + No comment provided by engineer. + Your contact sent a file that is larger than currently supported maximum size (%@). 您的联系人发送的文件大于当前支持的最大大小 (%@)。 From e582d2d742120ccc208b208f70f9d95878f91551 Mon Sep 17 00:00:00 2001 From: Diogo Date: Tue, 27 Aug 2024 14:32:54 +0100 Subject: [PATCH 2/4] android, desktop: allow for chat profile selection on new chat screen (#4741) * add api and types * basic ui * add search on profiles * profile images on select chat profile * incognito adjustments * basic api connection * handling errors * add loading state * header to scroll * selected profile on top (profile or incognito) * adjust share profile copy * avoid list moving around on selection commit * bigger profile pick * info icon interactive area * thumbs to match contacts list size * incognito sizes matching icons * title to section padding * add chevron * align borders and other chevron icon * prevent click on self * only prevent selection * update * selectable item area * no need for oninfo to be composable * simplify * wrap apis in try * remove redundant derivedStateOf * closure fns capital naming * simplify current user null check --------- Co-authored-by: Evgeny Poberezkin --- .../chat/simplex/common/model/ChatModel.kt | 3 +- .../chat/simplex/common/model/SimpleXAPI.kt | 35 +- .../newchat/ContactConnectionInfoView.kt | 2 +- .../common/views/newchat/NewChatView.kt | 338 +++++++++++++++++- .../views/usersettings/UserProfilesView.kt | 4 +- .../commonMain/resources/MR/base/strings.xml | 4 + 6 files changed, 363 insertions(+), 23 deletions(-) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/ChatModel.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/ChatModel.kt index e92b3d714a..de13f05dbd 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/ChatModel.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/ChatModel.kt @@ -784,7 +784,8 @@ object ChatModel { data class ShowingInvitation( val connId: String, val connReq: String, - val connChatUsed: Boolean + val connChatUsed: Boolean, + val conn: PendingContactConnection ) enum class ChatType(val type: String) { diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt index 060e75a9a1..c621b9eacf 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt @@ -1132,9 +1132,30 @@ object ChatController { suspend fun apiSetConnectionIncognito(rh: Long?, connId: Long, incognito: Boolean): PendingContactConnection? { val r = sendCmd(rh, CC.ApiSetConnectionIncognito(connId, incognito)) - if (r is CR.ConnectionIncognitoUpdated) return r.toConnection - Log.e(TAG, "apiSetConnectionIncognito bad response: ${r.responseType} ${r.details}") - return null + + return when (r) { + is CR.ConnectionIncognitoUpdated -> r.toConnection + else -> { + if (!(networkErrorAlert(r))) { + apiErrorAlert("apiSetConnectionIncognito", generalGetString(MR.strings.error_sending_message), r) + } + null + } + } + } + + suspend fun apiChangeConnectionUser(rh: Long?, connId: Long, userId: Long): PendingContactConnection? { + val r = sendCmd(rh, CC.ApiChangeConnectionUser(connId, userId)) + + return when (r) { + is CR.ConnectionUserChanged -> r.toConnection + else -> { + if (!(networkErrorAlert(r))) { + apiErrorAlert("apiChangeConnectionUser", generalGetString(MR.strings.error_sending_message), r) + } + null + } + } } suspend fun apiConnectPlan(rh: Long?, connReq: String): ConnectionPlan? { @@ -2916,6 +2937,7 @@ sealed class CC { class APIVerifyGroupMember(val groupId: Long, val groupMemberId: Long, val connectionCode: String?): CC() class APIAddContact(val userId: Long, val incognito: Boolean): CC() class ApiSetConnectionIncognito(val connId: Long, val incognito: Boolean): CC() + class ApiChangeConnectionUser(val connId: Long, val userId: Long): CC() class APIConnectPlan(val userId: Long, val connReq: String): CC() class APIConnect(val userId: Long, val incognito: Boolean, val connReq: String): CC() class ApiConnectContactViaAddress(val userId: Long, val incognito: Boolean, val contactId: Long): CC() @@ -3071,6 +3093,7 @@ sealed class CC { is APIVerifyGroupMember -> "/_verify code #$groupId $groupMemberId" + if (connectionCode != null) " $connectionCode" else "" is APIAddContact -> "/_connect $userId incognito=${onOff(incognito)}" is ApiSetConnectionIncognito -> "/_set incognito :$connId ${onOff(incognito)}" + is ApiChangeConnectionUser -> "/_set conn user :$connId $userId" is APIConnectPlan -> "/_connect plan $userId $connReq" is APIConnect -> "/_connect $userId incognito=${onOff(incognito)} $connReq" is ApiConnectContactViaAddress -> "/_connect contact $userId incognito=${onOff(incognito)} $contactId" @@ -3213,6 +3236,7 @@ sealed class CC { is APIVerifyGroupMember -> "apiVerifyGroupMember" is APIAddContact -> "apiAddContact" is ApiSetConnectionIncognito -> "apiSetConnectionIncognito" + is ApiChangeConnectionUser -> "apiChangeConnectionUser" is APIConnectPlan -> "apiConnectPlan" is APIConnect -> "apiConnect" is ApiConnectContactViaAddress -> "apiConnectContactViaAddress" @@ -4757,6 +4781,7 @@ sealed class CR { @Serializable @SerialName("connectionVerified") class ConnectionVerified(val user: UserRef, val verified: Boolean, val expectedCode: String): CR() @Serializable @SerialName("invitation") class Invitation(val user: UserRef, val connReqInvitation: String, val connection: PendingContactConnection): CR() @Serializable @SerialName("connectionIncognitoUpdated") class ConnectionIncognitoUpdated(val user: UserRef, val toConnection: PendingContactConnection): CR() + @Serializable @SerialName("connectionUserChanged") class ConnectionUserChanged(val user: UserRef, val fromConnection: PendingContactConnection, val toConnection: PendingContactConnection, val newUser: UserRef): CR() @Serializable @SerialName("connectionPlan") class CRConnectionPlan(val user: UserRef, val connectionPlan: ConnectionPlan): CR() @Serializable @SerialName("sentConfirmation") class SentConfirmation(val user: UserRef, val connection: PendingContactConnection): CR() @Serializable @SerialName("sentInvitation") class SentInvitation(val user: UserRef, val connection: PendingContactConnection): CR() @@ -4935,6 +4960,7 @@ sealed class CR { is ConnectionVerified -> "connectionVerified" is Invitation -> "invitation" is ConnectionIncognitoUpdated -> "connectionIncognitoUpdated" + is ConnectionUserChanged -> "ConnectionUserChanged" is CRConnectionPlan -> "connectionPlan" is SentConfirmation -> "sentConfirmation" is SentInvitation -> "sentInvitation" @@ -5103,6 +5129,7 @@ sealed class CR { is ConnectionVerified -> withUser(user, "verified: $verified\nconnectionCode: $expectedCode") is Invitation -> withUser(user, "connReqInvitation: $connReqInvitation\nconnection: $connection") is ConnectionIncognitoUpdated -> withUser(user, json.encodeToString(toConnection)) + is ConnectionUserChanged -> withUser(user, "fromConnection: ${json.encodeToString(fromConnection)}\ntoConnection: ${json.encodeToString(toConnection)}\nnewUser: ${json.encodeToString(newUser)}" ) is CRConnectionPlan -> withUser(user, json.encodeToString(connectionPlan)) is SentConfirmation -> withUser(user, json.encodeToString(connection)) is SentInvitation -> withUser(user, json.encodeToString(connection)) @@ -5553,6 +5580,7 @@ sealed class ChatErrorType { is AgentCommandError -> "agentCommandError" is InvalidFileDescription -> "invalidFileDescription" is ConnectionIncognitoChangeProhibited -> "connectionIncognitoChangeProhibited" + is ConnectionUserChangeProhibited -> "connectionUserChangeProhibited" is PeerChatVRangeIncompatible -> "peerChatVRangeIncompatible" is InternalError -> "internalError" is CEException -> "exception $message" @@ -5630,6 +5658,7 @@ sealed class ChatErrorType { @Serializable @SerialName("agentCommandError") class AgentCommandError(val message: String): ChatErrorType() @Serializable @SerialName("invalidFileDescription") class InvalidFileDescription(val message: String): ChatErrorType() @Serializable @SerialName("connectionIncognitoChangeProhibited") object ConnectionIncognitoChangeProhibited: ChatErrorType() + @Serializable @SerialName("connectionUserChangeProhibited") object ConnectionUserChangeProhibited: ChatErrorType() @Serializable @SerialName("peerChatVRangeIncompatible") object PeerChatVRangeIncompatible: ChatErrorType() @Serializable @SerialName("internalError") class InternalError(val message: String): ChatErrorType() @Serializable @SerialName("exception") class CEException(val message: String): ChatErrorType() diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/ContactConnectionInfoView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/ContactConnectionInfoView.kt index 88e483e92d..64ff7e4f40 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/ContactConnectionInfoView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/ContactConnectionInfoView.kt @@ -39,7 +39,7 @@ fun ContactConnectionInfoView( ) { LaunchedEffect(connReqInvitation) { if (connReqInvitation != null) { - chatModel.showingInvitation.value = ShowingInvitation(contactConnection.id, connReqInvitation, false) + chatModel.showingInvitation.value = ShowingInvitation(contactConnection.id, connReqInvitation, false, conn = contactConnection) } } /** When [AddContactLearnMore] is open, we don't need to drop [ChatModel.showingInvitation]. diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/NewChatView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/NewChatView.kt index d2e8ac7a6c..544f5f72bb 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/NewChatView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/NewChatView.kt @@ -2,20 +2,25 @@ package chat.simplex.common.views.newchat import SectionBottomSpacer import SectionItemView +import SectionSpacer import SectionTextFooter import SectionView +import TextIconSpaced import androidx.compose.foundation.* -import androidx.compose.foundation.gestures.scrollBy import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.pager.HorizontalPager import androidx.compose.foundation.pager.rememberPagerState +import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.text.BasicTextField import androidx.compose.material.* import androidx.compose.runtime.* import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.alpha +import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalClipboardManager import androidx.compose.ui.text.TextStyle @@ -32,6 +37,7 @@ import chat.simplex.common.ui.theme.* import chat.simplex.common.views.helpers.* import chat.simplex.common.views.usersettings.* import chat.simplex.res.MR +import kotlinx.coroutines.delay import kotlinx.coroutines.launch import java.net.URI @@ -43,7 +49,7 @@ enum class NewChatOption { fun ModalData.NewChatView(rh: RemoteHostInfo?, selection: NewChatOption, showQRCodeScanner: Boolean = false, close: () -> Unit) { val selection = remember { stateGetOrPut("selection") { selection } } val showQRCodeScanner = remember { stateGetOrPut("showQRCodeScanner") { showQRCodeScanner } } - val contactConnection: MutableState = rememberSaveable(stateSaver = serializableSaver()) { mutableStateOf(null) } + val contactConnection: MutableState = rememberSaveable(stateSaver = serializableSaver()) { mutableStateOf(chatModel.showingInvitation.value?.conn) } val connReqInvitation by remember { derivedStateOf { chatModel.showingInvitation.value?.connReq ?: "" } } val creatingConnReq = rememberSaveable { mutableStateOf(false) } val pastedLink = rememberSaveable { mutableStateOf("") } @@ -177,6 +183,15 @@ private fun CreatingLinkProgressView() { DefaultProgressView(stringResource(MR.strings.creating_link)) } +private fun updateShownConnection(conn: PendingContactConnection) { + chatModel.showingInvitation.value = chatModel.showingInvitation.value?.copy( + conn = conn, + connId = conn.id, + connReq = conn.connReqInv ?: "", + connChatUsed = true + ) +} + @Composable private fun RetryButton(onClick: () -> Unit) { Column( @@ -192,6 +207,248 @@ private fun RetryButton(onClick: () -> Unit) { } } +@Composable +private fun ProfilePickerOption( + title: String, + selected: Boolean, + disabled: Boolean, + onSelected: () -> Unit, + image: @Composable () -> Unit, + onInfo: (() -> Unit)? = null +) { + Row( + Modifier + .fillMaxWidth() + .sizeIn(minHeight = DEFAULT_MIN_SECTION_ITEM_HEIGHT + 8.dp) + .clickable(enabled = !disabled, onClick = onSelected) + .padding(horizontal = DEFAULT_PADDING, vertical = 4.dp), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + image() + TextIconSpaced(false) + Text(title, modifier = Modifier.align(Alignment.CenterVertically)) + if (onInfo != null) { + Spacer(Modifier.padding(6.dp)) + Column(Modifier + .size(48.dp) + .clip(CircleShape) + .clickable( + enabled = !disabled, + onClick = { ModalManager.start.showModal { IncognitoView() } } + ), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center + ) { + Icon( + painterResource(MR.images.ic_info), + stringResource(MR.strings.incognito), + tint = MaterialTheme.colors.primary + ) + } + } + Spacer(Modifier.weight(1f)) + if (selected) { + Icon( + painterResource( + MR.images.ic_check + ), + title, + Modifier.size(20.dp), + tint = MaterialTheme.colors.primary, + ) + } + } + Divider( + Modifier.padding( + start = DEFAULT_PADDING_HALF, + end = DEFAULT_PADDING_HALF, + ) + ) +} + +private fun filteredProfiles(users: List, searchTextOrPassword: String): List { + val s = searchTextOrPassword.trim() + val lower = s.lowercase() + return users.filter { u -> + if ((u.activeUser || !u.hidden) && (s == "" || u.anyNameContains(lower))) { + true + } else { + correctPassword(u, s) + } + } +} + +@Composable +private fun ActiveProfilePicker( + search: MutableState, + contactConnection: PendingContactConnection?, + close: () -> Unit, + rhId: Long? +) { + val switchingProfile = remember { mutableStateOf(false) } + val incognito = remember { + chatModel.showingInvitation.value?.conn?.incognito ?: controller.appPrefs.incognito.get() + } + val selectedProfile by remember { chatModel.currentUser } + val searchTextOrPassword = rememberSaveable { search } + val profiles = remember { + chatModel.users.map { it.user }.sortedBy { !it.activeUser } + } + val filteredProfiles by remember { + derivedStateOf { filteredProfiles(profiles, searchTextOrPassword.value) } + } + + var progressByTimeout by rememberSaveable { mutableStateOf(false) } + + LaunchedEffect(switchingProfile.value) { + progressByTimeout = if (switchingProfile.value) { + delay(500) + switchingProfile.value + } else { + false + } + } + + @Composable + fun ProfilePickerUserOption(user: User) { + val selected = selectedProfile?.userId == user.userId && !incognito + + ProfilePickerOption( + title = user.chatViewName, + disabled = switchingProfile.value || selected, + selected = selected, + onSelected = { + switchingProfile.value = true + withApi { + try { + if (contactConnection != null) { + val conn = controller.apiChangeConnectionUser(rhId, contactConnection.pccConnId, user.userId) + if (conn != null) { + withChats { + updateContactConnection(rhId, conn) + updateShownConnection(conn) + } + controller.changeActiveUser_( + rhId = user.remoteHostId, + toUserId = user.userId, + viewPwd = if (user.hidden) searchTextOrPassword.value else null + ) + + if (chatModel.currentUser.value?.userId != user.userId) { + AlertManager.shared.showAlertMsg(generalGetString( + MR.strings.switching_profile_error_title), + String.format(generalGetString(MR.strings.switching_profile_error_message), user.chatViewName) + ) + } + + withChats { + updateContactConnection(user.remoteHostId, conn) + } + close.invoke() + } + } + } finally { + switchingProfile.value = false + } + } + }, + image = { ProfileImage(size = 42.dp, image = user.image) } + ) + } + + @Composable + fun IncognitoUserOption() { + ProfilePickerOption( + disabled = switchingProfile.value, + title = stringResource(MR.strings.incognito), + selected = incognito, + onSelected = { + if (!incognito) { + switchingProfile.value = true + withApi { + try { + if (contactConnection != null) { + val conn = controller.apiSetConnectionIncognito(rhId, contactConnection.pccConnId, true) + + if (conn != null) { + withChats { + updateContactConnection(rhId, conn) + updateShownConnection(conn) + } + close.invoke() + } + } + } finally { + switchingProfile.value = false + } + } + } + }, + image = { + Spacer(Modifier.width(8.dp)) + Icon( + painterResource(MR.images.ic_theater_comedy_filled), + contentDescription = stringResource(MR.strings.incognito), + Modifier.size(32.dp), + tint = Indigo, + ) + Spacer(Modifier.width(2.dp)) + }, + onInfo = { ModalManager.start.showModal { IncognitoView() } }, + ) + } + + BoxWithConstraints { + Column( + Modifier + .fillMaxSize() + .alpha(if (progressByTimeout) 0.6f else 1f) + ) { + LazyColumnWithScrollBar(userScrollEnabled = !switchingProfile.value) { + item { + AppBarTitle(stringResource(MR.strings.select_chat_profile), hostDevice(rhId), bottomPadding = DEFAULT_PADDING) + } + val activeProfile = filteredProfiles.firstOrNull { it.activeUser } + + if (activeProfile != null) { + val otherProfiles = filteredProfiles.filter { it.userId != activeProfile.userId } + + if (incognito) { + item { + IncognitoUserOption() + } + item { + ProfilePickerUserOption(activeProfile) + } + } else { + item { + ProfilePickerUserOption(activeProfile) + } + item { + IncognitoUserOption() + } + } + + itemsIndexed(otherProfiles) { _, p -> + ProfilePickerUserOption(p) + } + } else { + item { + IncognitoUserOption() + } + itemsIndexed(filteredProfiles) { _, p -> + ProfilePickerUserOption(p) + } + } + } + } + if (progressByTimeout) { + DefaultProgressView("") + } + } +} + @Composable private fun InviteView(rhId: Long?, connReqInvitation: String, contactConnection: MutableState) { SectionView(stringResource(MR.strings.share_this_1_time_link).uppercase(), headerBottomPadding = 5.dp) { @@ -204,23 +461,72 @@ private fun InviteView(rhId: Long?, connReqInvitation: String, contactConnection SimpleXLinkQRCode(connReqInvitation, onShare = { chatModel.markShowingInvitationUsed() }) } - Spacer(Modifier.height(10.dp)) - val incognito = remember { mutableStateOf(controller.appPrefs.incognito.get()) } - IncognitoToggle(controller.appPrefs.incognito, incognito) { - ModalManager.start.showModal { IncognitoView() } + Spacer(Modifier.height(DEFAULT_PADDING)) + val incognito by remember(chatModel.showingInvitation.value?.conn?.incognito, controller.appPrefs.incognito.get()) { + derivedStateOf { + chatModel.showingInvitation.value?.conn?.incognito ?: controller.appPrefs.incognito.get() + } } - KeyChangeEffect(incognito.value) { - withBGApi { - val contactConn = contactConnection.value ?: return@withBGApi - val conn = controller.apiSetConnectionIncognito(rhId, contactConn.pccConnId, incognito.value) ?: return@withBGApi - withChats { - contactConnection.value = conn - updateContactConnection(rhId, conn) + val currentUser = remember { chatModel.currentUser }.value + + if (currentUser != null) { + SectionView(stringResource(MR.strings.new_chat_share_profile).uppercase(), headerBottomPadding = 5.dp) { + SectionItemView( + padding = PaddingValues( + top = 0.dp, + bottom = 0.dp, + start = 16.dp, + end = 16.dp + ), + click = { + ModalManager.start.showCustomModal { close -> + val search = rememberSaveable { mutableStateOf("") } + ModalView( + { close() }, + endButtons = { + SearchTextField(Modifier.fillMaxWidth(), placeholder = stringResource(MR.strings.search_verb), alwaysVisible = true) { search.value = it } + }, + content = { + ActiveProfilePicker( + search = search, + close = close, + rhId = rhId, + contactConnection = contactConnection.value + ) + }) + } + } + ) { + if (incognito) { + Spacer(Modifier.width(8.dp)) + Icon( + painterResource(MR.images.ic_theater_comedy_filled), + contentDescription = stringResource(MR.strings.incognito), + tint = Indigo, + modifier = Modifier.size(32.dp) + ) + Spacer(Modifier.width(2.dp)) + } else { + ProfileImage(size = 42.dp, image = currentUser.image) + } + TextIconSpaced(false) + Text( + text = if (incognito) stringResource(MR.strings.incognito) else currentUser.chatViewName, + color = MaterialTheme.colors.onBackground + ) + Column(modifier = Modifier.fillMaxWidth(), horizontalAlignment = Alignment.End) { + Icon( + painter = painterResource(MR.images.ic_arrow_forward_ios), + contentDescription = stringResource(MR.strings.new_chat_share_profile), + tint = MaterialTheme.colors.secondary, + ) + } } } - chatModel.markShowingInvitationUsed() + if (incognito) { + SectionTextFooter(generalGetString(MR.strings.connect__a_new_random_profile_will_be_shared)) + } } - SectionTextFooter(sharedProfileInfo(chatModel, incognito.value)) } @Composable @@ -366,7 +672,7 @@ private fun createInvitation( if (r != null) { withChats { updateContactConnection(rhId, r.second) - chatModel.showingInvitation.value = ShowingInvitation(connId = r.second.id, connReq = simplexChatLink(r.first), connChatUsed = false) + chatModel.showingInvitation.value = ShowingInvitation(connId = r.second.id, connReq = simplexChatLink(r.first), connChatUsed = false, conn = r.second) contactConnection.value = r.second } } else { diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/UserProfilesView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/UserProfilesView.kt index a7bf5920e4..d4334dfed2 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/UserProfilesView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/UserProfilesView.kt @@ -303,7 +303,7 @@ private fun ProfileActionView(action: UserProfileAction, user: User, doAction: ( } } -private fun filteredUsers(m: ChatModel, searchTextOrPassword: String): List { +fun filteredUsers(m: ChatModel, searchTextOrPassword: String): List { val s = searchTextOrPassword.trim() val lower = s.lowercase() return m.users.filter { u -> @@ -317,7 +317,7 @@ private fun filteredUsers(m: ChatModel, searchTextOrPassword: String): List !u.user.hidden }.size -private fun correctPassword(user: User, pwd: String): Boolean { +fun correctPassword(user: User, pwd: String): Boolean { val ph = user.viewPwdHash return ph != null && pwd != "" && chatPasswordHash(pwd, ph.salt) == ph.hash } diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml index f5272ce7fc..9e9beef86b 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml @@ -665,6 +665,10 @@ 1-time link SimpleX address Or show this code + Share profile + Select chat profile + Error switching profile + Your connection was moved to %s but an unexpected error occurred while redirecting you to the profile. Or scan QR code Keep unused invitation? You can view invitation link again in connection details. From 05e7f350378b01c700b934adf9850f3d00291df3 Mon Sep 17 00:00:00 2001 From: Diogo Date: Tue, 27 Aug 2024 22:12:55 +0100 Subject: [PATCH 3/4] core: fix associated agent user for recreated connections (#4771) * core: fix associated user for recreated connections * fix test for connection recreation --- src/Simplex/Chat.hs | 2 +- tests/ChatTests/Profiles.hs | 67 +++++++++++++++++++++---------------- 2 files changed, 40 insertions(+), 29 deletions(-) diff --git a/src/Simplex/Chat.hs b/src/Simplex/Chat.hs index dc3b4b2e54..796a128abe 100644 --- a/src/Simplex/Chat.hs +++ b/src/Simplex/Chat.hs @@ -1709,7 +1709,7 @@ processChatCommand' vr = \case pure conn' recreateConn user conn@PendingContactConnection {customUserProfileId} newUser = do subMode <- chatReadVar subscriptionMode - (agConnId, cReq) <- withAgent $ \a -> createConnection a (aUserId user) True SCMInvitation Nothing IKPQOn subMode + (agConnId, cReq) <- withAgent $ \a -> createConnection a (aUserId newUser) True SCMInvitation Nothing IKPQOn subMode conn' <- withFastStore' $ \db -> do deleteConnectionRecord db user connId forM_ customUserProfileId $ \profileId -> diff --git a/tests/ChatTests/Profiles.hs b/tests/ChatTests/Profiles.hs index 878546ba21..a36eef8ca9 100644 --- a/tests/ChatTests/Profiles.hs +++ b/tests/ChatTests/Profiles.hs @@ -1,6 +1,7 @@ {-# LANGUAGE DuplicateRecordFields #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE PostfixOperators #-} +{-# LANGUAGE TypeApplications #-} module ChatTests.Profiles where @@ -18,6 +19,8 @@ import Simplex.Chat.Types (ConnStatus (..), Profile (..)) import Simplex.Chat.Types.Shared (GroupMemberRole (..)) import Simplex.Chat.Types.UITheme import Simplex.Messaging.Encoding.String (StrEncoding (..)) +import Simplex.Messaging.Server.Env.STM hiding (subscriptions) +import Simplex.Messaging.Transport import Simplex.Messaging.Util (encodeJSON) import System.Directory (copyFile, createDirectoryIfMissing) import Test.Hspec hiding (it) @@ -1653,34 +1656,42 @@ testChangePCCUserAndThenIncognito = testChat2 aliceProfile bobProfile $ ] testChangePCCUserDiffSrv :: HasCallStack => FilePath -> IO () -testChangePCCUserDiffSrv = testChat2 aliceProfile bobProfile $ - \alice bob -> do - -- Create a new invite - alice ##> "/connect" - _ <- getInvitation alice - alice ##> "/_set incognito :1 on" - alice <## "connection 1 changed to incognito" - -- Create new user with different servers - alice ##> "/create user alisa" - showActiveUser alice "alisa" - alice #$> ("/smp smp://2345-w==@smp2.example.im smp://3456-w==@smp3.example.im:5224", id, "ok") - alice ##> "/user alice" - showActiveUser alice "alice (Alice)" - -- Change connection to newly created user and use the newly created connection - alice ##> "/_set conn user :1 2" - alice <## "connection 1 changed from user alice to user alisa, new link:" - alice <## "" - inv <- getTermLine alice - alice <## "" - alice `hasContactProfiles` ["alice"] - alice ##> "/user alisa" - showActiveUser alice "alisa" - -- Connect - bob ##> ("/connect " <> inv) - bob <## "confirmation sent!" - concurrently_ - (alice <## "bob (Bob): contact is connected") - (bob <## "alisa: contact is connected") +testChangePCCUserDiffSrv tmp = do + withSmpServer' serverCfg' $ do + withNewTestChatCfgOpts tmp testCfg testOpts "alice" aliceProfile $ \alice -> do + withNewTestChatCfgOpts tmp testCfg testOpts "bob" bobProfile $ \bob -> do + -- Create a new invite + alice ##> "/connect" + _ <- getInvitation alice + alice ##> "/_set incognito :1 on" + alice <## "connection 1 changed to incognito" + -- Create new user with different servers + alice ##> "/create user alisa" + showActiveUser alice "alisa" + alice #$> ("/smp smp://LcJUMfVhwD8yxjAiSaDzzGF3-kLG4Uh0Fl_ZIjrRwjI=:server_password@localhost:7003", id, "ok") + alice ##> "/user alice" + showActiveUser alice "alice (Alice)" + -- Change connection to newly created user and use the newly created connection + alice ##> "/_set conn user :1 2" + alice <## "connection 1 changed from user alice to user alisa, new link:" + alice <## "" + inv <- getTermLine alice + alice <## "" + alice `hasContactProfiles` ["alice"] + alice ##> "/user alisa" + showActiveUser alice "alisa" + -- Connect + bob ##> ("/connect " <> inv) + bob <## "confirmation sent!" + concurrently_ + (alice <## "bob (Bob): contact is connected") + (bob <## "alisa: contact is connected") + where + serverCfg' = + smpServerCfg + { transports = [("7003", transport @TLS), ("7002", transport @TLS)], + msgQueueQuota = 2 + } testSetConnectionAlias :: HasCallStack => FilePath -> IO () testSetConnectionAlias = testChat2 aliceProfile bobProfile $ From 8cc075eda8a958ccfe1629a9d9f253c3083c6851 Mon Sep 17 00:00:00 2001 From: Evgeny Date: Tue, 27 Aug 2024 22:13:20 +0100 Subject: [PATCH 4/4] ios: show correct message times (#4779) --- apps/ios/Shared/Views/Chat/ChatView.swift | 6 +++--- apps/ios/SimpleXChat/ChatTypes.swift | 20 +------------------- 2 files changed, 4 insertions(+), 22 deletions(-) diff --git a/apps/ios/Shared/Views/Chat/ChatView.swift b/apps/ios/Shared/Views/Chat/ChatView.swift index d94be2bb81..acdcabd7e2 100644 --- a/apps/ios/Shared/Views/Chat/ChatView.swift +++ b/apps/ios/Shared/Views/Chat/ChatView.swift @@ -723,11 +723,11 @@ struct ChatView: View { let im = ItemsModel.shared if let i, i > 0 && im.reversedChatItems.count >= i { let nextItem = im.reversedChatItems[i - 1] - let largeGap = !nextItem.chatDir.sameDirection(chatItem.chatDir) || nextItem.meta.createdAt.timeIntervalSince(chatItem.meta.createdAt) > 60 + let largeGap = !nextItem.chatDir.sameDirection(chatItem.chatDir) || nextItem.meta.itemTs.timeIntervalSince(chatItem.meta.itemTs) > 60 return ( - timestamp: largeGap || formatTimestampText(chatItem.meta.createdAt) != formatTimestampText(nextItem.meta.createdAt), + timestamp: largeGap || formatTimestampText(chatItem.meta.itemTs) != formatTimestampText(nextItem.meta.itemTs), largeGap: largeGap, - date: Calendar.current.isDate(chatItem.meta.createdAt, inSameDayAs: nextItem.meta.createdAt) ? nil : nextItem.meta.createdAt + date: Calendar.current.isDate(chatItem.meta.itemTs, inSameDayAs: nextItem.meta.itemTs) ? nil : nextItem.meta.itemTs ) } else { return (timestamp: true, largeGap: true, date: nil) diff --git a/apps/ios/SimpleXChat/ChatTypes.swift b/apps/ios/SimpleXChat/ChatTypes.swift index d51e5a7cc3..07340bb963 100644 --- a/apps/ios/SimpleXChat/ChatTypes.swift +++ b/apps/ios/SimpleXChat/ChatTypes.swift @@ -2765,26 +2765,8 @@ public struct CITimed: Decodable, Hashable { public var deleteAt: Date? } -let msgTimeFormat = Date.FormatStyle.dateTime.hour().minute() -let msgDateFormat = Date.FormatStyle.dateTime.day(.twoDigits).month(.twoDigits) - public func formatTimestampText(_ date: Date) -> Text { - Text(verbatim: date.formatted(recent(date) ? msgTimeFormat : msgDateFormat)) -} - -private func recent(_ date: Date) -> Bool { - let now = Date() - let calendar = Calendar.current - - guard let previousDay = calendar.date(byAdding: DateComponents(day: -1), to: now), - let previousDay18 = calendar.date(bySettingHour: 18, minute: 0, second: 0, of: previousDay), - let currentDay00 = calendar.date(bySettingHour: 0, minute: 0, second: 0, of: now), - let currentDay12 = calendar.date(bySettingHour: 12, minute: 0, second: 0, of: now) else { - return false - } - - let isSameDay = calendar.isDate(date, inSameDayAs: now) - return isSameDay || (now < currentDay12 && date >= previousDay18 && date < currentDay00) + Text(verbatim: date.formatted(date: .omitted, time: .shortened)) } public enum CIStatus: Decodable, Hashable {