diff --git a/README.md b/README.md index 40d552b84d..554c6068d9 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ # SimpleX - the first messaging platform that has no user identifiers of any kind - 100% private by design! -[](http://simplex.chat/blog/20221108-simplex-chat-v4.2-security-audit-new-website.html)     [](https://www.privacyguides.org/en/real-time-communication/#simplex-chat)     [](https://www.kuketz-blog.de/simplex-eindruecke-vom-messenger-ohne-identifier/) +[](http://simplex.chat/blog/20221108-simplex-chat-v4.2-security-audit-new-website.html)     [](https://www.privacyguides.org/en/real-time-communication/#simplex-chat)     [](https://www.whonix.org/wiki/Chat#Recommendation)     [](https://www.kuketz-blog.de/simplex-eindruecke-vom-messenger-ohne-identifier/) ## Welcome to SimpleX Chat! @@ -110,6 +110,15 @@ After you connect, you can [verify connection security code](./blog/20230103-sim Read about the app features and settings in the new [User guide](./docs/guide/README.md). +## Contribute + +We would love to have you join the development! You can help us with: + +- [share the color theme](./docs/THEMES.md) you use in Android app! +- writing a tutorial or recipes about hosting servers, chat bot automations, etc. +- contributing to SimpleX Chat knowledge-base. +- developing features - please connect to us via chat so we can help you get started. + ## Help translating SimpleX Chat Thanks to our users and [Weblate](https://hosted.weblate.org/engage/simplex-chat/), SimpleX Chat apps, website and documents are translated to many other languages. @@ -141,15 +150,6 @@ Join our translators to help SimpleX grow! Languages in progress: Arabic, Japanese, Korean, Portuguese and [others](https://hosted.weblate.org/projects/simplex-chat/#languages). We will be adding more languages as some of the already added are completed – please suggest new languages, review the [translation guide](./docs/TRANSLATIONS.md) and get in touch with us! -## Contribute - -We would love to have you join the development! You can help us with: - -- [share the color theme](./docs/THEMES.md) you use in Android app! -- writing a tutorial or recipes about hosting servers, chat bot automations, etc. -- contributing to SimpleX Chat knowledge-base. -- developing features - please connect to us via chat so we can help you get started. - ## Please support us with your donations Huge thank you to everybody who donated to SimpleX Chat! diff --git a/apps/ios/Shared/Model/ChatModel.swift b/apps/ios/Shared/Model/ChatModel.swift index 63d8b38e3c..9b9fda0397 100644 --- a/apps/ios/Shared/Model/ChatModel.swift +++ b/apps/ios/Shared/Model/ChatModel.swift @@ -1152,27 +1152,6 @@ final class Chat: ObservableObject, Identifiable, ChatLike { ) } - var userCanSend: Bool { - switch chatInfo { - case .direct: return true - case let .group(groupInfo): - let m = groupInfo.membership - return m.memberActive && m.memberRole >= .member - case .local: - return true - default: return false - } - } - - var userIsObserver: Bool { - switch chatInfo { - case let .group(groupInfo): - let m = groupInfo.membership - return m.memberActive && m.memberRole == .observer - default: return false - } - } - var unreadTag: Bool { switch chatInfo.chatSettings?.enableNtfs { case .all: chatStats.unreadChat || chatStats.unreadCount > 0 diff --git a/apps/ios/Shared/Views/Chat/ChatView.swift b/apps/ios/Shared/Views/Chat/ChatView.swift index 9e648ef98c..c136ebc01b 100644 --- a/apps/ios/Shared/Views/Chat/ChatView.swift +++ b/apps/ios/Shared/Views/Chat/ChatView.swift @@ -98,14 +98,24 @@ struct ChatView: View { } connectingText() if selectedChatItems == nil { + let reason = chat.chatInfo.userCantSendReason ComposeView( chat: chat, composeState: $composeState, keyboardVisible: $keyboardVisible, keyboardHiddenDate: $keyboardHiddenDate, - selectedRange: $selectedRange + selectedRange: $selectedRange, + disabledText: reason?.composeLabel ) .disabled(!cInfo.sendMsgEnabled) + .if(!cInfo.sendMsgEnabled) { v in + v.disabled(true).onTapGesture { + AlertManager.shared.showAlertMsg( + title: "You can't send messages!", + message: reason?.alertMessage + ) + } + } } else { SelectedItemsBottomToolbar( chatItems: ItemsModel.shared.reversedChatItems, diff --git a/apps/ios/Shared/Views/Chat/ComposeMessage/ComposeView.swift b/apps/ios/Shared/Views/Chat/ComposeMessage/ComposeView.swift index 3e9c340266..8993de886f 100644 --- a/apps/ios/Shared/Views/Chat/ComposeMessage/ComposeView.swift +++ b/apps/ios/Shared/Views/Chat/ComposeMessage/ComposeView.swift @@ -327,6 +327,7 @@ struct ComposeView: View { @Binding var keyboardVisible: Bool @Binding var keyboardHiddenDate: Date @Binding var selectedRange: NSRange + var disabledText: LocalizedStringKey? = nil @State var linkUrl: URL? = nil @State var hasSimplexLink: Bool = false @@ -391,7 +392,7 @@ struct ComposeView: View { Image(systemName: "paperclip") .resizable() } - .disabled(composeState.attachmentDisabled || !chat.userCanSend || (chat.chatInfo.contact?.nextSendGrpInv ?? false)) + .disabled(composeState.attachmentDisabled || !chat.chatInfo.sendMsgEnabled || (chat.chatInfo.contact?.nextSendGrpInv ?? false)) .frame(width: 25, height: 25) .padding(.bottom, 16) .padding(.leading, 12) @@ -441,19 +442,13 @@ struct ComposeView: View { : theme.colors.primary ) .padding(.trailing, 12) - .disabled(!chat.userCanSend) + .disabled(!chat.chatInfo.sendMsgEnabled) - if chat.userIsObserver { - Text("you are observer") + if let disabledText { + Text(disabledText) .italic() .foregroundColor(theme.colors.secondary) .padding(.horizontal, 12) - .onTapGesture { - AlertManager.shared.showAlertMsg( - title: "You can't send messages!", - message: "Please contact group admin." - ) - } } } } @@ -479,8 +474,8 @@ struct ComposeView: View { hasSimplexLink = false } } - .onChange(of: chat.userCanSend) { canSend in - if !canSend { + .onChange(of: chat.chatInfo.sendMsgEnabled) { sendEnabled in + if !sendEnabled { cancelCurrentVoiceRecording() clearCurrentDraft() clearState() diff --git a/apps/ios/Shared/Views/Chat/ComposeMessage/SendMessageView.swift b/apps/ios/Shared/Views/Chat/ComposeMessage/SendMessageView.swift index d7b29a0ecb..e7b02c9aea 100644 --- a/apps/ios/Shared/Views/Chat/ComposeMessage/SendMessageView.swift +++ b/apps/ios/Shared/Views/Chat/ComposeMessage/SendMessageView.swift @@ -15,6 +15,7 @@ struct SendMessageView: View { @Binding var composeState: ComposeState @Binding var selectedRange: NSRange @EnvironmentObject var theme: AppTheme + @Environment(\.isEnabled) var isEnabled var sendMessage: (Int?) -> Void var sendLiveMessage: (() async -> Void)? = nil var updateLiveMessage: (() async -> Void)? = nil @@ -255,6 +256,7 @@ struct SendMessageView: View { } private struct RecordVoiceMessageButton: View { + @Environment(\.isEnabled) var isEnabled @EnvironmentObject var theme: AppTheme var startVoiceMessageRecording: (() -> Void)? var finishVoiceMessageRecording: (() -> Void)? @@ -263,11 +265,11 @@ struct SendMessageView: View { @State private var pressed: TimeInterval? = nil var body: some View { - Image(systemName: "mic.fill") + Image(systemName: isEnabled ? "mic.fill" : "mic") .resizable() .scaledToFit() .frame(width: 20, height: 20) - .foregroundColor(theme.colors.primary) + .foregroundColor(isEnabled ? theme.colors.primary : theme.colors.secondary) .opacity(holdingVMR ? 0.7 : 1) .disabled(disabled) .frame(width: 31, height: 31) @@ -352,7 +354,7 @@ struct SendMessageView: View { Image(systemName: "bolt.fill") .resizable() .scaledToFit() - .foregroundColor(theme.colors.primary) + .foregroundColor(isEnabled ? theme.colors.primary : theme.colors.secondary) .frame(width: 20, height: 20) } .frame(width: 29, height: 29) diff --git a/apps/ios/Shared/Views/Chat/Group/GroupChatInfoView.swift b/apps/ios/Shared/Views/Chat/Group/GroupChatInfoView.swift index 96a4981be0..15749b0761 100644 --- a/apps/ios/Shared/Views/Chat/Group/GroupChatInfoView.swift +++ b/apps/ios/Shared/Views/Chat/Group/GroupChatInfoView.swift @@ -144,17 +144,9 @@ struct GroupChatInfoView: View { let filteredMembers = s == "" ? members : members.filter { $0.wrapped.localAliasAndFullName.localizedLowercase.contains(s) } - MemberRowView(groupInfo: groupInfo, groupMember: GMember(groupInfo.membership), user: true, alert: $alert) + MemberRowView(chat: chat, groupInfo: groupInfo, groupMember: GMember(groupInfo.membership), user: true, alert: $alert) ForEach(filteredMembers) { member in - ZStack { - NavigationLink { - memberInfoView(member) - } label: { - EmptyView() - } - .opacity(0) - MemberRowView(groupInfo: groupInfo, groupMember: member, alert: $alert) - } + MemberRowView(chat: chat, groupInfo: groupInfo, groupMember: member, alert: $alert) } } @@ -358,6 +350,7 @@ struct GroupChatInfoView: View { } private struct MemberRowView: View { + var chat: Chat var groupInfo: GroupInfo @ObservedObject var groupMember: GMember @EnvironmentObject var theme: AppTheme @@ -366,7 +359,7 @@ struct GroupChatInfoView: View { var body: some View { let member = groupMember.wrapped - let v = HStack{ + let v1 = HStack{ MemberProfileImage(member, size: 38) .padding(.trailing, 2) // TODO server connection status @@ -383,6 +376,20 @@ struct GroupChatInfoView: View { memberInfo(member) } + let v = ZStack { + if user { + v1 + } else { + NavigationLink { + memberInfoView() + } label: { + EmptyView() + } + .opacity(0) + v1 + } + } + if user { v } else if groupInfo.membership.memberRole >= .admin { @@ -407,6 +414,11 @@ struct GroupChatInfoView: View { } } + private func memberInfoView() -> some View { + GroupMemberInfoView(groupInfo: groupInfo, chat: chat, groupMember: groupMember) + .navigationBarHidden(false) + } + private func memberConnStatus(_ member: GroupMember) -> LocalizedStringKey { if member.activeConn?.connDisabled ?? false { return "disabled" @@ -485,11 +497,6 @@ struct GroupChatInfoView: View { .foregroundColor(theme.colors.secondary) } } - - private func memberInfoView(_ groupMember: GMember) -> some View { - GroupMemberInfoView(groupInfo: groupInfo, chat: chat, groupMember: groupMember) - .navigationBarHidden(false) - } private func groupLinkButton() -> some View { NavigationLink { diff --git a/apps/ios/Shared/Views/ChatList/ChatListNavLink.swift b/apps/ios/Shared/Views/ChatList/ChatListNavLink.swift index f9cf5e98e4..81d78fbadd 100644 --- a/apps/ios/Shared/Views/ChatList/ChatListNavLink.swift +++ b/apps/ios/Shared/Views/ChatList/ChatListNavLink.swift @@ -94,7 +94,7 @@ struct ChatListNavLink: View { Group { if contact.activeConn == nil && contact.profile.contactLink != nil && contact.active { ChatPreviewView(chat: chat, progressByTimeout: Binding.constant(false)) - .frame(height: dynamicRowHeight) + .frameCompat(height: dynamicRowHeight) .swipeActions(edge: .trailing, allowsFullSwipe: true) { Button { deleteContactDialog( @@ -121,6 +121,7 @@ struct ChatListNavLink: View { selection: $chatModel.chatId, label: { ChatPreviewView(chat: chat, progressByTimeout: Binding.constant(false)) } ) + .frameCompat(height: dynamicRowHeight) .swipeActions(edge: .leading, allowsFullSwipe: true) { markReadButton() toggleFavoriteButton() @@ -145,7 +146,6 @@ struct ChatListNavLink: View { } .tint(.red) } - .frame(height: dynamicRowHeight) } } .alert(item: $alert) { $0.alert } @@ -163,7 +163,7 @@ struct ChatListNavLink: View { switch (groupInfo.membership.memberStatus) { case .memInvited: ChatPreviewView(chat: chat, progressByTimeout: $progressByTimeout) - .frame(height: dynamicRowHeight) + .frameCompat(height: dynamicRowHeight) .swipeActions(edge: .trailing, allowsFullSwipe: true) { joinGroupButton() if groupInfo.canDelete { @@ -183,7 +183,7 @@ struct ChatListNavLink: View { .disabled(inProgress) case .memAccepted: ChatPreviewView(chat: chat, progressByTimeout: Binding.constant(false)) - .frame(height: dynamicRowHeight) + .frameCompat(height: dynamicRowHeight) .onTapGesture { AlertManager.shared.showAlert(groupInvitationAcceptedAlert()) } @@ -203,7 +203,7 @@ struct ChatListNavLink: View { label: { ChatPreviewView(chat: chat, progressByTimeout: Binding.constant(false)) }, disabled: !groupInfo.ready ) - .frame(height: dynamicRowHeight) + .frameCompat(height: dynamicRowHeight) .swipeActions(edge: .leading, allowsFullSwipe: true) { markReadButton() toggleFavoriteButton() @@ -250,7 +250,7 @@ struct ChatListNavLink: View { label: { ChatPreviewView(chat: chat, progressByTimeout: Binding.constant(false)) }, disabled: !noteFolder.ready ) - .frame(height: dynamicRowHeight) + .frameCompat(height: dynamicRowHeight) .swipeActions(edge: .leading, allowsFullSwipe: true) { markReadButton() } @@ -433,6 +433,7 @@ struct ChatListNavLink: View { private func contactRequestNavLink(_ contactRequest: UserContactRequest) -> some View { ContactRequestView(contactRequest: contactRequest, chat: chat) + .frameCompat(height: dynamicRowHeight) .swipeActions(edge: .trailing, allowsFullSwipe: true) { Button { Task { await acceptContactRequest(incognito: false, contactRequest: contactRequest) } @@ -451,7 +452,6 @@ struct ChatListNavLink: View { } .tint(.red) } - .frame(height: dynamicRowHeight) .contentShape(Rectangle()) .onTapGesture { showContactRequestDialog = true } .confirmationDialog("Accept connection request?", isPresented: $showContactRequestDialog, titleVisibility: .visible) { @@ -463,6 +463,7 @@ struct ChatListNavLink: View { private func contactConnectionNavLink(_ contactConnection: PendingContactConnection) -> some View { ContactConnectionView(chat: chat) + .frameCompat(height: dynamicRowHeight) .swipeActions(edge: .trailing, allowsFullSwipe: true) { Button { AlertManager.shared.showAlert(deleteContactConnectionAlert(contactConnection) { a in @@ -480,7 +481,6 @@ struct ChatListNavLink: View { } .tint(theme.colors.primary) } - .frame(height: dynamicRowHeight) .appSheet(isPresented: $showContactConnectionInfo) { Group { if case let .contactConnection(contactConnection) = chat.chatInfo { @@ -583,7 +583,7 @@ struct ChatListNavLink: View { Text("invalid chat data") .foregroundColor(.red) .padding(4) - .frame(height: dynamicRowHeight) + .frameCompat(height: dynamicRowHeight) .onTapGesture { showInvalidJSON = true } .appSheet(isPresented: $showInvalidJSON) { invalidJSONView(dataToString(json)) @@ -603,6 +603,24 @@ struct ChatListNavLink: View { } } +extension View { + @inline(__always) + @ViewBuilder fileprivate func frameCompat(height: CGFloat) -> some View { + if #available(iOS 16, *) { + self.frame(height: height) + } else { + VStack(spacing: 0) { + Divider() + .padding(.leading, 16) + self + .frame(height: height) + .padding(.horizontal, 8) + .padding(.vertical, 8) + } + } + } +} + func rejectContactRequestAlert(_ contactRequest: UserContactRequest) -> Alert { Alert( title: Text("Reject contact request"), diff --git a/apps/ios/Shared/Views/ChatList/ChatListView.swift b/apps/ios/Shared/Views/ChatList/ChatListView.swift index 5c491b6303..f34f930c6f 100644 --- a/apps/ios/Shared/Views/ChatList/ChatListView.swift +++ b/apps/ios/Shared/Views/ChatList/ChatListView.swift @@ -367,13 +367,7 @@ struct ChatListView: View { .offset(x: -8) } else { ForEach(cs, id: \.viewId) { chat in - VStack(spacing: .zero) { - Divider() - .padding(.leading, 16) - ChatListNavLink(chat: chat, parentSheet: $sheet) - .padding(.horizontal, 8) - .padding(.vertical, 6) - } + ChatListNavLink(chat: chat, parentSheet: $sheet) .scaleEffect(x: 1, y: oneHandUI ? -1 : 1, anchor: .center) .listRowSeparator(.hidden) .listRowInsets(EdgeInsets()) diff --git a/apps/ios/Shared/Views/Onboarding/ChooseServerOperators.swift b/apps/ios/Shared/Views/Onboarding/ChooseServerOperators.swift index 17e1735472..656cef4a04 100644 --- a/apps/ios/Shared/Views/Onboarding/ChooseServerOperators.swift +++ b/apps/ios/Shared/Views/Onboarding/ChooseServerOperators.swift @@ -67,7 +67,7 @@ struct OnboardingConditionsView: View { var body: some View { GeometryReader { g in - ScrollView { + let v = ScrollView { VStack(alignment: .leading, spacing: 20) { Text("Conditions of use") .font(.largeTitle) @@ -107,6 +107,7 @@ struct OnboardingConditionsView: View { .frame(minHeight: 40) } } + .padding(25) .frame(minHeight: g.size.height) } .onAppear { @@ -127,9 +128,14 @@ struct OnboardingConditionsView: View { } } .frame(maxHeight: .infinity, alignment: .top) + if #available(iOS 16.4, *) { + v.scrollBounceBehavior(.basedOnSize) + } else { + v + } } .frame(maxHeight: .infinity, alignment: .top) - .padding(25) + .navigationBarHidden(true) // necessary on iOS 15 } private func continueToNextStep() { diff --git a/apps/ios/Shared/Views/Onboarding/CreateProfile.swift b/apps/ios/Shared/Views/Onboarding/CreateProfile.swift index c022a2a012..ae72cb1be5 100644 --- a/apps/ios/Shared/Views/Onboarding/CreateProfile.swift +++ b/apps/ios/Shared/Views/Onboarding/CreateProfile.swift @@ -62,8 +62,7 @@ struct CreateProfile: View { .frame(height: 20) } footer: { VStack(alignment: .leading, spacing: 8) { - Text("Your profile, contacts and delivered messages are stored on your device.") - Text("The profile is only shared with your contacts.") + Text("Your profile is stored on your device and only shared with your contacts.") } .foregroundColor(theme.colors.secondary) .frame(maxWidth: .infinity, alignment: .leading) @@ -118,25 +117,22 @@ struct CreateFirstProfile: View { @State private var nextStepNavLinkActive = false var body: some View { - VStack(alignment: .leading, spacing: 20) { - VStack(alignment: .center, spacing: 20) { - Text("Create your profile") + let v = VStack(alignment: .leading, spacing: 16) { + VStack(alignment: .center, spacing: 16) { + Text("Create profile") .font(.largeTitle) .bold() .multilineTextAlignment(.center) - - Text("Your profile, contacts and delivered messages are stored on your device.") - .font(.callout) - .foregroundColor(theme.colors.secondary) - .multilineTextAlignment(.center) - - Text("The profile is only shared with your contacts.") + + Text("Your profile is stored on your device and only shared with your contacts.") .font(.callout) .foregroundColor(theme.colors.secondary) .multilineTextAlignment(.center) } + .fixedSize(horizontal: false, vertical: true) .frame(maxWidth: .infinity) // Ensures it takes up the full width .padding(.horizontal, 10) + .onTapGesture { focusDisplayName = false } HStack { let name = displayName.trimmingCharacters(in: .whitespaces) @@ -174,12 +170,23 @@ struct CreateFirstProfile: View { } } .onAppear() { - focusDisplayName = true + if #available(iOS 16, *) { + focusDisplayName = true + } else { + // it does not work before animation completes on iOS 15 + DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { + focusDisplayName = true + } + } } .padding(.horizontal, 25) - .padding(.top, 10) .padding(.bottom, 25) .frame(maxWidth: .infinity, alignment: .leading) + if #available(iOS 16, *) { + return v.padding(.top, 10) + } else { + return v.padding(.top, 75).ignoresSafeArea(.all, edges: .top) + } } func createProfileButton() -> some View { diff --git a/apps/ios/Shared/Views/Onboarding/SetNotificationsMode.swift b/apps/ios/Shared/Views/Onboarding/SetNotificationsMode.swift index 97e1f49382..31865e7af9 100644 --- a/apps/ios/Shared/Views/Onboarding/SetNotificationsMode.swift +++ b/apps/ios/Shared/Views/Onboarding/SetNotificationsMode.swift @@ -17,7 +17,7 @@ struct SetNotificationsMode: View { var body: some View { GeometryReader { g in - ScrollView { + let v = ScrollView { VStack(alignment: .center, spacing: 20) { Text("Push notifications") .font(.largeTitle) @@ -57,11 +57,17 @@ struct SetNotificationsMode: View { .padding(25) .frame(minHeight: g.size.height) } + if #available(iOS 16.4, *) { + v.scrollBounceBehavior(.basedOnSize) + } else { + v + } } .frame(maxHeight: .infinity) .sheet(isPresented: $showInfo) { NotificationsInfoView() } + .navigationBarHidden(true) // necessary on iOS 15 } private func setNotificationsMode(_ token: DeviceToken, _ mode: NotificationsMode) { diff --git a/apps/ios/Shared/Views/Onboarding/SimpleXInfo.swift b/apps/ios/Shared/Views/Onboarding/SimpleXInfo.swift index e55cc4037a..9f41a37b1d 100644 --- a/apps/ios/Shared/Views/Onboarding/SimpleXInfo.swift +++ b/apps/ios/Shared/Views/Onboarding/SimpleXInfo.swift @@ -18,7 +18,7 @@ struct SimpleXInfo: View { var body: some View { GeometryReader { g in - ScrollView { + let v = ScrollView { VStack(alignment: .leading) { VStack(alignment: .center, spacing: 10) { Image(colorScheme == .light ? "logo" : "logo-light") @@ -36,7 +36,7 @@ struct SimpleXInfo: View { .font(.headline) } } - + Spacer() VStack(alignment: .leading) { @@ -66,6 +66,9 @@ struct SimpleXInfo: View { } } } + .padding(.horizontal, 25) + .padding(.top, 75) + .padding(.bottom, 25) .frame(minHeight: g.size.height) } .sheet(isPresented: Binding( @@ -88,14 +91,17 @@ struct SimpleXInfo: View { createProfileNavLinkActive: $createProfileNavLinkActive ) } + if #available(iOS 16.4, *) { + v.scrollBounceBehavior(.basedOnSize) + } else { + v + } } .onAppear() { setLastVersionDefault() } .frame(maxHeight: .infinity) - .padding(.horizontal, 25) - .padding(.top, 75) - .padding(.bottom, 25) + .navigationBarHidden(true) // necessary on iOS 15 } private func onboardingInfoRow(_ image: String, _ title: LocalizedStringKey, _ text: LocalizedStringKey, width: CGFloat) -> some View { diff --git a/apps/ios/SimpleX Localizations/ar.xcloc/Localized Contents/ar.xliff b/apps/ios/SimpleX Localizations/ar.xcloc/Localized Contents/ar.xliff index 278b9ec9b2..e965e5a1a5 100644 --- a/apps/ios/SimpleX Localizations/ar.xcloc/Localized Contents/ar.xliff +++ b/apps/ios/SimpleX Localizations/ar.xcloc/Localized Contents/ar.xliff @@ -2826,8 +2826,8 @@ We will be adding server redundancy to prevent lost messages. The old database was not removed during the migration, it can be deleted. No comment provided by engineer. - - The profile is only shared with your contacts. + + Your profile is stored on your device and only shared with your contacts. No comment provided by engineer. 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 56553b3283..776199ac1f 100644 --- a/apps/ios/SimpleX Localizations/bg.xcloc/Localized Contents/bg.xliff +++ b/apps/ios/SimpleX Localizations/bg.xcloc/Localized Contents/bg.xliff @@ -7329,11 +7329,6 @@ It can happen because of some bug or when the connection is compromised.Старата база данни не бе премахната по време на миграцията, тя може да бъде изтрита. No comment provided by engineer. - - The profile is only shared with your contacts. - Профилът се споделя само с вашите контакти. - No comment provided by engineer. - The same conditions will apply to operator **%@**. No comment provided by engineer. @@ -8577,6 +8572,11 @@ Repeat connection request? Вашият профил **%@** ще бъде споделен. No comment provided by engineer. + + Your profile is stored on your device and only shared with your contacts. + Профилът се споделя само с вашите контакти. + No comment provided by engineer. + Your profile is stored on your device and shared only with your contacts. SimpleX servers cannot see your profile. Вашият профил се съхранява на вашето устройство и се споделя само с вашите контакти. SimpleX сървърите не могат да видят вашия профил. @@ -8586,11 +8586,6 @@ Repeat connection request? Your profile was changed. If you save it, the updated profile will be sent to all your contacts. alert message - - Your profile, contacts and delivered messages are stored on your device. - Вашият профил, контакти и доставени съобщения се съхраняват на вашето устройство. - No comment provided by engineer. - Your random profile Вашият автоматично генериран профил diff --git a/apps/ios/SimpleX Localizations/bn.xcloc/Localized Contents/bn.xliff b/apps/ios/SimpleX Localizations/bn.xcloc/Localized Contents/bn.xliff index 7002f790df..bf7753675e 100644 --- a/apps/ios/SimpleX Localizations/bn.xcloc/Localized Contents/bn.xliff +++ b/apps/ios/SimpleX Localizations/bn.xcloc/Localized Contents/bn.xliff @@ -3422,8 +3422,8 @@ It can happen because of some bug or when the connection is compromised.The old database was not removed during the migration, it can be deleted. No comment provided by engineer. - - The profile is only shared with your contacts. + + Your profile is stored on your device and only shared with your contacts. No comment provided by engineer. 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 21bf0aef60..0400839cb0 100644 --- a/apps/ios/SimpleX Localizations/cs.xcloc/Localized Contents/cs.xliff +++ b/apps/ios/SimpleX Localizations/cs.xcloc/Localized Contents/cs.xliff @@ -1942,6 +1942,7 @@ This is your own one-time link! Create profile + Vytvořte si profil No comment provided by engineer. @@ -7080,11 +7081,6 @@ Může se to stát kvůli nějaké chybě, nebo pokud je spojení kompromitován Stará databáze nebyla během přenášení odstraněna, lze ji smazat. No comment provided by engineer. - - The profile is only shared with your contacts. - Profil je sdílen pouze s vašimi kontakty. - No comment provided by engineer. - The same conditions will apply to operator **%@**. No comment provided by engineer. @@ -8271,6 +8267,11 @@ Repeat connection request? Váš profil **%@** bude sdílen. No comment provided by engineer. + + Your profile is stored on your device and only shared with your contacts. + Profil je sdílen pouze s vašimi kontakty. + No comment provided by engineer. + Your profile is stored on your device and shared only with your contacts. SimpleX servers cannot see your profile. Váš profil je uložen ve vašem zařízení a sdílen pouze s vašimi kontakty. Servery SimpleX nevidí váš profil. @@ -8280,11 +8281,6 @@ Repeat connection request? Your profile was changed. If you save it, the updated profile will be sent to all your contacts. alert message - - Your profile, contacts and delivered messages are stored on your device. - Váš profil, kontakty a doručené zprávy jsou uloženy ve vašem zařízení. - No comment provided by engineer. - Your random profile Váš náhodný profil 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 a113d35bbd..06fd7c5a1d 100644 --- a/apps/ios/SimpleX Localizations/de.xcloc/Localized Contents/de.xliff +++ b/apps/ios/SimpleX Localizations/de.xcloc/Localized Contents/de.xliff @@ -7763,11 +7763,6 @@ Dies kann passieren, wenn es einen Fehler gegeben hat oder die Verbindung kompro Die alte Datenbank wurde während der Migration nicht entfernt. Sie kann gelöscht werden. No comment provided by engineer. - - The profile is only shared with your contacts. - Das Profil wird nur mit Ihren Kontakten geteilt. - No comment provided by engineer. - The same conditions will apply to operator **%@**. Dieselben Nutzungsbedingungen gelten auch für den Betreiber **%@**. @@ -9081,6 +9076,11 @@ Verbindungsanfrage wiederholen? Ihr Profil **%@** wird geteilt. No comment provided by engineer. + + Your profile is stored on your device and only shared with your contacts. + Das Profil wird nur mit Ihren Kontakten geteilt. + No comment provided by engineer. + Your profile is stored on your device and shared only with your contacts. SimpleX servers cannot see your profile. Ihr Profil wird auf Ihrem Gerät gespeichert und nur mit Ihren Kontakten geteilt. SimpleX-Server können Ihr Profil nicht einsehen. @@ -9091,11 +9091,6 @@ Verbindungsanfrage wiederholen? Ihr Profil wurde geändert. Wenn Sie es speichern, wird das aktualisierte Profil an alle Ihre Kontakte gesendet. alert message - - Your profile, contacts and delivered messages are stored on your device. - Ihr Profil, Ihre Kontakte und zugestellten Nachrichten werden auf Ihrem Gerät gespeichert. - No comment provided by engineer. - Your random profile Ihr Zufallsprofil diff --git a/apps/ios/SimpleX Localizations/el.xcloc/Localized Contents/el.xliff b/apps/ios/SimpleX Localizations/el.xcloc/Localized Contents/el.xliff index b601d1fa74..fc1846942c 100644 --- a/apps/ios/SimpleX Localizations/el.xcloc/Localized Contents/el.xliff +++ b/apps/ios/SimpleX Localizations/el.xcloc/Localized Contents/el.xliff @@ -3043,8 +3043,8 @@ It can happen because of some bug or when the connection is compromised.The old database was not removed during the migration, it can be deleted. No comment provided by engineer. - - The profile is only shared with your contacts. + + Your profile is stored on your device and only shared with your contacts. No comment provided by engineer. 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 641af86c2a..fd71e0dee6 100644 --- a/apps/ios/SimpleX Localizations/en.xcloc/Localized Contents/en.xliff +++ b/apps/ios/SimpleX Localizations/en.xcloc/Localized Contents/en.xliff @@ -7764,11 +7764,6 @@ It can happen because of some bug or when the connection is compromised.The old database was not removed during the migration, it can be deleted. No comment provided by engineer. - - The profile is only shared with your contacts. - The profile is only shared with your contacts. - No comment provided by engineer. - The same conditions will apply to operator **%@**. The same conditions will apply to operator **%@**. @@ -9082,6 +9077,11 @@ Repeat connection request? Your profile **%@** will be shared. No comment provided by engineer. + + Your profile is stored on your device and only shared with your contacts. + Your profile is stored on your device and only shared with your contacts. + No comment provided by engineer. + Your profile is stored on your device and shared only with your contacts. SimpleX servers cannot see your profile. Your profile is stored on your device and shared only with your contacts. SimpleX servers cannot see your profile. @@ -9092,11 +9092,6 @@ Repeat connection request? Your profile was changed. If you save it, the updated profile will be sent to all your contacts. alert message - - Your profile, contacts and delivered messages are stored on your device. - Your profile, contacts and delivered messages are stored on your device. - No comment provided by engineer. - Your random profile Your random profile 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 73f88e1cab..d39fb61249 100644 --- a/apps/ios/SimpleX Localizations/es.xcloc/Localized Contents/es.xliff +++ b/apps/ios/SimpleX Localizations/es.xcloc/Localized Contents/es.xliff @@ -7763,11 +7763,6 @@ Puede ocurrir por algún bug o cuando la conexión está comprometida. La base de datos antigua no se eliminó durante la migración, puede eliminarse. No comment provided by engineer. - - The profile is only shared with your contacts. - El perfil sólo se comparte con tus contactos. - No comment provided by engineer. - The same conditions will apply to operator **%@**. Las mismas condiciones se aplicarán al operador **%@**. @@ -9081,6 +9076,11 @@ Repeat connection request? El perfil **%@** será compartido. No comment provided by engineer. + + Your profile is stored on your device and only shared with your contacts. + El perfil sólo se comparte con tus contactos. + No comment provided by engineer. + Your profile is stored on your device and shared only with your contacts. SimpleX servers cannot see your profile. Tu perfil es almacenado en tu dispositivo y solamente se comparte con tus contactos. Los servidores SimpleX no pueden ver tu perfil. @@ -9091,11 +9091,6 @@ Repeat connection request? Tu perfil ha sido modificado. Si lo guardas la actualización será enviada a todos tus contactos. alert message - - Your profile, contacts and delivered messages are stored on your device. - Tu perfil, contactos y mensajes se almacenan en tu dispositivo. - No comment provided by engineer. - Your random profile Tu perfil aleatorio 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 5281fbc701..a54666bb10 100644 --- a/apps/ios/SimpleX Localizations/fi.xcloc/Localized Contents/fi.xliff +++ b/apps/ios/SimpleX Localizations/fi.xcloc/Localized Contents/fi.xliff @@ -1923,6 +1923,7 @@ This is your own one-time link! Create profile + Luo profiilisi No comment provided by engineer. @@ -7054,11 +7055,6 @@ Tämä voi johtua jostain virheestä tai siitä, että yhteys on vaarantunut.Vanhaa tietokantaa ei poistettu siirron aikana, se voidaan kuitenkin poistaa. No comment provided by engineer. - - The profile is only shared with your contacts. - Profiili jaetaan vain kontaktiesi kanssa. - No comment provided by engineer. - The same conditions will apply to operator **%@**. No comment provided by engineer. @@ -8244,6 +8240,11 @@ Repeat connection request? Profiilisi **%@** jaetaan. No comment provided by engineer. + + Your profile is stored on your device and only shared with your contacts. + Profiili jaetaan vain kontaktiesi kanssa. + No comment provided by engineer. + Your profile is stored on your device and shared only with your contacts. SimpleX servers cannot see your profile. Profiilisi tallennetaan laitteeseesi ja jaetaan vain yhteystietojesi kanssa. SimpleX-palvelimet eivät näe profiiliasi. @@ -8253,11 +8254,6 @@ Repeat connection request? Your profile was changed. If you save it, the updated profile will be sent to all your contacts. alert message - - Your profile, contacts and delivered messages are stored on your device. - Profiilisi, kontaktisi ja toimitetut viestit tallennetaan laitteellesi. - No comment provided by engineer. - Your random profile Satunnainen profiilisi 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 1e5da0b0ed..59bde0650e 100644 --- a/apps/ios/SimpleX Localizations/fr.xcloc/Localized Contents/fr.xliff +++ b/apps/ios/SimpleX Localizations/fr.xcloc/Localized Contents/fr.xliff @@ -7696,11 +7696,6 @@ Cela peut se produire en raison d'un bug ou lorsque la connexion est compromise. L'ancienne base de données n'a pas été supprimée lors de la migration, elle peut être supprimée. No comment provided by engineer. - - The profile is only shared with your contacts. - Le profil n'est partagé qu'avec vos contacts. - No comment provided by engineer. - The same conditions will apply to operator **%@**. Les mêmes conditions s'appliquent à l'opérateur **%@**. @@ -9003,6 +8998,11 @@ Répéter la demande de connexion ? Votre profil **%@** sera partagé. No comment provided by engineer. + + Your profile is stored on your device and only shared with your contacts. + Le profil n'est partagé qu'avec vos contacts. + No comment provided by engineer. + Your profile is stored on your device and shared only with your contacts. SimpleX servers cannot see your profile. Votre profil est stocké sur votre appareil et est seulement partagé avec vos contacts. Les serveurs SimpleX ne peuvent pas voir votre profil. @@ -9013,11 +9013,6 @@ Répéter la demande de connexion ? Votre profil a été modifié. Si vous l'enregistrez, le profil mis à jour sera envoyé à tous vos contacts. alert message - - Your profile, contacts and delivered messages are stored on your device. - Votre profil, vos contacts et les messages reçus sont stockés sur votre appareil. - No comment provided by engineer. - Your random profile Votre profil aléatoire diff --git a/apps/ios/SimpleX Localizations/he.xcloc/Localized Contents/he.xliff b/apps/ios/SimpleX Localizations/he.xcloc/Localized Contents/he.xliff index 08f46bb056..f76d7eba1e 100644 --- a/apps/ios/SimpleX Localizations/he.xcloc/Localized Contents/he.xliff +++ b/apps/ios/SimpleX Localizations/he.xcloc/Localized Contents/he.xliff @@ -3569,8 +3569,8 @@ It can happen because of some bug or when the connection is compromised.The old database was not removed during the migration, it can be deleted. No comment provided by engineer. - - The profile is only shared with your contacts. + + Your profile is stored on your device and only shared with your contacts. No comment provided by engineer. diff --git a/apps/ios/SimpleX Localizations/hr.xcloc/Localized Contents/hr.xliff b/apps/ios/SimpleX Localizations/hr.xcloc/Localized Contents/hr.xliff index bdb3083f5a..6ad4d159c7 100644 --- a/apps/ios/SimpleX Localizations/hr.xcloc/Localized Contents/hr.xliff +++ b/apps/ios/SimpleX Localizations/hr.xcloc/Localized Contents/hr.xliff @@ -2619,8 +2619,8 @@ We will be adding server redundancy to prevent lost messages. The old database was not removed during the migration, it can be deleted. No comment provided by engineer. - - The profile is only shared with your contacts. + + Your profile is stored on your device and only shared with your contacts. No comment provided by engineer. 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 9be5879eb6..78bee138e4 100644 --- a/apps/ios/SimpleX Localizations/hu.xcloc/Localized Contents/hu.xliff +++ b/apps/ios/SimpleX Localizations/hu.xcloc/Localized Contents/hu.xliff @@ -7763,11 +7763,6 @@ Ez valamilyen hiba vagy sérült kapcsolat esetén fordulhat elő. A régi adatbázis nem lett eltávolítva az átköltöztetéskor, ezért törölhető. No comment provided by engineer. - - The profile is only shared with your contacts. - A profilja csak a partnereivel van megosztva. - No comment provided by engineer. - The same conditions will apply to operator **%@**. Ugyanezek a feltételek lesznek elfogadva a következő üzemeltető számára is: **%@**. @@ -9081,6 +9076,11 @@ Megismétli a meghívási kérést? A(z) **%@** nevű profilja meg lesz osztva. No comment provided by engineer. + + Your profile is stored on your device and only shared with your contacts. + A profilja csak a partnereivel van megosztva. + No comment provided by engineer. + Your profile is stored on your device and shared only with your contacts. SimpleX servers cannot see your profile. A profilja az eszközén van tárolva és csak a partnereivel van megosztva. A SimpleX-kiszolgálók nem láthatják a profilját. @@ -9091,11 +9091,6 @@ Megismétli a meghívási kérést? A profilja módosult. Ha elmenti, a profilfrissítés el lesz küldve a partnerei számára. alert message - - Your profile, contacts and delivered messages are stored on your device. - A profilja, a partnerei és az elküldött üzenetei a saját eszközén vannak tárolva. - No comment provided by engineer. - Your random profile Véletlenszerű profil 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 0c0c12004e..cf5f61918f 100644 --- a/apps/ios/SimpleX Localizations/it.xcloc/Localized Contents/it.xliff +++ b/apps/ios/SimpleX Localizations/it.xcloc/Localized Contents/it.xliff @@ -7763,11 +7763,6 @@ Può accadere a causa di qualche bug o quando la connessione è compromessa.Il database vecchio non è stato rimosso durante la migrazione, può essere eliminato. No comment provided by engineer. - - The profile is only shared with your contacts. - Il profilo è condiviso solo con i tuoi contatti. - No comment provided by engineer. - The same conditions will apply to operator **%@**. Le stesse condizioni si applicheranno all'operatore **%@**. @@ -9081,6 +9076,11 @@ Ripetere la richiesta di connessione? Verrà condiviso il tuo profilo **%@**. No comment provided by engineer. + + Your profile is stored on your device and only shared with your contacts. + Il profilo è condiviso solo con i tuoi contatti. + No comment provided by engineer. + Your profile is stored on your device and shared only with your contacts. SimpleX servers cannot see your profile. Il tuo profilo è memorizzato sul tuo dispositivo e condiviso solo con i tuoi contatti. I server di SimpleX non possono vedere il tuo profilo. @@ -9091,11 +9091,6 @@ Ripetere la richiesta di connessione? Il tuo profilo è stato cambiato. Se lo salvi, il profilo aggiornato verrà inviato a tutti i tuoi contatti. alert message - - Your profile, contacts and delivered messages are stored on your device. - Il tuo profilo, i contatti e i messaggi recapitati sono memorizzati sul tuo dispositivo. - No comment provided by engineer. - Your random profile Il tuo profilo casuale 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 26f415dd13..27134216a7 100644 --- a/apps/ios/SimpleX Localizations/ja.xcloc/Localized Contents/ja.xliff +++ b/apps/ios/SimpleX Localizations/ja.xcloc/Localized Contents/ja.xliff @@ -1990,6 +1990,7 @@ This is your own one-time link! Create profile + プロフィールを作成する No comment provided by engineer. @@ -7125,11 +7126,6 @@ It can happen because of some bug or when the connection is compromised.古いデータベースは移行時に削除されなかったので、削除することができます。 No comment provided by engineer. - - The profile is only shared with your contacts. - プロフィールは連絡先にしか共有されません。 - No comment provided by engineer. - The same conditions will apply to operator **%@**. No comment provided by engineer. @@ -8315,6 +8311,11 @@ Repeat connection request? あなたのプロファイル **%@** が共有されます。 No comment provided by engineer. + + Your profile is stored on your device and only shared with your contacts. + プロフィールは連絡先にしか共有されません。 + No comment provided by engineer. + Your profile is stored on your device and shared only with your contacts. SimpleX servers cannot see your profile. プロフィールはデバイスに保存され、連絡先とのみ共有されます。 SimpleX サーバーはあなたのプロファイルを参照できません。 @@ -8324,11 +8325,6 @@ Repeat connection request? Your profile was changed. If you save it, the updated profile will be sent to all your contacts. alert message - - Your profile, contacts and delivered messages are stored on your device. - あなたのプロフィール、連絡先、送信したメッセージがご自分の端末に保存されます。 - No comment provided by engineer. - Your random profile あなたのランダム・プロフィール diff --git a/apps/ios/SimpleX Localizations/ko.xcloc/Localized Contents/ko.xliff b/apps/ios/SimpleX Localizations/ko.xcloc/Localized Contents/ko.xliff index e35732f046..019f63cbc0 100644 --- a/apps/ios/SimpleX Localizations/ko.xcloc/Localized Contents/ko.xliff +++ b/apps/ios/SimpleX Localizations/ko.xcloc/Localized Contents/ko.xliff @@ -2867,8 +2867,8 @@ We will be adding server redundancy to prevent lost messages. The old database was not removed during the migration, it can be deleted. No comment provided by engineer. - - The profile is only shared with your contacts. + + Your profile is stored on your device and only shared with your contacts. No comment provided by engineer. diff --git a/apps/ios/SimpleX Localizations/lt.xcloc/Localized Contents/lt.xliff b/apps/ios/SimpleX Localizations/lt.xcloc/Localized Contents/lt.xliff index 54a713478f..0f795170c6 100644 --- a/apps/ios/SimpleX Localizations/lt.xcloc/Localized Contents/lt.xliff +++ b/apps/ios/SimpleX Localizations/lt.xcloc/Localized Contents/lt.xliff @@ -2631,8 +2631,8 @@ We will be adding server redundancy to prevent lost messages. The old database was not removed during the migration, it can be deleted. No comment provided by engineer. - - The profile is only shared with your contacts. + + Your profile is stored on your device and only shared with your contacts. No comment provided by engineer. 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 681502e255..4008c57ac0 100644 --- a/apps/ios/SimpleX Localizations/nl.xcloc/Localized Contents/nl.xliff +++ b/apps/ios/SimpleX Localizations/nl.xcloc/Localized Contents/nl.xliff @@ -7760,11 +7760,6 @@ Het kan gebeuren vanwege een bug of wanneer de verbinding is aangetast. De oude database is niet verwijderd tijdens de migratie, deze kan worden verwijderd. No comment provided by engineer. - - The profile is only shared with your contacts. - Het profiel wordt alleen gedeeld met uw contacten. - No comment provided by engineer. - The same conditions will apply to operator **%@**. Dezelfde voorwaarden gelden voor operator **%@**. @@ -9074,6 +9069,11 @@ Verbindingsverzoek herhalen? Uw profiel **%@** wordt gedeeld. No comment provided by engineer. + + Your profile is stored on your device and only shared with your contacts. + Het profiel wordt alleen gedeeld met uw contacten. + No comment provided by engineer. + Your profile is stored on your device and shared only with your contacts. SimpleX servers cannot see your profile. Uw profiel wordt op uw apparaat opgeslagen en alleen gedeeld met uw contacten. SimpleX servers kunnen uw profiel niet zien. @@ -9084,11 +9084,6 @@ Verbindingsverzoek herhalen? Je profiel is gewijzigd. Als je het opslaat, wordt het bijgewerkte profiel naar al je contacten verzonden. alert message - - Your profile, contacts and delivered messages are stored on your device. - Uw profiel, contacten en afgeleverde berichten worden op uw apparaat opgeslagen. - No comment provided by engineer. - Your random profile Je willekeurige profiel 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 01bc0b8508..175c8b4112 100644 --- a/apps/ios/SimpleX Localizations/pl.xcloc/Localized Contents/pl.xliff +++ b/apps/ios/SimpleX Localizations/pl.xcloc/Localized Contents/pl.xliff @@ -7583,11 +7583,6 @@ Może się to zdarzyć z powodu jakiegoś błędu lub gdy połączenie jest skom Stara baza danych nie została usunięta podczas migracji, można ją usunąć. No comment provided by engineer. - - The profile is only shared with your contacts. - Profil jest udostępniany tylko Twoim kontaktom. - No comment provided by engineer. - The same conditions will apply to operator **%@**. No comment provided by engineer. @@ -8870,6 +8865,11 @@ Powtórzyć prośbę połączenia? Twój profil **%@** zostanie udostępniony. No comment provided by engineer. + + Your profile is stored on your device and only shared with your contacts. + Profil jest udostępniany tylko Twoim kontaktom. + No comment provided by engineer. + Your profile is stored on your device and shared only with your contacts. SimpleX servers cannot see your profile. Twój profil jest przechowywany na urządzeniu i udostępniany tylko Twoim kontaktom. Serwery SimpleX nie mogą zobaczyć Twojego profilu. @@ -8880,11 +8880,6 @@ Powtórzyć prośbę połączenia? Twój profil został zmieniony. Jeśli go zapiszesz, zaktualizowany profil zostanie wysłany do wszystkich kontaktów. alert message - - Your profile, contacts and delivered messages are stored on your device. - Twój profil, kontakty i dostarczone wiadomości są przechowywane na Twoim urządzeniu. - No comment provided by engineer. - Your random profile Twój losowy profil diff --git a/apps/ios/SimpleX Localizations/pt-BR.xcloc/Localized Contents/pt-BR.xliff b/apps/ios/SimpleX Localizations/pt-BR.xcloc/Localized Contents/pt-BR.xliff index 93ba6f357b..bbb6c7d22a 100644 --- a/apps/ios/SimpleX Localizations/pt-BR.xcloc/Localized Contents/pt-BR.xliff +++ b/apps/ios/SimpleX Localizations/pt-BR.xcloc/Localized Contents/pt-BR.xliff @@ -3002,8 +3002,8 @@ We will be adding server redundancy to prevent lost messages. The old database was not removed during the migration, it can be deleted. No comment provided by engineer. - - The profile is only shared with your contacts. + + Your profile is stored on your device and only shared with your contacts. O perfil é compartilhado apenas com seus contatos. No comment provided by engineer. diff --git a/apps/ios/SimpleX Localizations/pt.xcloc/Localized Contents/pt.xliff b/apps/ios/SimpleX Localizations/pt.xcloc/Localized Contents/pt.xliff index de1787bdad..bc8bf79da1 100644 --- a/apps/ios/SimpleX Localizations/pt.xcloc/Localized Contents/pt.xliff +++ b/apps/ios/SimpleX Localizations/pt.xcloc/Localized Contents/pt.xliff @@ -3146,8 +3146,8 @@ It can happen because of some bug or when the connection is compromised.The old database was not removed during the migration, it can be deleted. No comment provided by engineer. - - The profile is only shared with your contacts. + + Your profile is stored on your device and only shared with your contacts. No comment provided by engineer. 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 a7b63e38ba..419fa75375 100644 --- a/apps/ios/SimpleX Localizations/ru.xcloc/Localized Contents/ru.xliff +++ b/apps/ios/SimpleX Localizations/ru.xcloc/Localized Contents/ru.xliff @@ -7715,11 +7715,6 @@ It can happen because of some bug or when the connection is compromised.Предыдущая версия данных чата не удалена при перемещении, её можно удалить. No comment provided by engineer. - - The profile is only shared with your contacts. - Профиль отправляется только Вашим контактам. - No comment provided by engineer. - The same conditions will apply to operator **%@**. Те же самые условия будут приняты для оператора **%@**. @@ -9021,6 +9016,11 @@ Repeat connection request? Будет отправлен Ваш профиль **%@**. No comment provided by engineer. + + Your profile is stored on your device and only shared with your contacts. + Ваш профиль храниться на Вашем устройстве и отправляется только контактам. + No comment provided by engineer. + Your profile is stored on your device and shared only with your contacts. SimpleX servers cannot see your profile. Ваш профиль хранится на Вашем устройстве и отправляется только Вашим контактам. SimpleX серверы не могут получить доступ к Вашему профилю. @@ -9031,11 +9031,6 @@ Repeat connection request? Ваш профиль был изменен. Если вы сохраните его, обновленный профиль будет отправлен всем вашим контактам. alert message - - Your profile, contacts and delivered messages are stored on your device. - Ваш профиль, контакты и доставленные сообщения хранятся на Вашем устройстве. - No comment provided by engineer. - Your random profile Случайный профиль 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 be68dc9780..671dd87d7d 100644 --- a/apps/ios/SimpleX Localizations/th.xcloc/Localized Contents/th.xliff +++ b/apps/ios/SimpleX Localizations/th.xcloc/Localized Contents/th.xliff @@ -7028,11 +7028,6 @@ It can happen because of some bug or when the connection is compromised.ฐานข้อมูลเก่าไม่ได้ถูกลบในระหว่างการย้ายข้อมูล แต่สามารถลบได้ No comment provided by engineer. - - The profile is only shared with your contacts. - โปรไฟล์นี้แชร์กับผู้ติดต่อของคุณเท่านั้น - No comment provided by engineer. - The same conditions will apply to operator **%@**. No comment provided by engineer. @@ -8212,6 +8207,11 @@ Repeat connection request? Your profile **%@** will be shared. No comment provided by engineer. + + Your profile is stored on your device and only shared with your contacts. + โปรไฟล์นี้แชร์กับผู้ติดต่อของคุณเท่านั้น + No comment provided by engineer. + Your profile is stored on your device and shared only with your contacts. SimpleX servers cannot see your profile. โปรไฟล์ของคุณจะถูกจัดเก็บไว้ในอุปกรณ์ของคุณและแชร์กับผู้ติดต่อของคุณเท่านั้น เซิร์ฟเวอร์ SimpleX ไม่สามารถดูโปรไฟล์ของคุณได้ @@ -8221,11 +8221,6 @@ Repeat connection request? Your profile was changed. If you save it, the updated profile will be sent to all your contacts. alert message - - Your profile, contacts and delivered messages are stored on your device. - โปรไฟล์ รายชื่อผู้ติดต่อ และข้อความที่ส่งของคุณจะถูกจัดเก็บไว้ในอุปกรณ์ของคุณ - No comment provided by engineer. - Your random profile โปรไฟล์แบบสุ่มของคุณ 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 6eb1daf84b..bbee40c2b9 100644 --- a/apps/ios/SimpleX Localizations/tr.xcloc/Localized Contents/tr.xliff +++ b/apps/ios/SimpleX Localizations/tr.xcloc/Localized Contents/tr.xliff @@ -7599,11 +7599,6 @@ Bazı hatalar nedeniyle veya bağlantı tehlikeye girdiğinde meydana gelebilir. Eski veritabanı geçiş sırasında kaldırılmadı, silinebilir. No comment provided by engineer. - - The profile is only shared with your contacts. - Profil sadece kişilerinle paylaşılacak. - No comment provided by engineer. - The same conditions will apply to operator **%@**. No comment provided by engineer. @@ -8886,6 +8881,11 @@ Bağlantı isteği tekrarlansın mı? Profiliniz **%@** paylaşılacaktır. No comment provided by engineer. + + Your profile is stored on your device and only shared with your contacts. + Profil sadece kişilerinle paylaşılacak. + No comment provided by engineer. + Your profile is stored on your device and shared only with your contacts. SimpleX servers cannot see your profile. Profiliniz cihazınızda saklanır ve sadece kişilerinizle paylaşılır. SimpleX sunucuları profilinizi göremez. @@ -8896,11 +8896,6 @@ Bağlantı isteği tekrarlansın mı? Profiliniz değiştirildi. Kaydederseniz, güncellenmiş profil tüm kişilerinize gönderilecektir. alert message - - Your profile, contacts and delivered messages are stored on your device. - Profiliniz, kişileriniz ve gönderilmiş mesajlar cihazınızda saklanır. - No comment provided by engineer. - Your random profile Rasgele profiliniz 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 7c8c6f4254..c0375e3b02 100644 --- a/apps/ios/SimpleX Localizations/uk.xcloc/Localized Contents/uk.xliff +++ b/apps/ios/SimpleX Localizations/uk.xcloc/Localized Contents/uk.xliff @@ -7638,11 +7638,6 @@ It can happen because of some bug or when the connection is compromised.Стара база даних не була видалена під час міграції, її можна видалити. No comment provided by engineer. - - The profile is only shared with your contacts. - Профіль доступний лише вашим контактам. - No comment provided by engineer. - The same conditions will apply to operator **%@**. Такі ж умови діятимуть і для оператора **%@**. @@ -8945,6 +8940,11 @@ Repeat connection request? Ваш профіль **%@** буде опублікований. No comment provided by engineer. + + Your profile is stored on your device and only shared with your contacts. + Профіль доступний лише вашим контактам. + No comment provided by engineer. + Your profile is stored on your device and shared only with your contacts. SimpleX servers cannot see your profile. Ваш профіль зберігається на вашому пристрої і доступний лише вашим контактам. Сервери SimpleX не бачать ваш профіль. @@ -8955,11 +8955,6 @@ Repeat connection request? Ваш профіль було змінено. Якщо ви збережете його, оновлений профіль буде надіслано всім вашим контактам. alert message - - Your profile, contacts and delivered messages are stored on your device. - Ваш профіль, контакти та доставлені повідомлення зберігаються на вашому пристрої. - No comment provided by engineer. - Your random profile Ваш випадковий профіль 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 03e053326a..d5411f86e3 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 @@ -7708,11 +7708,6 @@ It can happen because of some bug or when the connection is compromised.旧数据库在迁移过程中没有被移除,可以删除。 No comment provided by engineer. - - The profile is only shared with your contacts. - 该资料仅与您的联系人共享。 - No comment provided by engineer. - The same conditions will apply to operator **%@**. No comment provided by engineer. @@ -8987,6 +8982,11 @@ Repeat connection request? 您的个人资料 **%@** 将被共享。 No comment provided by engineer. + + Your profile is stored on your device and only shared with your contacts. + 该资料仅与您的联系人共享。 + No comment provided by engineer. + Your profile is stored on your device and shared only with your contacts. SimpleX servers cannot see your profile. 您的资料存储在您的设备上并仅与您的联系人共享。 SimpleX 服务器无法看到您的资料。 @@ -8996,11 +8996,6 @@ Repeat connection request? Your profile was changed. If you save it, the updated profile will be sent to all your contacts. alert message - - Your profile, contacts and delivered messages are stored on your device. - 您的资料、联系人和发送的消息存储在您的设备上。 - No comment provided by engineer. - Your random profile 您的随机资料 diff --git a/apps/ios/SimpleX Localizations/zh-Hant.xcloc/Localized Contents/zh-Hant.xliff b/apps/ios/SimpleX Localizations/zh-Hant.xcloc/Localized Contents/zh-Hant.xliff index 8a771369e6..3ea46ee364 100644 --- a/apps/ios/SimpleX Localizations/zh-Hant.xcloc/Localized Contents/zh-Hant.xliff +++ b/apps/ios/SimpleX Localizations/zh-Hant.xcloc/Localized Contents/zh-Hant.xliff @@ -3054,8 +3054,8 @@ We will be adding server redundancy to prevent lost messages. 舊的數據庫在遷移過程中沒有被移除,可以刪除。 No comment provided by engineer. - - The profile is only shared with your contacts. + + Your profile is stored on your device and only shared with your contacts. 你的個人檔案只會和你的聯絡人分享。 No comment provided by engineer. diff --git a/apps/ios/SimpleX.xcodeproj/project.pbxproj b/apps/ios/SimpleX.xcodeproj/project.pbxproj index 5ebc7f9b4b..9326ae9abe 100644 --- a/apps/ios/SimpleX.xcodeproj/project.pbxproj +++ b/apps/ios/SimpleX.xcodeproj/project.pbxproj @@ -174,8 +174,8 @@ 64C3B0212A0D359700E19930 /* CustomTimePicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64C3B0202A0D359700E19930 /* CustomTimePicker.swift */; }; 64C8299D2D54AEEE006B9E89 /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C829982D54AEED006B9E89 /* libgmp.a */; }; 64C8299E2D54AEEE006B9E89 /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C829992D54AEEE006B9E89 /* libffi.a */; }; - 64C8299F2D54AEEE006B9E89 /* libHSsimplex-chat-6.3.4.1-Cm6JGiMgJjo4088oWn41JO-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C8299A2D54AEEE006B9E89 /* libHSsimplex-chat-6.3.4.1-Cm6JGiMgJjo4088oWn41JO-ghc9.6.3.a */; }; - 64C829A02D54AEEE006B9E89 /* libHSsimplex-chat-6.3.4.1-Cm6JGiMgJjo4088oWn41JO.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C8299B2D54AEEE006B9E89 /* libHSsimplex-chat-6.3.4.1-Cm6JGiMgJjo4088oWn41JO.a */; }; + 64C8299F2D54AEEE006B9E89 /* libHSsimplex-chat-6.3.6.0-64eNxtIoLF9BaOhAoPagss-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C8299A2D54AEEE006B9E89 /* libHSsimplex-chat-6.3.6.0-64eNxtIoLF9BaOhAoPagss-ghc9.6.3.a */; }; + 64C829A02D54AEEE006B9E89 /* libHSsimplex-chat-6.3.6.0-64eNxtIoLF9BaOhAoPagss.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C8299B2D54AEEE006B9E89 /* libHSsimplex-chat-6.3.6.0-64eNxtIoLF9BaOhAoPagss.a */; }; 64C829A12D54AEEE006B9E89 /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C8299C2D54AEEE006B9E89 /* libgmpxx.a */; }; 64D0C2C029F9688300B38D5F /* UserAddressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64D0C2BF29F9688300B38D5F /* UserAddressView.swift */; }; 64D0C2C229FA57AB00B38D5F /* UserAddressLearnMore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64D0C2C129FA57AB00B38D5F /* UserAddressLearnMore.swift */; }; @@ -533,8 +533,8 @@ 64C3B0202A0D359700E19930 /* CustomTimePicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomTimePicker.swift; sourceTree = ""; }; 64C829982D54AEED006B9E89 /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = ""; }; 64C829992D54AEEE006B9E89 /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = ""; }; - 64C8299A2D54AEEE006B9E89 /* libHSsimplex-chat-6.3.4.1-Cm6JGiMgJjo4088oWn41JO-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.3.4.1-Cm6JGiMgJjo4088oWn41JO-ghc9.6.3.a"; sourceTree = ""; }; - 64C8299B2D54AEEE006B9E89 /* libHSsimplex-chat-6.3.4.1-Cm6JGiMgJjo4088oWn41JO.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.3.4.1-Cm6JGiMgJjo4088oWn41JO.a"; sourceTree = ""; }; + 64C8299A2D54AEEE006B9E89 /* libHSsimplex-chat-6.3.6.0-64eNxtIoLF9BaOhAoPagss-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.3.6.0-64eNxtIoLF9BaOhAoPagss-ghc9.6.3.a"; sourceTree = ""; }; + 64C8299B2D54AEEE006B9E89 /* libHSsimplex-chat-6.3.6.0-64eNxtIoLF9BaOhAoPagss.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.3.6.0-64eNxtIoLF9BaOhAoPagss.a"; sourceTree = ""; }; 64C8299C2D54AEEE006B9E89 /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = ""; }; 64D0C2BF29F9688300B38D5F /* UserAddressView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserAddressView.swift; sourceTree = ""; }; 64D0C2C129FA57AB00B38D5F /* UserAddressLearnMore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserAddressLearnMore.swift; sourceTree = ""; }; @@ -692,8 +692,8 @@ 64C8299D2D54AEEE006B9E89 /* libgmp.a in Frameworks */, 64C8299E2D54AEEE006B9E89 /* libffi.a in Frameworks */, 64C829A12D54AEEE006B9E89 /* libgmpxx.a in Frameworks */, - 64C8299F2D54AEEE006B9E89 /* libHSsimplex-chat-6.3.4.1-Cm6JGiMgJjo4088oWn41JO-ghc9.6.3.a in Frameworks */, - 64C829A02D54AEEE006B9E89 /* libHSsimplex-chat-6.3.4.1-Cm6JGiMgJjo4088oWn41JO.a in Frameworks */, + 64C8299F2D54AEEE006B9E89 /* libHSsimplex-chat-6.3.6.0-64eNxtIoLF9BaOhAoPagss-ghc9.6.3.a in Frameworks */, + 64C829A02D54AEEE006B9E89 /* libHSsimplex-chat-6.3.6.0-64eNxtIoLF9BaOhAoPagss.a in Frameworks */, CE38A29C2C3FCD72005ED185 /* SwiftyGif in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -778,8 +778,8 @@ 64C829992D54AEEE006B9E89 /* libffi.a */, 64C829982D54AEED006B9E89 /* libgmp.a */, 64C8299C2D54AEEE006B9E89 /* libgmpxx.a */, - 64C8299A2D54AEEE006B9E89 /* libHSsimplex-chat-6.3.4.1-Cm6JGiMgJjo4088oWn41JO-ghc9.6.3.a */, - 64C8299B2D54AEEE006B9E89 /* libHSsimplex-chat-6.3.4.1-Cm6JGiMgJjo4088oWn41JO.a */, + 64C8299A2D54AEEE006B9E89 /* libHSsimplex-chat-6.3.6.0-64eNxtIoLF9BaOhAoPagss-ghc9.6.3.a */, + 64C8299B2D54AEEE006B9E89 /* libHSsimplex-chat-6.3.6.0-64eNxtIoLF9BaOhAoPagss.a */, ); path = Libraries; sourceTree = ""; @@ -1971,7 +1971,7 @@ CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES; CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 277; + CURRENT_PROJECT_VERSION = 282; DEAD_CODE_STRIPPING = YES; DEVELOPMENT_TEAM = 5NN7GUYB6T; ENABLE_BITCODE = NO; @@ -1996,7 +1996,7 @@ "@executable_path/Frameworks", ); LLVM_LTO = YES_THIN; - MARKETING_VERSION = 6.3.4; + MARKETING_VERSION = 6.3.6; OTHER_LDFLAGS = "-Wl,-stack_size,0x1000000"; PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.app; PRODUCT_NAME = SimpleX; @@ -2021,7 +2021,7 @@ CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES; CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 277; + CURRENT_PROJECT_VERSION = 282; DEAD_CODE_STRIPPING = YES; DEVELOPMENT_TEAM = 5NN7GUYB6T; ENABLE_BITCODE = NO; @@ -2046,7 +2046,7 @@ "@executable_path/Frameworks", ); LLVM_LTO = YES; - MARKETING_VERSION = 6.3.4; + MARKETING_VERSION = 6.3.6; OTHER_LDFLAGS = "-Wl,-stack_size,0x1000000"; PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.app; PRODUCT_NAME = SimpleX; @@ -2063,11 +2063,11 @@ buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 277; + CURRENT_PROJECT_VERSION = 282; DEVELOPMENT_TEAM = 5NN7GUYB6T; GENERATE_INFOPLIST_FILE = YES; IPHONEOS_DEPLOYMENT_TARGET = 15.0; - MARKETING_VERSION = 6.3.4; + MARKETING_VERSION = 6.3.6; PRODUCT_BUNDLE_IDENTIFIER = "chat.simplex.Tests-iOS"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; @@ -2083,11 +2083,11 @@ buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 277; + CURRENT_PROJECT_VERSION = 282; DEVELOPMENT_TEAM = 5NN7GUYB6T; GENERATE_INFOPLIST_FILE = YES; IPHONEOS_DEPLOYMENT_TARGET = 15.0; - MARKETING_VERSION = 6.3.4; + MARKETING_VERSION = 6.3.6; PRODUCT_BUNDLE_IDENTIFIER = "chat.simplex.Tests-iOS"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; @@ -2108,7 +2108,7 @@ CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 277; + CURRENT_PROJECT_VERSION = 282; DEVELOPMENT_TEAM = 5NN7GUYB6T; ENABLE_BITCODE = NO; GCC_OPTIMIZATION_LEVEL = s; @@ -2123,7 +2123,7 @@ "@executable_path/../../Frameworks", ); LLVM_LTO = YES; - MARKETING_VERSION = 6.3.4; + MARKETING_VERSION = 6.3.6; PRODUCT_BUNDLE_IDENTIFIER = "chat.simplex.app.SimpleX-NSE"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -2145,7 +2145,7 @@ CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 277; + CURRENT_PROJECT_VERSION = 282; DEVELOPMENT_TEAM = 5NN7GUYB6T; ENABLE_BITCODE = NO; ENABLE_CODE_COVERAGE = NO; @@ -2160,7 +2160,7 @@ "@executable_path/../../Frameworks", ); LLVM_LTO = YES; - MARKETING_VERSION = 6.3.4; + MARKETING_VERSION = 6.3.6; PRODUCT_BUNDLE_IDENTIFIER = "chat.simplex.app.SimpleX-NSE"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -2182,7 +2182,7 @@ CLANG_TIDY_BUGPRONE_REDUNDANT_BRANCH_CONDITION = YES; CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 277; + CURRENT_PROJECT_VERSION = 282; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5NN7GUYB6T; DYLIB_COMPATIBILITY_VERSION = 1; @@ -2208,7 +2208,7 @@ "$(PROJECT_DIR)/Libraries/sim", ); LLVM_LTO = YES; - MARKETING_VERSION = 6.3.4; + MARKETING_VERSION = 6.3.6; PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.SimpleXChat; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SDKROOT = iphoneos; @@ -2233,7 +2233,7 @@ CLANG_TIDY_BUGPRONE_REDUNDANT_BRANCH_CONDITION = YES; CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 277; + CURRENT_PROJECT_VERSION = 282; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5NN7GUYB6T; DYLIB_COMPATIBILITY_VERSION = 1; @@ -2259,7 +2259,7 @@ "$(PROJECT_DIR)/Libraries/sim", ); LLVM_LTO = YES; - MARKETING_VERSION = 6.3.4; + MARKETING_VERSION = 6.3.6; PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.SimpleXChat; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SDKROOT = iphoneos; @@ -2284,7 +2284,7 @@ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; CODE_SIGN_ENTITLEMENTS = "SimpleX SE/SimpleX SE.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 277; + CURRENT_PROJECT_VERSION = 282; DEVELOPMENT_TEAM = 5NN7GUYB6T; ENABLE_USER_SCRIPT_SANDBOXING = YES; GCC_C_LANGUAGE_STANDARD = gnu17; @@ -2299,7 +2299,7 @@ "@executable_path/../../Frameworks", ); LOCALIZATION_PREFERS_STRING_CATALOGS = YES; - MARKETING_VERSION = 6.3.4; + MARKETING_VERSION = 6.3.6; PRODUCT_BUNDLE_IDENTIFIER = "chat.simplex.app.SimpleX-SE"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; @@ -2318,7 +2318,7 @@ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; CODE_SIGN_ENTITLEMENTS = "SimpleX SE/SimpleX SE.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 277; + CURRENT_PROJECT_VERSION = 282; DEVELOPMENT_TEAM = 5NN7GUYB6T; ENABLE_USER_SCRIPT_SANDBOXING = YES; GCC_C_LANGUAGE_STANDARD = gnu17; @@ -2333,7 +2333,7 @@ "@executable_path/../../Frameworks", ); LOCALIZATION_PREFERS_STRING_CATALOGS = YES; - MARKETING_VERSION = 6.3.4; + MARKETING_VERSION = 6.3.6; PRODUCT_BUNDLE_IDENTIFIER = "chat.simplex.app.SimpleX-SE"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; diff --git a/apps/ios/SimpleXChat/ChatTypes.swift b/apps/ios/SimpleXChat/ChatTypes.swift index 960fdd466d..88246465e1 100644 --- a/apps/ios/SimpleXChat/ChatTypes.swift +++ b/apps/ios/SimpleXChat/ChatTypes.swift @@ -1333,6 +1333,19 @@ public enum ChatInfo: Identifiable, Decodable, NamedChat, Hashable { } } + public var userCantSendReason: (composeLabel: LocalizedStringKey, alertMessage: LocalizedStringKey?)? { + get { + switch self { + case let .direct(contact): return contact.userCantSendReason + case let .group(groupInfo): return groupInfo.userCantSendReason + case let .local(noteFolder): return noteFolder.userCantSendReason + case let .contactRequest(contactRequest): return contactRequest.userCantSendReason + case let .contactConnection(contactConnection): return contactConnection.userCantSendReason + case .invalidJSON: return ("can't send messages", nil) + } + } + } + public var sendMsgEnabled: Bool { get { switch self { @@ -1642,15 +1655,16 @@ public struct Contact: Identifiable, Decodable, NamedChat, Hashable { public var ready: Bool { get { activeConn?.connStatus == .ready } } public var sndReady: Bool { get { ready || activeConn?.connStatus == .sndReady } } public var active: Bool { get { contactStatus == .active } } - public var sendMsgEnabled: Bool { get { - ( - sndReady - && active - && !(activeConn?.connectionStats?.ratchetSyncSendProhibited ?? false) - && !(activeConn?.connDisabled ?? true) - ) - || nextSendGrpInv - } } + public var userCantSendReason: (composeLabel: LocalizedStringKey, alertMessage: LocalizedStringKey?)? { + // TODO [short links] this will have additional statuses for pending contact requests before they are accepted + if nextSendGrpInv { return nil } + if !active { return ("contact deleted", nil) } + if !sndReady { return ("contact not ready", nil) } + if activeConn?.connectionStats?.ratchetSyncSendProhibited ?? false { return ("not synchronized", nil) } + if activeConn?.connDisabled ?? true { return ("contact disabled", nil) } + return nil + } + public var sendMsgEnabled: Bool { userCantSendReason == nil } public var nextSendGrpInv: Bool { get { contactGroupMemberId != nil && !contactGrpInvSent } } public var displayName: String { localAlias == "" ? profile.displayName : localAlias } public var fullName: String { get { profile.fullName } } @@ -1829,6 +1843,7 @@ public struct UserContactRequest: Decodable, NamedChat, Hashable { public var id: ChatId { get { "<@\(contactRequestId)" } } public var apiId: Int64 { get { contactRequestId } } var ready: Bool { get { true } } + public var userCantSendReason: (composeLabel: LocalizedStringKey, alertMessage: LocalizedStringKey?)? { ("can't send messages", nil) } public var sendMsgEnabled: Bool { get { false } } public var displayName: String { get { profile.displayName } } public var fullName: String { get { profile.fullName } } @@ -1861,6 +1876,7 @@ public struct PendingContactConnection: Decodable, NamedChat, Hashable { public var id: ChatId { get { ":\(pccConnId)" } } public var apiId: Int64 { get { pccConnId } } var ready: Bool { get { false } } + public var userCantSendReason: (composeLabel: LocalizedStringKey, alertMessage: LocalizedStringKey?)? { ("can't send messages", nil) } public var sendMsgEnabled: Bool { get { false } } var localDisplayName: String { get { String.localizedStringWithFormat(NSLocalizedString("connection:%@", comment: "connection information"), pccConnId) } @@ -1990,7 +2006,20 @@ public struct GroupInfo: Identifiable, Decodable, NamedChat, Hashable { public var id: ChatId { get { "#\(groupId)" } } public var apiId: Int64 { get { groupId } } public var ready: Bool { get { true } } - public var sendMsgEnabled: Bool { get { membership.memberActive } } + public var userCantSendReason: (composeLabel: LocalizedStringKey, alertMessage: LocalizedStringKey?)? { + return if membership.memberActive { + membership.memberRole == .observer ? ("you are observer", "Please contact group admin.") : nil + } else { + switch membership.memberStatus { + case .memRejected: ("request to join rejected", nil) + case .memGroupDeleted: ("group is deleted", nil) + case .memRemoved: ("removed from group", nil) + case .memLeft: ("you left", nil) + default: ("can't send messages", nil) + } + } + } + public var sendMsgEnabled: Bool { userCantSendReason == nil } public var displayName: String { localAlias == "" ? groupProfile.displayName : localAlias } public var fullName: String { get { groupProfile.fullName } } public var image: String? { get { groupProfile.image } } @@ -2357,6 +2386,7 @@ public struct NoteFolder: Identifiable, Decodable, NamedChat, Hashable { public var id: ChatId { get { "*\(noteFolderId)" } } public var apiId: Int64 { get { noteFolderId } } public var ready: Bool { get { true } } + public var userCantSendReason: (composeLabel: LocalizedStringKey, alertMessage: LocalizedStringKey?)? { nil } public var sendMsgEnabled: Bool { get { true } } public var displayName: String { get { ChatInfo.privateNotesChatName } } public var fullName: String { get { "" } } diff --git a/apps/ios/bg.lproj/Localizable.strings b/apps/ios/bg.lproj/Localizable.strings index f241158185..e4bc8f2150 100644 --- a/apps/ios/bg.lproj/Localizable.strings +++ b/apps/ios/bg.lproj/Localizable.strings @@ -3777,7 +3777,7 @@ chat item action */ "The old database was not removed during the migration, it can be deleted." = "Старата база данни не бе премахната по време на миграцията, тя може да бъде изтрита."; /* No comment provided by engineer. */ -"The profile is only shared with your contacts." = "Профилът се споделя само с вашите контакти."; +"Your profile is stored on your device and only shared with your contacts." = "Профилът се споделя само с вашите контакти."; /* No comment provided by engineer. */ "The second tick we missed! ✅" = "Втората отметка, която пропуснахме! ✅"; diff --git a/apps/ios/cs.lproj/Localizable.strings b/apps/ios/cs.lproj/Localizable.strings index 003ac23325..08a94615a3 100644 --- a/apps/ios/cs.lproj/Localizable.strings +++ b/apps/ios/cs.lproj/Localizable.strings @@ -822,6 +822,9 @@ set passcode view */ /* No comment provided by engineer. */ "Create new profile in [desktop app](https://simplex.chat/downloads/). 💻" = "Vytvořit nový profil v [desktop app](https://simplex.chat/downloads/). 💻"; +/* No comment provided by engineer. */ +"Create profile" = "Vytvořte si profil"; + /* server test step */ "Create queue" = "Vytvořit frontu"; @@ -2986,7 +2989,7 @@ chat item action */ "The old database was not removed during the migration, it can be deleted." = "Stará databáze nebyla během přenášení odstraněna, lze ji smazat."; /* No comment provided by engineer. */ -"The profile is only shared with your contacts." = "Profil je sdílen pouze s vašimi kontakty."; +"Your profile is stored on your device and only shared with your contacts." = "Profil je sdílen pouze s vašimi kontakty."; /* No comment provided by engineer. */ "The second tick we missed! ✅" = "Druhé zaškrtnutí jsme přehlédli! ✅"; diff --git a/apps/ios/de.lproj/Localizable.strings b/apps/ios/de.lproj/Localizable.strings index 0eab764216..8da7835c43 100644 --- a/apps/ios/de.lproj/Localizable.strings +++ b/apps/ios/de.lproj/Localizable.strings @@ -5101,7 +5101,7 @@ report reason */ "The old database was not removed during the migration, it can be deleted." = "Die alte Datenbank wurde während der Migration nicht entfernt. Sie kann gelöscht werden."; /* No comment provided by engineer. */ -"The profile is only shared with your contacts." = "Das Profil wird nur mit Ihren Kontakten geteilt."; +"Your profile is stored on your device and only shared with your contacts." = "Das Profil wird nur mit Ihren Kontakten geteilt."; /* No comment provided by engineer. */ "The same conditions will apply to operator **%@**." = "Dieselben Nutzungsbedingungen gelten auch für den Betreiber **%@**."; diff --git a/apps/ios/es.lproj/Localizable.strings b/apps/ios/es.lproj/Localizable.strings index e797b73b98..28ba0f0642 100644 --- a/apps/ios/es.lproj/Localizable.strings +++ b/apps/ios/es.lproj/Localizable.strings @@ -5101,7 +5101,7 @@ report reason */ "The old database was not removed during the migration, it can be deleted." = "La base de datos antigua no se eliminó durante la migración, puede eliminarse."; /* No comment provided by engineer. */ -"The profile is only shared with your contacts." = "El perfil sólo se comparte con tus contactos."; +"Your profile is stored on your device and only shared with your contacts." = "El perfil sólo se comparte con tus contactos."; /* No comment provided by engineer. */ "The same conditions will apply to operator **%@**." = "Las mismas condiciones se aplicarán al operador **%@**."; diff --git a/apps/ios/fi.lproj/Localizable.strings b/apps/ios/fi.lproj/Localizable.strings index c4031adf9a..4891c7fb26 100644 --- a/apps/ios/fi.lproj/Localizable.strings +++ b/apps/ios/fi.lproj/Localizable.strings @@ -768,6 +768,9 @@ set passcode view */ /* No comment provided by engineer. */ "Create new profile in [desktop app](https://simplex.chat/downloads/). 💻" = "Luo uusi profiili [työpöytäsovelluksessa](https://simplex.chat/downloads/). 💻"; +/* No comment provided by engineer. */ +"Create profile" = "Luo profiilisi"; + /* server test step */ "Create queue" = "Luo jono"; @@ -2908,7 +2911,7 @@ chat item action */ "The old database was not removed during the migration, it can be deleted." = "Vanhaa tietokantaa ei poistettu siirron aikana, se voidaan kuitenkin poistaa."; /* No comment provided by engineer. */ -"The profile is only shared with your contacts." = "Profiili jaetaan vain kontaktiesi kanssa."; +"Your profile is stored on your device and only shared with your contacts." = "Profiili jaetaan vain kontaktiesi kanssa."; /* No comment provided by engineer. */ "The second tick we missed! ✅" = "Toinen kuittaus, joka uupui! ✅"; diff --git a/apps/ios/fr.lproj/Localizable.strings b/apps/ios/fr.lproj/Localizable.strings index 1c16f8847d..4dd75039dc 100644 --- a/apps/ios/fr.lproj/Localizable.strings +++ b/apps/ios/fr.lproj/Localizable.strings @@ -4884,7 +4884,7 @@ chat item action */ "The old database was not removed during the migration, it can be deleted." = "L'ancienne base de données n'a pas été supprimée lors de la migration, elle peut être supprimée."; /* No comment provided by engineer. */ -"The profile is only shared with your contacts." = "Le profil n'est partagé qu'avec vos contacts."; +"Your profile is stored on your device and only shared with your contacts." = "Le profil n'est partagé qu'avec vos contacts."; /* No comment provided by engineer. */ "The same conditions will apply to operator **%@**." = "Les mêmes conditions s'appliquent à l'opérateur **%@**."; diff --git a/apps/ios/hu.lproj/Localizable.strings b/apps/ios/hu.lproj/Localizable.strings index c190cccaba..5a9b6b4e38 100644 --- a/apps/ios/hu.lproj/Localizable.strings +++ b/apps/ios/hu.lproj/Localizable.strings @@ -5101,7 +5101,7 @@ report reason */ "The old database was not removed during the migration, it can be deleted." = "A régi adatbázis nem lett eltávolítva az átköltöztetéskor, ezért törölhető."; /* No comment provided by engineer. */ -"The profile is only shared with your contacts." = "A profilja csak a partnereivel van megosztva."; +"Your profile is stored on your device and only shared with your contacts." = "A profilja csak a partnereivel van megosztva."; /* No comment provided by engineer. */ "The same conditions will apply to operator **%@**." = "Ugyanezek a feltételek lesznek elfogadva a következő üzemeltető számára is: **%@**."; diff --git a/apps/ios/it.lproj/Localizable.strings b/apps/ios/it.lproj/Localizable.strings index f67a492cc4..b914a06079 100644 --- a/apps/ios/it.lproj/Localizable.strings +++ b/apps/ios/it.lproj/Localizable.strings @@ -5101,7 +5101,7 @@ report reason */ "The old database was not removed during the migration, it can be deleted." = "Il database vecchio non è stato rimosso durante la migrazione, può essere eliminato."; /* No comment provided by engineer. */ -"The profile is only shared with your contacts." = "Il profilo è condiviso solo con i tuoi contatti."; +"Your profile is stored on your device and only shared with your contacts." = "Il profilo è condiviso solo con i tuoi contatti."; /* No comment provided by engineer. */ "The same conditions will apply to operator **%@**." = "Le stesse condizioni si applicheranno all'operatore **%@**."; diff --git a/apps/ios/ja.lproj/Localizable.strings b/apps/ios/ja.lproj/Localizable.strings index 9d0cccf591..d214f88e1c 100644 --- a/apps/ios/ja.lproj/Localizable.strings +++ b/apps/ios/ja.lproj/Localizable.strings @@ -957,6 +957,9 @@ set passcode view */ /* No comment provided by engineer. */ "Create new profile in [desktop app](https://simplex.chat/downloads/). 💻" = "[デスクトップアプリ](https://simplex.chat/downloads/)で新しいプロファイルを作成します。 💻"; +/* No comment provided by engineer. */ +"Create profile" = "プロフィールを作成する"; + /* server test step */ "Create queue" = "キューの作成"; @@ -3109,7 +3112,7 @@ chat item action */ "The old database was not removed during the migration, it can be deleted." = "古いデータベースは移行時に削除されなかったので、削除することができます。"; /* No comment provided by engineer. */ -"The profile is only shared with your contacts." = "プロフィールは連絡先にしか共有されません。"; +"Your profile is stored on your device and only shared with your contacts." = "プロフィールは連絡先にしか共有されません。"; /* No comment provided by engineer. */ "The second tick we missed! ✅" = "長らくお待たせしました! ✅"; diff --git a/apps/ios/nl.lproj/Localizable.strings b/apps/ios/nl.lproj/Localizable.strings index d2cfcba0de..232de56641 100644 --- a/apps/ios/nl.lproj/Localizable.strings +++ b/apps/ios/nl.lproj/Localizable.strings @@ -5092,7 +5092,7 @@ report reason */ "The old database was not removed during the migration, it can be deleted." = "De oude database is niet verwijderd tijdens de migratie, deze kan worden verwijderd."; /* No comment provided by engineer. */ -"The profile is only shared with your contacts." = "Het profiel wordt alleen gedeeld met uw contacten."; +"Your profile is stored on your device and only shared with your contacts." = "Het profiel wordt alleen gedeeld met uw contacten."; /* No comment provided by engineer. */ "The same conditions will apply to operator **%@**." = "Dezelfde voorwaarden gelden voor operator **%@**."; diff --git a/apps/ios/pl.lproj/Localizable.strings b/apps/ios/pl.lproj/Localizable.strings index 867f3beff4..31a9b87662 100644 --- a/apps/ios/pl.lproj/Localizable.strings +++ b/apps/ios/pl.lproj/Localizable.strings @@ -4557,7 +4557,7 @@ chat item action */ "The old database was not removed during the migration, it can be deleted." = "Stara baza danych nie została usunięta podczas migracji, można ją usunąć."; /* No comment provided by engineer. */ -"The profile is only shared with your contacts." = "Profil jest udostępniany tylko Twoim kontaktom."; +"Your profile is stored on your device and only shared with your contacts." = "Profil jest udostępniany tylko Twoim kontaktom."; /* No comment provided by engineer. */ "The second tick we missed! ✅" = "Drugi tik, który przegapiliśmy! ✅"; diff --git a/apps/ios/ru.lproj/Localizable.strings b/apps/ios/ru.lproj/Localizable.strings index b819d013b9..cb837836ff 100644 --- a/apps/ios/ru.lproj/Localizable.strings +++ b/apps/ios/ru.lproj/Localizable.strings @@ -4957,7 +4957,7 @@ report reason */ "The old database was not removed during the migration, it can be deleted." = "Предыдущая версия данных чата не удалена при перемещении, её можно удалить."; /* No comment provided by engineer. */ -"The profile is only shared with your contacts." = "Профиль отправляется только Вашим контактам."; +"Your profile is stored on your device and only shared with your contacts." = "Ваш профиль храниться на Вашем устройстве и отправляется только контактам."; /* No comment provided by engineer. */ "The same conditions will apply to operator **%@**." = "Те же самые условия будут приняты для оператора **%@**."; diff --git a/apps/ios/th.lproj/Localizable.strings b/apps/ios/th.lproj/Localizable.strings index 6b3381922a..57c0466eb9 100644 --- a/apps/ios/th.lproj/Localizable.strings +++ b/apps/ios/th.lproj/Localizable.strings @@ -2830,7 +2830,7 @@ chat item action */ "The old database was not removed during the migration, it can be deleted." = "ฐานข้อมูลเก่าไม่ได้ถูกลบในระหว่างการย้ายข้อมูล แต่สามารถลบได้"; /* No comment provided by engineer. */ -"The profile is only shared with your contacts." = "โปรไฟล์นี้แชร์กับผู้ติดต่อของคุณเท่านั้น"; +"Your profile is stored on your device and only shared with your contacts." = "โปรไฟล์นี้แชร์กับผู้ติดต่อของคุณเท่านั้น"; /* No comment provided by engineer. */ "The second tick we missed! ✅" = "ขีดที่สองที่เราพลาด! ✅"; diff --git a/apps/ios/tr.lproj/Localizable.strings b/apps/ios/tr.lproj/Localizable.strings index ab0703333e..e3bb11d1cc 100644 --- a/apps/ios/tr.lproj/Localizable.strings +++ b/apps/ios/tr.lproj/Localizable.strings @@ -4602,7 +4602,7 @@ chat item action */ "The old database was not removed during the migration, it can be deleted." = "Eski veritabanı geçiş sırasında kaldırılmadı, silinebilir."; /* No comment provided by engineer. */ -"The profile is only shared with your contacts." = "Profil sadece kişilerinle paylaşılacak."; +"Your profile is stored on your device and only shared with your contacts." = "Profil sadece kişilerinle paylaşılacak."; /* No comment provided by engineer. */ "The second tick we missed! ✅" = "Özlediğimiz ikinci tik! ✅"; diff --git a/apps/ios/uk.lproj/Localizable.strings b/apps/ios/uk.lproj/Localizable.strings index 8e2b514ed4..734b8dda82 100644 --- a/apps/ios/uk.lproj/Localizable.strings +++ b/apps/ios/uk.lproj/Localizable.strings @@ -4722,7 +4722,7 @@ chat item action */ "The old database was not removed during the migration, it can be deleted." = "Стара база даних не була видалена під час міграції, її можна видалити."; /* No comment provided by engineer. */ -"The profile is only shared with your contacts." = "Профіль доступний лише вашим контактам."; +"Your profile is stored on your device and only shared with your contacts." = "Профіль доступний лише вашим контактам."; /* No comment provided by engineer. */ "The same conditions will apply to operator **%@**." = "Такі ж умови діятимуть і для оператора **%@**."; diff --git a/apps/ios/zh-Hans.lproj/Localizable.strings b/apps/ios/zh-Hans.lproj/Localizable.strings index 6ceeeb22d0..e3f9669d9f 100644 --- a/apps/ios/zh-Hans.lproj/Localizable.strings +++ b/apps/ios/zh-Hans.lproj/Localizable.strings @@ -4923,7 +4923,7 @@ chat item action */ "The old database was not removed during the migration, it can be deleted." = "旧数据库在迁移过程中没有被移除,可以删除。"; /* No comment provided by engineer. */ -"The profile is only shared with your contacts." = "该资料仅与您的联系人共享。"; +"Your profile is stored on your device and only shared with your contacts." = "该资料仅与您的联系人共享。"; /* No comment provided by engineer. */ "The second tick we missed! ✅" = "我们错过的第二个\"√\"!✅"; diff --git a/apps/multiplatform/common/build.gradle.kts b/apps/multiplatform/common/build.gradle.kts index 345a75b1e7..e2927e4aaf 100644 --- a/apps/multiplatform/common/build.gradle.kts +++ b/apps/multiplatform/common/build.gradle.kts @@ -155,6 +155,7 @@ buildConfig { buildConfigField("String", "DESKTOP_VERSION_NAME", "\"${extra["desktop.version_name"]}\"") buildConfigField("int", "DESKTOP_VERSION_CODE", "${extra["desktop.version_code"]}") buildConfigField("String", "DATABASE_BACKEND", "\"${extra["database.backend"]}\"") + buildConfigField("Boolean", "ANDROID_BUNDLE", "${extra["android.bundle"]}") } } diff --git a/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/platform/PlatformTextField.android.kt b/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/platform/PlatformTextField.android.kt index 54e437afb1..4f48ccca52 100644 --- a/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/platform/PlatformTextField.android.kt +++ b/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/platform/PlatformTextField.android.kt @@ -42,7 +42,6 @@ import chat.simplex.common.views.helpers.* import chat.simplex.res.MR import dev.icerock.moko.resources.StringResource import kotlinx.coroutines.delay -import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.filter import java.lang.reflect.Field import java.net.URI @@ -51,10 +50,10 @@ import java.net.URI actual fun PlatformTextField( composeState: MutableState, sendMsgEnabled: Boolean, + disabledText: String?, sendMsgButtonDisabled: Boolean, textStyle: MutableState, showDeleteTextButton: MutableState, - userIsObserver: Boolean, placeholder: String, showVoiceButton: Boolean, onMessageChange: (ComposeMessage) -> Unit, @@ -197,16 +196,16 @@ actual fun PlatformTextField( showDeleteTextButton.value = it.lineCount >= 4 && !cs.inProgress } if (composeState.value.preview is ComposePreview.VoicePreview) { - ComposeOverlay(MR.strings.voice_message_send_text, textStyle, padding) - } else if (userIsObserver) { - ComposeOverlay(MR.strings.you_are_observer, textStyle, padding) + ComposeOverlay(generalGetString(MR.strings.voice_message_send_text), textStyle, padding) + } else if (disabledText != null) { + ComposeOverlay(disabledText, textStyle, padding) } } @Composable -private fun ComposeOverlay(textId: StringResource, textStyle: MutableState, padding: PaddingValues) { +private fun ComposeOverlay(text: String, textStyle: MutableState, padding: PaddingValues) { Text( - generalGetString(textId), + text, Modifier.padding(padding), color = MaterialTheme.colors.secondary, style = textStyle.value.copy(fontStyle = FontStyle.Italic) 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 6ee609020a..61c20587bf 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 @@ -1204,6 +1204,7 @@ interface SomeChat { val apiId: Long val ready: Boolean val chatDeleted: Boolean + val userCantSendReason: Pair? val sendMsgEnabled: Boolean val incognito: Boolean fun featureEnabled(feature: ChatFeature): Boolean @@ -1228,14 +1229,6 @@ data class Chat( else -> false } - val userIsObserver: Boolean get() = when(chatInfo) { - is ChatInfo.Group -> { - val m = chatInfo.groupInfo.membership - m.memberActive && m.memberRole == GroupMemberRole.Observer - } - else -> false - } - val unreadTag: Boolean get() = when (chatInfo.chatSettings?.enableNtfs) { All -> chatStats.unreadChat || chatStats.unreadCount > 0 Mentions -> chatStats.unreadChat || chatStats.unreadMentions > 0 @@ -1282,6 +1275,7 @@ sealed class ChatInfo: SomeChat, NamedChat { override val apiId get() = contact.apiId override val ready get() = contact.ready override val chatDeleted get() = contact.chatDeleted + override val userCantSendReason get() = contact.userCantSendReason override val sendMsgEnabled get() = contact.sendMsgEnabled override val incognito get() = contact.incognito override fun featureEnabled(feature: ChatFeature) = contact.featureEnabled(feature) @@ -1307,6 +1301,7 @@ sealed class ChatInfo: SomeChat, NamedChat { override val apiId get() = groupInfo.apiId override val ready get() = groupInfo.ready override val chatDeleted get() = groupInfo.chatDeleted + override val userCantSendReason get() = groupInfo.userCantSendReason override val sendMsgEnabled get() = groupInfo.sendMsgEnabled override val incognito get() = groupInfo.incognito override fun featureEnabled(feature: ChatFeature) = groupInfo.featureEnabled(feature) @@ -1331,6 +1326,7 @@ sealed class ChatInfo: SomeChat, NamedChat { override val apiId get() = noteFolder.apiId override val ready get() = noteFolder.ready override val chatDeleted get() = noteFolder.chatDeleted + override val userCantSendReason get() = noteFolder.userCantSendReason override val sendMsgEnabled get() = noteFolder.sendMsgEnabled override val incognito get() = noteFolder.incognito override fun featureEnabled(feature: ChatFeature) = noteFolder.featureEnabled(feature) @@ -1355,6 +1351,7 @@ sealed class ChatInfo: SomeChat, NamedChat { override val apiId get() = contactRequest.apiId override val ready get() = contactRequest.ready override val chatDeleted get() = contactRequest.chatDeleted + override val userCantSendReason get() = contactRequest.userCantSendReason override val sendMsgEnabled get() = contactRequest.sendMsgEnabled override val incognito get() = contactRequest.incognito override fun featureEnabled(feature: ChatFeature) = contactRequest.featureEnabled(feature) @@ -1379,6 +1376,7 @@ sealed class ChatInfo: SomeChat, NamedChat { override val apiId get() = contactConnection.apiId override val ready get() = contactConnection.ready override val chatDeleted get() = contactConnection.chatDeleted + override val userCantSendReason get() = contactConnection.userCantSendReason override val sendMsgEnabled get() = contactConnection.sendMsgEnabled override val incognito get() = contactConnection.incognito override fun featureEnabled(feature: ChatFeature) = contactConnection.featureEnabled(feature) @@ -1408,6 +1406,7 @@ sealed class ChatInfo: SomeChat, NamedChat { override val id get() = "?$apiId" override val ready get() = false override val chatDeleted get() = false + override val userCantSendReason get() = generalGetString(MR.strings.cant_send_message_generic) to null override val sendMsgEnabled get() = false override val incognito get() = false override fun featureEnabled(feature: ChatFeature) = false @@ -1450,14 +1449,6 @@ sealed class ChatInfo: SomeChat, NamedChat { is InvalidJSON -> updatedAt } - val userCanSend: Boolean - get() = when (this) { - is ChatInfo.Direct -> true - is ChatInfo.Group -> groupInfo.membership.memberRole >= GroupMemberRole.Member - is ChatInfo.Local -> true - else -> false - } - val chatTags: List? get() = when (this) { is Direct -> contact.chatTags @@ -1528,13 +1519,17 @@ data class Contact( override val ready get() = activeConn?.connStatus == ConnStatus.Ready val sndReady get() = ready || activeConn?.connStatus == ConnStatus.SndReady val active get() = contactStatus == ContactStatus.Active - override val sendMsgEnabled get() = ( - sndReady - && active - && !(activeConn?.connectionStats?.ratchetSyncSendProhibited ?: false) - && !(activeConn?.connDisabled ?: true) - ) - || nextSendGrpInv + override val userCantSendReason: Pair? + get() { + // TODO [short links] this will have additional statuses for pending contact requests before they are accepted + if (nextSendGrpInv) return null + if (!active) return generalGetString(MR.strings.cant_send_message_contact_deleted) to null + if (!sndReady) return generalGetString(MR.strings.cant_send_message_contact_not_ready) to null + if (activeConn?.connectionStats?.ratchetSyncSendProhibited == true) return generalGetString(MR.strings.cant_send_message_contact_not_synchronized) to null + if (activeConn?.connDisabled == true) return generalGetString(MR.strings.cant_send_message_contact_disabled) to null + return null + } + override val sendMsgEnabled get() = userCantSendReason == null val nextSendGrpInv get() = contactGroupMemberId != null && !contactGrpInvSent override val incognito get() = contactConnIncognito override fun featureEnabled(feature: ChatFeature) = when (feature) { @@ -1768,7 +1763,23 @@ data class GroupInfo ( override val apiId get() = groupId override val ready get() = membership.memberActive override val chatDeleted get() = false - override val sendMsgEnabled get() = membership.memberActive + override val userCantSendReason: Pair? get() = + if (membership.memberActive) { + if (membership.memberRole == GroupMemberRole.Observer) { + generalGetString(MR.strings.observer_cant_send_message_title) to generalGetString(MR.strings.observer_cant_send_message_desc) + } else { + null + } + } else { + when (membership.memberStatus) { + GroupMemberStatus.MemRejected -> generalGetString(MR.strings.cant_send_message_rejected) to null + GroupMemberStatus.MemGroupDeleted -> generalGetString(MR.strings.cant_send_message_group_deleted) to null + GroupMemberStatus.MemRemoved -> generalGetString(MR.strings.cant_send_message_mem_removed) to null + GroupMemberStatus.MemLeft -> generalGetString(MR.strings.cant_send_message_you_left) to null + else -> generalGetString(MR.strings.cant_send_message_generic) to null + } + } + override val sendMsgEnabled get() = userCantSendReason == null override val incognito get() = membership.memberIncognito override fun featureEnabled(feature: ChatFeature) = when (feature) { ChatFeature.TimedMessages -> fullGroupPreferences.timedMessages.on @@ -2144,6 +2155,7 @@ class NoteFolder( override val apiId get() = noteFolderId override val chatDeleted get() = false override val ready get() = true + override val userCantSendReason: Pair? = null override val sendMsgEnabled get() = true override val incognito get() = false override fun featureEnabled(feature: ChatFeature) = feature == ChatFeature.Voice @@ -2180,6 +2192,7 @@ class UserContactRequest ( override val apiId get() = contactRequestId override val chatDeleted get() = false override val ready get() = true + override val userCantSendReason = generalGetString(MR.strings.cant_send_message_generic) to null override val sendMsgEnabled get() = false override val incognito get() = false override fun featureEnabled(feature: ChatFeature) = false @@ -2219,6 +2232,7 @@ class PendingContactConnection( override val apiId get() = pccConnId override val chatDeleted get() = false override val ready get() = false + override val userCantSendReason = generalGetString(MR.strings.cant_send_message_generic) to null override val sendMsgEnabled get() = false override val incognito get() = customUserProfileId != null override fun featureEnabled(feature: ChatFeature) = false diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/platform/PlatformTextField.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/platform/PlatformTextField.kt index 1daf5a7ba7..6b301b9df4 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/platform/PlatformTextField.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/platform/PlatformTextField.kt @@ -12,10 +12,10 @@ import java.net.URI expect fun PlatformTextField( composeState: MutableState, sendMsgEnabled: Boolean, + disabledText: String?, sendMsgButtonDisabled: Boolean, textStyle: MutableState, showDeleteTextButton: MutableState, - userIsObserver: Boolean, placeholder: String, showVoiceButton: Boolean, onMessageChange: (ComposeMessage) -> Unit, diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/TerminalView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/TerminalView.kt index ca4d4fc0da..37aa7fc1d1 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/TerminalView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/TerminalView.kt @@ -99,12 +99,11 @@ fun TerminalLayout( isDirectChat = false, liveMessageAlertShown = SharedPreference(get = { false }, set = {}), sendMsgEnabled = true, + userCantSendReason = null, sendButtonEnabled = true, nextSendGrpInv = false, needToAllowVoiceToContact = false, allowedVoiceByPrefs = false, - userIsObserver = false, - userCanSend = true, allowVoiceToContact = {}, placeholder = "", sendMessage = { sendCommand() }, diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt index b3fdcf79c0..6d7cdcdebe 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt @@ -723,7 +723,7 @@ fun ChatLayout( Modifier .fillMaxWidth() .desktopOnExternalDrag( - enabled = remember(attachmentDisabled.value, chatInfo.value?.userCanSend) { mutableStateOf(!attachmentDisabled.value && chatInfo.value?.userCanSend == true) }.value, + enabled = remember(attachmentDisabled.value, chatInfo.value?.sendMsgEnabled) { mutableStateOf(!attachmentDisabled.value && chatInfo.value?.sendMsgEnabled == true) }.value, onFiles = { paths -> composeState.onFilesAttached(paths.map { it.toURI() }) }, onImage = { file -> CoroutineScope(Dispatchers.IO).launch { composeState.processPickedMedia(listOf(file.toURI()), null) } }, onText = { diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ComposeView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ComposeView.kt index de9fc26905..894bcf3b37 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ComposeView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ComposeView.kt @@ -999,9 +999,8 @@ fun ComposeView( chatModel.sharedContent.value = null } - val userCanSend = rememberUpdatedState(chat.chatInfo.userCanSend) val sendMsgEnabled = rememberUpdatedState(chat.chatInfo.sendMsgEnabled) - val userIsObserver = rememberUpdatedState(chat.userIsObserver) + val userCantSendReason = rememberUpdatedState(chat.chatInfo.userCantSendReason) val nextSendGrpInv = rememberUpdatedState(chat.nextSendGrpInv) Column { @@ -1056,7 +1055,6 @@ fun ComposeView( val attachmentEnabled = !composeState.value.attachmentDisabled && sendMsgEnabled.value - && userCanSend.value && !isGroupAndProhibitedFiles && !nextSendGrpInv.value IconButton( @@ -1102,8 +1100,8 @@ fun ComposeView( } } - LaunchedEffect(rememberUpdatedState(chat.chatInfo.userCanSend).value) { - if (!chat.chatInfo.userCanSend) { + LaunchedEffect(rememberUpdatedState(chat.chatInfo.sendMsgEnabled).value) { + if (!chat.chatInfo.sendMsgEnabled) { clearCurrentDraft() clearState() } @@ -1159,13 +1157,12 @@ fun ComposeView( chat.chatInfo is ChatInfo.Direct, liveMessageAlertShown = chatModel.controller.appPrefs.liveMessageAlertShown, sendMsgEnabled = sendMsgEnabled.value, + userCantSendReason = userCantSendReason.value, sendButtonEnabled = sendMsgEnabled.value && !(simplexLinkProhibited || fileProhibited || voiceProhibited), nextSendGrpInv = nextSendGrpInv.value, needToAllowVoiceToContact, allowedVoiceByPrefs, allowVoiceToContact = ::allowVoiceToContact, - userIsObserver = userIsObserver.value, - userCanSend = userCanSend.value, sendButtonColor = sendButtonColor, timedMessageAllowed = timedMessageAllowed, customDisappearingMessageTimePref = chatModel.controller.appPrefs.customDisappearingMessageTime, diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/SendMsgView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/SendMsgView.kt index 5524eff655..5710f09ed5 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/SendMsgView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/SendMsgView.kt @@ -15,9 +15,7 @@ import androidx.compose.ui.draw.clip import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.graphics.* import androidx.compose.ui.graphics.painter.Painter -import androidx.compose.ui.layout.onSizeChanged import androidx.compose.ui.semantics.Role -import androidx.compose.ui.text.TextRange import androidx.compose.ui.text.TextStyle import androidx.compose.ui.unit.* import chat.simplex.common.model.* @@ -41,12 +39,11 @@ fun SendMsgView( isDirectChat: Boolean, liveMessageAlertShown: SharedPreference, sendMsgEnabled: Boolean, + userCantSendReason: Pair?, sendButtonEnabled: Boolean, nextSendGrpInv: Boolean, needToAllowVoiceToContact: Boolean, allowedVoiceByPrefs: Boolean, - userIsObserver: Boolean, - userCanSend: Boolean, sendButtonColor: Color = MaterialTheme.colors.primary, allowVoiceToContact: () -> Unit, timedMessageAllowed: Boolean = false, @@ -82,14 +79,14 @@ fun SendMsgView( (!allowedVoiceByPrefs && cs.preview is ComposePreview.VoicePreview) || cs.endLiveDisabled || !sendButtonEnabled - val clicksOnTextFieldDisabled = !sendMsgEnabled || cs.preview is ComposePreview.VoicePreview || !userCanSend || cs.inProgress + val clicksOnTextFieldDisabled = !sendMsgEnabled || cs.preview is ComposePreview.VoicePreview || cs.inProgress PlatformTextField( composeState, sendMsgEnabled, + disabledText = userCantSendReason?.first, sendMsgButtonDisabled, textStyle, showDeleteTextButton, - userIsObserver, if (clicksOnTextFieldDisabled) "" else placeholder, showVoiceButton, onMessageChange, @@ -102,16 +99,23 @@ fun SendMsgView( } } if (clicksOnTextFieldDisabled) { - Box( - Modifier - .matchParentSize() - .clickable(enabled = !userCanSend, indication = null, interactionSource = remember { MutableInteractionSource() }, onClick = { - AlertManager.shared.showAlertMsg( - title = generalGetString(MR.strings.observer_cant_send_message_title), - text = generalGetString(MR.strings.observer_cant_send_message_desc) - ) - }) - ) + if (userCantSendReason != null) { + Box( + Modifier + .matchParentSize() + .clickable(indication = null, interactionSource = remember { MutableInteractionSource() }, onClick = { + AlertManager.shared.showAlertMsg( + title = generalGetString(MR.strings.cant_send_message_alert_title), + text = userCantSendReason.second + ) + }) + ) + } else { + Box( + Modifier + .matchParentSize() + ) + } } if (showDeleteTextButton.value) { DeleteTextButton(composeState) @@ -135,11 +139,11 @@ fun SendMsgView( Row(verticalAlignment = Alignment.CenterVertically) { val stopRecOnNextClick = remember { mutableStateOf(false) } when { - needToAllowVoiceToContact || !allowedVoiceByPrefs || !userCanSend -> { - DisallowedVoiceButton(userCanSend) { + needToAllowVoiceToContact || !allowedVoiceByPrefs -> { + DisallowedVoiceButton { if (needToAllowVoiceToContact) { showNeedToAllowVoiceAlert(allowVoiceToContact) - } else if (!allowedVoiceByPrefs) { + } else { showDisabledVoiceAlert(isDirectChat) } } @@ -155,7 +159,7 @@ fun SendMsgView( && cs.contextItem is ComposeContextItem.NoContextItem ) { Spacer(Modifier.width(12.dp)) - StartLiveMessageButton(userCanSend) { + StartLiveMessageButton { if (composeState.value.preview is ComposePreview.NoPreview) { startLiveMessage(scope, sendLiveMessage, updateLiveMessage, sendButtonSize, sendButtonAlpha, composeState, liveMessageAlertShown) } @@ -343,8 +347,8 @@ private fun RecordVoiceView(recState: MutableState, stopRecOnNex } @Composable -private fun DisallowedVoiceButton(enabled: Boolean, onClick: () -> Unit) { - IconButton(onClick, Modifier.size(36.dp), enabled = enabled) { +private fun DisallowedVoiceButton(onClick: () -> Unit) { + IconButton(onClick, Modifier.size(36.dp)) { Icon( painterResource(MR.images.ic_keyboard_voice), stringResource(MR.strings.icon_descr_record_voice_message), @@ -460,14 +464,13 @@ private fun SendMsgButton( } @Composable -private fun StartLiveMessageButton(enabled: Boolean, onClick: () -> Unit) { +private fun StartLiveMessageButton(onClick: () -> Unit) { val interactionSource = remember { MutableInteractionSource() } val ripple = remember { ripple(bounded = false, radius = 24.dp) } Box( modifier = Modifier.requiredSize(36.dp) .clickable( onClick = onClick, - enabled = enabled, role = Role.Button, interactionSource = interactionSource, indication = ripple @@ -477,7 +480,7 @@ private fun StartLiveMessageButton(enabled: Boolean, onClick: () -> Unit) { Icon( BoltFilled, stringResource(MR.strings.icon_descr_send_message), - tint = if (enabled) MaterialTheme.colors.primary else MaterialTheme.colors.secondary, + tint = MaterialTheme.colors.primary, modifier = Modifier .size(36.dp) .padding(4.dp) @@ -576,12 +579,11 @@ fun PreviewSendMsgView() { isDirectChat = true, liveMessageAlertShown = SharedPreference(get = { true }, set = { }), sendMsgEnabled = true, + userCantSendReason = null, sendButtonEnabled = true, nextSendGrpInv = false, needToAllowVoiceToContact = false, allowedVoiceByPrefs = true, - userIsObserver = false, - userCanSend = true, allowVoiceToContact = {}, timedMessageAllowed = false, placeholder = "", @@ -612,12 +614,11 @@ fun PreviewSendMsgViewEditing() { isDirectChat = true, liveMessageAlertShown = SharedPreference(get = { true }, set = { }), sendMsgEnabled = true, + userCantSendReason = null, sendButtonEnabled = true, nextSendGrpInv = false, needToAllowVoiceToContact = false, allowedVoiceByPrefs = true, - userIsObserver = false, - userCanSend = true, allowVoiceToContact = {}, timedMessageAllowed = false, placeholder = "", @@ -648,12 +649,11 @@ fun PreviewSendMsgViewInProgress() { isDirectChat = true, liveMessageAlertShown = SharedPreference(get = { true }, set = { }), sendMsgEnabled = true, + userCantSendReason = null, sendButtonEnabled = true, nextSendGrpInv = false, needToAllowVoiceToContact = false, allowedVoiceByPrefs = true, - userIsObserver = false, - userCanSend = true, allowVoiceToContact = {}, timedMessageAllowed = false, placeholder = "", diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/SettingsView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/SettingsView.kt index 5bd45ccaab..7ea656e1e4 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/SettingsView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/SettingsView.kt @@ -21,6 +21,7 @@ import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.* +import chat.simplex.common.BuildConfigCommon import chat.simplex.common.model.* import chat.simplex.common.model.ChatController.appPrefs import chat.simplex.common.platform.* @@ -127,7 +128,9 @@ fun SettingsLayout( SectionDividerSpaced() SectionView(stringResource(MR.strings.settings_section_title_support)) { - ContributeItem(uriHandler) + if (!BuildConfigCommon.ANDROID_BUNDLE) { + ContributeItem(uriHandler) + } RateAppItem(uriHandler) StarOnGithubItem(uriHandler) } 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 1bea4c18d4..6726009a5f 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml @@ -487,8 +487,6 @@ The image cannot be decoded. Please, try a different image or contact developers. The video cannot be decoded. Please, try a different video or contact developers. you are observer - You can\'t send messages! - Please contact group admin. Files and media prohibited! Only group owners can enable files and media. Send direct message to connect @@ -508,6 +506,19 @@ Report content: only group moderators will see it. Report other: only group moderators will see it. + You can\'t send messages! + contact not ready + contact deleted + not synchronized + contact disabled + you are observer + Please contact group admin. + request to join rejected + group is deleted + removed from group + you left + can\'t send messages + Image Waiting for image diff --git a/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/platform/PlatformTextField.desktop.kt b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/platform/PlatformTextField.desktop.kt index d0d4fb5e92..41964b7d18 100644 --- a/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/platform/PlatformTextField.desktop.kt +++ b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/platform/PlatformTextField.desktop.kt @@ -44,10 +44,10 @@ import kotlin.text.substring actual fun PlatformTextField( composeState: MutableState, sendMsgEnabled: Boolean, + disabledText: String?, sendMsgButtonDisabled: Boolean, textStyle: MutableState, showDeleteTextButton: MutableState, - userIsObserver: Boolean, placeholder: String, showVoiceButton: Boolean, onMessageChange: (ComposeMessage) -> Unit, @@ -203,16 +203,16 @@ actual fun PlatformTextField( ) showDeleteTextButton.value = cs.message.text.split("\n").size >= 4 && !cs.inProgress if (composeState.value.preview is ComposePreview.VoicePreview) { - ComposeOverlay(MR.strings.voice_message_send_text, textStyle, padding) - } else if (userIsObserver) { - ComposeOverlay(MR.strings.you_are_observer, textStyle, padding) + ComposeOverlay(generalGetString(MR.strings.voice_message_send_text), textStyle, padding) + } else if (disabledText != null) { + ComposeOverlay(disabledText, textStyle, padding) } } @Composable -private fun ComposeOverlay(textId: StringResource, textStyle: MutableState, padding: PaddingValues) { +private fun ComposeOverlay(text: String, textStyle: MutableState, padding: PaddingValues) { Text( - generalGetString(textId), + text, Modifier.padding(padding), color = MaterialTheme.colors.secondary, style = textStyle.value.copy(fontStyle = FontStyle.Italic) diff --git a/apps/multiplatform/gradle.properties b/apps/multiplatform/gradle.properties index 18add58bcf..aa4c7a7470 100644 --- a/apps/multiplatform/gradle.properties +++ b/apps/multiplatform/gradle.properties @@ -24,11 +24,13 @@ android.nonTransitiveRClass=true kotlin.mpp.androidSourceSetLayoutVersion=2 kotlin.jvm.target=11 -android.version_name=6.3.4 -android.version_code=288 +android.version_name=6.3.6 +android.version_code=295 -desktop.version_name=6.3.4 -desktop.version_code=101 +android.bundle=false + +desktop.version_name=6.3.6 +desktop.version_code=106 kotlin.version=1.9.23 gradle.plugin.version=8.2.0 diff --git a/cabal.project b/cabal.project index 3e6ccab8a5..f406b9820e 100644 --- a/cabal.project +++ b/cabal.project @@ -12,7 +12,7 @@ constraints: zip +disable-bzip2 +disable-zstd source-repository-package type: git location: https://github.com/simplex-chat/simplexmq.git - tag: deaec3cce286e959bd594b9620c307954b510a07 + tag: 3d62a383d5dcae6529d6d866233857182bcb4d47 source-repository-package type: git diff --git a/images/privacy-guides.jpg b/images/privacy-guides.jpg index f15a8862f7..5876d10c02 100644 Binary files a/images/privacy-guides.jpg and b/images/privacy-guides.jpg differ diff --git a/images/whonix-logo.jpg b/images/whonix-logo.jpg new file mode 100644 index 0000000000..c6fc4729b2 Binary files /dev/null and b/images/whonix-logo.jpg differ diff --git a/scripts/flatpak/chat.simplex.simplex.metainfo.xml b/scripts/flatpak/chat.simplex.simplex.metainfo.xml index 82987e211a..b15e382207 100644 --- a/scripts/flatpak/chat.simplex.simplex.metainfo.xml +++ b/scripts/flatpak/chat.simplex.simplex.metainfo.xml @@ -38,6 +38,32 @@ + + https://simplex.chat/blog/20250308-simplex-chat-v6-3-new-user-experience-safety-in-public-groups.html + +

New in v6.3.1-4:

+
    +
  • fixes mentions with trailing punctuation (e.g., hello @name!).
  • +
  • recognizes domain names as links (e.g., simplex.chat).
  • +
  • forward compatibility with "knocking" (a feature for group admins to review and to chat with the new members prior to admitting them to groups, it will be released in 6.4)
  • +
  • support for connecting via short connection links.
  • +
  • fix related to backward/forward compatibility of the app in some rare cases.
  • +
  • scrolling/navigation improvements.
  • +
  • faster onboarding (conditions and operators are combined to one screen).
  • +
+

New in v6.3.0:

+
    +
  • Mention members and get notified when mentioned.
  • +
  • Send private reports to moderators.
  • +
  • Delete, block and change role for multiple members at once
  • +
  • Faster sending messages and faster deletion.
  • +
  • Organize chats into lists to keep track of what's important.
  • +
  • Jump to found and forwarded messages.
  • +
  • Private media file names.
  • +
  • Message expiration in chats.
  • +
+
+
https://simplex.chat/blog/20250308-simplex-chat-v6-3-new-user-experience-safety-in-public-groups.html diff --git a/scripts/nix/sha256map.nix b/scripts/nix/sha256map.nix index 8d17a2ce99..84f9d0db34 100644 --- a/scripts/nix/sha256map.nix +++ b/scripts/nix/sha256map.nix @@ -1,5 +1,5 @@ { - "https://github.com/simplex-chat/simplexmq.git"."deaec3cce286e959bd594b9620c307954b510a07" = "0b8m4czjiwsi9169plslyk2rjw0f370vv7ha6qm2hpx14bxzz7xm"; + "https://github.com/simplex-chat/simplexmq.git"."3d62a383d5dcae6529d6d866233857182bcb4d47" = "133xm8jkim7agd6drwm3lbx1z7v8nf4l3asrm46ag3n2q201yfxc"; "https://github.com/simplex-chat/hs-socks.git"."a30cc7a79a08d8108316094f8f2f82a0c5e1ac51" = "0yasvnr7g91k76mjkamvzab2kvlb1g5pspjyjn2fr6v83swjhj38"; "https://github.com/simplex-chat/direct-sqlcipher.git"."f814ee68b16a9447fbb467ccc8f29bdd3546bfd9" = "1ql13f4kfwkbaq7nygkxgw84213i0zm7c1a8hwvramayxl38dq5d"; "https://github.com/simplex-chat/sqlcipher-simple.git"."a46bd361a19376c5211f1058908fc0ae6bf42446" = "1z0r78d8f0812kxbgsm735qf6xx8lvaz27k1a0b4a2m0sshpd5gl"; diff --git a/simplex-chat.cabal b/simplex-chat.cabal index a9dca273e3..96b2f941c7 100644 --- a/simplex-chat.cabal +++ b/simplex-chat.cabal @@ -5,7 +5,7 @@ cabal-version: 1.12 -- see: https://github.com/sol/hpack name: simplex-chat -version: 6.3.4.1 +version: 6.3.6.0 category: Web, System, Services, Cryptography homepage: https://github.com/simplex-chat/simplex-chat#readme author: simplex.chat diff --git a/src/Simplex/Chat/Library/Commands.hs b/src/Simplex/Chat/Library/Commands.hs index d3b945af4f..8c475b111b 100644 --- a/src/Simplex/Chat/Library/Commands.hs +++ b/src/Simplex/Chat/Library/Commands.hs @@ -1671,25 +1671,10 @@ processChatCommand' vr = \case case (pccConnStatus, connLinkInv) of (ConnNew, Just (CCLink cReqInv _)) -> do newUser <- privateGetUser newUserId - conn' <- ifM (canKeepLink cReqInv newUser) (updateConnRecord user conn newUser) (recreateConn user conn newUser) + conn' <- recreateConn user conn newUser pure $ CRConnectionUserChanged user conn conn' newUser _ -> throwChatError CEConnectionUserChangeProhibited where - canKeepLink :: ConnReqInvitation -> User -> CM Bool - canKeepLink (CRInvitationUri crData _) newUser = do - let ConnReqUriData {crSmpQueues = q :| _} = crData - SMPQueueUri {queueAddress = SMPQueueAddress {smpServer}} = q - newUserServers <- - map protoServer' . L.filter (\ServerCfg {enabled} -> enabled) - <$> getKnownAgentServers SPSMP newUser - pure $ smpServer `elem` newUserServers - updateConnRecord user@User {userId} conn@PendingContactConnection {customUserProfileId} newUser = do - withAgent $ \a -> changeConnectionUser a (aUserId user) (aConnId' conn) (aUserId newUser) - withFastStore' $ \db -> do - conn' <- updatePCCUser db userId conn newUserId - forM_ customUserProfileId $ \profileId -> - deletePCCIncognitoProfile db user profileId - pure conn' recreateConn user conn@PendingContactConnection {customUserProfileId, connLinkInv} newUser = do subMode <- chatReadVar subscriptionMode let userData = shortLinkUserData $ isJust $ connShortLink =<< connLinkInv diff --git a/src/Simplex/Chat/Store/Direct.hs b/src/Simplex/Chat/Store/Direct.hs index 4de832a8b1..9318f62f76 100644 --- a/src/Simplex/Chat/Store/Direct.hs +++ b/src/Simplex/Chat/Store/Direct.hs @@ -66,7 +66,6 @@ module Simplex.Chat.Store.Direct updateContactAccepted, getUserByContactRequestId, getPendingContactConnections, - updatePCCUser, getContactConnections, getConnectionById, getConnectionsContacts, @@ -440,19 +439,6 @@ updatePCCIncognito db User {userId} conn customUserProfileId = do (customUserProfileId, updatedAt, userId, pccConnId conn) pure (conn :: PendingContactConnection) {customUserProfileId, updatedAt} -updatePCCUser :: DB.Connection -> UserId -> PendingContactConnection -> UserId -> IO PendingContactConnection -updatePCCUser db userId conn newUserId = do - updatedAt <- getCurrentTime - DB.execute - db - [sql| - UPDATE connections - SET user_id = ?, custom_user_profile_id = NULL, updated_at = ? - WHERE user_id = ? AND connection_id = ? - |] - (newUserId, updatedAt, userId, pccConnId conn) - pure (conn :: PendingContactConnection) {customUserProfileId = Nothing, updatedAt} - deletePCCIncognitoProfile :: DB.Connection -> User -> ProfileId -> IO () deletePCCIncognitoProfile db User {userId} profileId = DB.execute diff --git a/src/Simplex/Chat/Store/Messages.hs b/src/Simplex/Chat/Store/Messages.hs index bdbb3fe67d..752a4a2c6d 100644 --- a/src/Simplex/Chat/Store/Messages.hs +++ b/src/Simplex/Chat/Store/Messages.hs @@ -171,7 +171,7 @@ import Simplex.Messaging.Crypto.File (CryptoFile (..), CryptoFileArgs (..)) import Simplex.Messaging.Util (eitherToMaybe) import UnliftIO.STM #if defined(dbPostgres) -import Database.PostgreSQL.Simple (FromRow, Only (..), Query, ToRow, (:.) (..)) +import Database.PostgreSQL.Simple (FromRow, In (..), Only (..), Query, ToRow, (:.) (..)) import Database.PostgreSQL.Simple.SqlQQ (sql) #else import Database.SQLite.Simple (FromRow, Only (..), Query, ToRow, (:.) (..)) @@ -2370,8 +2370,14 @@ updateGroupChatItemModerated db User {userId} GroupInfo {groupId} ci m@GroupMemb updateMemberCIsModerated :: MsgDirectionI d => DB.Connection -> User -> GroupInfo -> GroupMember -> GroupMember -> SMsgDirection d -> UTCTime -> IO () updateMemberCIsModerated db User {userId} GroupInfo {groupId, membership} member byGroupMember md deletedTs = do itemIds <- updateCIs =<< getCurrentTime +#if defined(dbPostgres) + let inItemIds = Only $ In (map fromOnly itemIds) + DB.execute db "DELETE FROM messages WHERE message_id IN (SELECT message_id FROM chat_item_messages WHERE chat_item_id IN ?)" inItemIds + DB.execute db "DELETE FROM chat_item_versions WHERE chat_item_id IN ?" inItemIds +#else DB.executeMany db deleteChatItemMessagesQuery itemIds DB.executeMany db "DELETE FROM chat_item_versions WHERE chat_item_id = ?" itemIds +#endif where memId = groupMemberId' member updateQuery = @@ -2887,7 +2893,7 @@ getGroupCIMentions db ciId = SELECT r.display_name, r.member_id, m.group_member_id, m.member_role, p.display_name, p.local_alias FROM chat_item_mentions r LEFT JOIN group_members m ON r.group_id = m.group_id AND r.member_id = m.member_id - LEFT JOIN contact_profiles p ON p.contact_profile_id = COALESCE(m.member_profile_id, m.contact_profile_id) + LEFT JOIN contact_profiles p ON p.contact_profile_id = COALESCE(m.member_profile_id, m.contact_profile_id) WHERE r.chat_item_id = ? |] (Only ciId) diff --git a/src/Simplex/Chat/Store/SQLite/Migrations/agent_query_plans.txt b/src/Simplex/Chat/Store/SQLite/Migrations/agent_query_plans.txt index 13215dcb75..a85ba4a4cb 100644 --- a/src/Simplex/Chat/Store/SQLite/Migrations/agent_query_plans.txt +++ b/src/Simplex/Chat/Store/SQLite/Migrations/agent_query_plans.txt @@ -1071,10 +1071,6 @@ Query: UPDATE connections SET smp_agent_version = ? WHERE conn_id = ? Plan: SEARCH connections USING PRIMARY KEY (conn_id=?) -Query: UPDATE connections SET user_id = ? WHERE conn_id = ? and user_id = ? -Plan: -SEARCH connections USING PRIMARY KEY (conn_id=?) - Query: UPDATE messages SET msg_body = x'' WHERE conn_id = ? AND internal_id = ? Plan: SEARCH messages USING PRIMARY KEY (conn_id=? AND internal_id=?) diff --git a/src/Simplex/Chat/Store/SQLite/Migrations/chat_query_plans.txt b/src/Simplex/Chat/Store/SQLite/Migrations/chat_query_plans.txt index 88c6c33b41..e9ade30f93 100644 --- a/src/Simplex/Chat/Store/SQLite/Migrations/chat_query_plans.txt +++ b/src/Simplex/Chat/Store/SQLite/Migrations/chat_query_plans.txt @@ -3186,7 +3186,7 @@ Query: SELECT r.display_name, r.member_id, m.group_member_id, m.member_role, p.display_name, p.local_alias FROM chat_item_mentions r LEFT JOIN group_members m ON r.group_id = m.group_id AND r.member_id = m.member_id - LEFT JOIN contact_profiles p ON p.contact_profile_id = COALESCE(m.member_profile_id, m.contact_profile_id) + LEFT JOIN contact_profiles p ON p.contact_profile_id = COALESCE(m.member_profile_id, m.contact_profile_id) WHERE r.chat_item_id = ? Plan: @@ -4215,14 +4215,6 @@ Query: Plan: SEARCH connections USING INTEGER PRIMARY KEY (rowid=?) -Query: - UPDATE connections - SET user_id = ?, custom_user_profile_id = NULL, updated_at = ? - WHERE user_id = ? AND connection_id = ? - -Plan: -SEARCH connections USING INTEGER PRIMARY KEY (rowid=?) - Query: UPDATE contact_profiles SET contact_link = ?, updated_at = ? diff --git a/src/Simplex/Chat/View.hs b/src/Simplex/Chat/View.hs index 42d1132961..4ba5acbb43 100644 --- a/src/Simplex/Chat/View.hs +++ b/src/Simplex/Chat/View.hs @@ -1747,10 +1747,9 @@ viewConnectionIncognitoUpdated PendingContactConnection {pccConnId, customUserPr | otherwise = ["connection " <> sShow pccConnId <> " changed to non incognito"] viewConnectionUserChanged :: User -> PendingContactConnection -> User -> PendingContactConnection -> [StyledString] -viewConnectionUserChanged User {localDisplayName = n} PendingContactConnection {pccConnId, connLinkInv} User {localDisplayName = n'} PendingContactConnection {connLinkInv = connLinkInv'} = - case (connLinkInv, connLinkInv') of - (Just ccLink, Just ccLink') - | ccLink /= ccLink' -> [userChangedStr <> ", new link:"] <> newLink ccLink' +viewConnectionUserChanged User {localDisplayName = n} PendingContactConnection {pccConnId} User {localDisplayName = n'} PendingContactConnection {connLinkInv = connLinkInv'} = + case connLinkInv' of + Just ccLink' -> [userChangedStr <> ", new link:"] <> newLink ccLink' _ -> [userChangedStr] where userChangedStr = "connection " <> sShow pccConnId <> " changed from user " <> plain n <> " to user " <> plain n' diff --git a/tests/ChatClient.hs b/tests/ChatClient.hs index 2d0bde5058..e3bab5a0ec 100644 --- a/tests/ChatClient.hs +++ b/tests/ChatClient.hs @@ -17,6 +17,7 @@ import Control.Concurrent (forkIOWithUnmask, killThread, threadDelay) import Control.Concurrent.Async import Control.Concurrent.STM import Control.Exception (bracket, bracket_) +import Control.Logger.Simple import Control.Monad import Control.Monad.Except import Control.Monad.Reader @@ -519,7 +520,7 @@ smpServerCfg = allowSMPProxy = True, serverClientConcurrency = 16, information = Nothing, - startOptions = StartOptions {maintenance = False, compactLog = False, skipWarnings = False, confirmMigrations = MCYesUp} + startOptions = StartOptions {maintenance = False, logLevel = LogError, compactLog = False, skipWarnings = False, confirmMigrations = MCYesUp} } persistentServerStoreCfg :: FilePath -> AServerStoreCfg diff --git a/tests/ChatTests/Groups.hs b/tests/ChatTests/Groups.hs index 73a8735f63..431f19c77f 100644 --- a/tests/ChatTests/Groups.hs +++ b/tests/ChatTests/Groups.hs @@ -84,7 +84,10 @@ chatGroupTests = do describe "batch send messages" $ do it "send multiple messages api" testSendMulti it "send multiple timed messages" testSendMultiTimed +#if !defined(dbPostgres) + -- TODO [postgres] this test hangs with PostgreSQL it "send multiple messages (many chat batches)" testSendMultiManyBatches +#endif xit'' "shared message body is reused" testSharedMessageBody xit'' "shared batch body is reused" testSharedBatchBody describe "async group connections" $ do @@ -1821,7 +1824,7 @@ testDeleteMemberWithMessages = do cath <## "alice updated group #team:" cath <## "updated group preferences:" - cath <## "Full deletion: on" + cath <## "Full deletion: on" ] threadDelay 750000 bob #> "#team hello" @@ -6496,7 +6499,7 @@ testForwardQuoteMention = bob <## " hello @alice @cath", do cath <# "#team alice!> -> forwarded" - cath <## " hello @alice @cath" + cath <## " hello @alice @cath" ] -- forward mentions alice `send` "@bob <- #team hello" diff --git a/tests/ChatTests/Profiles.hs b/tests/ChatTests/Profiles.hs index 433615e62a..adff745200 100644 --- a/tests/ChatTests/Profiles.hs +++ b/tests/ChatTests/Profiles.hs @@ -1827,7 +1827,7 @@ testChangePCCUser = testChat2 aliceProfile bobProfile $ \alice bob -> do -- Create a new invite alice ##> "/connect" - inv <- getInvitation alice + _ <- getInvitation alice -- Create new user and go back to original user alice ##> "/create user alisa" showActiveUser alice "alisa" @@ -1837,12 +1837,18 @@ testChangePCCUser = testChat2 aliceProfile bobProfile $ showActiveUser alice "alice (Alice)" -- Change connection to newly created user alice ##> "/_set conn user :1 2" - alice <## "connection 1 changed from user alice to user alisa" + alice <## "connection 1 changed from user alice to user alisa, new link:" + alice <## "" + _ <- getTermLine alice + alice <## "" alice ##> "/user alisa" showActiveUser alice "alisa" -- Change connection back to other user alice ##> "/_set conn user :1 3" - alice <## "connection 1 changed from user alisa to user alisa2" + alice <## "connection 1 changed from user alisa to user alisa2, new link:" + alice <## "" + inv <- getTermLine alice + alice <## "" alice ##> "/user alisa2" showActiveUser alice "alisa2" -- Connect @@ -1851,13 +1857,14 @@ testChangePCCUser = testChat2 aliceProfile bobProfile $ concurrently_ (alice <## "bob (Bob): contact is connected") (bob <## "alisa2: contact is connected") + alice <##> bob testChangePCCUserFromIncognito :: HasCallStack => TestParams -> IO () testChangePCCUserFromIncognito = testChat2 aliceProfile bobProfile $ \alice bob -> do -- Create a new invite and set as incognito alice ##> "/connect" - inv <- getInvitation alice + _ <- getInvitation alice alice ##> "/_set incognito :1 on" alice <## "connection 1 changed to incognito" -- Create new user and go back to original user @@ -1867,13 +1874,19 @@ testChangePCCUserFromIncognito = testChat2 aliceProfile bobProfile $ showActiveUser alice "alice (Alice)" -- Change connection to newly created user alice ##> "/_set conn user :1 2" - alice <## "connection 1 changed from user alice to user alisa" + alice <## "connection 1 changed from user alice to user alisa, new link:" + alice <## "" + _ <- getTermLine alice + alice <## "" alice `hasContactProfiles` ["alice"] alice ##> "/user alisa" showActiveUser alice "alisa" -- Change connection back to initial user alice ##> "/_set conn user :1 1" - alice <## "connection 1 changed from user alisa to user alice" + alice <## "connection 1 changed from user alisa to user alice, new link:" + alice <## "" + inv <- getTermLine alice + alice <## "" alice ##> "/user alice" showActiveUser alice "alice (Alice)" -- Connect @@ -1882,13 +1895,14 @@ testChangePCCUserFromIncognito = testChat2 aliceProfile bobProfile $ concurrently_ (alice <## "bob (Bob): contact is connected") (bob <## "alice (Alice): contact is connected") + alice <##> bob testChangePCCUserAndThenIncognito :: HasCallStack => TestParams -> IO () testChangePCCUserAndThenIncognito = testChat2 aliceProfile bobProfile $ \alice bob -> do -- Create a new invite and set as incognito alice ##> "/connect" - inv <- getInvitation alice + _ <- getInvitation alice -- Create new user and go back to original user alice ##> "/create user alisa" showActiveUser alice "alisa" @@ -1896,7 +1910,10 @@ testChangePCCUserAndThenIncognito = testChat2 aliceProfile bobProfile $ showActiveUser alice "alice (Alice)" -- Change connection to newly created user alice ##> "/_set conn user :1 2" - alice <## "connection 1 changed from user alice to user alisa" + alice <## "connection 1 changed from user alice to user alisa, new link:" + alice <## "" + inv <- getTermLine alice + alice <## "" alice ##> "/user alisa" showActiveUser alice "alisa" -- Change connection to incognito and make sure it's attached to the newly created user profile @@ -1911,6 +1928,10 @@ testChangePCCUserAndThenIncognito = testChat2 aliceProfile bobProfile $ alice <## ("bob (Bob): contact is connected, your incognito profile for this contact is " <> alisaIncognito) alice <## ("use /i bob to print out this incognito profile again") ] + alice ?#> "@bob hi" + bob <# (alisaIncognito <> "> hi") + bob #> ("@" <> alisaIncognito <> " hey") + alice ?<# "bob> hey" testChangePCCUserDiffSrv :: HasCallStack => TestParams -> IO () testChangePCCUserDiffSrv ps = do @@ -1951,6 +1972,7 @@ testChangePCCUserDiffSrv ps = do concurrently_ (alice <## "bob (Bob): contact is connected") (bob <## "alisa: contact is connected") + alice <##> bob where serverCfg' = smpServerCfg diff --git a/website/src/_includes/hero.html b/website/src/_includes/hero.html index c0e2b3f30b..6ebfb883ef 100644 --- a/website/src/_includes/hero.html +++ b/website/src/_includes/hero.html @@ -31,6 +31,10 @@ Privacy Guides + + Whonix + + Heise Online @@ -43,7 +47,7 @@ Opt Out Podcast - +
@@ -66,7 +70,7 @@ - + {#

PLAY

diff --git a/website/src/img/whonix-dark.png b/website/src/img/whonix-dark.png new file mode 100644 index 0000000000..f361f4d1f6 Binary files /dev/null and b/website/src/img/whonix-dark.png differ diff --git a/website/src/img/whonix-light.png b/website/src/img/whonix-light.png new file mode 100644 index 0000000000..d8616b4a4b Binary files /dev/null and b/website/src/img/whonix-light.png differ