Merge branch 'master' into stable

This commit is contained in:
Evgeny Poberezkin
2025-08-02 18:27:14 +01:00
140 changed files with 3607 additions and 780 deletions
+35 -18
View File
@@ -99,26 +99,43 @@ jobs:
# =========================
build-linux:
name: "ubuntu-${{ matrix.os }} (CLI,Desktop), GHC: ${{ matrix.ghc }}"
name: "ubuntu-${{ matrix.os }}-${{ matrix.arch }} (CLI,Desktop), GHC: ${{ matrix.ghc }}"
needs: [maybe-release, variables]
runs-on: ubuntu-${{ matrix.os }}
runs-on: ${{ matrix.runner }}
strategy:
fail-fast: false
matrix:
include:
- os: 22.04
os_underscore: 22_04
arch: x86_64
runner: "ubuntu-22.04"
ghc: "8.10.7"
should_run: ${{ !(github.ref == 'refs/heads/stable' || startsWith(github.ref, 'refs/tags/v')) }}
- os: 22.04
ghc: ${{ needs.variables.outputs.GHC_VER }}
cli_asset_name: simplex-chat-ubuntu-22_04-x86-64
desktop_asset_name: simplex-desktop-ubuntu-22_04-x86_64.deb
os_underscore: 22_04
arch: x86_64
runner: "ubuntu-22.04"
should_run: true
ghc: ${{ needs.variables.outputs.GHC_VER }}
- os: 24.04
ghc: ${{ needs.variables.outputs.GHC_VER }}
cli_asset_name: simplex-chat-ubuntu-24_04-x86-64
desktop_asset_name: simplex-desktop-ubuntu-24_04-x86_64.deb
os_underscore: 24_04
arch: x86_64
runner: "ubuntu-24.04"
should_run: true
ghc: ${{ needs.variables.outputs.GHC_VER }}
- os: 22.04
os_underscore: 22_04
arch: aarch64
runner: "ubuntu-22.04-arm"
should_run: true
ghc: ${{ needs.variables.outputs.GHC_VER }}
- os: 24.04
os_underscore: 24_04
arch: aarch64
runner: "ubuntu-24.04-arm"
should_run: true
ghc: ${{ needs.variables.outputs.GHC_VER }}
steps:
- name: Checkout Code
if: matrix.should_run == true
@@ -143,7 +160,7 @@ jobs:
path: |
~/.cabal/store
dist-newstyle
key: ubuntu-${{ matrix.os }}-ghc${{ matrix.ghc }}-${{ hashFiles('cabal.project', 'simplex-chat.cabal') }}
key: ubuntu-${{ matrix.os }}-${{ matrix.arch }}-ghc${{ matrix.ghc }}-${{ hashFiles('cabal.project', 'simplex-chat.cabal') }}
- name: Set up Docker Buildx
if: matrix.should_run == true
@@ -215,17 +232,17 @@ jobs:
if: startsWith(github.ref, 'refs/tags/v') && matrix.should_run == true
shell: bash
run: |
docker cp builder:/out/simplex-chat ./${{ matrix.cli_asset_name }}
path="${{ github.workspace }}/${{ matrix.cli_asset_name }}"
docker cp builder:/out/simplex-chat ./simplex-chat-ubuntu-${{ matrix.os_underscore }}-${{ matrix.arch }}
path="${{ github.workspace }}/simplex-chat-ubuntu-${{ matrix.os_underscore }}-${{ matrix.arch }}"
echo "bin_path=$path" >> $GITHUB_OUTPUT
echo "bin_hash=$(echo SHA2-256\(${{ matrix.cli_asset_name }}\)= $(openssl sha256 $path | cut -d' ' -f 2))" >> $GITHUB_OUTPUT
echo "bin_hash=$(echo SHA2-256\(simplex-chat-ubuntu-${{ matrix.os_underscore }}-${{ matrix.arch }}\)= $(openssl sha256 $path | cut -d' ' -f 2))" >> $GITHUB_OUTPUT
- name: Upload CLI
if: startsWith(github.ref, 'refs/tags/v') && matrix.should_run == true
uses: ./.github/actions/prepare-release
with:
bin_path: ${{ steps.linux_cli_prepare.outputs.bin_path }}
bin_name: ${{ matrix.cli_asset_name }}
bin_name: simplex-chat-ubuntu-${{ matrix.os_underscore }}-${{ matrix.arch }}
bin_hash: ${{ steps.linux_cli_prepare.outputs.bin_hash }}
github_ref: ${{ github.ref }}
github_token: ${{ secrets.GITHUB_TOKEN }}
@@ -241,16 +258,16 @@ jobs:
if: startsWith(github.ref, 'refs/tags/v') && matrix.should_run == true
shell: bash
run: |
path=$(echo ${{ github.workspace }}/apps/multiplatform/release/main/deb/simplex_amd64.deb )
path=$(echo ${{ github.workspace }}/apps/multiplatform/release/main/deb/simplex_${{ matrix.arch }}.deb )
echo "package_path=$path" >> $GITHUB_OUTPUT
echo "package_hash=$(echo SHA2-256\(${{ matrix.desktop_asset_name }}\)= $(openssl sha256 $path | cut -d' ' -f 2))" >> $GITHUB_OUTPUT
echo "package_hash=$(echo SHA2-256\(simplex-desktop-ubuntu-${{ matrix.os_underscore }}-${{ matrix.arch }}.deb\)= $(openssl sha256 $path | cut -d' ' -f 2))" >> $GITHUB_OUTPUT
- name: Upload Desktop
uses: ./.github/actions/prepare-release
if: startsWith(github.ref, 'refs/tags/v') && matrix.should_run == true
with:
bin_path: ${{ steps.linux_desktop_build.outputs.package_path }}
bin_name: ${{ matrix.desktop_asset_name }}
bin_name: simplex-desktop-ubuntu-${{ matrix.os_underscore }}-${{ matrix.arch }}.deb
bin_hash: ${{ steps.linux_desktop_build.outputs.package_hash }}
github_ref: ${{ github.ref }}
github_token: ${{ secrets.GITHUB_TOKEN }}
@@ -268,14 +285,14 @@ jobs:
run: |
path=$(echo ${{ github.workspace }}/apps/multiplatform/release/main/*imple*.AppImage)
echo "appimage_path=$path" >> $GITHUB_OUTPUT
echo "appimage_hash=$(echo SHA2-256\(simplex-desktop-x86_64.AppImage\)= $(openssl sha256 $path | cut -d' ' -f 2))" >> $GITHUB_OUTPUT
echo "appimage_hash=$(echo SHA2-256\(simplex-desktop-${{ matrix.arch }}.AppImage\)= $(openssl sha256 $path | cut -d' ' -f 2))" >> $GITHUB_OUTPUT
- name: Upload AppImage
if: startsWith(github.ref, 'refs/tags/v') && matrix.os == '22.04' && matrix.should_run == true
uses: ./.github/actions/prepare-release
with:
bin_path: ${{ steps.linux_appimage_build.outputs.appimage_path }}
bin_name: "simplex-desktop-x86_64.AppImage"
bin_name: "simplex-desktop-${{ matrix.arch }}.AppImage"
bin_hash: ${{ steps.linux_appimage_build.outputs.appimage_hash }}
github_ref: ${{ github.ref }}
github_token: ${{ secrets.GITHUB_TOKEN }}
+2
View File
@@ -235,6 +235,8 @@ You can use SimpleX with your own servers and still communicate with people usin
Recent and important updates:
[Jul 29, 2025 SimpleX Chat v6.4.1: welcome your contacts, review members to protect groups, and more.](./blog/20250729-simplex-chat-v6-4-1-welcome-contacts-protect-groups-app-security.md)
[Jul 3, 2025 SimpleX network: new experience of connecting with people — available in SimpleX Chat v6.4-beta.4](./blog/20250703-simplex-network-protocol-extension-for-securely-connecting-people.md)
[Mar 8, 2025. SimpleX Chat v6.3: new user experience and safety in public groups](./blog/20250308-simplex-chat-v6-3-new-user-experience-safety-in-public-groups.md)
+10
View File
@@ -18,6 +18,7 @@ enum ChatCommand: ChatCmdProtocol {
case setAllContactReceipts(enable: Bool)
case apiSetUserContactReceipts(userId: Int64, userMsgReceiptSettings: UserMsgReceiptSettings)
case apiSetUserGroupReceipts(userId: Int64, userMsgReceiptSettings: UserMsgReceiptSettings)
case apiSetUserAutoAcceptMemberContacts(userId: Int64, enable: Bool)
case apiHideUser(userId: Int64, viewPwd: String)
case apiUnhideUser(userId: Int64, viewPwd: String)
case apiMuteUser(userId: Int64)
@@ -83,6 +84,7 @@ enum ChatCommand: ChatCmdProtocol {
case apiAddGroupShortLink(groupId: Int64)
case apiCreateMemberContact(groupId: Int64, groupMemberId: Int64)
case apiSendMemberContactInvitation(contactId: Int64, msg: MsgContent)
case apiAcceptMemberContact(contactId: Int64)
case apiTestProtoServer(userId: Int64, server: String)
case apiGetServerOperators
case apiSetServerOperators(operators: [ServerOperator])
@@ -198,6 +200,8 @@ enum ChatCommand: ChatCmdProtocol {
case let .apiSetUserGroupReceipts(userId, userMsgReceiptSettings):
let umrs = userMsgReceiptSettings
return "/_set receipts groups \(userId) \(onOff(umrs.enable)) clear_overrides=\(onOff(umrs.clearOverrides))"
case let .apiSetUserAutoAcceptMemberContacts(userId, enable):
return "/_set accept member contacts \(userId) \(onOff(enable))"
case let .apiHideUser(userId, viewPwd): return "/_hide user \(userId) \(encodeJSON(viewPwd))"
case let .apiUnhideUser(userId, viewPwd): return "/_unhide user \(userId) \(encodeJSON(viewPwd))"
case let .apiMuteUser(userId): return "/_mute user \(userId)"
@@ -273,6 +277,7 @@ enum ChatCommand: ChatCmdProtocol {
case let .apiAddGroupShortLink(groupId): return "/_short link #\(groupId)"
case let .apiCreateMemberContact(groupId, groupMemberId): return "/_create member contact #\(groupId) \(groupMemberId)"
case let .apiSendMemberContactInvitation(contactId, mc): return "/_invite member contact @\(contactId) \(mc.cmdString)"
case let .apiAcceptMemberContact(contactId): return "/_accept member contact @\(contactId)"
case let .apiTestProtoServer(userId, server): return "/_server test \(userId) \(server)"
case .apiGetServerOperators: return "/_operators"
case let .apiSetServerOperators(operators): return "/_operators \(encodeJSON(operators))"
@@ -391,6 +396,7 @@ enum ChatCommand: ChatCmdProtocol {
case .setAllContactReceipts: return "setAllContactReceipts"
case .apiSetUserContactReceipts: return "apiSetUserContactReceipts"
case .apiSetUserGroupReceipts: return "apiSetUserGroupReceipts"
case .apiSetUserAutoAcceptMemberContacts: return "apiSetUserAutoAcceptMemberContacts"
case .apiHideUser: return "apiHideUser"
case .apiUnhideUser: return "apiUnhideUser"
case .apiMuteUser: return "apiMuteUser"
@@ -457,6 +463,7 @@ enum ChatCommand: ChatCmdProtocol {
case .apiAddGroupShortLink: return "apiAddGroupShortLink"
case .apiCreateMemberContact: return "apiCreateMemberContact"
case .apiSendMemberContactInvitation: return "apiSendMemberContactInvitation"
case .apiAcceptMemberContact: return "apiAcceptMemberContact"
case .apiTestProtoServer: return "apiTestProtoServer"
case .apiGetServerOperators: return "apiGetServerOperators"
case .apiSetServerOperators: return "apiSetServerOperators"
@@ -912,6 +919,7 @@ enum ChatResponse2: Decodable, ChatAPIResult {
case groupLinkDeleted(user: UserRef, groupInfo: GroupInfo)
case newMemberContact(user: UserRef, contact: Contact, groupInfo: GroupInfo, member: GroupMember)
case newMemberContactSentInv(user: UserRef, contact: Contact, groupInfo: GroupInfo, member: GroupMember)
case memberContactAccepted(user: UserRef, contact: Contact)
// receiving file responses
case rcvFileAccepted(user: UserRef, chatItem: AChatItem)
case rcvFileAcceptedSndCancelled(user: UserRef, rcvFileTransfer: RcvFileTransfer)
@@ -960,6 +968,7 @@ enum ChatResponse2: Decodable, ChatAPIResult {
case .groupLinkDeleted: "groupLinkDeleted"
case .newMemberContact: "newMemberContact"
case .newMemberContactSentInv: "newMemberContactSentInv"
case .memberContactAccepted: "memberContactAccepted"
case .rcvFileAccepted: "rcvFileAccepted"
case .rcvFileAcceptedSndCancelled: "rcvFileAcceptedSndCancelled"
case .standaloneFileInfo: "standaloneFileInfo"
@@ -1004,6 +1013,7 @@ enum ChatResponse2: Decodable, ChatAPIResult {
case let .groupLinkDeleted(u, groupInfo): return withUser(u, String(describing: groupInfo))
case let .newMemberContact(u, contact, groupInfo, member): return withUser(u, "contact: \(contact)\ngroupInfo: \(groupInfo)\nmember: \(member)")
case let .newMemberContactSentInv(u, contact, groupInfo, member): return withUser(u, "contact: \(contact)\ngroupInfo: \(groupInfo)\nmember: \(member)")
case let .memberContactAccepted(u, contact): return withUser(u, "contact: \(contact)")
case let .rcvFileAccepted(u, chatItem): return withUser(u, String(describing: chatItem))
case .rcvFileAcceptedSndCancelled: return noDetails
case let .standaloneFileInfo(fileMeta): return String(describing: fileMeta)
+31
View File
@@ -289,6 +289,10 @@ func apiSetUserGroupReceipts(_ userId: Int64, userMsgReceiptSettings: UserMsgRec
try await sendCommandOkResp(.apiSetUserGroupReceipts(userId: userId, userMsgReceiptSettings: userMsgReceiptSettings))
}
func apiSetUserAutoAcceptMemberContacts(_ userId: Int64, enable: Bool) async throws {
try await sendCommandOkResp(.apiSetUserAutoAcceptMemberContacts(userId: userId, enable: enable))
}
func apiHideUser(_ userId: Int64, viewPwd: String) async throws -> User {
try await setUserPrivacy_(.apiHideUser(userId: userId, viewPwd: viewPwd))
}
@@ -1916,6 +1920,33 @@ func apiSendMemberContactInvitation(_ contactId: Int64, _ msg: MsgContent) async
throw r.unexpected
}
func apiAcceptMemberContact(contactId: Int64) async -> Contact? {
let r: APIResult<ChatResponse2>? = await chatApiSendCmdWithRetry(.apiAcceptMemberContact(contactId: contactId))
if case let .result(.memberContactAccepted(_, contact)) = r { return contact }
if let r { AlertManager.shared.showAlert(apiConnectResponseAlert(r)) }
return nil
}
func acceptMemberContact(contactId: Int64, inProgress: Binding<Bool>? = nil) async {
await MainActor.run { inProgress?.wrappedValue = true }
if let contact = await apiAcceptMemberContact(contactId: contactId) {
await MainActor.run {
ChatModel.shared.updateContact(contact)
NetworkModel.shared.setContactNetworkStatus(contact, .connected)
inProgress?.wrappedValue = false
}
if contact.sndReady {
DispatchQueue.main.async {
dismissAllSheets(animated: true) {
ItemsModel.shared.loadOpenChat(contact.id)
}
}
}
} else {
await MainActor.run { inProgress?.wrappedValue = false }
}
}
func apiGetVersion() throws -> CoreVersionInfo {
let r: ChatResponse2 = try chatSendCmdSync(.showVersion)
if case let .versionInfo(info, _, _) = r { return info }
@@ -111,6 +111,7 @@ struct ChatInfoView: View {
@State private var sendReceiptsUserDefault = true
@State private var progressIndicator = false
@AppStorage(DEFAULT_DEVELOPER_TOOLS) private var developerTools = false
@State private var showSecrets: Set<Int> = []
enum ChatInfoViewAlert: Identifiable {
case clearChatAlert
@@ -397,10 +398,11 @@ struct ChatInfoView: View {
.padding(.bottom, 2)
}
if let descr = cInfo.shortDescr?.trimmingCharacters(in: .whitespacesAndNewlines), descr != "" {
Text(descr)
.font(.subheadline)
let r = markdownText(descr, textStyle: .subheadline, showSecrets: showSecrets, backgroundColor: theme.colors.background)
msgTextResultView(r, Text(AttributedString(r.string)), showSecrets: $showSecrets, centered: true, smallFont: true)
.multilineTextAlignment(.center)
.lineLimit(4)
.fixedSize(horizontal: false, vertical: true)
}
}
.frame(maxWidth: .infinity, alignment: .center)
@@ -120,13 +120,14 @@ struct MsgContentView: View {
}
}
func msgTextResultView(_ r: MsgTextResult, _ t: Text, showSecrets: Binding<Set<Int>>? = nil) -> some View {
func msgTextResultView(_ r: MsgTextResult, _ t: Text, showSecrets: Binding<Set<Int>>? = nil, centered: Bool = false, smallFont: Bool = false) -> some View {
t.if(r.hasSecrets, transform: hiddenSecretsView)
.if(r.handleTaps) { $0.overlay(handleTextTaps(r.string, showSecrets: showSecrets)) }
.if(r.handleTaps) { $0.overlay(handleTextTaps(r.string, showSecrets: showSecrets, centered: centered, smallFont: smallFont)) }
}
// smallFont parameter is used to pad height, otherwise CTFrameGetLines fails to see them as lines - it's needed if font is not .body
@inline(__always)
private func handleTextTaps(_ s: NSAttributedString, showSecrets: Binding<Set<Int>>? = nil) -> some View {
private func handleTextTaps(_ s: NSAttributedString, showSecrets: Binding<Set<Int>>? = nil, centered: Bool, smallFont: Bool) -> some View {
return GeometryReader { g in
Rectangle()
.fill(Color.clear)
@@ -135,17 +136,29 @@ private func handleTextTaps(_ s: NSAttributedString, showSecrets: Binding<Set<In
let t = event.translation
if t.width * t.width + t.height * t.height > 100 { return }
let framesetter = CTFramesetterCreateWithAttributedString(s as CFAttributedString)
let path = CGPath(rect: CGRect(origin: .zero, size: g.size), transform: nil)
let paddedSize = smallFont ? CGSize(width: g.size.width, height: g.size.height + 1.0) : g.size
let path = CGPath(rect: CGRect(origin: .zero, size: paddedSize), transform: nil)
let frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, s.length), path, nil)
let point = CGPoint(x: event.location.x, y: g.size.height - event.location.y) // Flip y for UIKit
var index: CFIndex?
if let lines = CTFrameGetLines(frame) as? [CTLine] {
var origins = [CGPoint](repeating: .zero, count: lines.count)
CTFrameGetLineOrigins(frame, CFRangeMake(0, 0), &origins)
var maxWidth: CGFloat = 0
if centered {
for line in lines {
let bounds = CTLineGetBoundsWithOptions(line, .useOpticalBounds)
if bounds.width > maxWidth {
maxWidth = bounds.width
}
}
}
for i in 0 ..< lines.count {
let bounds = CTLineGetBoundsWithOptions(lines[i], .useOpticalBounds)
if bounds.offsetBy(dx: origins[i].x, dy: origins[i].y).contains(point) {
index = CTLineGetStringIndexForPosition(lines[i], point)
let offsetX = centered ? (maxWidth - bounds.width) / 2 : 0
if bounds.offsetBy(dx: origins[i].x + offsetX, dy: origins[i].y).contains(point) {
let relativePoint = centered ? CGPoint(x: point.x - origins[i].x - offsetX, y: point.y - origins[i].y) : point
index = CTLineGetStringIndexForPosition(lines[i], relativePoint)
break
}
}
@@ -207,6 +220,31 @@ private let secretAttrKey = NSAttributedString.Key("chat.simplex.app.secret")
typealias MsgTextResult = (string: NSMutableAttributedString, hasSecrets: Bool, handleTaps: Bool)
@inline(__always)
func markdownText(
_ s: String,
textStyle: UIFont.TextStyle = .body,
sender: String? = nil,
preview: Bool = false,
mentions: [String: CIMention]? = nil,
userMemberId: String? = nil,
showSecrets: Set<Int>? = nil,
backgroundColor: Color
) -> MsgTextResult {
messageText(
s,
parseSimpleXMarkdown(s),
textStyle: textStyle,
sender: sender,
preview: preview,
mentions: mentions,
userMemberId: userMemberId,
showSecrets: showSecrets,
backgroundColor: UIColor(backgroundColor)
)
}
func messageText(
_ text: String,
_ formattedText: [FormattedText]?,
@@ -335,6 +373,7 @@ func messageText(
attrs[linkAttrKey] = NSURL(string: "tel:" + t.replacingOccurrences(of: " ", with: ""))
handleTaps = true
}
case .unknown: ()
case .none: ()
}
res.append(NSAttributedString(string: t, attributes: attrs))
@@ -230,7 +230,7 @@ struct ChatItemInfoView: View {
private func itemVersionView(_ itemVersion: ChatItemVersion, _ maxWidth: CGFloat, current: Bool) -> some View {
let backgroundColor = chatItemFrameColor(ci, theme)
return VStack(alignment: .leading, spacing: 4) {
textBubble(itemVersion.msgContent.text, itemVersion.formattedText, nil, backgroundColor: UIColor(backgroundColor))
textBubble(itemVersion.msgContent.text, itemVersion.formattedText, nil, backgroundColor: backgroundColor)
.padding(.horizontal, 12)
.padding(.vertical, 6)
.background(backgroundColor)
@@ -258,7 +258,7 @@ struct ChatItemInfoView: View {
.frame(maxWidth: maxWidth, alignment: .leading)
}
@ViewBuilder private func textBubble(_ text: String, _ formattedText: [FormattedText]?, _ sender: String? = nil, backgroundColor: UIColor) -> some View {
@ViewBuilder private func textBubble(_ text: String, _ formattedText: [FormattedText]?, _ sender: String? = nil, backgroundColor: Color) -> some View {
if text != "" {
TextBubble(text: text, formattedText: formattedText, sender: sender, mentions: ci.mentions, userMemberId: userMemberId, backgroundColor: backgroundColor)
} else {
@@ -275,11 +275,11 @@ struct ChatItemInfoView: View {
var sender: String? = nil
var mentions: [String: CIMention]?
var userMemberId: String?
var backgroundColor: UIColor
var backgroundColor: Color
@State private var showSecrets: Set<Int> = []
var body: some View {
let r = messageText(text, formattedText, sender: sender, mentions: mentions, userMemberId: userMemberId, showSecrets: showSecrets, backgroundColor: backgroundColor)
let r = messageText(text, formattedText, sender: sender, mentions: mentions, userMemberId: userMemberId, showSecrets: showSecrets, backgroundColor: UIColor(backgroundColor))
return msgTextResultView(r, Text(AttributedString(r.string)), showSecrets: $showSecrets)
}
}
@@ -305,7 +305,7 @@ struct ChatItemInfoView: View {
private func quotedMsgView(_ qi: CIQuote, _ maxWidth: CGFloat) -> some View {
let backgroundColor = quotedMsgFrameColor(qi, theme)
return VStack(alignment: .leading, spacing: 4) {
textBubble(qi.text, qi.formattedText, qi.getSender(nil), backgroundColor: UIColor(backgroundColor))
textBubble(qi.text, qi.formattedText, qi.getSender(nil), backgroundColor: backgroundColor)
.padding(.horizontal, 12)
.padding(.vertical, 6)
.background(quotedMsgFrameColor(qi, theme))
+8 -5
View File
@@ -403,7 +403,7 @@ struct ChatView: View {
private func connectInProgressView(_ s: String) -> some View {
VStack(spacing: 0) {
Divider()
HStack(spacing: 12) {
ProgressView()
Text(s)
@@ -733,7 +733,7 @@ struct ChatView: View {
return Group {
if case .chatBanner = ci.content {
VStack {
ChatBannerView(chat: chat)
ChatBannerView(chat: $chat)
.padding(.bottom, 90)
.padding(.top, 8)
@@ -822,7 +822,8 @@ struct ChatView: View {
struct ChatBannerView: View {
@EnvironmentObject var theme: AppTheme
@AppStorage(DEFAULT_CHAT_ITEM_ROUNDNESS) private var roundness = defaultChatItemRoundness
@ObservedObject var chat: Chat
@Binding @ObservedObject var chat: Chat
@State private var showSecrets: Set<Int> = []
var body: some View {
let v = VStack(spacing: 8) {
@@ -846,8 +847,8 @@ struct ChatView: View {
}
if let shortDescr = chat.chatInfo.shortDescr {
Text(shortDescr)
.font(.subheadline)
let r = markdownText(shortDescr, textStyle: .subheadline, showSecrets: showSecrets, backgroundColor: theme.colors.background)
msgTextResultView(r, Text(AttributedString(r.string)), showSecrets: $showSecrets, centered: true, smallFont: true)
.multilineTextAlignment(.center)
.lineLimit(4)
.fixedSize(horizontal: false, vertical: true)
@@ -957,6 +958,8 @@ struct ChatView: View {
if !contact.sndReady && contact.active && !contact.sendMsgToConnect && !contact.nextAcceptContactRequest {
contact.preparedContact?.uiConnLinkType == .con
? "contact should accept…"
: contact.contactGroupMemberId != nil
? "contact should accept…"
: "connecting…"
} else {
nil
@@ -453,6 +453,8 @@ struct ComposeView: View {
}
} else if contact?.nextAcceptContactRequest == true, let crId = contact?.contactRequestId {
ContextContactRequestActionsView(contactRequestId: crId)
} else if let ct = contact, ct.nextAcceptContactRequest, let groupDirectInv = ct.groupDirectInv {
ContextMemberContactActionsView(contact: ct, groupDirectInv: groupDirectInv)
} else {
HStack (alignment: .center) {
attachmentButton()
@@ -0,0 +1,110 @@
//
// ContextMemberContactActionsView.swift
// SimpleX (iOS)
//
// Created by spaced4ndy on 31.07.2025.
// Copyright © 2025 SimpleX Chat. All rights reserved.
//
import SwiftUI
import SimpleXChat
struct ContextMemberContactActionsView: View {
@EnvironmentObject var theme: AppTheme
var contact: Contact
var groupDirectInv: GroupDirectInvitation
@UserDefault(DEFAULT_TOOLBAR_MATERIAL) private var toolbarMaterial = ToolbarMaterial.defaultMaterial
@State private var inProgress = false
@State private var progressByTimeout = false
var body: some View {
VStack {
if groupDirectInv.memberRemoved {
Label("Member is deleted - can't accept request", systemImage: "info.circle")
.foregroundColor(theme.colors.secondary)
.font(.subheadline)
.padding(.horizontal)
.frame(maxWidth: .infinity, minHeight: 60)
} else {
HStack(spacing: 0) {
Button(role: .destructive, action: { showRejectMemberContactRequestAlert(contact) }) {
Label("Reject", systemImage: "multiply")
}
.frame(maxWidth: .infinity, minHeight: 60)
Button {
acceptMemberContactRequest(contact, inProgress: $inProgress)
} label: {
Label("Accept", systemImage: "checkmark")
}
.frame(maxWidth: .infinity, minHeight: 60)
}
}
}
.disabled(inProgress || groupDirectInv.memberRemoved)
.frame(maxWidth: .infinity)
.background(ToolbarMaterial.material(toolbarMaterial))
.opacity(progressByTimeout ? 0.4 : 1)
.overlay {
if progressByTimeout {
ProgressView()
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}
.onChange(of: inProgress) { inPrgrs in
if inPrgrs {
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
progressByTimeout = inProgress
}
} else {
progressByTimeout = false
}
}
}
}
func showRejectMemberContactRequestAlert(_ contact: Contact) {
showAlert(
NSLocalizedString("Reject contact request", comment: "alert title"),
message: NSLocalizedString("The sender will NOT be notified", comment: "alert message"),
actions: {[
UIAlertAction(title: NSLocalizedString("Reject", comment: "alert action"), style: .destructive) { _ in
deleteContact(contact)
},
cancelAlertAction
]}
)
}
private func deleteContact(_ contact: Contact) {
Task {
do {
_ = try await apiDeleteContact(id: contact.contactId, chatDeleteMode: .full(notify: false))
await MainActor.run {
ChatModel.shared.removeChat(contact.id)
ChatModel.shared.chatId = nil
}
} catch let error {
logger.error("apiDeleteContact: \(responseError(error))")
await MainActor.run {
showAlert(
NSLocalizedString("Error deleting chat!", comment: "alert title"),
message: responseError(error)
)
}
}
}
}
func acceptMemberContactRequest(_ contact: Contact, inProgress: Binding<Bool>? = nil) {
Task {
await acceptMemberContact(contactId: contact.contactId, inProgress: inProgress)
}
}
#Preview {
ContextMemberContactActionsView(
contact: Contact.sampleData,
groupDirectInv: GroupDirectInvitation.sampleData
)
}
@@ -34,6 +34,7 @@ struct GroupChatInfoView: View {
@AppStorage(DEFAULT_DEVELOPER_TOOLS) private var developerTools = false
@State private var searchText: String = ""
@FocusState private var searchFocussed
@State private var showSecrets: Set<Int> = []
enum GroupChatInfoViewAlert: Identifiable {
case deleteGroupAlert
@@ -253,10 +254,11 @@ struct GroupChatInfoView: View {
.padding(.bottom, 2)
}
if let descr = cInfo.shortDescr?.trimmingCharacters(in: .whitespacesAndNewlines), descr != "" {
Text(descr)
.font(.subheadline)
let r = markdownText(descr, textStyle: .subheadline, showSecrets: showSecrets, backgroundColor: theme.colors.background)
msgTextResultView(r, Text(AttributedString(r.string)), showSecrets: $showSecrets, centered: true, smallFont: true)
.multilineTextAlignment(.center)
.lineLimit(4)
.fixedSize(horizontal: false, vertical: true)
}
}
.frame(maxWidth: .infinity, alignment: .center)
@@ -59,7 +59,7 @@ struct GroupWelcomeView: View {
}
private func textPreview() -> some View {
let r = messageText(welcomeText, parseSimpleXMarkdown(welcomeText), sender: nil, mentions: nil, userMemberId: nil, showSecrets: showSecrets, backgroundColor: UIColor(theme.colors.background))
let r = markdownText(welcomeText, showSecrets: showSecrets, backgroundColor: theme.colors.background)
return msgTextResultView(r, Text(AttributedString(r.string)), showSecrets: $showSecrets)
.frame(minHeight: 130, alignment: .topLeading)
.frame(maxWidth: .infinity, alignment: .leading)
@@ -130,26 +130,54 @@ struct ChatListNavLink: View {
}
}
.swipeActions(edge: .trailing, allowsFullSwipe: true) {
if contact.nextAcceptContactRequest,
let contactRequestId = contact.contactRequestId {
Button {
Task { await acceptContactRequest(incognito: false, contactRequestId: contactRequestId) }
} label: { SwipeLabel(NSLocalizedString("Accept", comment: "swipe action"), systemImage: "checkmark", inverted: oneHandUI) }
.tint(theme.colors.primary)
if !ChatModel.shared.addressShortLinkDataSet {
if contact.nextAcceptContactRequest {
if let contactRequestId = contact.contactRequestId {
Button {
Task { await acceptContactRequest(incognito: true, contactRequestId: contactRequestId) }
} label: {
SwipeLabel(NSLocalizedString("Accept incognito", comment: "swipe action"), systemImage: "theatermasks.fill", inverted: oneHandUI)
Task { await acceptContactRequest(incognito: false, contactRequestId: contactRequestId) }
} label: { SwipeLabel(NSLocalizedString("Accept", comment: "swipe action"), systemImage: "checkmark", inverted: oneHandUI) }
.tint(theme.colors.primary)
if !ChatModel.shared.addressShortLinkDataSet {
Button {
Task { await acceptContactRequest(incognito: true, contactRequestId: contactRequestId) }
} label: {
SwipeLabel(NSLocalizedString("Accept incognito", comment: "swipe action"), systemImage: "theatermasks.fill", inverted: oneHandUI)
}
.tint(.indigo)
}
.tint(.indigo)
Button {
AlertManager.shared.showAlert(rejectContactRequestAlert(contactRequestId))
} label: {
SwipeLabel(NSLocalizedString("Reject", comment: "swipe action"), systemImage: "multiply", inverted: oneHandUI)
}
.tint(.red)
} else if let groupDirectInv = contact.groupDirectInv, !groupDirectInv.memberRemoved {
Button {
acceptMemberContactRequest(contact)
} label: {
Label("Accept", systemImage: "checkmark")
}
.tint(theme.colors.primary)
Button {
showRejectMemberContactRequestAlert(contact)
} label: {
Label("Reject", systemImage: "multiply")
}
.tint(.red)
} else {
Button {
deleteContactDialog(
chat,
contact,
dismissToChatList: false,
showAlert: { alert = $0 },
showActionSheet: { actionSheet = $0 },
showSheetContent: { sheet = $0 }
)
} label: {
deleteLabel
}
.tint(.red)
}
Button {
AlertManager.shared.showAlert(rejectContactRequestAlert(contactRequestId))
} label: {
SwipeLabel(NSLocalizedString("Reject", comment: "swipe action"), systemImage: "multiply", inverted: oneHandUI)
}
.tint(.red)
} else {
tagChatButton(chat)
if !chat.chatItems.isEmpty {
@@ -167,7 +167,7 @@ struct ChatPreviewView: View {
let color =
deleting
? theme.colors.secondary
: contact.nextAcceptContactRequest || contact.sendMsgToConnect
: (contact.nextAcceptContactRequest && !(contact.groupDirectInv?.memberRemoved ?? false)) || contact.sendMsgToConnect
? theme.colors.primary
: !contact.sndReady
? theme.colors.secondary
@@ -274,7 +274,7 @@ struct ChatPreviewView: View {
private func messageDraft(_ draft: ComposeState) -> (Text, Bool) {
let msg = draft.message
let r = messageText(msg, parseSimpleXMarkdown(msg), sender: nil, preview: true, mentions: draft.mentions, userMemberId: nil, showSecrets: nil, backgroundColor: UIColor(theme.colors.background))
let r = markdownText(msg, preview: true, mentions: draft.mentions, backgroundColor: theme.colors.background)
return (image("rectangle.and.pencil.and.ellipsis", color: theme.colors.primary)
+ attachment()
+ Text(AttributedString(r.string)),
@@ -81,14 +81,16 @@ struct ContactListNavLink: View {
ItemsModel.shared.loadOpenChat(contact.id)
}
} label: {
contactRequestPreview()
contactRequestPreview(color: contact.groupDirectInv?.memberRemoved == true ? theme.colors.secondary : theme.colors.primary)
}
.swipeActions(edge: .trailing, allowsFullSwipe: true) {
if let contactRequestId = contact.contactRequestId {
Button {
Task { await acceptContactRequest(incognito: false, contactRequestId: contactRequestId) }
} label: { Label("Accept", systemImage: "checkmark") }
.tint(theme.colors.primary)
} label: {
Label("Accept", systemImage: "checkmark")
}
.tint(theme.colors.primary)
if !ChatModel.shared.addressShortLinkDataSet {
Button {
Task { await acceptContactRequest(incognito: true, contactRequestId: contactRequestId) }
@@ -103,6 +105,33 @@ struct ContactListNavLink: View {
Label("Reject", systemImage: "multiply")
}
.tint(.red)
} else if let groupDirectInv = contact.groupDirectInv, !groupDirectInv.memberRemoved {
Button {
acceptMemberContactRequest(contact)
} label: {
Label("Accept", systemImage: "checkmark")
}
.tint(theme.colors.primary)
Button {
showRejectMemberContactRequestAlert(contact)
} label: {
Label("Reject", systemImage: "multiply")
}
.tint(.red)
} else {
Button {
deleteContactDialog(
chat,
contact,
dismissToChatList: false,
showAlert: { alert = $0 },
showActionSheet: { actionSheet = $0 },
showSheetContent: { sheet = $0 }
)
} label: {
Label("Delete", systemImage: "trash")
}
.tint(.red)
}
}
}
@@ -254,7 +283,7 @@ struct ContactListNavLink: View {
Button {
showContactRequestDialog = true
} label: {
contactRequestPreview()
contactRequestPreview(color: theme.colors.primary)
}
.swipeActions(edge: .trailing, allowsFullSwipe: true) {
Button {
@@ -285,12 +314,12 @@ struct ContactListNavLink: View {
}
}
func contactRequestPreview() -> some View {
func contactRequestPreview(color: Color) -> some View {
HStack{
ProfileImage(imageStr: chat.chatInfo.image, size: 30)
Text(chat.chatInfo.chatViewName)
.foregroundColor(.accentColor)
.foregroundColor(color)
.lineLimit(1)
Spacer()
@@ -299,7 +328,7 @@ struct ContactListNavLink: View {
.resizable()
.scaledToFill()
.frame(width: 14, height: 14)
.foregroundColor(.accentColor)
.foregroundColor(color)
}
}
}
@@ -32,6 +32,8 @@ struct PrivacySettings: View {
@State private var groupReceiptsReset = false
@State private var groupReceiptsOverrides = 0
@State private var groupReceiptsDialogue = false
@State private var autoAcceptMemberContacts = false
@State private var autoAcceptMemberContactsReset = false
@State private var alert: PrivacySettingsViewAlert?
enum PrivacySettingsViewAlert: Identifiable {
@@ -149,6 +151,18 @@ struct PrivacySettings: View {
}
}
Section {
settingsRow("checkmark", color: theme.colors.secondary) {
Toggle("Auto-accept", isOn: $autoAcceptMemberContacts)
}
} header: {
Text("Contact requests from groups")
.foregroundColor(theme.colors.secondary)
} footer: {
Text("This setting is for your current profile **\(m.currentUser?.displayName ?? "")**.")
.foregroundColor(theme.colors.secondary)
}
Section {
settingsRow("person", color: theme.colors.secondary) {
Toggle("Contacts", isOn: $contactReceipts)
@@ -207,6 +221,13 @@ struct PrivacySettings: View {
setOrAskSendReceiptsGroups(groupReceipts)
}
}
.onChange(of: autoAcceptMemberContacts) { _ in
if autoAcceptMemberContactsReset {
autoAcceptMemberContactsReset = false
} else {
setAutoAcceptGrpDirectInvs(autoAcceptMemberContacts)
}
}
.onAppear {
if let u = m.currentUser {
if contactReceipts != u.sendRcptsContacts {
@@ -217,6 +238,10 @@ struct PrivacySettings: View {
groupReceiptsReset = true
groupReceipts = u.sendRcptsSmallGroups
}
if autoAcceptMemberContacts != u.autoAcceptMemberContacts {
autoAcceptMemberContactsReset = true
autoAcceptMemberContacts = u.autoAcceptMemberContacts
}
}
}
.alert(item: $alert) { alert in
@@ -333,6 +358,23 @@ struct PrivacySettings: View {
}
}
private func setAutoAcceptGrpDirectInvs(_ enable: Bool) {
Task {
do {
if let currentUser = m.currentUser {
try await apiSetUserAutoAcceptMemberContacts(currentUser.userId, enable: enable)
await MainActor.run {
var updatedUser = currentUser
updatedUser.autoAcceptMemberContacts = enable
m.updateUser(updatedUser)
}
}
} catch let error {
alert = .error(title: "Error setting auto-accept", error: "Error: \(responseError(error))")
}
}
}
private func simplexLockRow(_ value: LocalizedStringKey) -> some View {
HStack {
Text("SimpleX Lock")
@@ -445,7 +487,7 @@ struct SimplexLockView: View {
Toggle("Allow sharing", isOn: $allowShareExtension)
}
}
if performLA && laMode == .passcode {
Section(header: Text("Self-destruct passcode").foregroundColor(theme.colors.secondary)) {
Toggle(isOn: $selfDestruct) {
@@ -465,6 +465,7 @@ time interval</note>
</trans-unit>
<trans-unit id="1 year" xml:space="preserve">
<source>1 year</source>
<target>1 година</target>
<note>delete after time</note>
</trans-unit>
<trans-unit id="1-time link" xml:space="preserve">
@@ -565,10 +566,12 @@ swipe action</note>
</trans-unit>
<trans-unit id="Accept as member" xml:space="preserve">
<source>Accept as member</source>
<target>Приеми като член</target>
<note>alert action</note>
</trans-unit>
<trans-unit id="Accept as observer" xml:space="preserve">
<source>Accept as observer</source>
<target>Приеми като наблюдател</target>
<note>alert action</note>
</trans-unit>
<trans-unit id="Accept conditions" xml:space="preserve">
@@ -583,6 +586,7 @@ swipe action</note>
</trans-unit>
<trans-unit id="Accept contact request" xml:space="preserve">
<source>Accept contact request</source>
<target>Приеми заявка за контакт</target>
<note>alert title</note>
</trans-unit>
<trans-unit id="Accept contact request from %@?" xml:space="preserve">
@@ -1993,6 +1997,10 @@ This is your own one-time link!</source>
<target>Настройки за контакт</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Contact requests from groups" xml:space="preserve">
<source>Contact requests from groups</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Contact will be deleted - this cannot be undone!" xml:space="preserve">
<source>Contact will be deleted - this cannot be undone!</source>
<note>No comment provided by engineer.</note>
@@ -3179,7 +3187,7 @@ chat item action</note>
<trans-unit id="Error deleting chat!" xml:space="preserve">
<source>Error deleting chat!</source>
<target>Грешка при изтриването на чата!</target>
<note>No comment provided by engineer.</note>
<note>alert title</note>
</trans-unit>
<trans-unit id="Error deleting connection" xml:space="preserve">
<source>Error deleting connection</source>
@@ -3354,6 +3362,10 @@ chat item action</note>
<target>Грешка при изпращане на съобщение</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error setting auto-accept" xml:space="preserve">
<source>Error setting auto-accept</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error setting delivery receipts!" xml:space="preserve">
<source>Error setting delivery receipts!</source>
<target>Грешка при настройването на потвърждениeто за доставка!!</target>
@@ -4617,6 +4629,10 @@ This is your link for group %@!</source>
<source>Member inactive</source>
<note>item status text</note>
</trans-unit>
<trans-unit id="Member is deleted - can't accept request" xml:space="preserve">
<source>Member is deleted - can't accept request</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Member reports" xml:space="preserve">
<source>Member reports</source>
<note>chat feature</note>
@@ -7716,6 +7732,10 @@ It can happen because of some bug or when the connection is compromised.</source
<target>Тази настройка се прилага за съобщения в текущия ви профил **%@**.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This setting is for your current profile **%@**." xml:space="preserve">
<source>This setting is for your current profile **%@**.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Time to disappear is set only for new contacts." xml:space="preserve">
<source>Time to disappear is set only for new contacts.</source>
<note>No comment provided by engineer.</note>
@@ -9115,11 +9135,6 @@ marked deleted chat item preview text</note>
<target>свързан</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="connected directly" xml:space="preserve">
<source>connected directly</source>
<target>свързан директно</target>
<note>rcv group event chat item</note>
</trans-unit>
<trans-unit id="connecting" xml:space="preserve">
<source>connecting</source>
<target>свързване</target>
@@ -9685,6 +9700,14 @@ time to disappear</note>
<source>request to join rejected</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="requested connection" xml:space="preserve">
<source>requested connection</source>
<note>rcv group event chat item</note>
</trans-unit>
<trans-unit id="requested connection from group %@" xml:space="preserve">
<source>requested connection from group %@</source>
<note>rcv direct event chat item</note>
</trans-unit>
<trans-unit id="requested to connect" xml:space="preserve">
<source>requested to connect</source>
<note>chat list item title</note>
@@ -1900,6 +1900,10 @@ This is your own one-time link!</source>
<target>Předvolby kontaktů</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Contact requests from groups" xml:space="preserve">
<source>Contact requests from groups</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Contact will be deleted - this cannot be undone!" xml:space="preserve">
<source>Contact will be deleted - this cannot be undone!</source>
<note>No comment provided by engineer.</note>
@@ -3054,7 +3058,7 @@ chat item action</note>
<trans-unit id="Error deleting chat!" xml:space="preserve">
<source>Error deleting chat!</source>
<target>Chyba při mazání chatu!</target>
<note>No comment provided by engineer.</note>
<note>alert title</note>
</trans-unit>
<trans-unit id="Error deleting connection" xml:space="preserve">
<source>Error deleting connection</source>
@@ -3225,6 +3229,10 @@ chat item action</note>
<target>Chyba při odesílání zprávy</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error setting auto-accept" xml:space="preserve">
<source>Error setting auto-accept</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error setting delivery receipts!" xml:space="preserve">
<source>Error setting delivery receipts!</source>
<target>Chyba nastavování potvrzení o doručení!</target>
@@ -4448,6 +4456,10 @@ This is your link for group %@!</source>
<source>Member inactive</source>
<note>item status text</note>
</trans-unit>
<trans-unit id="Member is deleted - can't accept request" xml:space="preserve">
<source>Member is deleted - can't accept request</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Member reports" xml:space="preserve">
<source>Member reports</source>
<note>chat feature</note>
@@ -7470,6 +7482,10 @@ Může se to stát kvůli nějaké chybě, nebo pokud je spojení kompromitován
<target>Toto nastavení platí pro zprávy ve vašem aktuálním chat profilu **%@**.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This setting is for your current profile **%@**." xml:space="preserve">
<source>This setting is for your current profile **%@**.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Time to disappear is set only for new contacts." xml:space="preserve">
<source>Time to disappear is set only for new contacts.</source>
<note>No comment provided by engineer.</note>
@@ -8815,11 +8831,6 @@ marked deleted chat item preview text</note>
<target>připojeno</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="connected directly" xml:space="preserve">
<source>connected directly</source>
<target>připojeno přímo</target>
<note>rcv group event chat item</note>
</trans-unit>
<trans-unit id="connecting" xml:space="preserve">
<source>connecting</source>
<target>připojování</target>
@@ -9377,6 +9388,14 @@ time to disappear</note>
<source>request to join rejected</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="requested connection" xml:space="preserve">
<source>requested connection</source>
<note>rcv group event chat item</note>
</trans-unit>
<trans-unit id="requested connection from group %@" xml:space="preserve">
<source>requested connection from group %@</source>
<note>rcv direct event chat item</note>
</trans-unit>
<trans-unit id="requested to connect" xml:space="preserve">
<source>requested to connect</source>
<note>chat list item title</note>
@@ -2085,6 +2085,10 @@ Das ist Ihr eigener Einmal-Link!</target>
<target>Kontakt-Präferenzen</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Contact requests from groups" xml:space="preserve">
<source>Contact requests from groups</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Contact will be deleted - this cannot be undone!" xml:space="preserve">
<source>Contact will be deleted - this cannot be undone!</source>
<target>Kontakt wird gelöscht. Dies kann nicht rückgängig gemacht werden!</target>
@@ -3338,7 +3342,7 @@ chat item action</note>
<trans-unit id="Error deleting chat!" xml:space="preserve">
<source>Error deleting chat!</source>
<target>Fehler beim Löschen des Chats!</target>
<note>No comment provided by engineer.</note>
<note>alert title</note>
</trans-unit>
<trans-unit id="Error deleting connection" xml:space="preserve">
<source>Error deleting connection</source>
@@ -3525,6 +3529,10 @@ chat item action</note>
<target>Fehler beim Senden der Nachricht</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error setting auto-accept" xml:space="preserve">
<source>Error setting auto-accept</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error setting delivery receipts!" xml:space="preserve">
<source>Error setting delivery receipts!</source>
<target>Fehler beim Setzen von Empfangsbestätigungen!</target>
@@ -4862,6 +4870,10 @@ Das ist Ihr Link für die Gruppe %@!</target>
<target>Mitglied inaktiv</target>
<note>item status text</note>
</trans-unit>
<trans-unit id="Member is deleted - can't accept request" xml:space="preserve">
<source>Member is deleted - can't accept request</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Member reports" xml:space="preserve">
<source>Member reports</source>
<target>Mitglieder-Meldungen</target>
@@ -8224,6 +8236,10 @@ Dies kann passieren, wenn es einen Fehler gegeben hat oder die Verbindung kompro
<target>Diese Einstellung gilt für Nachrichten in Ihrem aktuellen Chat-Profil **%@**.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This setting is for your current profile **%@**." xml:space="preserve">
<source>This setting is for your current profile **%@**.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Time to disappear is set only for new contacts." xml:space="preserve">
<source>Time to disappear is set only for new contacts.</source>
<target>Die Zeit bis zum Verschwinden wird nur für neue Kontakte eingestellt.</target>
@@ -9708,11 +9724,6 @@ marked deleted chat item preview text</note>
<target>Verbunden</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="connected directly" xml:space="preserve">
<source>connected directly</source>
<target>Direkt miteinander verbunden</target>
<note>rcv group event chat item</note>
</trans-unit>
<trans-unit id="connecting" xml:space="preserve">
<source>connecting</source>
<target>verbinde</target>
@@ -10302,6 +10313,14 @@ time to disappear</note>
<target>Beitrittsanfrage abgelehnt</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="requested connection" xml:space="preserve">
<source>requested connection</source>
<note>rcv group event chat item</note>
</trans-unit>
<trans-unit id="requested connection from group %@" xml:space="preserve">
<source>requested connection from group %@</source>
<note>rcv direct event chat item</note>
</trans-unit>
<trans-unit id="requested to connect" xml:space="preserve">
<source>requested to connect</source>
<target>Zur Verbindung aufgefordert</target>
@@ -2085,6 +2085,11 @@ This is your own one-time link!</target>
<target>Contact preferences</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Contact requests from groups" xml:space="preserve">
<source>Contact requests from groups</source>
<target>Contact requests from groups</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Contact will be deleted - this cannot be undone!" xml:space="preserve">
<source>Contact will be deleted - this cannot be undone!</source>
<target>Contact will be deleted - this cannot be undone!</target>
@@ -3338,7 +3343,7 @@ chat item action</note>
<trans-unit id="Error deleting chat!" xml:space="preserve">
<source>Error deleting chat!</source>
<target>Error deleting chat!</target>
<note>No comment provided by engineer.</note>
<note>alert title</note>
</trans-unit>
<trans-unit id="Error deleting connection" xml:space="preserve">
<source>Error deleting connection</source>
@@ -3525,6 +3530,11 @@ chat item action</note>
<target>Error sending message</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error setting auto-accept" xml:space="preserve">
<source>Error setting auto-accept</source>
<target>Error setting auto-accept</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error setting delivery receipts!" xml:space="preserve">
<source>Error setting delivery receipts!</source>
<target>Error setting delivery receipts!</target>
@@ -4862,6 +4872,11 @@ This is your link for group %@!</target>
<target>Member inactive</target>
<note>item status text</note>
</trans-unit>
<trans-unit id="Member is deleted - can't accept request" xml:space="preserve">
<source>Member is deleted - can't accept request</source>
<target>Member is deleted - can't accept request</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Member reports" xml:space="preserve">
<source>Member reports</source>
<target>Member reports</target>
@@ -8224,6 +8239,11 @@ It can happen because of some bug or when the connection is compromised.</target
<target>This setting applies to messages in your current chat profile **%@**.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This setting is for your current profile **%@**." xml:space="preserve">
<source>This setting is for your current profile **%@**.</source>
<target>This setting is for your current profile **%@**.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Time to disappear is set only for new contacts." xml:space="preserve">
<source>Time to disappear is set only for new contacts.</source>
<target>Time to disappear is set only for new contacts.</target>
@@ -9708,11 +9728,6 @@ marked deleted chat item preview text</note>
<target>connected</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="connected directly" xml:space="preserve">
<source>connected directly</source>
<target>connected directly</target>
<note>rcv group event chat item</note>
</trans-unit>
<trans-unit id="connecting" xml:space="preserve">
<source>connecting</source>
<target>connecting</target>
@@ -10302,6 +10317,16 @@ time to disappear</note>
<target>request to join rejected</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="requested connection" xml:space="preserve">
<source>requested connection</source>
<target>requested connection</target>
<note>rcv group event chat item</note>
</trans-unit>
<trans-unit id="requested connection from group %@" xml:space="preserve">
<source>requested connection from group %@</source>
<target>requested connection from group %@</target>
<note>rcv direct event chat item</note>
</trans-unit>
<trans-unit id="requested to connect" xml:space="preserve">
<source>requested to connect</source>
<target>requested to connect</target>
@@ -1124,7 +1124,7 @@ swipe action</note>
</trans-unit>
<trans-unit id="Audio &amp; video calls" xml:space="preserve">
<source>Audio &amp; video calls</source>
<target>Llamadas y videollamadas</target>
<target>Llamadas y Videollamadas</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Audio and video calls" xml:space="preserve">
@@ -2085,6 +2085,10 @@ This is your own one-time link!</source>
<target>Preferencias de contacto</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Contact requests from groups" xml:space="preserve">
<source>Contact requests from groups</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Contact will be deleted - this cannot be undone!" xml:space="preserve">
<source>Contact will be deleted - this cannot be undone!</source>
<target>El contacto será eliminado. ¡No puede deshacerse!</target>
@@ -3017,7 +3021,7 @@ chat item action</note>
</trans-unit>
<trans-unit id="Enable disappearing messages by default." xml:space="preserve">
<source>Enable disappearing messages by default.</source>
<target>Activa por defecto los mensajes temporaes.</target>
<target>Activa por defecto los mensajes temporales.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Enable for all" xml:space="preserve">
@@ -3338,7 +3342,7 @@ chat item action</note>
<trans-unit id="Error deleting chat!" xml:space="preserve">
<source>Error deleting chat!</source>
<target>¡Error al eliminar chat!</target>
<note>No comment provided by engineer.</note>
<note>alert title</note>
</trans-unit>
<trans-unit id="Error deleting connection" xml:space="preserve">
<source>Error deleting connection</source>
@@ -3525,6 +3529,10 @@ chat item action</note>
<target>Error al enviar mensaje</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error setting auto-accept" xml:space="preserve">
<source>Error setting auto-accept</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error setting delivery receipts!" xml:space="preserve">
<source>Error setting delivery receipts!</source>
<target>¡Error al configurar confirmaciones de entrega!</target>
@@ -4167,7 +4175,7 @@ Error: %2$@</target>
</trans-unit>
<trans-unit id="Hide:" xml:space="preserve">
<source>Hide:</source>
<target>Ocultar:</target>
<target>Oculta:</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="History" xml:space="preserve">
@@ -4862,6 +4870,10 @@ This is your link for group %@!</source>
<target>Miembro inactivo</target>
<note>item status text</note>
</trans-unit>
<trans-unit id="Member is deleted - can't accept request" xml:space="preserve">
<source>Member is deleted - can't accept request</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Member reports" xml:space="preserve">
<source>Member reports</source>
<target>Informes de miembros</target>
@@ -8001,7 +8013,7 @@ Puede ocurrir por algún bug o cuando la conexión está comprometida.</target>
</trans-unit>
<trans-unit id="The address will be short, and your profile will be shared via the address." xml:space="preserve">
<source>The address will be short, and your profile will be shared via the address.</source>
<target>La dirección será corta y tu perfil se comparti mediante la dirección.</target>
<target>La dirección pasará a ser corta y tu perfil se compartido mediante la dirección.</target>
<note>alert message</note>
</trans-unit>
<trans-unit id="The app can notify you when you receive messages or contact requests - please open settings to enable." xml:space="preserve">
@@ -8224,6 +8236,10 @@ Puede ocurrir por algún bug o cuando la conexión está comprometida.</target>
<target>Esta configuración se aplica a los mensajes del perfil actual **%@**.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This setting is for your current profile **%@**." xml:space="preserve">
<source>This setting is for your current profile **%@**.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Time to disappear is set only for new contacts." xml:space="preserve">
<source>Time to disappear is set only for new contacts.</source>
<target>Mensajes temporales activados sólo para los contactos nuevos.</target>
@@ -9708,11 +9724,6 @@ marked deleted chat item preview text</note>
<target>conectado</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="connected directly" xml:space="preserve">
<source>connected directly</source>
<target>conectado directamente</target>
<note>rcv group event chat item</note>
</trans-unit>
<trans-unit id="connecting" xml:space="preserve">
<source>connecting</source>
<target>conectando...</target>
@@ -10302,6 +10313,14 @@ time to disappear</note>
<target>petición para unirse rechazada</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="requested connection" xml:space="preserve">
<source>requested connection</source>
<note>rcv group event chat item</note>
</trans-unit>
<trans-unit id="requested connection from group %@" xml:space="preserve">
<source>requested connection from group %@</source>
<note>rcv direct event chat item</note>
</trans-unit>
<trans-unit id="requested to connect" xml:space="preserve">
<source>requested to connect</source>
<target>solicitado para conectar</target>
@@ -1871,6 +1871,10 @@ This is your own one-time link!</source>
<target>Kontaktin asetukset</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Contact requests from groups" xml:space="preserve">
<source>Contact requests from groups</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Contact will be deleted - this cannot be undone!" xml:space="preserve">
<source>Contact will be deleted - this cannot be undone!</source>
<note>No comment provided by engineer.</note>
@@ -3023,7 +3027,7 @@ chat item action</note>
<trans-unit id="Error deleting chat!" xml:space="preserve">
<source>Error deleting chat!</source>
<target>Virhe keskutelun poistamisessa!</target>
<note>No comment provided by engineer.</note>
<note>alert title</note>
</trans-unit>
<trans-unit id="Error deleting connection" xml:space="preserve">
<source>Error deleting connection</source>
@@ -3193,6 +3197,10 @@ chat item action</note>
<target>Virhe viestin lähettämisessä</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error setting auto-accept" xml:space="preserve">
<source>Error setting auto-accept</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error setting delivery receipts!" xml:space="preserve">
<source>Error setting delivery receipts!</source>
<target>Virhe toimituskuittauksien asettamisessa!</target>
@@ -4416,6 +4424,10 @@ This is your link for group %@!</source>
<source>Member inactive</source>
<note>item status text</note>
</trans-unit>
<trans-unit id="Member is deleted - can't accept request" xml:space="preserve">
<source>Member is deleted - can't accept request</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Member reports" xml:space="preserve">
<source>Member reports</source>
<note>chat feature</note>
@@ -7434,6 +7446,10 @@ Tämä voi johtua jostain virheestä tai siitä, että yhteys on vaarantunut.</t
<target>Tämä asetus koskee nykyisen keskusteluprofiilisi viestejä *%@**.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This setting is for your current profile **%@**." xml:space="preserve">
<source>This setting is for your current profile **%@**.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Time to disappear is set only for new contacts." xml:space="preserve">
<source>Time to disappear is set only for new contacts.</source>
<note>No comment provided by engineer.</note>
@@ -8778,10 +8794,6 @@ marked deleted chat item preview text</note>
<target>yhdistetty</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="connected directly" xml:space="preserve">
<source>connected directly</source>
<note>rcv group event chat item</note>
</trans-unit>
<trans-unit id="connecting" xml:space="preserve">
<source>connecting</source>
<target>yhdistää</target>
@@ -9339,6 +9351,14 @@ time to disappear</note>
<source>request to join rejected</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="requested connection" xml:space="preserve">
<source>requested connection</source>
<note>rcv group event chat item</note>
</trans-unit>
<trans-unit id="requested connection from group %@" xml:space="preserve">
<source>requested connection from group %@</source>
<note>rcv direct event chat item</note>
</trans-unit>
<trans-unit id="requested to connect" xml:space="preserve">
<source>requested to connect</source>
<note>chat list item title</note>
@@ -2069,6 +2069,10 @@ Il s'agit de votre propre lien unique !</target>
<target>Préférences de contact</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Contact requests from groups" xml:space="preserve">
<source>Contact requests from groups</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Contact will be deleted - this cannot be undone!" xml:space="preserve">
<source>Contact will be deleted - this cannot be undone!</source>
<target>Le contact sera supprimé - il n'est pas possible de revenir en arrière!</target>
@@ -3313,7 +3317,7 @@ chat item action</note>
<trans-unit id="Error deleting chat!" xml:space="preserve">
<source>Error deleting chat!</source>
<target>Erreur lors de la suppression du chat!</target>
<note>No comment provided by engineer.</note>
<note>alert title</note>
</trans-unit>
<trans-unit id="Error deleting connection" xml:space="preserve">
<source>Error deleting connection</source>
@@ -3498,6 +3502,10 @@ chat item action</note>
<target>Erreur lors de l'envoi du message</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error setting auto-accept" xml:space="preserve">
<source>Error setting auto-accept</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error setting delivery receipts!" xml:space="preserve">
<source>Error setting delivery receipts!</source>
<target>Erreur lors de la configuration des accusés de réception !</target>
@@ -4814,6 +4822,10 @@ Voici votre lien pour le groupe %@ !</target>
<target>Membre inactif</target>
<note>item status text</note>
</trans-unit>
<trans-unit id="Member is deleted - can't accept request" xml:space="preserve">
<source>Member is deleted - can't accept request</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Member reports" xml:space="preserve">
<source>Member reports</source>
<note>chat feature</note>
@@ -8082,6 +8094,10 @@ Cela peut se produire en raison d'un bug ou lorsque la connexion est compromise.
<target>Ce paramètre s'applique aux messages de votre profil de chat actuel **%@**.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This setting is for your current profile **%@**." xml:space="preserve">
<source>This setting is for your current profile **%@**.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Time to disappear is set only for new contacts." xml:space="preserve">
<source>Time to disappear is set only for new contacts.</source>
<note>No comment provided by engineer.</note>
@@ -9538,11 +9554,6 @@ marked deleted chat item preview text</note>
<target>connecté</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="connected directly" xml:space="preserve">
<source>connected directly</source>
<target>s'est connecté.e de manière directe</target>
<note>rcv group event chat item</note>
</trans-unit>
<trans-unit id="connecting" xml:space="preserve">
<source>connecting</source>
<target>connexion</target>
@@ -10116,6 +10127,14 @@ time to disappear</note>
<source>request to join rejected</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="requested connection" xml:space="preserve">
<source>requested connection</source>
<note>rcv group event chat item</note>
</trans-unit>
<trans-unit id="requested connection from group %@" xml:space="preserve">
<source>requested connection from group %@</source>
<note>rcv direct event chat item</note>
</trans-unit>
<trans-unit id="requested to connect" xml:space="preserve">
<source>requested to connect</source>
<target>demande à se connecter</target>
@@ -588,12 +588,12 @@ swipe action</note>
</trans-unit>
<trans-unit id="Accept contact request" xml:space="preserve">
<source>Accept contact request</source>
<target>Partnerkérés elfogadása</target>
<target>Partneri kapcsolatkérés elfogadása</target>
<note>alert title</note>
</trans-unit>
<trans-unit id="Accept contact request from %@?" xml:space="preserve">
<source>Accept contact request from %@?</source>
<target>Elfogadja %@ partnerkérését?</target>
<target>Elfogadja %@ partneri kapcsolatkérését?</target>
<note>notification body</note>
</trans-unit>
<trans-unit id="Accept incognito" xml:space="preserve">
@@ -1029,7 +1029,7 @@ swipe action</note>
</trans-unit>
<trans-unit id="App passcode" xml:space="preserve">
<source>App passcode</source>
<target>Alkalmazás jelkód</target>
<target>Alkalmazásjelkód</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="App passcode is replaced with self-destruct passcode." xml:space="preserve">
@@ -1169,7 +1169,7 @@ swipe action</note>
</trans-unit>
<trans-unit id="Auto-accept contact requests" xml:space="preserve">
<source>Auto-accept contact requests</source>
<target>Partnerkérések automatikus elfogadása</target>
<target>Partneri kapcsolatkérések automatikus elfogadása</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Auto-accept images" xml:space="preserve">
@@ -2085,6 +2085,10 @@ Ez a saját egyszer használható meghívója!</target>
<target>Partnerbeállítások</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Contact requests from groups" xml:space="preserve">
<source>Contact requests from groups</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Contact will be deleted - this cannot be undone!" xml:space="preserve">
<source>Contact will be deleted - this cannot be undone!</source>
<target>A partner törölve lesz ez a művelet nem vonható vissza!</target>
@@ -3217,7 +3221,7 @@ chat item action</note>
</trans-unit>
<trans-unit id="Error accepting contact request" xml:space="preserve">
<source>Error accepting contact request</source>
<target>Hiba történt a partnerkérés elfogadásakor</target>
<target>Hiba történt a partneri kapcsolatkérés elfogadásakor</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error accepting member" xml:space="preserve">
@@ -3338,7 +3342,7 @@ chat item action</note>
<trans-unit id="Error deleting chat!" xml:space="preserve">
<source>Error deleting chat!</source>
<target>Hiba történt a csevegés törlésekor!</target>
<note>No comment provided by engineer.</note>
<note>alert title</note>
</trans-unit>
<trans-unit id="Error deleting connection" xml:space="preserve">
<source>Error deleting connection</source>
@@ -3447,7 +3451,7 @@ chat item action</note>
</trans-unit>
<trans-unit id="Error rejecting contact request" xml:space="preserve">
<source>Error rejecting contact request</source>
<target>Hiba történt a partnerkérés elutasításakor</target>
<target>Hiba történt a partneri kapcsolatkérés elutasításakor</target>
<note>alert title</note>
</trans-unit>
<trans-unit id="Error removing member" xml:space="preserve">
@@ -3525,6 +3529,10 @@ chat item action</note>
<target>Hiba történt az üzenet elküldésekor</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error setting auto-accept" xml:space="preserve">
<source>Error setting auto-accept</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error setting delivery receipts!" xml:space="preserve">
<source>Error setting delivery receipts!</source>
<target>Hiba történt a kézbesítési jelentések beállításakor!</target>
@@ -4862,6 +4870,10 @@ Ez a saját hivatkozása a(z) %@ nevű csoporthoz!</target>
<target>Inaktív tag</target>
<note>item status text</note>
</trans-unit>
<trans-unit id="Member is deleted - can't accept request" xml:space="preserve">
<source>Member is deleted - can't accept request</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Member reports" xml:space="preserve">
<source>Member reports</source>
<target>Tagok jelentései</target>
@@ -5289,7 +5301,7 @@ Ez a saját hivatkozása a(z) %@ nevű csoporthoz!</target>
</trans-unit>
<trans-unit id="New contact request" xml:space="preserve">
<source>New contact request</source>
<target>Új partnerkérés</target>
<target>Új partneri kapcsolatkérés</target>
<note>notification</note>
</trans-unit>
<trans-unit id="New contact:" xml:space="preserve">
@@ -6484,7 +6496,7 @@ swipe action</note>
</trans-unit>
<trans-unit id="Reject contact request" xml:space="preserve">
<source>Reject contact request</source>
<target>Elutasítás</target>
<target>Partneri kapcsolatkérés elutasítása</target>
<note>alert title</note>
</trans-unit>
<trans-unit id="Reject member?" xml:space="preserve">
@@ -7025,7 +7037,7 @@ chat item action</note>
</trans-unit>
<trans-unit id="Send contact request?" xml:space="preserve">
<source>Send contact request?</source>
<target>Elküldi a partnerkérést?</target>
<target>Elküldi a partneri kapcsolatkérést?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Send delivery receipts to" xml:space="preserve">
@@ -8224,6 +8236,10 @@ Ez valamilyen hiba vagy sérült kapcsolat esetén fordulhat elő.</target>
<target>Ez a beállítás csak az Ön jelenlegi **%@** nevű csevegési profiljában lévő üzenetekre vonatkozik.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This setting is for your current profile **%@**." xml:space="preserve">
<source>This setting is for your current profile **%@**.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Time to disappear is set only for new contacts." xml:space="preserve">
<source>Time to disappear is set only for new contacts.</source>
<target>Az üzeneteltűnési idő csak az új partnerekre vonatkozik.</target>
@@ -9708,11 +9724,6 @@ marked deleted chat item preview text</note>
<target>kapcsolódott</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="connected directly" xml:space="preserve">
<source>connected directly</source>
<target>közvetlenül kapcsolódott</target>
<note>rcv group event chat item</note>
</trans-unit>
<trans-unit id="connecting" xml:space="preserve">
<source>connecting</source>
<target>kapcsolódás</target>
@@ -10302,6 +10313,14 @@ time to disappear</note>
<target>csatlakozási kérés elutasítva</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="requested connection" xml:space="preserve">
<source>requested connection</source>
<note>rcv group event chat item</note>
</trans-unit>
<trans-unit id="requested connection from group %@" xml:space="preserve">
<source>requested connection from group %@</source>
<note>rcv direct event chat item</note>
</trans-unit>
<trans-unit id="requested to connect" xml:space="preserve">
<source>requested to connect</source>
<target>függőben lévő kapcsolat</target>
@@ -2085,6 +2085,10 @@ Questo è il tuo link una tantum!</target>
<target>Preferenze del contatto</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Contact requests from groups" xml:space="preserve">
<source>Contact requests from groups</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Contact will be deleted - this cannot be undone!" xml:space="preserve">
<source>Contact will be deleted - this cannot be undone!</source>
<target>Il contatto verrà eliminato - non è reversibile!</target>
@@ -3338,7 +3342,7 @@ chat item action</note>
<trans-unit id="Error deleting chat!" xml:space="preserve">
<source>Error deleting chat!</source>
<target>Errore nell'eliminazione della chat!</target>
<note>No comment provided by engineer.</note>
<note>alert title</note>
</trans-unit>
<trans-unit id="Error deleting connection" xml:space="preserve">
<source>Error deleting connection</source>
@@ -3525,6 +3529,10 @@ chat item action</note>
<target>Errore nell'invio del messaggio</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error setting auto-accept" xml:space="preserve">
<source>Error setting auto-accept</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error setting delivery receipts!" xml:space="preserve">
<source>Error setting delivery receipts!</source>
<target>Errore nell'impostazione delle ricevute di consegna!</target>
@@ -4862,6 +4870,10 @@ Questo è il tuo link per il gruppo %@!</target>
<target>Membro inattivo</target>
<note>item status text</note>
</trans-unit>
<trans-unit id="Member is deleted - can't accept request" xml:space="preserve">
<source>Member is deleted - can't accept request</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Member reports" xml:space="preserve">
<source>Member reports</source>
<target>Segnalazioni dei membri</target>
@@ -8224,6 +8236,10 @@ Può accadere a causa di qualche bug o quando la connessione è compromessa.</ta
<target>Questa impostazione si applica ai messaggi del profilo di chat attuale **%@**.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This setting is for your current profile **%@**." xml:space="preserve">
<source>This setting is for your current profile **%@**.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Time to disappear is set only for new contacts." xml:space="preserve">
<source>Time to disappear is set only for new contacts.</source>
<target>Il tempo di scomparsa è impostato solo per i contatti nuovi.</target>
@@ -9708,11 +9724,6 @@ marked deleted chat item preview text</note>
<target>connesso/a</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="connected directly" xml:space="preserve">
<source>connected directly</source>
<target>si è connesso/a direttamente</target>
<note>rcv group event chat item</note>
</trans-unit>
<trans-unit id="connecting" xml:space="preserve">
<source>connecting</source>
<target>in connessione</target>
@@ -10302,6 +10313,14 @@ time to disappear</note>
<target>richiesta di entrare rifiutata</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="requested connection" xml:space="preserve">
<source>requested connection</source>
<note>rcv group event chat item</note>
</trans-unit>
<trans-unit id="requested connection from group %@" xml:space="preserve">
<source>requested connection from group %@</source>
<note>rcv direct event chat item</note>
</trans-unit>
<trans-unit id="requested to connect" xml:space="preserve">
<source>requested to connect</source>
<target>richiesto di connettersi</target>
@@ -1938,6 +1938,10 @@ This is your own one-time link!</source>
<target>連絡先の設定</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Contact requests from groups" xml:space="preserve">
<source>Contact requests from groups</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Contact will be deleted - this cannot be undone!" xml:space="preserve">
<source>Contact will be deleted - this cannot be undone!</source>
<note>No comment provided by engineer.</note>
@@ -3097,7 +3101,7 @@ chat item action</note>
<trans-unit id="Error deleting chat!" xml:space="preserve">
<source>Error deleting chat!</source>
<target>チャット削除にエラー発生!</target>
<note>No comment provided by engineer.</note>
<note>alert title</note>
</trans-unit>
<trans-unit id="Error deleting connection" xml:space="preserve">
<source>Error deleting connection</source>
@@ -3267,6 +3271,10 @@ chat item action</note>
<target>メッセージ送信にエラー発生</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error setting auto-accept" xml:space="preserve">
<source>Error setting auto-accept</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error setting delivery receipts!" xml:space="preserve">
<source>Error setting delivery receipts!</source>
<note>No comment provided by engineer.</note>
@@ -4489,6 +4497,10 @@ This is your link for group %@!</source>
<source>Member inactive</source>
<note>item status text</note>
</trans-unit>
<trans-unit id="Member is deleted - can't accept request" xml:space="preserve">
<source>Member is deleted - can't accept request</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Member reports" xml:space="preserve">
<source>Member reports</source>
<note>chat feature</note>
@@ -7504,6 +7516,10 @@ It can happen because of some bug or when the connection is compromised.</source
<target>この設定は現在のチャットプロフィール **%@** のメッセージに適用されます。</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This setting is for your current profile **%@**." xml:space="preserve">
<source>This setting is for your current profile **%@**.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Time to disappear is set only for new contacts." xml:space="preserve">
<source>Time to disappear is set only for new contacts.</source>
<note>No comment provided by engineer.</note>
@@ -8849,10 +8865,6 @@ marked deleted chat item preview text</note>
<target>接続中</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="connected directly" xml:space="preserve">
<source>connected directly</source>
<note>rcv group event chat item</note>
</trans-unit>
<trans-unit id="connecting" xml:space="preserve">
<source>connecting</source>
<target>接続待ち</target>
@@ -9410,6 +9422,14 @@ time to disappear</note>
<source>request to join rejected</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="requested connection" xml:space="preserve">
<source>requested connection</source>
<note>rcv group event chat item</note>
</trans-unit>
<trans-unit id="requested connection from group %@" xml:space="preserve">
<source>requested connection from group %@</source>
<note>rcv direct event chat item</note>
</trans-unit>
<trans-unit id="requested to connect" xml:space="preserve">
<source>requested to connect</source>
<note>chat list item title</note>
@@ -2077,6 +2077,10 @@ Dit is uw eigen eenmalige link!</target>
<target>Contact voorkeuren</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Contact requests from groups" xml:space="preserve">
<source>Contact requests from groups</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Contact will be deleted - this cannot be undone!" xml:space="preserve">
<source>Contact will be deleted - this cannot be undone!</source>
<target>Het contact wordt verwijderd. Dit kan niet ongedaan worden gemaakt!</target>
@@ -3324,7 +3328,7 @@ chat item action</note>
<trans-unit id="Error deleting chat!" xml:space="preserve">
<source>Error deleting chat!</source>
<target>Fout bij verwijderen gesprek!</target>
<note>No comment provided by engineer.</note>
<note>alert title</note>
</trans-unit>
<trans-unit id="Error deleting connection" xml:space="preserve">
<source>Error deleting connection</source>
@@ -3509,6 +3513,10 @@ chat item action</note>
<target>Fout bij verzenden van bericht</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error setting auto-accept" xml:space="preserve">
<source>Error setting auto-accept</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error setting delivery receipts!" xml:space="preserve">
<source>Error setting delivery receipts!</source>
<target>Fout bij het instellen van ontvangst bevestiging!</target>
@@ -4842,6 +4850,10 @@ Dit is jouw link voor groep %@!</target>
<target>Lid inactief</target>
<note>item status text</note>
</trans-unit>
<trans-unit id="Member is deleted - can't accept request" xml:space="preserve">
<source>Member is deleted - can't accept request</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Member reports" xml:space="preserve">
<source>Member reports</source>
<target>Ledenrapporten</target>
@@ -8173,6 +8185,10 @@ Het kan gebeuren vanwege een bug of wanneer de verbinding is aangetast.</target>
<target>Deze instelling is van toepassing op berichten in je huidige chatprofiel **%@**.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This setting is for your current profile **%@**." xml:space="preserve">
<source>This setting is for your current profile **%@**.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Time to disappear is set only for new contacts." xml:space="preserve">
<source>Time to disappear is set only for new contacts.</source>
<note>No comment provided by engineer.</note>
@@ -9642,11 +9658,6 @@ marked deleted chat item preview text</note>
<target>verbonden</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="connected directly" xml:space="preserve">
<source>connected directly</source>
<target>direct verbonden</target>
<note>rcv group event chat item</note>
</trans-unit>
<trans-unit id="connecting" xml:space="preserve">
<source>connecting</source>
<target>Verbinden</target>
@@ -10233,6 +10244,14 @@ time to disappear</note>
<target>verzoek tot toetreding afgewezen</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="requested connection" xml:space="preserve">
<source>requested connection</source>
<note>rcv group event chat item</note>
</trans-unit>
<trans-unit id="requested connection from group %@" xml:space="preserve">
<source>requested connection from group %@</source>
<note>rcv direct event chat item</note>
</trans-unit>
<trans-unit id="requested to connect" xml:space="preserve">
<source>requested to connect</source>
<target>verzocht om verbinding te maken</target>
@@ -2050,6 +2050,10 @@ To jest twój jednorazowy link!</target>
<target>Preferencje kontaktu</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Contact requests from groups" xml:space="preserve">
<source>Contact requests from groups</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Contact will be deleted - this cannot be undone!" xml:space="preserve">
<source>Contact will be deleted - this cannot be undone!</source>
<target>Kontakt zostanie usunięty nie można tego cofnąć!</target>
@@ -3268,7 +3272,7 @@ chat item action</note>
<trans-unit id="Error deleting chat!" xml:space="preserve">
<source>Error deleting chat!</source>
<target>Błąd usuwania czatu!</target>
<note>No comment provided by engineer.</note>
<note>alert title</note>
</trans-unit>
<trans-unit id="Error deleting connection" xml:space="preserve">
<source>Error deleting connection</source>
@@ -3448,6 +3452,10 @@ chat item action</note>
<target>Błąd wysyłania wiadomości</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error setting auto-accept" xml:space="preserve">
<source>Error setting auto-accept</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error setting delivery receipts!" xml:space="preserve">
<source>Error setting delivery receipts!</source>
<target>Błąd ustawiania potwierdzeń dostawy!</target>
@@ -4743,6 +4751,10 @@ To jest twój link do grupy %@!</target>
<target>Członek nieaktywny</target>
<note>item status text</note>
</trans-unit>
<trans-unit id="Member is deleted - can't accept request" xml:space="preserve">
<source>Member is deleted - can't accept request</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Member reports" xml:space="preserve">
<source>Member reports</source>
<note>chat feature</note>
@@ -7965,6 +7977,10 @@ Może się to zdarzyć z powodu jakiegoś błędu lub gdy połączenie jest skom
<target>To ustawienie dotyczy wiadomości Twojego bieżącego profilu czatu **%@**.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This setting is for your current profile **%@**." xml:space="preserve">
<source>This setting is for your current profile **%@**.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Time to disappear is set only for new contacts." xml:space="preserve">
<source>Time to disappear is set only for new contacts.</source>
<note>No comment provided by engineer.</note>
@@ -9404,11 +9420,6 @@ marked deleted chat item preview text</note>
<target>połączony</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="connected directly" xml:space="preserve">
<source>connected directly</source>
<target>połącz bezpośrednio</target>
<note>rcv group event chat item</note>
</trans-unit>
<trans-unit id="connecting" xml:space="preserve">
<source>connecting</source>
<target>łączenie</target>
@@ -9982,6 +9993,14 @@ time to disappear</note>
<source>request to join rejected</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="requested connection" xml:space="preserve">
<source>requested connection</source>
<note>rcv group event chat item</note>
</trans-unit>
<trans-unit id="requested connection from group %@" xml:space="preserve">
<source>requested connection from group %@</source>
<note>rcv direct event chat item</note>
</trans-unit>
<trans-unit id="requested to connect" xml:space="preserve">
<source>requested to connect</source>
<note>chat list item title</note>
@@ -2085,6 +2085,11 @@ This is your own one-time link!</source>
<target>Предпочтения контакта</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Contact requests from groups" xml:space="preserve">
<source>Contact requests from groups</source>
<target>Запросы на соединение из групп</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Contact will be deleted - this cannot be undone!" xml:space="preserve">
<source>Contact will be deleted - this cannot be undone!</source>
<target>Контакт будет удален — это нельзя отменить!</target>
@@ -3338,7 +3343,7 @@ chat item action</note>
<trans-unit id="Error deleting chat!" xml:space="preserve">
<source>Error deleting chat!</source>
<target>Ошибка при удалении чата!</target>
<note>No comment provided by engineer.</note>
<note>alert title</note>
</trans-unit>
<trans-unit id="Error deleting connection" xml:space="preserve">
<source>Error deleting connection</source>
@@ -3525,6 +3530,11 @@ chat item action</note>
<target>Ошибка при отправке сообщения</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error setting auto-accept" xml:space="preserve">
<source>Error setting auto-accept</source>
<target>Ошибка при установке автоприёма запросов</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error setting delivery receipts!" xml:space="preserve">
<source>Error setting delivery receipts!</source>
<target>Ошибка настроек отчётов о доставке!</target>
@@ -4861,6 +4871,11 @@ This is your link for group %@!</source>
<target>Член неактивен</target>
<note>item status text</note>
</trans-unit>
<trans-unit id="Member is deleted - can't accept request" xml:space="preserve">
<source>Member is deleted - can't accept request</source>
<target>Член группы удалён - невозможно принять запрос</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Member reports" xml:space="preserve">
<source>Member reports</source>
<target>Сообщения о нарушениях</target>
@@ -8223,6 +8238,11 @@ It can happen because of some bug or when the connection is compromised.</source
<target>Эта настройка применяется к сообщениям в Вашем текущем профиле чата **%@**.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This setting is for your current profile **%@**." xml:space="preserve">
<source>This setting is for your current profile **%@**.</source>
<target>Эта настройка применяется к Вашему текущему профилю чата **%@**.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Time to disappear is set only for new contacts." xml:space="preserve">
<source>Time to disappear is set only for new contacts.</source>
<target>Время удаления устанавливается только для новых контактов.</target>
@@ -9707,11 +9727,6 @@ marked deleted chat item preview text</note>
<target>соединение установлено</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="connected directly" xml:space="preserve">
<source>connected directly</source>
<target>соединен(а) напрямую</target>
<note>rcv group event chat item</note>
</trans-unit>
<trans-unit id="connecting" xml:space="preserve">
<source>connecting</source>
<target>соединяется</target>
@@ -10301,6 +10316,16 @@ time to disappear</note>
<target>запрос на вступление отклонён</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="requested connection" xml:space="preserve">
<source>requested connection</source>
<target>запрос на соединение</target>
<note>rcv group event chat item</note>
</trans-unit>
<trans-unit id="requested connection from group %@" xml:space="preserve">
<source>requested connection from group %@</source>
<target>запрос на соединение из группы %@</target>
<note>rcv direct event chat item</note>
</trans-unit>
<trans-unit id="requested to connect" xml:space="preserve">
<source>requested to connect</source>
<target>запрошено соединение</target>
@@ -1862,6 +1862,10 @@ This is your own one-time link!</source>
<target>การกําหนดลักษณะการติดต่อ</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Contact requests from groups" xml:space="preserve">
<source>Contact requests from groups</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Contact will be deleted - this cannot be undone!" xml:space="preserve">
<source>Contact will be deleted - this cannot be undone!</source>
<note>No comment provided by engineer.</note>
@@ -3008,7 +3012,7 @@ chat item action</note>
<trans-unit id="Error deleting chat!" xml:space="preserve">
<source>Error deleting chat!</source>
<target>เกิดข้อผิดพลาดในการลบแชท!</target>
<note>No comment provided by engineer.</note>
<note>alert title</note>
</trans-unit>
<trans-unit id="Error deleting connection" xml:space="preserve">
<source>Error deleting connection</source>
@@ -3178,6 +3182,10 @@ chat item action</note>
<target>เกิดข้อผิดพลาดในการส่งข้อความ</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error setting auto-accept" xml:space="preserve">
<source>Error setting auto-accept</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error setting delivery receipts!" xml:space="preserve">
<source>Error setting delivery receipts!</source>
<target>เกิดข้อผิดพลาดในการตั้งค่าใบตอบรับการจัดส่ง!</target>
@@ -4399,6 +4407,10 @@ This is your link for group %@!</source>
<source>Member inactive</source>
<note>item status text</note>
</trans-unit>
<trans-unit id="Member is deleted - can't accept request" xml:space="preserve">
<source>Member is deleted - can't accept request</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Member reports" xml:space="preserve">
<source>Member reports</source>
<note>chat feature</note>
@@ -7406,6 +7418,10 @@ It can happen because of some bug or when the connection is compromised.</source
<target>การตั้งค่านี้ใช้กับข้อความในโปรไฟล์แชทปัจจุบันของคุณ **%@**</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This setting is for your current profile **%@**." xml:space="preserve">
<source>This setting is for your current profile **%@**.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Time to disappear is set only for new contacts." xml:space="preserve">
<source>Time to disappear is set only for new contacts.</source>
<note>No comment provided by engineer.</note>
@@ -8746,10 +8762,6 @@ marked deleted chat item preview text</note>
<target>เชื่อมต่อสำเร็จ</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="connected directly" xml:space="preserve">
<source>connected directly</source>
<note>rcv group event chat item</note>
</trans-unit>
<trans-unit id="connecting" xml:space="preserve">
<source>connecting</source>
<target>กำลังเชื่อมต่อ</target>
@@ -9306,6 +9318,14 @@ time to disappear</note>
<source>request to join rejected</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="requested connection" xml:space="preserve">
<source>requested connection</source>
<note>rcv group event chat item</note>
</trans-unit>
<trans-unit id="requested connection from group %@" xml:space="preserve">
<source>requested connection from group %@</source>
<note>rcv direct event chat item</note>
</trans-unit>
<trans-unit id="requested to connect" xml:space="preserve">
<source>requested to connect</source>
<note>chat list item title</note>
@@ -2085,6 +2085,10 @@ Bu senin kendi tek kullanımlık bağlantın!</target>
<target>Kişi tercihleri</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Contact requests from groups" xml:space="preserve">
<source>Contact requests from groups</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Contact will be deleted - this cannot be undone!" xml:space="preserve">
<source>Contact will be deleted - this cannot be undone!</source>
<target>Kişiler silinecek - bu geri alınamaz !</target>
@@ -3336,7 +3340,7 @@ chat item action</note>
<trans-unit id="Error deleting chat!" xml:space="preserve">
<source>Error deleting chat!</source>
<target>Sohbet silinirken hata oluştu!</target>
<note>No comment provided by engineer.</note>
<note>alert title</note>
</trans-unit>
<trans-unit id="Error deleting connection" xml:space="preserve">
<source>Error deleting connection</source>
@@ -3523,6 +3527,10 @@ chat item action</note>
<target>Mesaj gönderilirken hata oluştu</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error setting auto-accept" xml:space="preserve">
<source>Error setting auto-accept</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error setting delivery receipts!" xml:space="preserve">
<source>Error setting delivery receipts!</source>
<target>Görüldü ayarlanırken hata oluştu!</target>
@@ -4859,6 +4867,10 @@ Bu senin grup için bağlantın %@!</target>
<target>Üye inaktif</target>
<note>item status text</note>
</trans-unit>
<trans-unit id="Member is deleted - can't accept request" xml:space="preserve">
<source>Member is deleted - can't accept request</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Member reports" xml:space="preserve">
<source>Member reports</source>
<target>Üye raporları</target>
@@ -8214,6 +8226,10 @@ Bazı hatalar nedeniyle veya bağlantı tehlikeye girdiğinde meydana gelebilir.
<target>Bu ayar, geçerli sohbet profiliniz **%@** deki mesajlara uygulanır.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This setting is for your current profile **%@**." xml:space="preserve">
<source>This setting is for your current profile **%@**.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Time to disappear is set only for new contacts." xml:space="preserve">
<source>Time to disappear is set only for new contacts.</source>
<note>No comment provided by engineer.</note>
@@ -9689,11 +9705,6 @@ marked deleted chat item preview text</note>
<target>bağlanıldı</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="connected directly" xml:space="preserve">
<source>connected directly</source>
<target>doğrudan bağlandı</target>
<note>rcv group event chat item</note>
</trans-unit>
<trans-unit id="connecting" xml:space="preserve">
<source>connecting</source>
<target>bağlanılıyor</target>
@@ -10283,6 +10294,14 @@ time to disappear</note>
<target>katılma isteği reddedildi</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="requested connection" xml:space="preserve">
<source>requested connection</source>
<note>rcv group event chat item</note>
</trans-unit>
<trans-unit id="requested connection from group %@" xml:space="preserve">
<source>requested connection from group %@</source>
<note>rcv direct event chat item</note>
</trans-unit>
<trans-unit id="requested to connect" xml:space="preserve">
<source>requested to connect</source>
<target>bağlanma isteği gönderildi</target>
File diff suppressed because it is too large Load Diff
@@ -2070,6 +2070,10 @@ This is your own one-time link!</source>
<target>联系人偏好设置</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Contact requests from groups" xml:space="preserve">
<source>Contact requests from groups</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Contact will be deleted - this cannot be undone!" xml:space="preserve">
<source>Contact will be deleted - this cannot be undone!</source>
<target>联系人将被删除-这是无法撤消的!</target>
@@ -3313,7 +3317,7 @@ chat item action</note>
<trans-unit id="Error deleting chat!" xml:space="preserve">
<source>Error deleting chat!</source>
<target>删除聊天错误!</target>
<note>No comment provided by engineer.</note>
<note>alert title</note>
</trans-unit>
<trans-unit id="Error deleting connection" xml:space="preserve">
<source>Error deleting connection</source>
@@ -3498,6 +3502,10 @@ chat item action</note>
<target>发送消息错误</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error setting auto-accept" xml:space="preserve">
<source>Error setting auto-accept</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error setting delivery receipts!" xml:space="preserve">
<source>Error setting delivery receipts!</source>
<target>设置送达回执出错!</target>
@@ -4830,6 +4838,10 @@ This is your link for group %@!</source>
<target>成员不活跃</target>
<note>item status text</note>
</trans-unit>
<trans-unit id="Member is deleted - can't accept request" xml:space="preserve">
<source>Member is deleted - can't accept request</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Member reports" xml:space="preserve">
<source>Member reports</source>
<target>成员举报</target>
@@ -8089,6 +8101,10 @@ It can happen because of some bug or when the connection is compromised.</source
<target>此设置适用于您当前聊天资料 **%@** 中的消息。</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This setting is for your current profile **%@**." xml:space="preserve">
<source>This setting is for your current profile **%@**.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Time to disappear is set only for new contacts." xml:space="preserve">
<source>Time to disappear is set only for new contacts.</source>
<note>No comment provided by engineer.</note>
@@ -9519,11 +9535,6 @@ marked deleted chat item preview text</note>
<target>已连接</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="connected directly" xml:space="preserve">
<source>connected directly</source>
<target>已直连</target>
<note>rcv group event chat item</note>
</trans-unit>
<trans-unit id="connecting" xml:space="preserve">
<source>connecting</source>
<target>连接中</target>
@@ -10097,6 +10108,14 @@ time to disappear</note>
<source>request to join rejected</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="requested connection" xml:space="preserve">
<source>requested connection</source>
<note>rcv group event chat item</note>
</trans-unit>
<trans-unit id="requested connection from group %@" xml:space="preserve">
<source>requested connection from group %@</source>
<note>rcv direct event chat item</note>
</trans-unit>
<trans-unit id="requested to connect" xml:space="preserve">
<source>requested to connect</source>
<note>chat list item title</note>
@@ -1,6 +1,9 @@
/* notification body */
"%d new events" = "%d нових подій";
/* notification body */
"From %d chat(s)" = "З %d чату(ів)";
/* notification body */
"From: %@" = "Від: %@";
+32 -28
View File
@@ -178,8 +178,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.4.1.2-6lmVvH3zwUh1WnLIod6T9y-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C8299A2D54AEEE006B9E89 /* libHSsimplex-chat-6.4.1.2-6lmVvH3zwUh1WnLIod6T9y-ghc9.6.3.a */; };
64C829A02D54AEEE006B9E89 /* libHSsimplex-chat-6.4.1.2-6lmVvH3zwUh1WnLIod6T9y.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C8299B2D54AEEE006B9E89 /* libHSsimplex-chat-6.4.1.2-6lmVvH3zwUh1WnLIod6T9y.a */; };
64C8299F2D54AEEE006B9E89 /* libHSsimplex-chat-6.4.2.1-B5zq2t60gbA45EwEeb0rfE-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C8299A2D54AEEE006B9E89 /* libHSsimplex-chat-6.4.2.1-B5zq2t60gbA45EwEeb0rfE-ghc9.6.3.a */; };
64C829A02D54AEEE006B9E89 /* libHSsimplex-chat-6.4.2.1-B5zq2t60gbA45EwEeb0rfE.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C8299B2D54AEEE006B9E89 /* libHSsimplex-chat-6.4.2.1-B5zq2t60gbA45EwEeb0rfE.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 */; };
@@ -189,6 +189,7 @@
64E972072881BB22008DBC02 /* CIGroupInvitationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64E972062881BB22008DBC02 /* CIGroupInvitationView.swift */; };
64EEB0F72C353F1C00972D62 /* ServersSummaryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64EEB0F62C353F1C00972D62 /* ServersSummaryView.swift */; };
64F1CC3B28B39D8600CD1FB1 /* IncognitoHelp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64F1CC3A28B39D8600CD1FB1 /* IncognitoHelp.swift */; };
64FC8F9D2E3B6DEF0068F384 /* ContextMemberContactActionsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64FC8F9C2E3B6DEF0068F384 /* ContextMemberContactActionsView.swift */; };
8C01E9C12C8EFC33008A4B0A /* objc.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C01E9C02C8EFC33008A4B0A /* objc.m */; };
8C01E9C22C8EFF8F008A4B0A /* objc.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C01E9BF2C8EFBB6008A4B0A /* objc.h */; };
8C69FE7D2B8C7D2700267E38 /* AppSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C69FE7C2B8C7D2700267E38 /* AppSettings.swift */; };
@@ -543,8 +544,8 @@
64C3B0202A0D359700E19930 /* CustomTimePicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomTimePicker.swift; sourceTree = "<group>"; };
64C829982D54AEED006B9E89 /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = "<group>"; };
64C829992D54AEEE006B9E89 /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = "<group>"; };
64C8299A2D54AEEE006B9E89 /* libHSsimplex-chat-6.4.1.2-6lmVvH3zwUh1WnLIod6T9y-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.4.1.2-6lmVvH3zwUh1WnLIod6T9y-ghc9.6.3.a"; sourceTree = "<group>"; };
64C8299B2D54AEEE006B9E89 /* libHSsimplex-chat-6.4.1.2-6lmVvH3zwUh1WnLIod6T9y.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.4.1.2-6lmVvH3zwUh1WnLIod6T9y.a"; sourceTree = "<group>"; };
64C8299A2D54AEEE006B9E89 /* libHSsimplex-chat-6.4.2.1-B5zq2t60gbA45EwEeb0rfE-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.4.2.1-B5zq2t60gbA45EwEeb0rfE-ghc9.6.3.a"; sourceTree = "<group>"; };
64C8299B2D54AEEE006B9E89 /* libHSsimplex-chat-6.4.2.1-B5zq2t60gbA45EwEeb0rfE.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.4.2.1-B5zq2t60gbA45EwEeb0rfE.a"; sourceTree = "<group>"; };
64C8299C2D54AEEE006B9E89 /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = "<group>"; };
64D0C2BF29F9688300B38D5F /* UserAddressView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserAddressView.swift; sourceTree = "<group>"; };
64D0C2C129FA57AB00B38D5F /* UserAddressLearnMore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserAddressLearnMore.swift; sourceTree = "<group>"; };
@@ -555,6 +556,7 @@
64E972062881BB22008DBC02 /* CIGroupInvitationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CIGroupInvitationView.swift; sourceTree = "<group>"; };
64EEB0F62C353F1C00972D62 /* ServersSummaryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServersSummaryView.swift; sourceTree = "<group>"; };
64F1CC3A28B39D8600CD1FB1 /* IncognitoHelp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IncognitoHelp.swift; sourceTree = "<group>"; };
64FC8F9C2E3B6DEF0068F384 /* ContextMemberContactActionsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContextMemberContactActionsView.swift; sourceTree = "<group>"; };
8C01E9BF2C8EFBB6008A4B0A /* objc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = objc.h; sourceTree = "<group>"; };
8C01E9C02C8EFC33008A4B0A /* objc.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = objc.m; sourceTree = "<group>"; };
8C69FE7C2B8C7D2700267E38 /* AppSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppSettings.swift; sourceTree = "<group>"; };
@@ -704,8 +706,8 @@
64C8299D2D54AEEE006B9E89 /* libgmp.a in Frameworks */,
64C8299E2D54AEEE006B9E89 /* libffi.a in Frameworks */,
64C829A12D54AEEE006B9E89 /* libgmpxx.a in Frameworks */,
64C8299F2D54AEEE006B9E89 /* libHSsimplex-chat-6.4.1.2-6lmVvH3zwUh1WnLIod6T9y-ghc9.6.3.a in Frameworks */,
64C829A02D54AEEE006B9E89 /* libHSsimplex-chat-6.4.1.2-6lmVvH3zwUh1WnLIod6T9y.a in Frameworks */,
64C8299F2D54AEEE006B9E89 /* libHSsimplex-chat-6.4.2.1-B5zq2t60gbA45EwEeb0rfE-ghc9.6.3.a in Frameworks */,
64C829A02D54AEEE006B9E89 /* libHSsimplex-chat-6.4.2.1-B5zq2t60gbA45EwEeb0rfE.a in Frameworks */,
CE38A29C2C3FCD72005ED185 /* SwiftyGif in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -790,8 +792,8 @@
64C829992D54AEEE006B9E89 /* libffi.a */,
64C829982D54AEED006B9E89 /* libgmp.a */,
64C8299C2D54AEEE006B9E89 /* libgmpxx.a */,
64C8299A2D54AEEE006B9E89 /* libHSsimplex-chat-6.4.1.2-6lmVvH3zwUh1WnLIod6T9y-ghc9.6.3.a */,
64C8299B2D54AEEE006B9E89 /* libHSsimplex-chat-6.4.1.2-6lmVvH3zwUh1WnLIod6T9y.a */,
64C8299A2D54AEEE006B9E89 /* libHSsimplex-chat-6.4.2.1-B5zq2t60gbA45EwEeb0rfE-ghc9.6.3.a */,
64C8299B2D54AEEE006B9E89 /* libHSsimplex-chat-6.4.2.1-B5zq2t60gbA45EwEeb0rfE.a */,
);
path = Libraries;
sourceTree = "<group>";
@@ -1090,6 +1092,7 @@
64A77A012DC4AD6100FDEF2F /* ContextPendingMemberActionsView.swift */,
64E5E3622DF71A4E00A4D530 /* ContextContactRequestActionsView.swift */,
64E5E3662DFC16A900A4D530 /* ContextProfilePickerView.swift */,
64FC8F9C2E3B6DEF0068F384 /* ContextMemberContactActionsView.swift */,
);
path = ComposeMessage;
sourceTree = "<group>";
@@ -1521,6 +1524,7 @@
5CB9250D27A9432000ACCCDD /* ChatListNavLink.swift in Sources */,
649BCDA0280460FD00C3A862 /* ComposeImageView.swift in Sources */,
5CA059ED279559F40002BEB4 /* ContentView.swift in Sources */,
64FC8F9D2E3B6DEF0068F384 /* ContextMemberContactActionsView.swift in Sources */,
5C05DF532840AA1D00C683F9 /* CallSettings.swift in Sources */,
640417CD2B29B8C200CCB412 /* NewChatMenuButton.swift in Sources */,
5CFE0921282EEAF60002594B /* ZoomableScrollView.swift in Sources */,
@@ -1995,7 +1999,7 @@
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 292;
CURRENT_PROJECT_VERSION = 293;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_BITCODE = NO;
@@ -2020,7 +2024,7 @@
"@executable_path/Frameworks",
);
LLVM_LTO = YES_THIN;
MARKETING_VERSION = 6.4.1;
MARKETING_VERSION = 6.4.2;
OTHER_LDFLAGS = "-Wl,-stack_size,0x1000000";
PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.app;
PRODUCT_NAME = SimpleX;
@@ -2045,7 +2049,7 @@
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 292;
CURRENT_PROJECT_VERSION = 293;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_BITCODE = NO;
@@ -2070,7 +2074,7 @@
"@executable_path/Frameworks",
);
LLVM_LTO = YES;
MARKETING_VERSION = 6.4.1;
MARKETING_VERSION = 6.4.2;
OTHER_LDFLAGS = "-Wl,-stack_size,0x1000000";
PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.app;
PRODUCT_NAME = SimpleX;
@@ -2087,11 +2091,11 @@
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 292;
CURRENT_PROJECT_VERSION = 293;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
GENERATE_INFOPLIST_FILE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
MARKETING_VERSION = 6.4.1;
MARKETING_VERSION = 6.4.2;
PRODUCT_BUNDLE_IDENTIFIER = "chat.simplex.Tests-iOS";
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = iphoneos;
@@ -2107,11 +2111,11 @@
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 292;
CURRENT_PROJECT_VERSION = 293;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
GENERATE_INFOPLIST_FILE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
MARKETING_VERSION = 6.4.1;
MARKETING_VERSION = 6.4.2;
PRODUCT_BUNDLE_IDENTIFIER = "chat.simplex.Tests-iOS";
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = iphoneos;
@@ -2132,7 +2136,7 @@
CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 292;
CURRENT_PROJECT_VERSION = 293;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_BITCODE = NO;
GCC_OPTIMIZATION_LEVEL = s;
@@ -2147,7 +2151,7 @@
"@executable_path/../../Frameworks",
);
LLVM_LTO = YES;
MARKETING_VERSION = 6.4.1;
MARKETING_VERSION = 6.4.2;
PRODUCT_BUNDLE_IDENTIFIER = "chat.simplex.app.SimpleX-NSE";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
@@ -2169,7 +2173,7 @@
CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 292;
CURRENT_PROJECT_VERSION = 293;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_BITCODE = NO;
ENABLE_CODE_COVERAGE = NO;
@@ -2184,7 +2188,7 @@
"@executable_path/../../Frameworks",
);
LLVM_LTO = YES;
MARKETING_VERSION = 6.4.1;
MARKETING_VERSION = 6.4.2;
PRODUCT_BUNDLE_IDENTIFIER = "chat.simplex.app.SimpleX-NSE";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
@@ -2206,7 +2210,7 @@
CLANG_TIDY_BUGPRONE_REDUNDANT_BRANCH_CONDITION = YES;
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 292;
CURRENT_PROJECT_VERSION = 293;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
DYLIB_COMPATIBILITY_VERSION = 1;
@@ -2232,7 +2236,7 @@
"$(PROJECT_DIR)/Libraries/sim",
);
LLVM_LTO = YES;
MARKETING_VERSION = 6.4.1;
MARKETING_VERSION = 6.4.2;
PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.SimpleXChat;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
SDKROOT = iphoneos;
@@ -2257,7 +2261,7 @@
CLANG_TIDY_BUGPRONE_REDUNDANT_BRANCH_CONDITION = YES;
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 292;
CURRENT_PROJECT_VERSION = 293;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
DYLIB_COMPATIBILITY_VERSION = 1;
@@ -2283,7 +2287,7 @@
"$(PROJECT_DIR)/Libraries/sim",
);
LLVM_LTO = YES;
MARKETING_VERSION = 6.4.1;
MARKETING_VERSION = 6.4.2;
PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.SimpleXChat;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
SDKROOT = iphoneos;
@@ -2308,7 +2312,7 @@
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CODE_SIGN_ENTITLEMENTS = "SimpleX SE/SimpleX SE.entitlements";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 292;
CURRENT_PROJECT_VERSION = 293;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
GCC_C_LANGUAGE_STANDARD = gnu17;
@@ -2323,7 +2327,7 @@
"@executable_path/../../Frameworks",
);
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
MARKETING_VERSION = 6.4.1;
MARKETING_VERSION = 6.4.2;
PRODUCT_BUNDLE_IDENTIFIER = "chat.simplex.app.SimpleX-SE";
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = iphoneos;
@@ -2342,7 +2346,7 @@
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CODE_SIGN_ENTITLEMENTS = "SimpleX SE/SimpleX SE.entitlements";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 292;
CURRENT_PROJECT_VERSION = 293;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
GCC_C_LANGUAGE_STANDARD = gnu17;
@@ -2357,7 +2361,7 @@
"@executable_path/../../Frameworks",
);
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
MARKETING_VERSION = 6.4.1;
MARKETING_VERSION = 6.4.2;
PRODUCT_BUNDLE_IDENTIFIER = "chat.simplex.app.SimpleX-SE";
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = iphoneos;
+36 -4
View File
@@ -39,6 +39,7 @@ public struct User: Identifiable, Decodable, UserLike, NamedChat, Hashable {
public var showNtfs: Bool
public var sendRcptsContacts: Bool
public var sendRcptsSmallGroups: Bool
public var autoAcceptMemberContacts: Bool
public var viewPwdHash: UserPwdHash?
public var uiThemes: ThemeModeOverrides?
@@ -65,7 +66,8 @@ public struct User: Identifiable, Decodable, UserLike, NamedChat, Hashable {
activeOrder: 0,
showNtfs: true,
sendRcptsContacts: true,
sendRcptsSmallGroups: false
sendRcptsSmallGroups: false,
autoAcceptMemberContacts: false
)
}
@@ -1759,8 +1761,9 @@ public struct Contact: Identifiable, Decodable, NamedChat, Hashable {
var chatTs: Date?
public var preparedContact: PreparedContact?
public var contactRequestId: Int64?
var contactGroupMemberId: Int64?
public var contactGroupMemberId: Int64?
var contactGrpInvSent: Bool
public var groupDirectInv: GroupDirectInvitation?
public var chatTags: [Int64]
public var chatItemTTL: Int64?
public var uiThemes: ThemeModeOverrides?
@@ -1774,7 +1777,11 @@ public struct Contact: Identifiable, Decodable, NamedChat, Hashable {
public var nextSendGrpInv: Bool { get { contactGroupMemberId != nil && !contactGrpInvSent } }
public var nextConnectPrepared: Bool { active && preparedContact != nil && (activeConn == nil || activeConn?.connStatus == .prepared) }
public var profileChangeProhibited: Bool { activeConn != nil }
public var nextAcceptContactRequest: Bool { active && contactRequestId != nil && (activeConn == nil || activeConn?.connStatus == .new) }
public var nextAcceptContactRequest: Bool {
active &&
(contactRequestId != nil || groupDirectInv != nil) &&
(activeConn == nil || activeConn?.connStatus == .new || activeConn?.connStatus == .prepared)
}
public var sendMsgToConnect: Bool { nextSendGrpInv || nextConnectPrepared }
public var displayName: String { localAlias == "" ? profile.displayName : localAlias }
public var fullName: String { get { profile.fullName } }
@@ -1843,6 +1850,26 @@ public struct PreparedContact: Decodable, Hashable {
public var uiConnLinkType: ConnectionMode
}
public struct GroupDirectInvitation: Decodable, Hashable {
public var groupDirectInvLink: String
public var fromGroupId_: Int64?
public var fromGroupMemberId_: Int64?
public var fromGroupMemberConnId_: Int64?
public var groupDirectInvStartedConnection: Bool
public var memberRemoved: Bool {
fromGroupId_ == nil || fromGroupMemberId_ == nil || fromGroupMemberConnId_ == nil
}
public static let sampleData = GroupDirectInvitation(
groupDirectInvLink: "simplex_link",
fromGroupId_: 1,
fromGroupMemberId_: 1,
fromGroupMemberConnId_: 1,
groupDirectInvStartedConnection: false
)
}
public enum ConnectionMode: String, Decodable, Hashable {
case inv
case con
@@ -2895,6 +2922,7 @@ public struct ChatItem: Identifiable, Decodable, Hashable {
switch rcvDirectEvent {
case .contactDeleted: return false
case .profileUpdated: return false
case .groupInvLinkReceived: return true
}
case .rcvGroupEvent(rcvGroupEvent: let rcvGroupEvent):
switch rcvGroupEvent {
@@ -4421,6 +4449,7 @@ public enum Format: Decodable, Equatable, Hashable {
case mention(memberName: String)
case email
case phone
case unknown
public var isSimplexLink: Bool {
get {
@@ -4702,11 +4731,14 @@ public struct E2EEInfo: Decodable, Hashable {
public enum RcvDirectEvent: Decodable, Hashable {
case contactDeleted
case profileUpdated(fromProfile: Profile, toProfile: Profile)
case groupInvLinkReceived(groupProfile: Profile)
var text: String {
switch self {
case .contactDeleted: return NSLocalizedString("deleted contact", comment: "rcv direct event chat item")
case let .profileUpdated(fromProfile, toProfile): return profileUpdatedText(fromProfile, toProfile)
case let .groupInvLinkReceived(groupProfile):
return String.localizedStringWithFormat(NSLocalizedString("requested connection from group %@", comment: "rcv direct event chat item"), groupProfile.displayName)
}
}
@@ -4771,7 +4803,7 @@ public enum RcvGroupEvent: Decodable, Hashable {
case .groupDeleted: return NSLocalizedString("deleted group", comment: "rcv group event chat item")
case .groupUpdated: return NSLocalizedString("updated group profile", comment: "rcv group event chat item")
case .invitedViaGroupLink: return NSLocalizedString("invited via your group link", comment: "rcv group event chat item")
case .memberCreatedContact: return NSLocalizedString("connected directly", comment: "rcv group event chat item")
case .memberCreatedContact: return NSLocalizedString("requested connection", comment: "rcv group event chat item")
case let .memberProfileUpdated(fromProfile, toProfile): return profileUpdatedText(fromProfile, toProfile)
case .newMemberPendingReview: return NSLocalizedString("New member wants to join the group.", comment: "rcv group event chat item")
}
+13 -4
View File
@@ -283,6 +283,9 @@ time interval */
time interval */
"1 week" = "1 седмица";
/* delete after time */
"1 year" = "1 година";
/* No comment provided by engineer. */
"1-time link" = "Еднократен линк";
@@ -337,12 +340,21 @@ alert action
swipe action */
"Accept" = "Приеми";
/* alert action */
"Accept as member" = "Приеми като член";
/* alert action */
"Accept as observer" = "Приеми като наблюдател";
/* No comment provided by engineer. */
"Accept conditions" = "Приеми условията";
/* No comment provided by engineer. */
"Accept connection request?" = "Приемане на заявка за връзка?";
/* alert title */
"Accept contact request" = "Приеми заявка за контакт";
/* notification body */
"Accept contact request from %@?" = "Приемане на заявка за контакт от %@?";
@@ -1026,9 +1038,6 @@ set passcode view */
/* No comment provided by engineer. */
"Connected desktop" = "Свързано настолно устройство";
/* rcv group event chat item */
"connected directly" = "свързан директно";
/* No comment provided by engineer. */
"Connected to desktop" = "Свързан с настолно устройство";
@@ -1746,7 +1755,7 @@ chat item action */
/* alert title */
"Error deleting chat database" = "Грешка при изтриване на базата данни";
/* No comment provided by engineer. */
/* alert title */
"Error deleting chat!" = "Грешка при изтриването на чата!";
/* No comment provided by engineer. */
+1 -4
View File
@@ -746,9 +746,6 @@ set passcode view */
/* No comment provided by engineer. */
"connected" = "připojeno";
/* rcv group event chat item */
"connected directly" = "připojeno přímo";
/* No comment provided by engineer. */
"connecting" = "připojování";
@@ -1354,7 +1351,7 @@ swipe action */
/* alert title */
"Error deleting chat database" = "Chyba při mazání databáze chatu";
/* No comment provided by engineer. */
/* alert title */
"Error deleting chat!" = "Chyba při mazání chatu!";
/* No comment provided by engineer. */
+1 -4
View File
@@ -1275,9 +1275,6 @@ set passcode view */
/* No comment provided by engineer. */
"Connected desktop" = "Verbundener Desktop";
/* rcv group event chat item */
"connected directly" = "Direkt miteinander verbunden";
/* No comment provided by engineer. */
"Connected servers" = "Verbundene Server";
@@ -2256,7 +2253,7 @@ chat item action */
/* alert title */
"Error deleting chat with member" = "Fehler beim Löschen des Chats mit dem Mitglied";
/* No comment provided by engineer. */
/* alert title */
"Error deleting chat!" = "Fehler beim Löschen des Chats!";
/* No comment provided by engineer. */
+5 -8
View File
@@ -723,7 +723,7 @@ swipe action */
"attempts" = "intentos";
/* No comment provided by engineer. */
"Audio & video calls" = "Llamadas y videollamadas";
"Audio & video calls" = "Llamadas y Videollamadas";
/* No comment provided by engineer. */
"Audio and video calls" = "Llamadas y videollamadas";
@@ -1275,9 +1275,6 @@ set passcode view */
/* No comment provided by engineer. */
"Connected desktop" = "Ordenador conectado";
/* rcv group event chat item */
"connected directly" = "conectado directamente";
/* No comment provided by engineer. */
"Connected servers" = "Servidores conectados";
@@ -2014,7 +2011,7 @@ chat item action */
"Enable camera access" = "Permitir acceso a la cámara";
/* No comment provided by engineer. */
"Enable disappearing messages by default." = "Activa por defecto los mensajes temporaes.";
"Enable disappearing messages by default." = "Activa por defecto los mensajes temporales.";
/* No comment provided by engineer. */
"Enable Flux in Network & servers settings for better metadata privacy." = "Habilitar Flux en la configuración de Red y servidores para mejorar la privacidad de los metadatos.";
@@ -2256,7 +2253,7 @@ chat item action */
/* alert title */
"Error deleting chat with member" = "Error al eliminar el chat con el miembro";
/* No comment provided by engineer. */
/* alert title */
"Error deleting chat!" = "¡Error al eliminar chat!";
/* No comment provided by engineer. */
@@ -2769,7 +2766,7 @@ snd error text */
"Hide profile" = "Ocultar perfil";
/* No comment provided by engineer. */
"Hide:" = "Ocultar:";
"Hide:" = "Oculta:";
/* No comment provided by engineer. */
"History" = "Historial";
@@ -5293,7 +5290,7 @@ report reason */
"Thanks to the users contribute via Weblate!" = "¡Agradecimiento a los colaboradores! Puedes contribuir a través de Weblate";
/* alert message */
"The address will be short, and your profile will be shared via the address." = "La dirección será corta y tu perfil se comparti mediante la dirección.";
"The address will be short, and your profile will be shared via the address." = "La dirección pasará a ser corta y tu perfil se compartido mediante la dirección.";
/* No comment provided by engineer. */
"The app can notify you when you receive messages or contact requests - please open settings to enable." = "La aplicación puede notificarte cuando recibas mensajes o solicitudes de contacto: por favor, abre la configuración para activarlo.";
+1 -1
View File
@@ -1264,7 +1264,7 @@ swipe action */
/* alert title */
"Error deleting chat database" = "Virhe keskustelujen tietokannan poistamisessa";
/* No comment provided by engineer. */
/* alert title */
"Error deleting chat!" = "Virhe keskutelun poistamisessa!";
/* No comment provided by engineer. */
+1 -4
View File
@@ -1212,9 +1212,6 @@ set passcode view */
/* No comment provided by engineer. */
"Connected desktop" = "Bureau connecté";
/* rcv group event chat item */
"connected directly" = "s'est connecté.e de manière directe";
/* No comment provided by engineer. */
"Connected servers" = "Serveurs connectés";
@@ -2154,7 +2151,7 @@ chat item action */
/* alert title */
"Error deleting chat database" = "Erreur lors de la suppression de la base de données du chat";
/* No comment provided by engineer. */
/* alert title */
"Error deleting chat!" = "Erreur lors de la suppression du chat!";
/* No comment provided by engineer. */
+10 -13
View File
@@ -359,10 +359,10 @@ swipe action */
"Accept connection request?" = "Elfogadja a kapcsolódási kérést?";
/* alert title */
"Accept contact request" = "Partnerkérés elfogadása";
"Accept contact request" = "Partneri kapcsolatkérés elfogadása";
/* notification body */
"Accept contact request from %@?" = "Elfogadja %@ partnerkérését?";
"Accept contact request from %@?" = "Elfogadja %@ partneri kapcsolatkérését?";
/* alert action
swipe action */
@@ -660,7 +660,7 @@ swipe action */
"App icon" = "Alkalmazásikon";
/* No comment provided by engineer. */
"App passcode" = "Alkalmazás jelkód";
"App passcode" = "Alkalmazásjelkód";
/* No comment provided by engineer. */
"App passcode is replaced with self-destruct passcode." = "Az alkalmazásjelkód helyettesítve lesz egy önmegsemmisítő jelkóddal.";
@@ -756,7 +756,7 @@ swipe action */
"Auto-accept" = "Automatikus elfogadás";
/* No comment provided by engineer. */
"Auto-accept contact requests" = "Partnerkérések automatikus elfogadása";
"Auto-accept contact requests" = "Partneri kapcsolatkérések automatikus elfogadása";
/* No comment provided by engineer. */
"Auto-accept images" = "Képek automatikus elfogadása";
@@ -1275,9 +1275,6 @@ set passcode view */
/* No comment provided by engineer. */
"Connected desktop" = "Társított számítógép";
/* rcv group event chat item */
"connected directly" = "közvetlenül kapcsolódott";
/* No comment provided by engineer. */
"Connected servers" = "Kapcsolódott kiszolgálók";
@@ -2185,7 +2182,7 @@ chat item action */
"Error accepting conditions" = "Hiba történt a feltételek elfogadásakor";
/* No comment provided by engineer. */
"Error accepting contact request" = "Hiba történt a partnerkérés elfogadásakor";
"Error accepting contact request" = "Hiba történt a partneri kapcsolatkérés elfogadásakor";
/* alert title */
"Error accepting member" = "Hiba a tag befogadásakor";
@@ -2256,7 +2253,7 @@ chat item action */
/* alert title */
"Error deleting chat with member" = "Hiba a taggal való csevegés törlésekor";
/* No comment provided by engineer. */
/* alert title */
"Error deleting chat!" = "Hiba történt a csevegés törlésekor!";
/* No comment provided by engineer. */
@@ -2323,7 +2320,7 @@ chat item action */
"Error registering for notifications" = "Hiba történt az értesítések regisztrálásakor";
/* alert title */
"Error rejecting contact request" = "Hiba történt a partnerkérés elutasításakor";
"Error rejecting contact request" = "Hiba történt a partneri kapcsolatkérés elutasításakor";
/* alert title */
"Error removing member" = "Hiba történt a tag eltávolításakor";
@@ -3525,7 +3522,7 @@ snd error text */
"New chat experience 🎉" = "Új csevegési élmény 🎉";
/* notification */
"New contact request" = "Új partnerkérés";
"New contact request" = "Új partneri kapcsolatkérés";
/* notification */
"New contact:" = "Új kapcsolat:";
@@ -4309,7 +4306,7 @@ swipe action */
"Reject (sender NOT notified)" = "Elutasítás (a feladó NEM kap értesítést)";
/* alert title */
"Reject contact request" = "Elutasítás";
"Reject contact request" = "Partneri kapcsolatkérés elutasítása";
/* alert title */
"Reject member?" = "Elutasítja a tagot?";
@@ -4688,7 +4685,7 @@ chat item action */
"Send a live message - it will update for the recipient(s) as you type it" = "Élő üzenet küldése az üzenet a címzett(ek) számára valós időben frissül, ahogy Ön beírja az üzenetet";
/* No comment provided by engineer. */
"Send contact request?" = "Elküldi a partnerkérést?";
"Send contact request?" = "Elküldi a partneri kapcsolatkérést?";
/* No comment provided by engineer. */
"Send delivery receipts to" = "A kézbesítési jelentéseket a következő címre kell küldeni";
+1 -4
View File
@@ -1275,9 +1275,6 @@ set passcode view */
/* No comment provided by engineer. */
"Connected desktop" = "Desktop connesso";
/* rcv group event chat item */
"connected directly" = "si è connesso/a direttamente";
/* No comment provided by engineer. */
"Connected servers" = "Server connessi";
@@ -2256,7 +2253,7 @@ chat item action */
/* alert title */
"Error deleting chat with member" = "Errore di eliminazione della chat con il membro";
/* No comment provided by engineer. */
/* alert title */
"Error deleting chat!" = "Errore nell'eliminazione della chat!";
/* No comment provided by engineer. */
+1 -1
View File
@@ -1474,7 +1474,7 @@ swipe action */
/* alert title */
"Error deleting chat database" = "チャットデータベース削除にエラー発生";
/* No comment provided by engineer. */
/* alert title */
"Error deleting chat!" = "チャット削除にエラー発生!";
/* No comment provided by engineer. */
+1 -4
View File
@@ -1251,9 +1251,6 @@ set passcode view */
/* No comment provided by engineer. */
"Connected desktop" = "Verbonden desktop";
/* rcv group event chat item */
"connected directly" = "direct verbonden";
/* No comment provided by engineer. */
"Connected servers" = "Verbonden servers";
@@ -2211,7 +2208,7 @@ chat item action */
/* alert title */
"Error deleting chat with member" = "Fout bij het verwijderen van chat met lid";
/* No comment provided by engineer. */
/* alert title */
"Error deleting chat!" = "Fout bij verwijderen gesprek!";
/* No comment provided by engineer. */
+1 -4
View File
@@ -1176,9 +1176,6 @@ set passcode view */
/* No comment provided by engineer. */
"Connected desktop" = "Połączony komputer";
/* rcv group event chat item */
"connected directly" = "połącz bezpośrednio";
/* No comment provided by engineer. */
"Connected servers" = "Połączone serwery";
@@ -2025,7 +2022,7 @@ chat item action */
/* alert title */
"Error deleting chat database" = "Błąd usuwania bazy danych czatu";
/* No comment provided by engineer. */
/* alert title */
"Error deleting chat!" = "Błąd usuwania czatu!";
/* No comment provided by engineer. */
+19 -4
View File
@@ -1275,9 +1275,6 @@ set passcode view */
/* No comment provided by engineer. */
"Connected desktop" = "Подключенный компьютер";
/* rcv group event chat item */
"connected directly" = "соединен(а) напрямую";
/* No comment provided by engineer. */
"Connected servers" = "Подключенные серверы";
@@ -1413,6 +1410,9 @@ set passcode view */
/* No comment provided by engineer. */
"Contact preferences" = "Предпочтения контакта";
/* No comment provided by engineer. */
"Contact requests from groups" = "Запросы на соединение из групп";
/* No comment provided by engineer. */
"contact should accept…" = "контакт должен принять…";
@@ -2256,7 +2256,7 @@ chat item action */
/* alert title */
"Error deleting chat with member" = "Ошибка при удалении чата с членом группы";
/* No comment provided by engineer. */
/* alert title */
"Error deleting chat!" = "Ошибка при удалении чата!";
/* No comment provided by engineer. */
@@ -2370,6 +2370,9 @@ chat item action */
/* No comment provided by engineer. */
"Error sending message" = "Ошибка при отправке сообщения";
/* No comment provided by engineer. */
"Error setting auto-accept" = "Ошибка при установке автоприёма запросов";
/* No comment provided by engineer. */
"Error setting delivery receipts!" = "Ошибка настроек отчётов о доставке!";
@@ -3251,6 +3254,9 @@ snd error text */
/* item status text */
"Member inactive" = "Член неактивен";
/* No comment provided by engineer. */
"Member is deleted - can't accept request" = "Член группы удалён - невозможно принять запрос";
/* chat feature */
"Member reports" = "Сообщения о нарушениях";
@@ -4425,6 +4431,12 @@ swipe action */
/* No comment provided by engineer. */
"request to join rejected" = "запрос на вступление отклонён";
/* rcv group event chat item */
"requested connection" = "запрос на соединение";
/* rcv direct event chat item */
"requested connection from group %@" = "запрос на соединение из группы %@";
/* chat list item title */
"requested to connect" = "запрошено соединение";
@@ -5433,6 +5445,9 @@ report reason */
/* No comment provided by engineer. */
"This setting applies to messages in your current chat profile **%@**." = "Эта настройка применяется к сообщениям в Вашем текущем профиле чата **%@**.";
/* No comment provided by engineer. */
"This setting is for your current profile **%@**." = "Эта настройка применяется к Вашему текущему профилю чата **%@**.";
/* No comment provided by engineer. */
"Time to disappear is set only for new contacts." = "Время удаления устанавливается только для новых контактов.";
+1 -1
View File
@@ -1216,7 +1216,7 @@ swipe action */
/* alert title */
"Error deleting chat database" = "เกิดข้อผิดพลาดในการลบฐานข้อมูลแชท";
/* No comment provided by engineer. */
/* alert title */
"Error deleting chat!" = "เกิดข้อผิดพลาดในการลบแชท!";
/* No comment provided by engineer. */
+1 -4
View File
@@ -1275,9 +1275,6 @@ set passcode view */
/* No comment provided by engineer. */
"Connected desktop" = "Bilgisayara bağlandı";
/* rcv group event chat item */
"connected directly" = "doğrudan bağlandı";
/* No comment provided by engineer. */
"Connected servers" = "Bağlı sunucular";
@@ -2250,7 +2247,7 @@ chat item action */
/* alert title */
"Error deleting chat with member" = "Üye ile sohbet silme hatası";
/* No comment provided by engineer. */
/* alert title */
"Error deleting chat!" = "Sohbet silinirken hata oluştu!";
/* No comment provided by engineer. */
File diff suppressed because it is too large Load Diff
+1 -4
View File
@@ -1215,9 +1215,6 @@ set passcode view */
/* No comment provided by engineer. */
"Connected desktop" = "已连接的桌面";
/* rcv group event chat item */
"connected directly" = "已直连";
/* No comment provided by engineer. */
"Connected servers" = "已连接的服务器";
@@ -2154,7 +2151,7 @@ chat item action */
/* alert title */
"Error deleting chat database" = "删除聊天数据库错误";
/* No comment provided by engineer. */
/* alert title */
"Error deleting chat!" = "删除聊天错误!";
/* No comment provided by engineer. */
@@ -159,11 +159,11 @@ fun AppearanceScope.AppearanceLayout(
}
}
private fun findEnabledIcon(): AppIcon = AppIcon.values().first { icon ->
private fun findEnabledIcon(): AppIcon = AppIcon.values().firstOrNull { icon ->
androidAppContext.packageManager.getComponentEnabledSetting(
ComponentName(APPLICATION_ID, "chat.simplex.app.MainActivity_${icon.name.lowercase()}")
).let { it == COMPONENT_ENABLED_STATE_DEFAULT || it == COMPONENT_ENABLED_STATE_ENABLED }
}
} ?: AppIcon.DEFAULT
@Preview
@Composable
@@ -1228,6 +1228,7 @@ data class User(
override val showNtfs: Boolean,
val sendRcptsContacts: Boolean,
val sendRcptsSmallGroups: Boolean,
val autoAcceptMemberContacts: Boolean,
val viewPwdHash: UserPwdHash?,
val uiThemes: ThemeModeOverrides? = null,
): NamedChat, UserLike {
@@ -1257,6 +1258,7 @@ data class User(
showNtfs = true,
sendRcptsContacts = true,
sendRcptsSmallGroups = false,
autoAcceptMemberContacts = false,
viewPwdHash = null,
uiThemes = null,
)
@@ -1730,6 +1732,7 @@ data class Contact(
val contactRequestId: Long?,
val contactGroupMemberId: Long? = null,
val contactGrpInvSent: Boolean,
val groupDirectInv: GroupDirectInvitation? = null,
val chatTags: List<Long>,
val chatItemTTL: Long?,
override val chatDeleted: Boolean,
@@ -1745,7 +1748,10 @@ data class Contact(
val nextSendGrpInv get() = contactGroupMemberId != null && !contactGrpInvSent
override val nextConnectPrepared get() = active && preparedContact != null && (activeConn == null || activeConn.connStatus == ConnStatus.Prepared)
override val profileChangeProhibited get() = activeConn != null
val nextAcceptContactRequest get() = active && contactRequestId != null && (activeConn == null || activeConn.connStatus == ConnStatus.New)
val nextAcceptContactRequest get() =
active &&
(contactRequestId != null || groupDirectInv != null) &&
(activeConn == null || activeConn.connStatus == ConnStatus.New || activeConn.connStatus == ConnStatus.Prepared)
val sendMsgToConnect get() = nextSendGrpInv || nextConnectPrepared
override val incognito get() = contactConnIncognito
override fun featureEnabled(feature: ChatFeature) = when (feature) {
@@ -1836,6 +1842,18 @@ data class PreparedContact (
val uiConnLinkType: ConnectionMode
)
@Serializable
data class GroupDirectInvitation (
val groupDirectInvLink: String,
val fromGroupId_: Long?,
val fromGroupMemberId_: Long?,
val fromGroupMemberConnId_: Long?,
val groupDirectInvStartedConnection: Boolean
) {
val memberRemoved: Boolean
get() = fromGroupId_ == null || fromGroupMemberId_ == null || fromGroupMemberConnId_ == null
}
@Serializable
enum class ConnectionMode {
@SerialName("inv") Inv,
@@ -2843,6 +2861,7 @@ data class ChatItem (
is CIContent.RcvDirectEventContent -> when (content.rcvDirectEvent) {
is RcvDirectEvent.ContactDeleted -> false
is RcvDirectEvent.ProfileUpdated -> false
is RcvDirectEvent.GroupInvLinkReceived -> true
}
is CIContent.RcvGroupEventContent -> when (content.rcvGroupEvent) {
is RcvGroupEvent.MemberAdded -> false
@@ -4301,7 +4320,6 @@ sealed class MsgChatLink {
@Serializable
class FormattedText(val text: String, val format: Format? = null) {
// TODO make it dependent on simplexLinkMode preference
fun link(mode: SimplexLinkMode): String? = when (format) {
is Format.Uri -> if (text.startsWith("http://", ignoreCase = true) || text.startsWith("https://", ignoreCase = true)) text else "https://$text"
is Format.SimplexLink -> if (mode == SimplexLinkMode.BROWSER) text else format.simplexUri
@@ -4310,7 +4328,6 @@ class FormattedText(val text: String, val format: Format? = null) {
else -> null
}
// TODO make it dependent on simplexLinkMode preference
fun viewText(mode: SimplexLinkMode): String =
if (format is Format.SimplexLink && mode == SimplexLinkMode.DESCRIPTION) simplexLinkText(format.linkType, format.smpHosts) else text
@@ -4335,6 +4352,7 @@ sealed class Format {
@Serializable @SerialName("mention") class Mention(val memberName: String): Format()
@Serializable @SerialName("email") class Email: Format()
@Serializable @SerialName("phone") class Phone: Format()
@Serializable @SerialName("unknown") class Unknown: Format()
val style: SpanStyle @Composable get() = when (this) {
is Bold -> SpanStyle(fontWeight = FontWeight.Bold)
@@ -4348,6 +4366,7 @@ sealed class Format {
is Mention -> SpanStyle(fontWeight = FontWeight.Medium)
is Email -> linkStyle
is Phone -> linkStyle
is Unknown -> SpanStyle()
}
val isSimplexLink = this is SimplexLink
@@ -4511,10 +4530,12 @@ sealed class MsgErrorType() {
sealed class RcvDirectEvent() {
@Serializable @SerialName("contactDeleted") class ContactDeleted(): RcvDirectEvent()
@Serializable @SerialName("profileUpdated") class ProfileUpdated(val fromProfile: Profile, val toProfile: Profile): RcvDirectEvent()
@Serializable @SerialName("groupInvLinkReceived") class GroupInvLinkReceived(val groupProfile: GroupProfile): RcvDirectEvent()
val text: String get() = when (this) {
is ContactDeleted -> generalGetString(MR.strings.rcv_direct_event_contact_deleted)
is ProfileUpdated -> profileUpdatedText(fromProfile, toProfile)
is GroupInvLinkReceived -> generalGetString(MR.strings.rcv_direct_event_group_inv_link_received).format(groupProfile.displayName)
}
private fun profileUpdatedText(from: Profile, to: Profile): String =
@@ -857,6 +857,12 @@ object ChatController {
throw Exception("failed to set receipts for user groups ${r.responseType} ${r.details}")
}
suspend fun apiSetUserAutoAcceptMemberContacts(u: User, enable: Boolean) {
val r = sendCmd(u.remoteHostId, CC.ApiSetUserAutoAcceptMemberContacts(u.userId, enable))
if (r.result is CR.CmdOk) return
throw Exception("failed to set auto-accept ${r.responseType} ${r.details}")
}
suspend fun apiHideUser(u: User, viewPwd: String): User =
setUserPrivacy(u.remoteHostId, CC.ApiHideUser(u.userId, viewPwd))
@@ -2207,6 +2213,16 @@ object ChatController {
return null
}
suspend fun apiAcceptMemberContact(rh: Long?, contactId: Long): Contact? {
val r = sendCmdWithRetry(rh, CC.APIAcceptMemberContact(contactId))
if (r is API.Result && r.res is CR.MemberContactAccepted) return r.res.contact
if (r != null) {
Log.e(TAG, "apiAcceptMemberContact bad response: ${r.responseType} ${r.details}")
apiConnectResponseAlert(r)
}
return null
}
suspend fun allowFeatureToContact(rh: Long?, contact: Contact, feature: ChatFeature, param: Int? = null) {
val prefs = contact.mergedPreferences.toPreferences().setAllowed(feature, param = param)
val toContact = apiSetContactPrefs(rh, contact.contactId, prefs)
@@ -3510,6 +3526,7 @@ sealed class CC {
class SetAllContactReceipts(val enable: Boolean): CC()
class ApiSetUserContactReceipts(val userId: Long, val userMsgReceiptSettings: UserMsgReceiptSettings): CC()
class ApiSetUserGroupReceipts(val userId: Long, val userMsgReceiptSettings: UserMsgReceiptSettings): CC()
class ApiSetUserAutoAcceptMemberContacts(val userId: Long, val enable: Boolean): CC()
class ApiHideUser(val userId: Long, val viewPwd: String): CC()
class ApiUnhideUser(val userId: Long, val viewPwd: String): CC()
class ApiMuteUser(val userId: Long): CC()
@@ -3567,6 +3584,7 @@ sealed class CC {
class ApiAddGroupShortLink(val groupId: Long): CC()
class APICreateMemberContact(val groupId: Long, val groupMemberId: Long): CC()
class APISendMemberContactInvitation(val contactId: Long, val mc: MsgContent): CC()
class APIAcceptMemberContact(val contactId: Long): CC()
class APITestProtoServer(val userId: Long, val server: String): CC()
class ApiGetServerOperators(): CC()
class ApiSetServerOperators(val operators: List<ServerOperator>): CC()
@@ -3687,6 +3705,7 @@ sealed class CC {
val mrs = userMsgReceiptSettings
"/_set receipts groups $userId ${onOff(mrs.enable)} clear_overrides=${onOff(mrs.clearOverrides)}"
}
is ApiSetUserAutoAcceptMemberContacts -> "/_set accept member contacts $userId ${onOff(enable)}"
is ApiHideUser -> "/_hide user $userId ${json.encodeToString(viewPwd)}"
is ApiUnhideUser -> "/_unhide user $userId ${json.encodeToString(viewPwd)}"
is ApiMuteUser -> "/_mute user $userId"
@@ -3762,6 +3781,7 @@ sealed class CC {
is ApiAddGroupShortLink -> "/_short link #$groupId"
is APICreateMemberContact -> "/_create member contact #$groupId $groupMemberId"
is APISendMemberContactInvitation -> "/_invite member contact @$contactId ${mc.cmdString}"
is APIAcceptMemberContact -> "/_accept member contact @$contactId"
is APITestProtoServer -> "/_server test $userId $server"
is ApiGetServerOperators -> "/_operators"
is ApiSetServerOperators -> "/_operators ${json.encodeToString(operators)}"
@@ -3879,6 +3899,7 @@ sealed class CC {
is SetAllContactReceipts -> "setAllContactReceipts"
is ApiSetUserContactReceipts -> "apiSetUserContactReceipts"
is ApiSetUserGroupReceipts -> "apiSetUserGroupReceipts"
is ApiSetUserAutoAcceptMemberContacts -> "apiSetUserAutoAcceptMemberContacts"
is ApiHideUser -> "apiHideUser"
is ApiUnhideUser -> "apiUnhideUser"
is ApiMuteUser -> "apiMuteUser"
@@ -3935,6 +3956,7 @@ sealed class CC {
is ApiAddGroupShortLink -> "apiAddGroupShortLink"
is APICreateMemberContact -> "apiCreateMemberContact"
is APISendMemberContactInvitation -> "apiSendMemberContactInvitation"
is APIAcceptMemberContact -> "apiAcceptMemberContact"
is APITestProtoServer -> "testProtoServer"
is ApiGetServerOperators -> "apiGetServerOperators"
is ApiSetServerOperators -> "apiSetServerOperators"
@@ -6127,6 +6149,7 @@ sealed class CR {
@Serializable @SerialName("groupLinkDeleted") class GroupLinkDeleted(val user: UserRef, val groupInfo: GroupInfo): CR()
@Serializable @SerialName("newMemberContact") class NewMemberContact(val user: UserRef, val contact: Contact, val groupInfo: GroupInfo, val member: GroupMember): CR()
@Serializable @SerialName("newMemberContactSentInv") class NewMemberContactSentInv(val user: UserRef, val contact: Contact, val groupInfo: GroupInfo, val member: GroupMember): CR()
@Serializable @SerialName("memberContactAccepted") class MemberContactAccepted(val user: UserRef, val contact: Contact): CR()
@Serializable @SerialName("newMemberContactReceivedInv") class NewMemberContactReceivedInv(val user: UserRef, val contact: Contact, val groupInfo: GroupInfo, val member: GroupMember): CR()
// receiving file events
@Serializable @SerialName("rcvFileAccepted") class RcvFileAccepted(val user: UserRef, val chatItem: AChatItem): CR()
@@ -6310,6 +6333,7 @@ sealed class CR {
is GroupLinkDeleted -> "groupLinkDeleted"
is NewMemberContact -> "newMemberContact"
is NewMemberContactSentInv -> "newMemberContactSentInv"
is MemberContactAccepted -> "memberContactAccepted"
is NewMemberContactReceivedInv -> "newMemberContactReceivedInv"
is RcvFileAcceptedSndCancelled -> "rcvFileAcceptedSndCancelled"
is StandaloneFileInfo -> "standaloneFileInfo"
@@ -6486,6 +6510,7 @@ sealed class CR {
is GroupLinkDeleted -> withUser(user, json.encodeToString(groupInfo))
is NewMemberContact -> withUser(user, "contact: $contact\ngroupInfo: $groupInfo\nmember: $member")
is NewMemberContactSentInv -> withUser(user, "contact: $contact\ngroupInfo: $groupInfo\nmember: $member")
is MemberContactAccepted -> withUser(user, "contact: $contact")
is NewMemberContactReceivedInv -> withUser(user, "contact: $contact\ngroupInfo: $groupInfo\nmember: $member")
is RcvFileAcceptedSndCancelled -> withUser(user, noDetails())
is StandaloneFileInfo -> json.encodeToString(fileMeta)
@@ -41,6 +41,7 @@ import chat.simplex.common.views.helpers.*
import chat.simplex.common.views.usersettings.*
import chat.simplex.common.platform.*
import chat.simplex.common.views.chat.group.ChatTTLOption
import chat.simplex.common.views.chat.item.MarkdownText
import chat.simplex.common.views.chatlist.updateChatSettings
import chat.simplex.common.views.newchat.*
import chat.simplex.res.MR
@@ -759,16 +760,16 @@ fun ChatInfoDescription(c: NamedChat, displayName: String, copyNameToClipboard:
}
val descr = c.shortDescr?.trim()
if (descr != null && descr != "") {
val copyDescr = { copyNameToClipboard(descr) }
Text(
MarkdownText(
descr,
style = MaterialTheme.typography.body2,
color = MaterialTheme.colors.onBackground,
textAlign = TextAlign.Center,
parseToMarkdown(descr),
toggleSecrets = true,
style = MaterialTheme.typography.body2.copy(color = MaterialTheme.colors.onBackground, lineHeight = 21.sp, textAlign = TextAlign.Center),
maxLines = 4,
overflow = TextOverflow.Ellipsis,
lineHeight = 21.sp,
modifier = Modifier.padding(top = DEFAULT_PADDING_HALF).combinedClickable(onClick = copyDescr, onLongClick = copyDescr).onRightClick(copyDescr)
uriHandler = LocalUriHandler.current,
modifier = Modifier.padding(top = DEFAULT_PADDING_HALF),
linkMode = chatModel.simplexLinkMode.value
)
}
}
@@ -770,6 +770,8 @@ private fun connectingText(chatInfo: ChatInfo): String? {
) {
if (chatInfo.contact.preparedContact?.uiConnLinkType == ConnectionMode.Con) {
generalGetString(MR.strings.contact_should_accept)
} else if (chatInfo.contact.contactGroupMemberId != null) {
generalGetString(MR.strings.contact_should_accept)
} else {
generalGetString(MR.strings.contact_connection_pending)
}
@@ -1851,16 +1853,16 @@ fun BoxScope.ChatItemsList(
val descr = chatInfo.shortDescr?.trim()
if (descr != null && descr != "") {
Text(
MarkdownText(
descr,
style = MaterialTheme.typography.body2,
color = MaterialTheme.colors.onBackground,
textAlign = TextAlign.Center,
parseToMarkdown(descr),
toggleSecrets = true,
style = MaterialTheme.typography.body2.copy(color = MaterialTheme.colors.onBackground, lineHeight = 21.sp, textAlign = TextAlign.Center),
maxLines = 4,
overflow = TextOverflow.Ellipsis,
lineHeight = 21.sp,
modifier = Modifier
.padding(top = DEFAULT_PADDING_HALF)
uriHandler = LocalUriHandler.current,
modifier = Modifier.padding(top = DEFAULT_PADDING_HALF),
linkMode = linkMode
)
}
@@ -1869,6 +1871,7 @@ fun BoxScope.ChatItemsList(
Text(
contextStr,
style = MaterialTheme.typography.body2,
textAlign = TextAlign.Center,
color = MaterialTheme.colors.secondary,
modifier = Modifier.padding(top = DEFAULT_PADDING)
)
@@ -0,0 +1,172 @@
package chat.simplex.common.views.chat
import TextIconSpaced
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import chat.simplex.common.model.*
import chat.simplex.common.platform.chatModel
import chat.simplex.common.ui.theme.DEFAULT_PADDING_HALF
import chat.simplex.common.views.helpers.*
import chat.simplex.res.MR
import dev.icerock.moko.resources.compose.painterResource
import dev.icerock.moko.resources.compose.stringResource
import kotlinx.coroutines.*
@Composable
fun ComposeContextMemberContactActionsView(
rhId: Long?,
contact: Contact,
groupDirectInv: GroupDirectInvitation
) {
val inProgress = rememberSaveable { mutableStateOf(false) }
var progressByTimeout by rememberSaveable { mutableStateOf(false) }
KeyChangeEffect(chatModel.chatId.value) {
if (inProgress.value) {
inProgress.value = false
progressByTimeout = false
}
}
LaunchedEffect(inProgress.value) {
progressByTimeout = if (inProgress.value) {
delay(1000)
inProgress.value
} else {
false
}
}
Box(
Modifier.height(60.dp),
contentAlignment = Alignment.Center
) {
Column(
Modifier
.background(MaterialTheme.colors.surface)
.alpha(if (progressByTimeout) 0.6f else 1f)
) {
Divider()
if (groupDirectInv.memberRemoved) {
Row(
Modifier
.fillMaxSize()
.padding(horizontal = DEFAULT_PADDING_HALF),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(8.dp, Alignment.CenterHorizontally)
) {
Icon(painterResource(MR.images.ic_info), contentDescription = null, tint = MaterialTheme.colors.secondary)
Text(generalGetString(MR.strings.member_is_deleted_cant_accept_request), color = MaterialTheme.colors.secondary)
}
} else {
Row(
Modifier
.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceEvenly,
) {
var rejectButtonModifier = Modifier.fillMaxWidth().fillMaxHeight().weight(1F)
rejectButtonModifier =
if (inProgress.value) rejectButtonModifier
else rejectButtonModifier.clickable { showRejectMemberContactRequestAlert(rhId, contact) }
Row(
rejectButtonModifier,
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.Center
) {
Icon(
painterResource(MR.images.ic_close),
contentDescription = null,
tint = if (inProgress.value) MaterialTheme.colors.secondary else Color.Red,
)
TextIconSpaced(false)
Text(
stringResource(MR.strings.reject_contact_button),
color = if (inProgress.value) MaterialTheme.colors.secondary else Color.Red
)
}
var acceptButtonModifier = Modifier.fillMaxWidth().fillMaxHeight().weight(1F)
acceptButtonModifier =
if (inProgress.value) acceptButtonModifier
else acceptButtonModifier.clickable { acceptMemberContact(rhId, contact.contactId, inProgress = inProgress) }
Row(
acceptButtonModifier,
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.Center
) {
Icon(
painterResource(MR.images.ic_check),
contentDescription = null,
tint = if (inProgress.value) MaterialTheme.colors.secondary else MaterialTheme.colors.primary,
)
TextIconSpaced(false)
Text(
stringResource(MR.strings.accept_contact_button),
color = if (inProgress.value) MaterialTheme.colors.secondary else MaterialTheme.colors.primary
)
}
}
}
}
if (progressByTimeout) {
ComposeProgressIndicator()
}
}
}
fun showRejectMemberContactRequestAlert(rhId: Long?, contact: Contact) {
AlertManager.shared.showAlertDialog(
title = generalGetString(MR.strings.reject_contact_request),
text = generalGetString(MR.strings.the_sender_will_not_be_notified),
confirmText = generalGetString(MR.strings.reject_contact_button),
onConfirm = {
AlertManager.shared.hideAlert()
deleteMemberContact(rhId, contact)
},
destructive = true,
hostDevice = hostDevice(rhId),
)
}
private fun deleteMemberContact(rhId: Long?, contact: Contact) {
withBGApi {
chatModel.controller.apiDeleteContact(rhId, contact.contactId, chatDeleteMode = ContactDeleteMode.Full().toChatDeleteMode(notify = false))
withContext(Dispatchers.Main) {
chatModel.chatsContext.removeChat(rhId, contact.id)
chatModel.chatId.value = null
}
}
}
fun acceptMemberContact(
rhId: Long?,
contactId: Long,
close: ((chat: Chat) -> Unit)? = null,
inProgress: MutableState<Boolean>? = null
) {
withBGApi {
inProgress?.value = true
val contact = chatModel.controller.apiAcceptMemberContact(rhId, contactId)
if (contact != null) {
withContext(Dispatchers.Main) {
chatModel.chatsContext.updateContact(rhId, contact)
inProgress?.value = false
}
chatModel.setContactNetworkStatus(contact, NetworkStatus.Connected())
val chat = Chat(remoteHostId = rhId, ChatInfo.Direct(contact), listOf())
close?.invoke(chat)
} else {
inProgress?.value = false
}
}
}
@@ -1248,6 +1248,7 @@ fun ComposeView(
SimpleButtonIconEnded(
text = stringResource(MR.strings.compose_view_connect),
icon = painterResource(icon),
style = MaterialTheme.typography.body2,
color = if (composeState.value.inProgress) MaterialTheme.colors.secondary else MaterialTheme.colors.primary,
disabled = composeState.value.inProgress,
click = { withApi { sendRequest() } }
@@ -1467,6 +1468,16 @@ fun ComposeView(
rhId = rhId,
contactRequestId = chat.chatInfo.contact.contactRequestId
)
} else if (
chat.chatInfo is ChatInfo.Direct
&& chat.chatInfo.contact.nextAcceptContactRequest
&& chat.chatInfo.contact.groupDirectInv != null
) {
ComposeContextMemberContactActionsView(
rhId = rhId,
contact = chat.chatInfo.contact,
groupDirectInv = chat.chatInfo.contact.groupDirectInv
)
} else {
Row(Modifier.padding(end = 8.dp), verticalAlignment = Alignment.Bottom) {
AttachmentButton()
@@ -34,7 +34,7 @@ import chat.simplex.common.views.newchat.*
import chat.simplex.common.views.usersettings.SettingsActionItem
import chat.simplex.common.model.GroupInfo
import chat.simplex.common.platform.*
import chat.simplex.common.views.chatlist.openLoadedChat
import chat.simplex.common.views.chatlist.openDirectChat
import chat.simplex.res.MR
import dev.icerock.moko.resources.StringResource
import kotlinx.datetime.Clock
@@ -57,6 +57,7 @@ fun GroupMemberInfoView(
val connStats = remember { mutableStateOf(connectionStats) }
val developerTools = chatModel.controller.appPrefs.developerTools.get()
var progressIndicator by remember { mutableStateOf(false) }
val scope = rememberCoroutineScope()
fun syncMemberConnection() {
withBGApi {
@@ -86,12 +87,10 @@ fun GroupMemberInfoView(
developerTools,
connectionCode,
getContactChat = { chatModel.getContactChat(it) },
openDirectChat = {
withBGApi {
apiLoadMessages(chatModel.chatsContext, rhId, ChatType.Direct, it, ChatPagination.Initial(ChatPagination.INITIAL_COUNT))
if (chatModel.getContactChat(it) != null) {
closeAll()
}
openDirectChat = { contactId ->
scope.launch {
openDirectChat(rhId, contactId)
closeAll()
}
},
createMemberContact = {
@@ -104,7 +103,7 @@ fun GroupMemberInfoView(
withContext(Dispatchers.Main) {
chatModel.chatsContext.addChat(memberChat)
}
openLoadedChat(memberChat)
openDirectChat(rhId, memberContact.contactId)
closeAll()
chatModel.setContactNetworkStatus(memberContact, NetworkStatus.Connected())
}
@@ -271,8 +271,14 @@ suspend fun setGroupMembers(rhId: Long?, groupInfo: GroupInfo, chatModel: ChatMo
@Composable
fun ContactMenuItems(chat: Chat, contact: Contact, chatModel: ChatModel, showMenu: MutableState<Boolean>, showMarkRead: Boolean) {
if (contact.nextAcceptContactRequest && contact.contactRequestId != null) {
ContactRequestMenuItems(chat.remoteHostId, contactRequestId = contact.contactRequestId, chatModel, showMenu)
if (contact.nextAcceptContactRequest) {
if (contact.contactRequestId != null) {
ContactRequestMenuItems(chat.remoteHostId, contactRequestId = contact.contactRequestId, chatModel, showMenu)
} else if (contact.groupDirectInv != null && !contact.groupDirectInv.memberRemoved) {
MemberContactRequestMenuItems(chat.remoteHostId, contact, showMenu)
} else {
DeleteContactAction(chat, chatModel, showMenu)
}
} else {
if (contact.activeConn != null) {
if (showMarkRead) {
@@ -545,6 +551,28 @@ fun ContactRequestMenuItems(rhId: Long?, contactRequestId: Long, chatModel: Chat
)
}
@Composable
fun MemberContactRequestMenuItems(rhId: Long?, contact: Contact, showMenu: MutableState<Boolean>, onSuccess: ((chat: Chat) -> Unit)? = null) {
ItemAction(
stringResource(MR.strings.accept_contact_button),
painterResource(MR.images.ic_check),
color = MaterialTheme.colors.onBackground,
onClick = {
acceptMemberContact(rhId, contact.contactId, onSuccess)
showMenu.value = false
}
)
ItemAction(
stringResource(MR.strings.reject_contact_button),
painterResource(MR.images.ic_close),
onClick = {
showRejectMemberContactRequestAlert(rhId, contact)
showMenu.value = false
},
color = Color.Red
)
}
@Composable
fun ContactConnectionMenuItems(rhId: Long?, chatInfo: ChatInfo.ContactConnection, chatModel: ChatModel, showMenu: MutableState<Boolean>) {
ItemAction(
@@ -144,7 +144,7 @@ fun ChatPreviewView(
}
val color = if (deleting)
MaterialTheme.colors.secondary
else if (cInfo.contact.nextAcceptContactRequest || cInfo.contact.sendMsgToConnect) {
else if ((cInfo.contact.nextAcceptContactRequest && cInfo.contact.groupDirectInv?.memberRemoved != true) || cInfo.contact.sendMsgToConnect) {
MaterialTheme.colors.primary
} else if (!cInfo.contact.sndReady) {
MaterialTheme.colors.secondary
@@ -73,14 +73,25 @@ fun ContactListNavLinkView(chat: Chat, nextChatSelected: State<Boolean>, showDel
},
dropdownMenuItems = {
tryOrShowError("${chat.id}ContactListNavLinkDropdown", error = {}) {
if (contactType == ContactType.CONTACT_WITH_REQUEST && chat.chatInfo.contact.contactRequestId != null) {
ContactRequestMenuItems(
rhId = chat.remoteHostId,
contactRequestId = chat.chatInfo.contact.contactRequestId,
chatModel = chatModel,
showMenu = showMenu,
onSuccess = { onRequestAccepted(it) }
)
if (contactType == ContactType.CONTACT_WITH_REQUEST) {
if (chat.chatInfo.contact.contactRequestId != null) {
ContactRequestMenuItems(
rhId = chat.remoteHostId,
contactRequestId = chat.chatInfo.contact.contactRequestId,
chatModel = chatModel,
showMenu = showMenu,
onSuccess = { onRequestAccepted(it) }
)
} else if (chat.chatInfo.contact.groupDirectInv != null && !chat.chatInfo.contact.groupDirectInv.memberRemoved) {
MemberContactRequestMenuItems(
rhId = chat.remoteHostId,
contact = chat.chatInfo.contact,
showMenu = showMenu,
onSuccess = { onRequestAccepted(it) }
)
} else {
DeleteContactAction(chat, chatModel, showMenu)
}
} else {
DeleteContactAction(chat, chatModel, showMenu)
}
@@ -31,19 +31,23 @@ fun ContactPreviewView(
Icon(painterResource(MR.images.ic_verified_user), null, Modifier.size(19.dp).padding(end = 3.dp, top = 1.dp), tint = MaterialTheme.colors.secondary)
}
val deleting by remember(disabled, chat.id) { mutableStateOf(chatModel.deletedChats.value.contains(chat.remoteHostId to chat.chatInfo.id)) }
val textColor = when {
deleting -> MaterialTheme.colors.secondary
contactType == ContactType.CARD -> MaterialTheme.colors.primary
contactType == ContactType.CONTACT_WITH_REQUEST ->
if (chat.chatInfo is ChatInfo.Direct && chat.chatInfo.contact.groupDirectInv?.memberRemoved == true)
MaterialTheme.colors.secondary
else
MaterialTheme.colors.primary
contactType == ContactType.REQUEST -> MaterialTheme.colors.primary
contactType == ContactType.RECENT -> if (chat.chatInfo.nextConnect) MaterialTheme.colors.primary else Color.Unspecified
else -> Color.Unspecified
}
@Composable
fun chatPreviewTitle() {
val deleting by remember(disabled, chat.id) { mutableStateOf(chatModel.deletedChats.value.contains(chat.remoteHostId to chat.chatInfo.id)) }
val textColor = when {
deleting -> MaterialTheme.colors.secondary
contactType == ContactType.CARD -> MaterialTheme.colors.primary
contactType == ContactType.CONTACT_WITH_REQUEST -> MaterialTheme.colors.primary
contactType == ContactType.REQUEST -> MaterialTheme.colors.primary
contactType == ContactType.RECENT -> if (chat.chatInfo.nextConnect) MaterialTheme.colors.primary else Color.Unspecified
else -> Color.Unspecified
}
when (cInfo) {
is ChatInfo.Direct ->
Row(verticalAlignment = Alignment.CenterVertically) {
@@ -90,7 +94,7 @@ fun ContactPreviewView(
Icon(
painterResource(MR.images.ic_check),
contentDescription = null,
tint = MaterialTheme.colors.primary,
tint = textColor,
modifier = Modifier
.size(23.dp)
)
@@ -46,7 +46,7 @@ fun <T> ExposedDropDownSetting(
horizontalArrangement = Arrangement.End
) {
Text(
values.first { it.first == selection.value }.second + (if (label != null) " $label" else ""),
(values.firstOrNull { it.first == selection.value }?.second ?: "") + (if (label != null) " $label" else ""),
Modifier.widthIn(max = maxWidth),
maxLines = 1,
overflow = TextOverflow.Ellipsis,
@@ -120,8 +120,10 @@ fun <T> ExposedDropDownSettingWithIcon(
),
contentAlignment = Alignment.Center
) {
val choice = values.first { it.first == selection.value }
Icon(painterResource(choice.second), choice.third, Modifier.padding(boxSize * iconPaddingPercent).fillMaxSize(), tint = iconColor)
val choice = values.firstOrNull { it.first == selection.value }
if (choice != null) {
Icon(painterResource(choice.second), choice.third, Modifier.padding(boxSize * iconPaddingPercent).fillMaxSize(), tint = iconColor)
}
}
DefaultExposedDropdownMenu(
modifier = Modifier.widthIn(min = minWidth),
@@ -91,7 +91,7 @@ fun <T> SectionViewSelectable(
}
}
}
SectionTextFooter(values.first { it.value == currentValue.value }.description)
SectionTextFooter(values.firstOrNull { it.value == currentValue.value }?.description ?: AnnotatedString(""))
}
@Composable
@@ -221,7 +221,7 @@ fun <T> SectionItemWithValue(
horizontalArrangement = Arrangement.End
) {
Text(
values.first { it.value == currentValue.value }.title + (if (label != null) " $label" else ""),
(values.firstOrNull { it.value == currentValue.value }?.title ?: "") + (if (label != null) " $label" else ""),
maxLines = 1,
overflow = TextOverflow.Ellipsis,
color = MaterialTheme.colors.secondary
@@ -25,6 +25,7 @@ import chat.simplex.common.views.helpers.*
import chat.simplex.common.platform.*
import chat.simplex.common.views.*
import chat.simplex.common.views.chat.group.GroupLinkView
import chat.simplex.common.views.chatlist.openGroupChat
import chat.simplex.common.views.usersettings.*
import chat.simplex.res.MR
import kotlinx.coroutines.delay
@@ -44,8 +45,7 @@ fun AddGroupView(chatModel: ChatModel, rh: RemoteHostInfo?, close: () -> Unit, c
if (groupInfo != null) {
withContext(Dispatchers.Main) {
chatModel.chatsContext.updateGroup(rhId = rhId, groupInfo)
chatModel.chatsContext.chatItems.clearAndNotify()
chatModel.chatId.value = groupInfo.id
openGroupChat(rhId, groupInfo.groupId)
}
setGroupMembers(rhId, groupInfo, chatModel)
closeAll.invoke()
@@ -62,7 +62,7 @@ fun NotificationsSettingsLayout(
if (appPlatform == AppPlatform.ANDROID) {
SettingsActionItemWithContent(null, stringResource(MR.strings.settings_notifications_mode_title), { showPage(CurrentPage.NOTIFICATIONS_MODE) }) {
Text(
modes.first { it.value == notificationsMode.value }.title,
modes.firstOrNull { it.value == notificationsMode.value }?.title ?: "",
maxLines = 1,
overflow = TextOverflow.Ellipsis,
color = MaterialTheme.colors.secondary
@@ -71,7 +71,7 @@ fun NotificationsSettingsLayout(
}
SettingsActionItemWithContent(null, stringResource(MR.strings.settings_notification_preview_mode_title), { showPage(CurrentPage.NOTIFICATION_PREVIEW_MODE) }) {
Text(
previewModes.first { it.value == notificationPreviewMode.value }.title,
previewModes.firstOrNull { it.value == notificationPreviewMode.value }?.title ?: "",
maxLines = 1,
overflow = TextOverflow.Ellipsis,
color = MaterialTheme.colors.secondary
@@ -161,7 +161,22 @@ fun PrivacySettingsView(
}
}
fun setAutoAcceptGrpDirectInvs(enable: Boolean) {
withApi {
chatModel.controller.apiSetUserAutoAcceptMemberContacts(currentUser, enable)
chatModel.currentUser.value = currentUser.copy(autoAcceptMemberContacts = enable)
}
}
if (!chatModel.desktopNoUserNoRemote) {
SectionDividerSpaced(maxTopPadding = true)
ContacRequestsFromGroupsSection(
currentUser = currentUser,
setAutoAcceptGrpDirectInvs = { enable ->
setAutoAcceptGrpDirectInvs(enable)
}
)
SectionDividerSpaced(maxTopPadding = true)
DeliveryReceiptsSection(
currentUser = currentUser,
@@ -275,6 +290,34 @@ expect fun PrivacyDeviceSection(
setPerformLA: (Boolean) -> Unit,
)
@Composable
private fun ContacRequestsFromGroupsSection(
currentUser: User,
setAutoAcceptGrpDirectInvs: (Boolean) -> Unit
) {
SectionView(stringResource(MR.strings.settings_section_title_contact_requests_from_groups)) {
SettingsActionItemWithContent(painterResource(MR.images.ic_check), stringResource(MR.strings.auto_accept_contact)) {
DefaultSwitch(
checked = currentUser.autoAcceptMemberContacts,
onCheckedChange = { enable ->
setAutoAcceptGrpDirectInvs(enable)
}
)
}
}
SectionTextFooter(
remember(currentUser.displayName) {
buildAnnotatedString {
append(generalGetString(MR.strings.this_setting_is_for_your_current_profile) + " ")
withStyle(SpanStyle(fontWeight = FontWeight.Bold)) {
append(currentUser.displayName)
}
append(".")
}
}
)
}
@Composable
private fun DeliveryReceiptsSection(
currentUser: User,
@@ -594,7 +594,7 @@ fun UseOnionHosts(
onSelected = {}
)
}
SectionTextFooter(values.first { it.value == onionHosts.value }.description)
SectionTextFooter(values.firstOrNull { it.value == onionHosts.value }?.description ?: AnnotatedString(""))
}
}
@@ -1365,7 +1365,7 @@
<string name="v5_3_simpler_incognito_mode">وضع التخفي اصبح أسهل</string>
<string name="v5_3_simpler_incognito_mode_descr">فعّل وضع التخفي عند الاتصال.</string>
<string name="member_contact_send_direct_message">أرسل لاتصال</string>
<string name="rcv_group_event_member_created_contact">متصل مباشرةً</string>
<string name="rcv_group_event_member_created_contact">طُلب اتصال</string>
<string name="connect_plan_already_connecting">جارٍ الاتصال بالفعل!</string>
<string name="v5_4_better_groups">مجموعات أفضل</string>
<string name="rcv_group_and_other_events">و%d أحداث أخرى</string>
@@ -2496,4 +2496,8 @@
<string name="share_old_link_alert_button">شارك الرابط القديم</string>
<string name="share_group_profile_via_link_alert_text">سيكون الرابط قصيراً، وسيتم مشاركة الملف التعريفي للمجموعة عبر الرابط.</string>
<string name="upgrade_group_link">رقِّ رابط المجموعة</string>
<string name="settings_section_title_contact_requests_from_groups">طلبات الاتصال من المجموعات</string>
<string name="member_is_deleted_cant_accept_request">حُذف العضو - لا يمكن قبول الطلب</string>
<string name="rcv_direct_event_group_inv_link_received">طُلب اتصال من المجموعة %1$s</string>
<string name="this_setting_is_for_your_current_profile">هذا الإعداد لملف تعريفك الحالي</string>
</resources>
@@ -732,6 +732,9 @@
<string name="reject_contact_request">Reject contact request</string>
<string name="the_sender_will_not_be_notified">The sender will NOT be notified.</string>
<!-- ComposeContextMemberContactActionsView.kt -->
<string name="member_is_deleted_cant_accept_request">Member is deleted - can\'t accept request</string>
<!-- Clear Chat - ChatListNavLinkView.kt -->
<string name="clear_chat_question">Clear chat?</string>
<string name="clear_note_folder_question">Clear private notes?</string>
@@ -1395,6 +1398,7 @@
<string name="empty_chat_profile_is_created">An empty chat profile with the provided name is created, and the app opens as usual.</string>
<string name="if_you_enter_passcode_data_removed">If you enter this passcode when opening the app, all app data will be irreversibly removed!</string>
<string name="set_passcode">Set passcode</string>
<string name="this_setting_is_for_your_current_profile">This setting is for your current profile</string>
<string name="receipts_section_description">These settings are for your current profile</string>
<string name="receipts_section_description_1">They can be overridden in contact and group settings.</string>
<string name="receipts_section_contacts">Contacts</string>
@@ -1438,6 +1442,7 @@
<string name="settings_section_title_chats">CHATS</string>
<string name="settings_section_title_files">FILES</string>
<string name="settings_section_title_delivery_receipts">SEND DELIVERY RECEIPTS TO</string>
<string name="settings_section_title_contact_requests_from_groups">CONTACT REQUESTS FROM GROUPS</string>
<string name="settings_restart_app">Restart</string>
<string name="settings_shutdown">Shutdown</string>
<string name="settings_developer_tools">Developer tools</string>
@@ -1646,6 +1651,7 @@
<!-- Direct event chat items -->
<string name="rcv_direct_event_contact_deleted">deleted contact</string>
<string name="rcv_direct_event_group_inv_link_received">requested connection from group %1$s</string>
<!-- Group event chat items -->
<string name="rcv_group_event_member_added">invited %1$s</string>
@@ -1662,7 +1668,7 @@
<string name="rcv_group_event_group_deleted">deleted group</string>
<string name="rcv_group_event_updated_group_profile">updated group profile</string>
<string name="rcv_group_event_invited_via_your_group_link">invited via your group link</string>
<string name="rcv_group_event_member_created_contact">connected directly</string>
<string name="rcv_group_event_member_created_contact">requested connection</string>
<string name="rcv_group_event_new_member_pending_review">New member wants to join the group.</string>
<string name="snd_group_event_changed_member_role">you changed role of %s to %s</string>
<string name="snd_group_event_changed_role_for_yourself">you changed role for yourself to %s</string>
@@ -788,7 +788,7 @@
<string name="mark_code_verified">Маркирай като проверено</string>
<string name="is_not_verified">%s не е потвърдено</string>
<string name="is_verified">%s е потвърдено</string>
<string name="rate_the_app">Оценете приложението</string>
<string name="rate_the_app">Оцени приложението</string>
<string name="ensure_ICE_server_address_are_correct_format_and_unique">Уверете се, че адресите на WebRTC ICE сървъра са в правилен формат, разделени на редове и не са дублирани.</string>
<string name="network_and_servers">Мрежа и сървъри</string>
<string name="network_settings_title">Разширени настройки</string>
@@ -1006,7 +1006,7 @@
<string name="scan_code">Сканирай код</string>
<string name="scan_code_from_contacts_app">Сканирайте кода за сигурност от приложението на вашия контакт.</string>
<string name="security_code">Код за сигурност</string>
<string name="chat_with_the_founder">Изпращайте въпроси и идеи</string>
<string name="chat_with_the_founder">Изпрати въпроси и идеи</string>
<string name="smp_save_servers_question">Запази сървърите\?</string>
<string name="saved_ICE_servers_will_be_removed">Запазените WebRTC ICE сървъри ще бъдат премахнати.</string>
<string name="save_servers_button">Запази</string>
@@ -1056,7 +1056,7 @@
<string name="reset_verb">Нулиране</string>
<string name="send_verb">Изпрати</string>
<string name="add_contact_or_create_group">Започни нов чат</string>
<string name="send_us_an_email">Изпратете ни имейл</string>
<string name="send_us_an_email">Изпрати ни мейл</string>
<string name="smp_servers_test_some_failed">Някои сървъри не минаха теста:</string>
<string name="shutdown_alert_question">Изключване\?</string>
<string name="secret_text">таен</string>
@@ -1083,7 +1083,7 @@
<string name="revoke_file__action">Отзови файл</string>
<string name="stop_snd_file__message">Изпращането на файла ще бъде спряно.</string>
<string name="smp_servers_save">Запази сървърите</string>
<string name="send_live_message_desc">Изпратете съобщение на живо - то ще се актуализира за получателя(ите), докато го пишете</string>
<string name="send_live_message_desc">Изпрати съобщение на живо - то ще се актуализира за получателя(ите), докато го пишете</string>
<string name="smp_servers_test_failed">Тестът на сървъра е неуспешен!</string>
<string name="v4_2_security_assessment">Оценка на сигурността</string>
<string name="share_file">Сподели файл…</string>
@@ -1532,7 +1532,7 @@
<string name="tap_to_scan">Докосни за сканиране</string>
<string name="keep_invitation_link">Запази</string>
<string name="tap_to_paste_link">Докосни за поставяне на линк за връзка</string>
<string name="search_or_paste_simplex_link">Търсене или поставяне на SimpleX линк</string>
<string name="search_or_paste_simplex_link">Търси или постави SimpleX линк</string>
<string name="start_chat_question">Стартирай чата?</string>
<string name="chat_is_stopped_you_should_transfer_database">Чатът е спрян. Ако вече сте използвали тази база данни на друго устройство, трябва да я прехвърлите обратно, преди да стартирате чата отново.</string>
<string name="remote_ctrl_error_bad_invitation">Настолното устройство има грешен код за връзка</string>
@@ -2065,7 +2065,7 @@
<string name="action_button_add_members">Покани</string>
<string name="icon_descr_sound_muted">Звукът е заглушен</string>
<string name="appearance_app_toolbars">Панели на приложението</string>
<string name="cant_call_member_send_message_alert_text">Изпратете съобщение за да се активират обажданията.</string>
<string name="cant_call_member_send_message_alert_text">Изпрати съобщение за да се активират обажданията.</string>
<string name="info_view_search_button">търсене</string>
<string name="info_view_video_button">видео</string>
<string name="contact_deleted">Контактът е изтрит!</string>
@@ -2290,9 +2290,9 @@
<string name="chat_banner_accept_contact_request">Приеми заявка за контакт</string>
<string name="rcv_group_event_member_accepted">%1$s приет</string>
<string name="rcv_group_event_user_accepted">бяхте приети</string>
<string name="accept_pending_member_alert_title">Приемете член</string>
<string name="accept_pending_member_alert_title">Приеми член</string>
<string name="compose_view_add_message">Добави съобщение</string>
<string name="add_short_link">Добави кратък линк</string>
<string name="add_short_link">Обнови адрес</string>
<string name="member_criteria_all">всички</string>
<string name="block_members_desc">Всички нови съобщения от тези членове ще бъдат скрити!</string>
<string name="enable_sending_member_reports">Позволи докладването на съобщения на модераторите.</string>
@@ -2420,7 +2420,7 @@
<string name="private_routing_timeout">Време за изчакване на поверително рутиране</string>
<string name="network_option_protocol_timeout_background">Време за изчакване на протокола във фонов режим</string>
<string name="network_option_tcp_connection_timeout_background">Времето на изчакване за установяване на TCP връзка във фонов режим</string>
<string name="share_profile_via_link_alert_text">Профилът ще бъде споделен с адреса.</string>
<string name="share_profile_via_link_alert_text">Адресът ще бъде кратък и вашият профил ще бъде споделен чрез него.</string>
<string name="disable_sending_member_reports">Забранете докладването на съобщения на модератори.</string>
<string name="reject_pending_member_button">Отхвърляне</string>
<string name="reject_contact_request">Отхвърляне на заявка за контакт</string>
@@ -2453,15 +2453,15 @@
<string name="v6_3_reports">Изпращане на лични доклади за нарушения</string>
<string name="compose_view_send_request">Изпрати заявка</string>
<string name="compose_view_send_request_without_message">Изпрати заявка без съобщение</string>
<string name="v6_4_support_chat_descr">Изпратете личната си обратна връзка до групи.</string>
<string name="v6_4_support_chat_descr">Изпрати личната си обратна връзка до групи.</string>
<string name="sent_to_your_contact_after_connection">Изпратено до вашия контакт след осъществяване на връзка.</string>
<string name="text_field_set_chat_placeholder">Задаване на име на чат…</string>
<string name="set_member_admission">Задаване на достъп за членове</string>
<string name="v6_3_set_message_expiration_in_chats">Задаване на срок на валидност на съобщенията в чатовете.</string>
<string name="v6_4_1_welcome_contacts_descr">Задайте биография на профила и съобщение при посрещанее.</string>
<string name="share_group_profile_via_link">Споделяне на групов профил чрез линк</string>
<string name="share_profile_via_link_alert_confirm">Сподели профил</string>
<string name="share_profile_via_link">Сподели профил с адрес</string>
<string name="share_group_profile_via_link">Обнови групов линк?</string>
<string name="share_profile_via_link_alert_confirm">Обнови</string>
<string name="share_profile_via_link">Обнови адрес?</string>
<string name="v6_4_1_short_address_share">Споделете адреса си</string>
<string name="group_short_descr_field">Кратко описание:</string>
<string name="short_link_button_text">Кратък линк</string>
@@ -2500,4 +2500,8 @@
<string name="chat_banner_your_contact">Вашият контакт</string>
<string name="chat_banner_your_group">Вашата група</string>
<string name="context_user_picker_your_profile">Вашият профил</string>
<string name="share_old_address_alert_button">Сподели стар адрес</string>
<string name="share_old_link_alert_button">Сподели стар линк</string>
<string name="share_group_profile_via_link_alert_text">Линкът ще бъде кратък и профилът на групата ще бъде споделен чрез него.</string>
<string name="upgrade_group_link">Обнови групов линк</string>
</resources>
@@ -2400,7 +2400,7 @@
<string name="delete_member_support_chat_alert_title">Suprimir el xat amb membre?</string>
<string name="group_new_support_chats">%d xats amb membres</string>
<string name="member_criteria_all">tots(es)</string>
<string name="add_short_link">Afegir enllaç curt</string>
<string name="add_short_link">Actualitzar l\'adreça</string>
<string name="accept_contact_request">Acceptar la sol·licitud de contacte</string>
<string name="compose_view_add_message">Afegir un missatge</string>
<string name="context_user_picker_cant_change_profile_alert_title">No es pot canviar el perfil</string>
@@ -2419,16 +2419,16 @@
<string name="open_to_accept">Obrir per acceptar</string>
<string name="open_to_connect">Obrir per connectar</string>
<string name="group_preview_open_to_join">Obrir per entrar</string>
<string name="share_profile_via_link_alert_text">El perfil es compartirà amb l\'adreça.</string>
<string name="share_profile_via_link_alert_text">L\'adreça serà curta i el vostre perfil es compartirà a través d\'ella.</string>
<string name="reject_contact_request">Rebutjar la sol·licitud de contacte</string>
<string name="cant_send_message_request_is_sent">sol·licitud enviada</string>
<string name="compose_view_send_contact_request_alert_question">Enviar sol·licitud de contacte?</string>
<string name="compose_view_send_request">Enviar sol·licitud</string>
<string name="compose_view_send_request_without_message">Enviar sol·licitud sense missatge</string>
<string name="sent_to_your_contact_after_connection">Enviat al contacte després de la connexió.</string>
<string name="share_group_profile_via_link">Compartir el perfil del grup mitjançant un enllaç</string>
<string name="share_profile_via_link_alert_confirm">Compartir el perfil</string>
<string name="share_profile_via_link">Compartir el perfil amb l\'adreça</string>
<string name="share_group_profile_via_link">Actualitzar l\'enllaç del grup?</string>
<string name="share_profile_via_link_alert_confirm">Actualitzar</string>
<string name="share_profile_via_link">Actualitzar l\'adreça?</string>
<string name="the_sender_will_not_be_notified">L\'emissor(a) NO serà notificat(da).</string>
<string name="context_user_picker_cant_change_profile_alert_message">Per utilitzar un altre perfil després d\'un intent de connexió, suprimiu el xat i torneu a utilitzar l\'enllaç.</string>
<string name="address_welcome_message">Missatge de benvinguda</string>
@@ -2473,4 +2473,8 @@
<string name="v6_4_1_short_address_update">Actualitzar la vostra adreça</string>
<string name="connect_use_incognito_profile">Utilitzar el perfil d\'incògnit</string>
<string name="v6_4_1_welcome_contacts">Doneu la benvinguda als vostres contactes 👋</string>
<string name="share_old_address_alert_button">Compartir l\'adreça antiga</string>
<string name="share_old_link_alert_button">Compartir l\'enllaç antic</string>
<string name="share_group_profile_via_link_alert_text">L\'enllaç serà curt i el perfil del grup es compartirà a través d\'ell.</string>
<string name="upgrade_group_link">Actualitzar l\'enllaç del grup</string>
</resources>
@@ -1454,7 +1454,7 @@
<string name="v5_3_simpler_incognito_mode_descr">Inkognito beim Verbinden einschalten.</string>
<string name="v5_3_discover_join_groups_descr">- Verbindung mit dem Directory-Service (BETA)!\n- Empfangsbestätigungen (für bis zu 20 Mitglieder).\n- Schneller und stabiler.</string>
<string name="member_contact_send_direct_message">Zum Verbinden senden</string>
<string name="rcv_group_event_member_created_contact">Direkt miteinander verbunden</string>
<string name="rcv_group_event_member_created_contact">Angefragte Verbindung</string>
<string name="expand_verb">Erweitern</string>
<string name="connect_plan_repeat_connection_request">Verbindungsanfrage wiederholen?</string>
<string name="rcv_direct_event_contact_deleted">Gelöschter Kontakt</string>
@@ -2586,4 +2586,8 @@
<string name="share_old_link_alert_button">Alten Link teilen</string>
<string name="share_group_profile_via_link_alert_text">Der Link wird gekürzt sein, und das Gruppen-Profil wird über den Link geteilt.</string>
<string name="upgrade_group_link">Gruppen-Link aktualisieren</string>
<string name="settings_section_title_contact_requests_from_groups">KONTAKTANFRAGEN VON GRUPPEN</string>
<string name="member_is_deleted_cant_accept_request">Mitglied ist gelöscht - Anfrage kann nicht angenommen werden</string>
<string name="rcv_direct_event_group_inv_link_received">Angefragte Verbindung von Gruppe %1$s</string>
<string name="this_setting_is_for_your_current_profile">Diese Einstellung gilt für Ihr aktuelles Profil</string>
</resources>
@@ -395,4 +395,4 @@
<string name="onboarding_notifications_mode_off_desc"><![CDATA[<b> Καλύτερο για τη ζωή της μπαταρίας </b>. Θα λαμβάνετε ειδοποιήσεις μόνο όταν εκτελείται η εφαρμογή (ΧΩΡΙΣ υπηρεσία παρασκηνίου).]]></string>
<string name="app_check_for_updates_beta">Beta</string>
<string name="v6_1_better_calls">Καλύτερες κλήσεις</string>
</resources>
</resources>
@@ -44,7 +44,7 @@
<string name="accept">Aceptar</string>
<string name="audio_call_no_encryption">llamada (sin cifrar)</string>
<string name="icon_descr_audio_call">llamada</string>
<string name="settings_audio_video_calls">Llamadas y videollamadas</string>
<string name="settings_audio_video_calls">Llamadas y Videollamadas</string>
<string name="icon_descr_audio_off">Audio desactivado</string>
<string name="icon_descr_audio_on">Audio activado</string>
<string name="integrity_msg_bad_id">ID de mensaje erróneo</string>
@@ -52,7 +52,7 @@
<string name="users_delete_all_chats_deleted">Se eliminarán todos los chats y mensajes. ¡No puede deshacerse!</string>
<string name="accept_feature">Aceptar</string>
<string name="allow_to_send_disappearing">Se permiten mensajes temporales.</string>
<string name="keychain_is_storing_securely">Android Keystore se usará para almacenar la frase de contraseña de forma segura - permite que el servicio de notificación funcione.</string>
<string name="keychain_is_storing_securely">Android Keystore se usará para almacenar la frase de contraseña de forma segura - permite que el servicio de notificaciones funcione.</string>
<string name="users_add">Añadir perfil</string>
<string name="color_primary">Color</string>
<string name="allow_your_contacts_irreversibly_delete">Permites a tus contactos eliminar irreversiblemente los mensajes enviados. (24 horas)</string>
@@ -108,7 +108,7 @@
<string name="encrypted_audio_call">Llamada con cifrado de extremo a extremo</string>
<string name="status_e2e_encrypted">cifrado de extremo a extremo</string>
<string name="integrity_msg_duplicate">mensaje duplicado</string>
<string name="settings_developer_tools">Herramientas para desarrolladores</string>
<string name="settings_developer_tools">Herramientas de desarrollo</string>
<string name="delete_files_and_media_for_all_users">Eliminar los archivos de todos los perfiles</string>
<string name="delete_messages">Activar</string>
<string name="database_encrypted">¡Base de datos cifrada!</string>
@@ -996,7 +996,7 @@
<string name="file_will_be_received_when_contact_completes_uploading">El archivo se recibirá cuando el contacto termine de subirlo.</string>
<string name="image_will_be_received_when_contact_completes_uploading">La imagen se recibirá cuando el contacto termine de subirla.</string>
<string name="show_developer_options">Mostrar opciones para desarrolladores</string>
<string name="hide_dev_options">Ocultar:</string>
<string name="hide_dev_options">Oculta:</string>
<string name="show_dev_options">Muestra:</string>
<string name="delete_chat_profile">Eliminar perfil</string>
<string name="profile_password">Contraseña del perfil</string>
@@ -1380,7 +1380,7 @@
\n- confirmaciones de entrega (hasta 20 miembros).
\n- mayor rapidez y estabilidad.</string>
<string name="member_contact_send_direct_message">envia para conectar</string>
<string name="rcv_group_event_member_created_contact">conectado directamente</string>
<string name="rcv_group_event_member_created_contact">conexión solicitada</string>
<string name="expand_verb">Expandir</string>
<string name="encryption_renegotiation_error">Error de renegociación de cifrado</string>
<string name="rcv_direct_event_contact_deleted">contacto eliminado</string>
@@ -2459,7 +2459,7 @@
<string name="open_to_connect">Abrir para conectar</string>
<string name="group_preview_open_to_join">Abrir para unirte</string>
<string name="private_routing_timeout">Timeout enrutamiento privado</string>
<string name="share_profile_via_link_alert_text">La dirección será corta y tu perfil se comparti mediante la dirección.</string>
<string name="share_profile_via_link_alert_text">La dirección pasará a ser corta y tu perfil se compartido mediante la dirección.</string>
<string name="network_option_protocol_timeout_background">Timeout protocolo en segundo plano</string>
<string name="reject_contact_request">Rechazar solicitud del contacto</string>
<string name="v6_4_role_moderator_descr">Elimina mensajes y bloquea miembros.</string>
@@ -2500,7 +2500,7 @@
<string name="v6_4_1_new_interface_languages">4 idiomas nuevos</string>
<string name="v6_4_1_new_interface_languages_descr">Catalán, Indonesio, Rumano y Vietnamita - gracias a los colaboradores!</string>
<string name="v6_4_1_short_address_create">Crea tu dirección</string>
<string name="v6_4_1_keep_chats_clean_descr">Activa por defecto los mensajes temporaes</string>
<string name="v6_4_1_keep_chats_clean_descr">Activa por defecto los mensajes temporales</string>
<string name="v6_4_1_keep_chats_clean">Mantén los chats limpios</string>
<string name="v6_4_1_welcome_contacts_descr">Añade mensaje de bienvenida y biografía del perfil</string>
<string name="v6_4_1_short_address_share">Comparte tu dirección</string>
@@ -2511,4 +2511,8 @@
<string name="share_old_link_alert_button">Compartir enlace antiguo</string>
<string name="share_group_profile_via_link_alert_text">El enlace será corto y el perfil del grupo se compartirá mediante el enlace.</string>
<string name="upgrade_group_link">Actualizar enlace de grupo</string>
<string name="settings_section_title_contact_requests_from_groups">SOLICITUDES DE CONTACTO EN GRUPOS</string>
<string name="rcv_direct_event_group_inv_link_received">conexión solicitada desde el grupo %1$s</string>
<string name="this_setting_is_for_your_current_profile">Esta configuración se aplica al perfil actual</string>
<string name="member_is_deleted_cant_accept_request">Miembro eliminado, no puede aceptar solicitudes</string>
</resources>
@@ -90,7 +90,7 @@
<string name="conn_event_ratchet_sync_started">titkosítás elfogadása…</string>
<string name="invite_prohibited">Nem lehet meghívni a partnert!</string>
<string name="integrity_msg_bad_id">hibás az üzenet azonosítója</string>
<string name="v4_2_auto_accept_contact_requests">Partnerkérések automatikus elfogadása</string>
<string name="v4_2_auto_accept_contact_requests">Partneri kapcsolatkérések automatikus elfogadása</string>
<string name="impossible_to_recover_passphrase"><![CDATA[<b>Megjegyzés:</b> NEM fogja tudni helyreállítani, vagy módosítani a jelmondatot abban az esetben, ha elveszíti.]]></string>
<string name="callstatus_calling">hívás…</string>
<string name="color_secondary_variant">További másodlagos szín</string>
@@ -142,7 +142,7 @@
<string name="bad_desktop_address">Hibás a számítógép címe</string>
<string name="users_add">Profil hozzáadása</string>
<string name="attach">Mellékelés</string>
<string name="v5_0_app_passcode">Alkalmazás jelkód</string>
<string name="v5_0_app_passcode">Alkalmazásjelkód</string>
<string name="icon_descr_asked_to_receive">Felkérték a kép fogadására</string>
<string name="use_camera_button">Kamera</string>
<string name="cannot_access_keychain">Nem érhető el a Keystore az adatbázis jelszavának mentéséhez</string>
@@ -193,7 +193,7 @@
<string name="connect_button">Kapcsolódás</string>
<string name="connect_via_member_address_alert_title">Közvetlenül kapcsolódik?</string>
<string name="smp_server_test_connect">Kapcsolódás</string>
<string name="rcv_group_event_member_created_contact">közvetlenül kapcsolódott</string>
<string name="rcv_group_event_member_created_contact">partnerkapcsolatot kért</string>
<string name="connection_local_display_name">kapcsolat %1$d</string>
<string name="status_contact_has_e2e_encryption">a partner e2e titkosítással rendelkezik</string>
<string name="v5_4_incognito_groups_descr">Csoport létrehozása véletlenszerű profillal.</string>
@@ -583,7 +583,7 @@
<string name="error_aborting_address_change">Hiba történt a cím módosításának megszakításakor</string>
<string name="error_receiving_file">Hiba történt a fájl fogadásakor</string>
<string name="conn_event_ratchet_sync_ok">titkosítása rendben van</string>
<string name="error_deleting_contact_request">Hiba történt a partnerkérés törlésekor</string>
<string name="error_deleting_contact_request">Hiba történt a partneri kapcsolatkérés törlésekor</string>
<string name="receipts_groups_title_enable">Engedélyezi a kézbesítési jelentéseket a csoportok számára?</string>
<string name="fix_connection_not_supported_by_contact">Partner általi javítás nem támogatott</string>
<string name="file_not_found">Fájl nem található</string>
@@ -608,7 +608,7 @@
<string name="error_creating_address">Hiba történt a cím létrehozásakor</string>
<string name="feature_enabled">engedélyezve</string>
<string name="error_loading_details">Hiba történt a részletek betöltésekor</string>
<string name="error_accepting_contact_request">Hiba történt a partnerkérés elfogadásakor</string>
<string name="error_accepting_contact_request">Hiba történt a partneri kapcsolatkérés elfogadásakor</string>
<string name="snd_conn_event_ratchet_sync_allowed">a titkosítás újraegyeztetése engedélyezve van %s számára</string>
<string name="conn_event_ratchet_sync_required">a titkosítás újraegyeztetése szükséges</string>
<string name="v4_6_hidden_chat_profiles">Rejtett csevegési profilok</string>
@@ -737,13 +737,13 @@
<string name="network_use_onion_hosts_no_desc">Az onion kiszolgálók nem lesznek használva.</string>
<string name="custom_time_unit_minutes">perc</string>
<string name="learn_more">Tudjon meg többet</string>
<string name="notification_new_contact_request">Új partnerkérés</string>
<string name="notification_new_contact_request">Új partneri kapcsolatkérés</string>
<string name="joining_group">Csatlakozás a csoporthoz</string>
<string name="linked_desktop_options">Társított számítógép beállítások</string>
<string name="rcv_group_event_invited_via_your_group_link">meghíva a saját csoporthivatkozásán keresztül</string>
<string name="rcv_group_event_member_left">elhagyta a csoportot</string>
<string name="linked_desktops">Társított számítógépek</string>
<string name="la_no_app_password">Nincs alkalmazás jelkód</string>
<string name="la_no_app_password">Nincs alkalmazásjelkód</string>
<string name="muted_when_inactive">Némítás, ha inaktív!</string>
<string name="alert_title_group_invitation_expired">A meghívó lejárt!</string>
<string name="only_stored_on_members_devices">(csak a csoporttagok tárolják)</string>
@@ -1488,7 +1488,7 @@
<string name="you_can_view_invitation_link_again">A meghívási hivatkozást újra megtekintheti a kapcsolat részleteinél.</string>
<string name="start_chat_question">Elindítja a csevegést?</string>
<string name="recent_history">Látható előzmények</string>
<string name="la_app_passcode">Alkalmazás jelkód</string>
<string name="la_app_passcode">Alkalmazásjelkód</string>
<string name="add_contact_tab">Partner hozzáadása</string>
<string name="tap_to_scan">Koppintson ide a QR-kód beolvasásához</string>
<string name="tap_to_paste_link">Koppintson ide a hivatkozás beillesztéséhez</string>
@@ -2406,8 +2406,8 @@
<string name="connect_plan_open_chat">Csevegés megnyitása</string>
<string name="connect_plan_open_new_chat">Új csevegés megnyitása</string>
<string name="connect_plan_open_new_group">Új csoport megnyitása</string>
<string name="e2ee_info_e2ee"><![CDATA[Az üzenetek<b>végpontok közötti titkosítással</b> vannak védve.]]></string>
<string name="error_rejecting_contact_request">Hiba történt a partnerkérés elutasításakor</string>
<string name="e2ee_info_e2ee"><![CDATA[Az üzenetek <b>végpontok közötti titkosítással</b> vannak védve.]]></string>
<string name="error_rejecting_contact_request">Hiba történt a partneri kapcsolatkérés elutasításakor</string>
<string name="error_preparing_contact">Hiba a csevegés megnyitásakor</string>
<string name="error_preparing_group">Hiba a csoport megnyitásakor</string>
<string name="error_changing_user">Hiba a profil módosításakor</string>
@@ -2418,13 +2418,13 @@
<string name="compose_view_join_group">Csatlakozás a csoporthoz</string>
<string name="compose_view_add_message">Üzenet hozzáadása</string>
<string name="compose_view_connect">Kapcsolódás</string>
<string name="compose_view_send_contact_request_alert_question">Elküldi a partnerkérést?</string>
<string name="compose_view_send_contact_request_alert_question">Elküldi a partneri kapcsolatkérést?</string>
<string name="compose_view_send_contact_request_alert_text"><![CDATA[Csak azután tud üzeneteket küldeni, <b>miután a kérését elfogadták</b>.]]></string>
<string name="compose_view_send_request_without_message">Kérés küldése üzenet nélkül</string>
<string name="compose_view_send_request">Kérés küldése</string>
<string name="cant_send_message_request_is_sent">kérés elküldve</string>
<string name="accept_contact_request">Partnerkérés elfogadása</string>
<string name="reject_contact_request">Elutasítás</string>
<string name="accept_contact_request">Partneri kapcsolatkérés elfogadása</string>
<string name="reject_contact_request">Partneri kapcsolatkérés elutasítása</string>
<string name="the_sender_will_not_be_notified">A feladó NEM lesz értesítve.</string>
<string name="context_user_picker_your_profile">Saját profil</string>
<string name="sent_to_your_contact_after_connection">Elküldés a partnernek a kapcsolódást követően.</string>
@@ -2454,7 +2454,7 @@
<string name="short_descr__field">Bemutatkozás:</string>
<string name="bio_too_large">A bemutatkozás túl hosszú</string>
<string name="group_descr_too_large">A leírás túl hosszú</string>
<string name="chat_banner_accept_contact_request">Partnerkérés elfogadása</string>
<string name="chat_banner_accept_contact_request">Partneri kapcsolatkérés elfogadása</string>
<string name="chat_banner_business_connection">Üzleti kapcsolat</string>
<string name="chat_banner_group">Csoport</string>
<string name="chat_banner_join_group">Koppintson a „Csatlakozás a csoporthoz” gombra</string>
@@ -2474,9 +2474,13 @@
<string name="v6_4_1_short_address_update">Cím frissítése</string>
<string name="v6_4_1_welcome_contacts">Üdvözölje a partnereit 👋</string>
<string name="v6_4_1_new_interface_languages">4 új kezelőfelületi nyelv</string>
<string name="v6_4_1_new_interface_languages_descr">Katalán, indonéz, román és vietnami - köszönjük felhasználóinknak!</string>
<string name="v6_4_1_new_interface_languages_descr">Katalán, indonéz, román és vietnami köszönjük felhasználóinknak!</string>
<string name="upgrade_group_link">Csoporthivatkozás frissítése</string>
<string name="share_group_profile_via_link_alert_text">A hivatkozás rövid lesz és a csoportprofil meg lesz osztva a hivatkozáson keresztül.</string>
<string name="share_old_address_alert_button">Régi cím megosztása</string>
<string name="share_old_link_alert_button">Régi hivatkozás megosztása</string>
<string name="settings_section_title_contact_requests_from_groups">PARTNERI KAPCSOLATKÉRÉSEK A CSOPORTOKBÓL</string>
<string name="member_is_deleted_cant_accept_request">A tag törölve lett nem lehet elfogadni a kérést</string>
<string name="rcv_direct_event_group_inv_link_received">a(z) %1$s nevű csoportból partnerkapcsolatot kért</string>
<string name="this_setting_is_for_your_current_profile">Ez a beállítás a jelenlegi profiljára vonatkozik</string>
</resources>
@@ -16,13 +16,13 @@
<string name="color_primary_variant">Accent suplimentar</string>
<string name="color_secondary_variant">Suplimentar secundar</string>
<string name="accept_feature">Acceptă</string>
<string name="v5_3_new_interface_languages">6 limbi noi pentru interfață</string>
<string name="v5_3_new_interface_languages">6 noi limbi de interfață</string>
<string name="alert_text_decryption_error_n_messages_failed_to_decrypt">%1$d mesaje nu au putut fi decriptate.</string>
<string name="integrity_msg_skipped">%1$d mesaj(e) omis(e)</string>
<string name="group_info_section_title_num_members">%1$s MEMBRI</string>
<string name="chat_item_ttl_day">1 zi</string>
<string name="send_disappearing_message_1_minute">1 minut</string>
<string name="one_time_link_short">Link unic</string>
<string name="one_time_link_short">Link de unică folosință</string>
<string name="send_disappearing_message_5_minutes">5 minute</string>
<string name="about_simplex">Despre SimpleX</string>
<string name="learn_more_about_address">Despre adresa SimpleX</string>
@@ -234,7 +234,7 @@
<string name="wallpaper_scale_repeat">Repetă</string>
<string name="send_link_previews">Trimiteți previzualizări de linkuri</string>
<string name="set_passphrase">Setați frază de acces</string>
<string name="share_address">Partajează adresă</string>
<string name="share_address">Partajează adresa</string>
<string name="info_row_sent_at">Trimis la</string>
<string name="color_secondary">Secundar</string>
<string name="color_sent_message">Mesaj trimis</string>
@@ -286,7 +286,7 @@
<string name="text_field_set_contact_placeholder">Nume contact…</string>
<string name="icon_descr_send_message">Trimite mesaj</string>
<string name="send_disappearing_message">Trimiteți un mesaj care dispare</string>
<string name="connect_via_link_or_qr_from_clipboard_or_in_person">(scanează sau lipește din Copiate)</string>
<string name="connect_via_link_or_qr_from_clipboard_or_in_person">(scanează sau lipește din clipboard)</string>
<string name="show_QR_code">Afișează codul QR</string>
<string name="smp_servers_test_failed">Testul serverului a eșuat!</string>
<string name="show_dev_options">Afișează:</string>
@@ -322,19 +322,19 @@
<string name="simplex_service_notification_title">Serviciul SimpleX Chat</string>
<string name="icon_descr_address">Adresă SimpleX</string>
<string name="settings_shutdown">Oprește</string>
<string name="simplex_links">Link-uri SimpleX</string>
<string name="simplex_links_are_prohibited_in_group">Link-urile SimpleX sunt interzise.</string>
<string name="simplex_links">Linkuri SimpleX</string>
<string name="simplex_links_are_prohibited_in_group">Linkurile SimpleX sunt interzise.</string>
<string name="v4_2_security_assessment_desc">Securitatea chatului SimpleX a fost auditată de Trail of Bits.</string>
<string name="ntf_channel_messages">Mesaje SimpleX Chat</string>
<string name="ntf_channel_calls">Apeluri SimpleX Chat</string>
<string name="simplex_address">Adresă SimpleX</string>
<string name="core_simplexmq_version">simplexmq: v%s (%2s)</string>
<string name="simplex_links_not_allowed">Link-uri SimpleX nepermise</string>
<string name="simplex_links_not_allowed">Linkurile SimpleX nu sunt permise</string>
<string name="icon_descr_simplex_team">Echipa SimpleX</string>
<string name="shutdown_alert_question">Opriți?</string>
<string name="simplex_link_contact">Adresă de contact SimpleX</string>
<string name="simplex_link_group">Link pentru grup SimpleX</string>
<string name="simplex_link_mode">Link-uri SimpleX</string>
<string name="simplex_link_mode">Linkuri SimpleX</string>
<string name="simplex_link_invitation">Invitație de unică folosință SimpleX</string>
<string name="image_descr_simplex_logo">Logo SimpleX</string>
<string name="receipts_section_groups">Grupuri mici (max 20)</string>
@@ -520,7 +520,7 @@
<string name="connect_plan_connect_to_yourself">Te conectezi la tine?</string>
<string name="migrate_from_device_check_connection_and_try_again">Verifică conexiunea la internet și încearcă din nou</string>
<string name="settings_section_title_chat_colors">Culori conversație</string>
<string name="settings_section_title_chat_theme">Aspectul discuției</string>
<string name="settings_section_title_chat_theme">Temă pentru chat</string>
<string name="onboarding_notifications_mode_periodic_desc"><![CDATA[<b>Bun pentru baterie</b>. Aplicația verifică mesajele la fiecare 10 minute. Pot fi pierdute apeluri sau mesaje urgente.]]></string>
<string name="theme_black">Negru</string>
<string name="block_for_all_question">Blocați membrul pentru toți?</string>
@@ -530,7 +530,7 @@
<string name="cannot_share_message_alert_title">Nu se poate trimite mesajul</string>
<string name="clear_contacts_selection_button">Șterge</string>
<string name="v5_8_safe_files_descr">Confirmați fișiere de la servere necunoscute.</string>
<string name="rcv_conn_event_switch_queue_phase_completed">schimbat adresa pentru dumneavoastră</string>
<string name="rcv_conn_event_switch_queue_phase_completed">am schimbat adresa pentru tine</string>
<string name="confirm_new_passphrase">Confirmați parola nouă…</string>
<string name="connect_via_link_verb">Conectare</string>
<string name="connection_local_display_name">conexiune %1$d</string>
@@ -613,7 +613,7 @@
<string name="for_me_only">Șterge pentru mine</string>
<string name="ttl_d">%dd</string>
<string name="deleted_description">șters</string>
<string name="button_delete_contact">Șterge contact</string>
<string name="button_delete_contact">Șterge contactul</string>
<string name="info_row_deleted_at">Șters la</string>
<string name="desktop_app_version_is_incompatible">Versiunea aplicației desktop %s nu este compatibilă cu această aplicație.</string>
<string name="delete_member_message__question">Ștergeți mesajul membrului?</string>
@@ -624,7 +624,7 @@
<string name="num_contacts_selected">%d contact(e) selectat(e)</string>
<string name="share_text_deleted_at">Șters la: %s</string>
<string name="users_delete_question">Ștergi profilul de conversație?</string>
<string name="delete_profile">Ștergeți profilul</string>
<string name="delete_profile">Șterge profilul</string>
<string name="chat_preferences_default">implicit (%s)</string>
<string name="delivery_receipts_title">Confirmări de livrare!</string>
<string name="delivery_receipts_are_disabled">Confirmările de livrare sunt dezactivate!</string>
@@ -636,12 +636,12 @@
<string name="delete_after">Șterge după</string>
<string name="full_deletion">Ștergeți pentru toată lumea</string>
<string name="simplex_link_mode_description">Descriere</string>
<string name="smp_server_test_delete_file">Șterge fișier</string>
<string name="smp_server_test_delete_queue">Ștergeți coada</string>
<string name="smp_server_test_delete_file">Șterge fișierul</string>
<string name="smp_server_test_delete_queue">Șterge coada</string>
<string name="delete_contact_question">Ștergeți contactul?</string>
<string name="delete_contact_menu_action">Șterge</string>
<string name="delete_group_menu_action">Șterge</string>
<string name="delete_files_and_media_question">Ștergi fișiere și media?</string>
<string name="delete_files_and_media_question">Ștergi fișierele și conținutul media?</string>
<string name="ttl_days">%d zile</string>
<string name="ttl_day">%d zi</string>
<string name="delete_address">Șterge adresa</string>
@@ -767,8 +767,8 @@
<string name="forwarded_description">redirecționat</string>
<string name="error_showing_message">eroare la afișarea mesajului</string>
<string name="error_showing_content">eroare la afișarea conținutului</string>
<string name="e2ee_info_no_pq"><![CDATA[Mesajele, fisierele si apelurile sunt protejate prin <b>criptare cap-coadă</b> cu secretizare înaintată perfecta, repudiere si recuperare în caz de spargere.]]></string>
<string name="e2ee_info_pq"><![CDATA[Mesajele, fisierele si apelurile sunt protejate prin <b>criptare cap-coadă rezistentă la algoritmi cuantici</b> cu secretizare înaintată perfecta, repudiere si recuperare în caz de spargere.]]></string>
<string name="e2ee_info_no_pq"><![CDATA[Mesajele, fișierele și apelurile sunt protejate prin <b>criptare end-to-end</b>, cu confidențialitate perfectă în avans, nerepudiere și recuperare în caz de compromitere.]]></string>
<string name="e2ee_info_pq"><![CDATA[Mesajele, fișierele și apelurile sunt protejate prin <b>criptare end-to-end</b> rezistentă la computere cuantice, cu confidențialitate perfectă în avans, nerepudiere și recuperare în caz de compromitere.]]></string>
<string name="e2ee_info_no_pq_short">Acest chat este protejat prin criptare end-to-end.</string>
<string name="simplex_link_mode_full">Link complet</string>
<string name="description_via_one_time_link_incognito">incognito printr-un link de unică folosință</string>
@@ -883,7 +883,7 @@
<string name="alert_title_group_invitation_expired">Invitația a expirat!</string>
<string name="info_row_group">Grup</string>
<string name="invite_to_group_button">Invitați în grup</string>
<string name="disconnect_remote_hosts">Deconectați telefoanele mobile</string>
<string name="disconnect_remote_hosts">Deconectează dispozitivele mobile</string>
<string name="failed_to_create_user_invalid_title">Nume afișat nevalid!</string>
<string name="failed_to_active_user_title">Eroare la schimbarea profilului!</string>
<string name="no_media_servers_configured">Fără servere media și de fișiere.</string>
@@ -938,7 +938,7 @@
<string name="error_changing_address">Eroare la schimbarea adresei</string>
<string name="error_synchronizing_connection">Eroare la sincronizarea conexiunii</string>
<string name="error_alert_title">Eroare</string>
<string name="smp_server_test_disconnect">Deconectați-vă</string>
<string name="smp_server_test_disconnect">Deconectează</string>
<string name="possible_slow_function_desc">Execuția funcției durează prea mult: %1$d secunde: %2$s</string>
<string name="hide_notification">Ascunde</string>
<string name="la_enter_app_passcode">Introduceți parola</string>
@@ -973,7 +973,7 @@
<string name="image_will_be_received_when_contact_is_online">Imaginea va fi primită când contactul dvs. va fi online, vă rugăm să așteptați sau să verificați mai târziu!</string>
<string name="chat_ttl_options_footer">Șterge mesajele din conversație de pe dispozitiv.</string>
<string name="if_you_choose_to_reject_the_sender_will_not_be_notified">Dacă alegeți să respingeți, expeditorul NU va fi notificat.</string>
<string name="how_to_use_simplex_chat">Cum să o utilizezi</string>
<string name="how_to_use_simplex_chat">Cum se utilizează</string>
<string name="markdown_in_messages">Marcare în mesaje</string>
<string name="network_proxy_incorrect_config_title">Eroare la salvarea proxy-ului</string>
<string name="network_disable_socks_info">Dacă confirmi, serverele de mesagerie vor putea vedea adresa ta IP, iar furnizorul tău - la ce servere te conectezi.</string>
@@ -992,9 +992,9 @@
<string name="app_check_for_updates_installed_successfully_title">Instalat cu succes</string>
<string name="app_check_for_updates_notice_disable">Dezactivează</string>
<string name="developer_options_section">Opțiuni dezvoltator</string>
<string name="shutdown_alert_desc">Notificările vor înceta să funcționeze până când nu redeschideți aplicația.</string>
<string name="shutdown_alert_desc">Notificările vor înceta să funcționeze până când nu redeschideți aplicația</string>
<string name="prefs_error_saving_settings">Eroare la salvarea setărilor</string>
<string name="delete_messages_after">Ștergeți mesajele după</string>
<string name="delete_messages_after">Șterge mesajele după</string>
<string name="ttl_sec">%d sec</string>
<string name="icon_descr_email">Email</string>
<string name="error_saving_user_password">Eroare la salvarea parolei utilizatorului</string>
@@ -1010,7 +1010,7 @@
<string name="v5_2_favourites_filter">Găsește conversații mai rapid</string>
<string name="theme_light">Luminos</string>
<string name="privacy_chat_list_open_links_no">Nu</string>
<string name="privacy_chat_list_open_web_link_question">Deschide linkul web?</string>
<string name="privacy_chat_list_open_web_link_question">Deschizi link-ul web?</string>
<string name="settings_section_title_messages">MESAJE ȘI FIȘIERE</string>
<string name="group_member_role_moderator">moderator</string>
<string name="initial_member_role">Rol inițial</string>
@@ -1038,7 +1038,7 @@
<string name="ensure_ICE_server_address_are_correct_format_and_unique">Asigurați -vă că adresele Serverului WebRTC ICE sunt în format corect, separate pe linii și nu sunt duplicate.</string>
<string name="update_network_smp_proxy_fallback_question">Rutarea mesajelor</string>
<string name="edit_image">Editați imaginea</string>
<string name="permissions_open_settings">Deschideți setările</string>
<string name="permissions_open_settings">Deschide setările</string>
<string name="permissions_grant_in_settings">Acordare în setări</string>
<string name="onboarding_notifications_mode_service">Instant</string>
<string name="onboarding_notifications_mode_subtitle">Cum afectează bateria</string>
@@ -1116,7 +1116,7 @@
<string name="connection_error_quota_desc">Conexiunea a atins limita de mesaje nelivrate, este posibil ca persoana de contact să fie offline.</string>
<string name="auth_disable_simplex_lock">Dezactivați SimpleX Lock</string>
<string name="migrate_from_device_error_saving_settings">Eroare la salvarea setărilor</string>
<string name="disconnect_desktop_question">Deconecti desktopul?</string>
<string name="disconnect_desktop_question">Deconectezi desktopul?</string>
<string name="dont_enable_receipts">Nu activați</string>
<string name="error_receiving_file">Eroare la primirea fișierului</string>
<string name="error_deleting_contact_request">Eroare la ștergerea solicitării de contact</string>
@@ -1157,7 +1157,7 @@
<string name="old_database_archive">Arhivă veche a bazei de date</string>
<string name="open_database_folder">Deschideți folderul bazei de date</string>
<string name="chat_item_ttl_default">implicit (%s)</string>
<string name="enable_automatic_deletion_question">Activi ștergerea automată a mesajelor?</string>
<string name="enable_automatic_deletion_question">Activezi ștergerea automată a mesajelor?</string>
<string name="notifications_will_be_hidden">Notificările vor fi livrate doar până când aplicația se oprește!</string>
<string name="database_will_be_encrypted_and_passphrase_stored">Baza de date va fi criptată, iar parola va fi stocată în Keystore.</string>
<string name="encrypted_database">Bază de date criptată</string>
@@ -1231,9 +1231,9 @@
<string name="error">Eroare</string>
<string name="desktop_incompatible_version">Versiune incompatibilă</string>
<string name="new_mobile_device">Dispozitiv mobil nou</string>
<string name="multicast_discoverable_via_local_network">Descoperibil prin rețeaua locală</string>
<string name="discover_on_network">Descoperiți prin intermediul rețelei locale</string>
<string name="open_port_in_firewall_title">Deschideți portul în firewall</string>
<string name="multicast_discoverable_via_local_network">Detectabil prin rețeaua locală</string>
<string name="discover_on_network">Detectează prin rețeaua locală</string>
<string name="open_port_in_firewall_title">Deschide portul în firewall</string>
<string name="remote_ctrl_error_inactive">Desktopul este inactiv</string>
<string name="remote_ctrl_error_disconnected">Desktopul a fost deconectat</string>
<string name="remote_ctrl_error_bad_invitation">Desktopul are codul de invitație greșit</string>
@@ -1308,7 +1308,7 @@
<string name="message_forwarded_desc">Încă nu există conexiune directă, mesajul a fost redirecționat de administrator.</string>
<string name="v6_2_improved_chat_navigation_descr">- Deschide chatul la primul mesaj necitit.\n- Sări la mesajele citate.</string>
<string name="privacy_media_blur_radius_off">Oprit</string>
<string name="open_server_settings_button">Deschideți setările serverului</string>
<string name="open_server_settings_button">Deschide setările serverului</string>
<string name="snd_conn_event_ratchet_sync_ok">criptare ok pentru %s</string>
<string name="snd_group_event_group_profile_updated">profilul grupului a fost actualizat</string>
<string name="group_member_role_owner">proprietar</string>
@@ -1316,7 +1316,7 @@
<string name="group_member_status_left">ieșit</string>
<string name="fix_connection_not_supported_by_contact">Remedierea nu este suportată de contact</string>
<string name="servers_info_sessions_errors">Erori</string>
<string name="connect_plan_open_group">Deschideți grupul</string>
<string name="connect_plan_open_group">Deschide grupul</string>
<string name="delete_messages_cannot_be_undone_warning">Mesajele vor fi șterse - acest lucru nu poate fi anulat!</string>
<string name="error_encrypting_database">Eroare la criptarea bazei de date</string>
<string name="servers_info_files_tab">Fișiere</string>
@@ -1334,7 +1334,7 @@
<string name="invite_friends_short">Invită</string>
<string name="error_initializing_web_view_wrong_arch">Eroare la inițializarea WebView. Asigurați-vă că aveți WebView instalat și că arhitectura sa suportată este arm64.\nEroare: %s</string>
<string name="make_private_connection">Faceți o conexiune privată</string>
<string name="open_simplex_chat_to_accept_call">Deschideți SimpleX Chat pentru a accepta apelul</string>
<string name="open_simplex_chat_to_accept_call">Deschide SimpleX Chat pentru a accepta apelul</string>
<string name="enable_lock">Activați blocarea</string>
<string name="alert_text_fragment_encryption_out_of_sync_old_database">Se poate întâmpla atunci când tu sau conexiunea ta ați folosit backupul vechi al bazei de date.</string>
<string name="la_mode_passcode">Cod de acces</string>
@@ -1381,7 +1381,7 @@
<string name="media_and_file_servers">Servere media și fișiere</string>
<string name="xftp_servers_other">Alte servere XFTP</string>
<string name="network_smp_proxy_mode_never_description">NU utilizați rutare privată.</string>
<string name="allow_accepting_calls_from_lock_screen">Activați apelurile de pe ecranul de blocare prin Setări.</string>
<string name="allow_accepting_calls_from_lock_screen">Activează apelurile de pe ecranul de blocare prin Setări.</string>
<string name="receipts_contacts_disable_keep_overrides">Dezactivează (păstrează suprascrierile)</string>
<string name="if_you_enter_self_destruct_code">Dacă introduceți parola de autodistrugere în timp ce deschideți aplicația:</string>
<string name="privacy_media_blur_radius_medium">Mediu</string>
@@ -1419,7 +1419,7 @@
<string name="app_check_for_updates_button_install">Instalați update</string>
<string name="dont_create_address">Nu crea adresă</string>
<string name="onboarding_network_operators_app_will_use_for_routing">De exemplu, dacă persoana de contact primește mesaje prin intermediul unui server SimpleX Chat, aplicația le va livra prin intermediul unui server Flux.</string>
<string name="call_desktop_permission_denied_safari">Deschideți Setări Safari / Site-uri web / Microfon, apoi alegeți Permiteți pentru localhost.</string>
<string name="call_desktop_permission_denied_safari">Deschide Setările Safari / Site-uri web / Microfon, apoi selectează Permite pentru localhost.</string>
<string name="icon_descr_call_missed">Apel ratat</string>
<string name="alert_text_encryption_renegotiation_failed">Renegocierea criptării a eșuat.</string>
<string name="la_mode_off">Oprit</string>
@@ -1449,7 +1449,7 @@
<string name="v4_6_group_moderation_descr">Acum administratorii pot:\n- șterge mesajele membrilor.\n- dezactiva membrii (rol de observator)</string>
<string name="v5_1_message_reactions">Reacții la mesaje</string>
<string name="v5_0_large_files_support_descr">Rapid și fără așteptare până când expeditorul este online!</string>
<string name="v5_3_discover_join_groups">Descoperiți și alăturați-vă grupurilor</string>
<string name="v5_3_discover_join_groups">Descoperă și alătură-te grupurilor</string>
<string name="v5_2_disappear_one_message_descr">Chiar și atunci când este dezactivat în conversație.</string>
<string name="v5_2_more_things_descr">- livrare mai stabilă a mesajelor.\n- grupuri mai bune.\n- și multe altele!</string>
<string name="v5_2_disappear_one_message">Face ca un mesaj să dispară</string>
@@ -1547,7 +1547,7 @@
<string name="v4_2_group_links">Linkuri de grup</string>
<string name="v4_3_irreversible_message_deletion">Ștergere ireversibilă a mesajului</string>
<string name="v6_0_increase_font_size">Măriți dimensiunea fontului.</string>
<string name="disconnect_remote_host">Deconectați-vă</string>
<string name="disconnect_remote_host">Deconectează</string>
<string name="remote_ctrl_disconnected_with_reason">Deconectat din motivul: %s</string>
<string name="migrate_from_device_error_deleting_database">Eroare la ștergerea bazei de date</string>
<string name="migrate_from_device_error_uploading_archive">Eroare la încărcarea arhivei</string>
@@ -1608,7 +1608,7 @@
<string name="v6_0_chat_list_media">Redă din lista de conversații.</string>
<string name="please_try_later">Vă rugăm să încercați mai târziu.</string>
<string name="whats_new_read_more">Citeşte mai mult</string>
<string name="error_parsing_uri_desc">Vă rugăm să verifici dacă linkul SimpleX este corect.</string>
<string name="error_parsing_uri_desc">Te rog să verifici dacă linkul SimpleX este corect.</string>
<string name="observer_cant_send_message_desc">Vă rugăm să contactați administratorul grupului.</string>
<string name="migrate_from_device_database_init">Se pregătește încărcarea</string>
<string name="toast_permission_denied">Acces refuzat!</string>
@@ -1667,7 +1667,7 @@
<string name="network_proxy_password">Parolă</string>
<string name="network_smp_web_port_preset">Servere presetate</string>
<string name="paste_desktop_address">Lipiți adresa desktopului</string>
<string name="error_smp_test_certificate">Este posibil ca amprenta certificatului din adresa serverului să fie incorectă.</string>
<string name="error_smp_test_certificate">Este posibil ca amprenta certificatului din adresa serverului să fie incorectă</string>
<string name="network_option_ping_interval">Interval PING-uri</string>
<string name="network_option_protocol_timeout_per_kb">Expirare protocol per KB</string>
<string name="onboarding_notifications_mode_title">Notificări private</string>
@@ -1678,7 +1678,7 @@
<string name="password_to_show">Parolă de afișat</string>
<string name="maximum_message_size_reached_non_text">Vă rugăm să reduceți dimensiunea mesajului sau să eliminați fișierul media și să îl trimiteți din nou.</string>
<string name="protect_ip_address">Protejați adresa IP</string>
<string name="color_received_message">mesaj primit</string>
<string name="color_received_message">Mesaj primit</string>
<string name="v5_5_private_notes">Note private</string>
<string name="chat_bottom_bar">Bara de instrumente de chat accesibilă</string>
<string name="settings_section_title_user_theme">Temă de profil</string>
@@ -1718,7 +1718,7 @@
<string name="servers_info_subscriptions_connections_pending">În așteptare</string>
<string name="callstate_received_confirmation">confirmare primită…</string>
<string name="v4_6_hidden_chat_profiles_descr">Protejează-ți profilurile de chat cu o parolă!</string>
<string name="please_check_correct_link_and_maybe_ask_for_a_new_one">Vă rugăm să verifici dacă ați folosit linkul corect sau cereți contactului dumneavoastră trimită altul.</string>
<string name="please_check_correct_link_and_maybe_ask_for_a_new_one">Te rog să verifici dacă ai folosit linkul corect sau cere contactului tăuîți trimită unul nou.</string>
<string name="private_routing_error">Eroare de rutare privată</string>
<string name="group_member_status_rejected">respins</string>
<string name="color_received_quote">Răspuns primit</string>
@@ -1763,7 +1763,7 @@
<string name="servers_info_detailed_statistics_received_total">Primit total</string>
<string name="servers_info_detailed_statistics_receive_errors">Primiți erori</string>
<string name="servers_info_reconnect_server_message">Reconectați serverul pentru a forța livrarea mesajului. Consumă trafic suplimentar.</string>
<string name="servers_info_reset_stats">Resetați toate statisticile</string>
<string name="servers_info_reset_stats">Resetează toate statisticile</string>
<string name="sent_via_proxy">Trimis prin proxy</string>
<string name="sent_directly">Trimis direct</string>
<string name="reviewed_by_admins">revizuit de administratori</string>
@@ -1789,7 +1789,7 @@
<string name="servers_info">Informații despre servere</string>
<string name="servers_info_reconnect_servers_title">Reconectați serverele?</string>
<string name="servers_info_reset_stats_alert_message">Statisticile serverelor vor fi resetate - această acțiune nu poate fi anulată!</string>
<string name="servers_info_reconnect_all_servers_button">Reconectați toate serverele</string>
<string name="servers_info_reconnect_all_servers_button">Reconectează toate serverele</string>
<string name="servers_info_reconnect_server_title">Reconectați serverul?</string>
<string name="servers_info_detailed_statistics_sent_messages_total">Trimis total</string>
<string name="cannot_share_message_alert_text">Preferințele de chat selectate interzic acest mesaj.</string>
@@ -1810,7 +1810,7 @@
<string name="send_receipts">Trimite confirmări de citire</string>
<string name="accept_feature_set_1_day">Setați 1 zi</string>
<string name="v5_1_self_destruct_passcode">Parolă de autodistrugere</string>
<string name="servers_info_reconnect_servers_message">Reconectați toate serverele conectate pentru a forța livrarea mesajelor. Aceasta utilizează trafic suplimentar.</string>
<string name="servers_info_reconnect_servers_message">Reconectează toate serverele conectate pentru a forța livrarea mesajelor. Aceasta folosește trafic suplimentar.</string>
<string name="simplex_service_notification_text">Se primesc mesaje…</string>
<string name="report_reason_alert_title">Motivul raportării?</string>
<string name="group_preview_rejected">respins</string>
@@ -2025,7 +2025,7 @@
<string name="tap_to_activate_profile">Atingeți pentru a activa profilul.</string>
<string name="language_system">Sistem</string>
<string name="v4_4_french_interface_descr">Mulțumim utilizatorilor contribuiți prin Weblate!</string>
<string name="v4_4_verify_connection_security">Verificați securitatea conexiunii</string>
<string name="v4_4_verify_connection_security">Verifică securitatea conexiunii</string>
<string name="v4_5_transport_isolation">Izolarea transportului</string>
<string name="v4_5_private_filenames_descr">Pentru a proteja fusul orar, fișierele imagine/voce utilizează UTC.</string>
<string name="v5_1_better_messages_descr">- mesaje vocale de până la 5 minute.\n- timp personalizat de dispariție.\n- istoricul modificărilor.</string>
@@ -2041,12 +2041,12 @@
<string name="this_device_name">Numele acestui dispozitiv</string>
<string name="this_device">Acest dispozitiv</string>
<string name="unlink_desktop">Deconectare</string>
<string name="open_port_in_firewall_desc">Pentru a permite unei aplicații mobile să se conecteze la desktop, deschideți acest port în firewall, dacă îl aveți activat.</string>
<string name="open_port_in_firewall_desc">Pentru a permite unei aplicații mobile să se conecteze la desktop, deschideți acest port în firewall, dacă îl aveți activat</string>
<string name="verify_code_with_desktop">Verificați codul cu desktopul</string>
<string name="in_developing_desc">Această funcție nu este încă compatibilă. Încercați următoarea versiune.</string>
<string name="connect_plan_you_are_already_connecting_via_this_one_time_link">Vă conectați deja prin intermediul acestei legături unice!</string>
<string name="migrate_from_device_starting_chat_on_multiple_devices_unsupported">Atenție: inițierea chatului pe mai multe dispozitive nu este acceptată și va cauza erori de livrare a mesajelor.</string>
<string name="migrate_from_device_verify_database_passphrase">Verificați parola bazei de date</string>
<string name="migrate_from_device_verify_database_passphrase">Verifică parola bazei de date</string>
<string name="network_type_ethernet">Ethernet prin cablu</string>
<string name="subscription_results_ignored">Abonamente ignorate</string>
<string name="size">Mărime</string>
@@ -2154,7 +2154,7 @@
<string name="connect_plan_this_is_your_own_simplex_address">Aceasta este propria ta adresă SimpleX!</string>
<string name="migrate_from_device_uploading_archive">Se încarcă arhiva</string>
<string name="migrate_from_device_bytes_uploaded">%s a fost încărcat</string>
<string name="migrate_from_device_verify_passphrase">Verificați parola</string>
<string name="migrate_from_device_verify_passphrase">Verifică parola</string>
<string name="lock_not_enabled">Blocarea SimpleX nu este activă!</string>
<string name="la_lock_mode_system">Autentificare sistem</string>
<string name="database_initialization_error_desc">Baza de date nu funcționează corect. Atingeți pentru a afla mai multe.</string>
@@ -2192,7 +2192,7 @@
<string name="voice_messages_are_prohibited">Mesajele vocale sunt interzise.</string>
<string name="v6_1_better_security_descr">Protocoalele SimpleX analizate de Trail of Bits.</string>
<string name="remote_ctrl_connection_stopped_identity_desc">Acest link a fost utilizat cu un alt dispozitiv mobil, vă rugăm să creați un link nou pe desktop.</string>
<string name="verify_connections">Verificați conexiunile</string>
<string name="verify_connections">Verifică conexiunile</string>
<string name="migrate_from_device_try_again">Poți să încerci încă o dată.</string>
<string name="servers_info_proxied_servers_section_footer">Nu ești conectat la aceste servere. Rutarea privată este utilizată pentru a livra mesaje către ele.</string>
<string name="migrate_from_device_stopping_chat">Se oprește chatul</string>
@@ -2416,4 +2416,16 @@
<string name="contact_should_accept">contactul ar trebui să accepte…</string>
<string name="group_descr_too_large">Descriere prea lungă</string>
<string name="error_changing_user">Eroare la modificarea profilului</string>
<string name="connect_use_incognito_profile">Folosește profil incognito</string>
<string name="connect_plan_open_chat">Deschide conversația</string>
<string name="error_rejecting_contact_request">Eroare la respingerea cererii de contact</string>
<string name="v6_4_1_new_interface_languages">4 noi limbi de interfață</string>
<string name="v6_4_1_new_interface_languages_descr">Catalană, Indoneziană, Română și Vietnameză - mulțumită utilizatorilor noștri!</string>
<string name="e2ee_info_e2ee"><![CDATA[Mesajele sunt protejate prin <b>criptare end-to-end</b>.]]></string>
<string name="connect_plan_open_new_chat">Deschide conversație nouă</string>
<string name="connect_plan_open_new_group">Creează un grup nou</string>
<string name="open_to_accept">Deschide pentru a accepta</string>
<string name="open_to_connect">Deschide pentru conectare</string>
<string name="group_preview_open_to_join">Deschide pentru a te alătura</string>
<string name="private_routing_timeout">Timp de așteptare depășit pentru rutarea privată</string>
</resources>
@@ -1333,6 +1333,7 @@
<string name="no_history">Нет истории</string>
<string name="receipts_contacts_override_enabled">Отправка отчётов о доставке включена для %d контактов.</string>
<string name="sending_delivery_receipts_will_be_enabled_all_profiles">Отправка отчётов о доставке будет включена для всех контактов во всех видимых профилях чата.</string>
<string name="this_setting_is_for_your_current_profile">Установка для Вашего активного профиля</string>
<string name="receipts_section_description">Установки для Вашего активного профиля</string>
<string name="receipts_contacts_override_disabled">Отправка отчётов о доставке выключена для %d контактов.</string>
<string name="sync_connection_force_desc">Шифрование работает, и новое соглашение не требуется. Это может привести к ошибкам соединения!</string>
@@ -1359,6 +1360,7 @@
<string name="receipts_contacts_enable_keep_overrides">Включить (кроме исключений)</string>
<string name="receipts_contacts_title_enable">Выключить отчёты о доставке\?</string>
<string name="settings_section_title_delivery_receipts">ОТПРАВКА ОТЧЁТОВ О ДОСТАВКЕ</string>
<string name="settings_section_title_contact_requests_from_groups">ЗАПРОСЫ НА СОЕДИНЕНИЕ ИЗ ГРУПП</string>
<string name="conn_event_ratchet_sync_agreed">шифрование согласовано</string>
<string name="snd_conn_event_ratchet_sync_agreed">шифрование согласовано для %s</string>
<string name="conn_event_ratchet_sync_ok">шифрование работает</string>
@@ -1467,6 +1469,7 @@
<string name="connect_plan_repeat_connection_request">Повторить запрос на соединение?</string>
<string name="encryption_renegotiation_error">Ошибка нового соглашения о шифровании</string>
<string name="rcv_direct_event_contact_deleted">удалил(а) контакт</string>
<string name="rcv_direct_event_group_inv_link_received">запрос на соединение из группы %1$s</string>
<string name="error_alert_title">Ошибка</string>
<string name="v5_4_incognito_groups_descr">Создайте группу, используя случайный профиль.</string>
<string name="create_group_button">Создать группу</string>
@@ -2561,6 +2564,7 @@
<string name="group_short_descr_field">Цель:</string>
<string name="network_option_tcp_connection_timeout_background">Фоновый таймаут TCP-соединения</string>
<string name="the_sender_will_not_be_notified">Отправитель не будет уведомлён.</string>
<string name="member_is_deleted_cant_accept_request">Член группы удалён - невозможно принять запрос</string>
<string name="context_user_picker_cant_change_profile_alert_message">Чтобы использовать другой профиль после попытки соединения, удалите чат и используйте ссылку снова.</string>
<string name="address_welcome_message">Приветственное сообщение</string>
<string name="short_descr">О Вас:</string>
@@ -200,7 +200,7 @@
<string name="icon_descr_edited">редаговано</string>
<string name="icon_descr_sent_msg_status_send_failed">помилка відправки</string>
<string name="icon_descr_received_msg_status_unread">непрочитане</string>
<string name="group_preview_join_as">приєднатися як %s</string>
<string name="group_preview_join_as">Приєднуйтесь як %s</string>
<string name="icon_descr_cancel_image_preview">Скасувати попередній перегляд зображення</string>
<string name="icon_descr_cancel_file_preview">Скасувати попередній перегляд файлу</string>
<string name="icon_descr_waiting_for_image">Очікування на зображення</string>
@@ -571,7 +571,7 @@
<string name="personal_welcome">Вітаємо, %1$s!</string>
<string name="welcome">Вітаємо!</string>
<string name="this_text_is_available_in_settings">Цей текст доступний у налаштуваннях</string>
<string name="group_preview_you_are_invited">вас запрошено в групу</string>
<string name="group_preview_you_are_invited">Запрошуємо вас до групи</string>
<string name="share_message">Поділитися повідомленням…</string>
<string name="share_image">Поділитися медіа…</string>
<string name="share_file">Поділитися файлом…</string>
@@ -586,7 +586,7 @@
<string name="video_descr">Відео</string>
<string name="contact_sent_large_file">Ваш контакт відправив файл, розмір якого більший, ніж поточно підтримуваний максимальний розмір (%1$s).</string>
<string name="maximum_supported_file_size">Поточно максимально підтримуваний розмір файлу - %1$s.</string>
<string name="switch_receiving_address_desc">Адреса отримувача буде змінена на інший сервер. Зміна адреси завершиться після того, як відправник з\'явиться в мережі.</string>
<string name="switch_receiving_address_desc">Адреса отримання буде змінена на інший сервер. Зміна адреси буде завершена після того, як відправник з\'явиться в мережі.</string>
<string name="verify_security_code">Перевірити код безпеки</string>
<string name="icon_descr_send_message">Надіслати повідомлення</string>
<string name="icon_descr_record_voice_message">Записати голосове повідомлення</string>
@@ -1031,7 +1031,7 @@
<string name="stop_sharing">Зупинити поділ</string>
<string name="enter_welcome_message_optional">Введіть текст привітання... (необов\'язково)</string>
<string name="save_settings_question">Зберегти налаштування\?</string>
<string name="save_auto_accept_settings">Зберегти налаштування автоприйому</string>
<string name="save_auto_accept_settings">Зберегти налаштування адреси SimpleX</string>
<string name="email_invite_body">Привіт!
\nПриєднуйтесь до мене через SimpleX Chat: %s</string>
<string name="invite_friends">Запросити друзів</string>
@@ -1426,7 +1426,7 @@
\n- швидше та надійніше.</string>
<string name="settings_is_storing_in_clear_text">Ключова фраза зберігається в налаштуваннях як звичайний текст.</string>
<string name="connect_plan_you_have_already_requested_connection_via_this_address">Ви вже подали запит на підключення за цією адресою!</string>
<string name="member_contact_send_direct_message">надіслати приватне повідомлення</string>
<string name="member_contact_send_direct_message">відправити для підключення</string>
<string name="terminal_always_visible">Показувати консоль в новому вікні</string>
<string name="block_member_desc">Усі нові повідомлення від %s будуть приховані!</string>
<string name="rcv_group_event_member_created_contact">підключив(лась) безпосередньо</string>
@@ -2058,7 +2058,7 @@
<string name="migrate_from_device_remove_archive_question">Видалити архів?</string>
<string name="new_chat_share_profile">Поділитися профілем</string>
<string name="migrate_from_device_uploaded_archive_will_be_removed">Завантажений архів бази даних буде остаточно видалено з серверів.</string>
<string name="switching_profile_error_message">Підключення було перенесено до %s, але під час перенаправлення на профіль сталася непередбачена помилка.</string>
<string name="switching_profile_error_message">Ваше з\'єднання було переміщено на %s, але при перемиканні профілю сталася помилка.</string>
<string name="system_mode_toast">Режим системи</string>
<string name="network_proxy_auth_mode_no_auth">Не використовуйте облікові дані з проксі.</string>
<string name="network_proxy_auth">Аутентифікація проксі</string>
@@ -2088,7 +2088,7 @@
<string name="forward_files_messages_deleted_after_selection_desc">Повідомлення були видалені після того, як ви їх вибрали.</string>
<string name="error_forwarding_messages">Помилка при пересиланні повідомлень</string>
<string name="icon_descr_sound_muted">Звук вимкнено</string>
<string name="error_initializing_web_view_wrong_arch">Помилка ініціалізації WebView. Переконайтеся, що WebView встановлено, і його підтримувана архітектура — arm64. \nПомилка: %s</string>
<string name="error_initializing_web_view_wrong_arch">Помилка під час ініціалізації WebView. Переконайтеся, що WebView встановлено і що його архітектура підтримується arm64.\nПомилка: %s</string>
<string name="settings_message_shape_tail">Хвіст</string>
<string name="settings_message_shape_corner">Кут</string>
<string name="settings_section_title_message_shape">Форма повідомлення</string>
@@ -2419,7 +2419,7 @@
<string name="admission_stage_review">Схвалювати учасників</string>
<string name="member_criteria_off">вимкнено</string>
<string name="admission_stage_review_descr">Схвалювати учасників для вступу до групи.</string>
<string name="add_short_link">Додати коротке посилання</string>
<string name="add_short_link">Адреса оновлення</string>
<string name="cant_send_message_contact_not_synchronized">не синхронізовано</string>
<string name="reviewed_by_admins">схвалено адміністраторами</string>
<string name="group_member_status_pending_review">очікує на схвалення</string>
@@ -2436,4 +2436,80 @@
<string name="reject_pending_member_button">Відхилити</string>
<string name="reject_pending_member_alert_title">Відхилити учасника?</string>
<string name="cant_send_message_you_left">ви вийшли</string>
<string name="v6_4_1_new_interface_languages">4 нові мови інтерфейсу</string>
<string name="accept_contact_request">Прийняти запит на контакт</string>
<string name="chat_banner_accept_contact_request">Прийняти запит на контакт</string>
<string name="compose_view_add_message">Додати повідомлення</string>
<string name="short_descr__field">Біо:</string>
<string name="bio_too_large">Біографія занадто велика</string>
<string name="chat_banner_business_connection">Бізнес-зв\'язок</string>
<string name="context_user_picker_cant_change_profile_alert_title">Не вдається змінити профіль</string>
<string name="v6_4_1_new_interface_languages_descr">Каталонська, індонезійська, румунська та в\'єтнамська - завдяки нашим користувачам!</string>
<string name="e2ee_info_e2ee"><![CDATA[Повідомлення захищені <b>наскрізним шифруванням</b>.]]></string>
<string name="compose_view_send_contact_request_alert_text"><![CDATA[Ви зможете надсилати повідомлення <b>лише після того, як ваш запит буде прийнятий</b>.]]></string>
<string name="v6_4_support_chat">Чат з адміністраторами</string>
<string name="v6_4_review_members_descr">Спілкуйтеся з учасниками до того, як вони приєднаються.</string>
<string name="compose_view_connect">Підключіться</string>
<string name="v6_4_connect_faster">Підключайтеся швидше! 🚀</string>
<string name="contact_should_accept">контакт повинен прийняти…</string>
<string name="v6_4_1_short_address_create">Створіть свою адресу</string>
<string name="group_descr_too_large">Опис занадто великий</string>
<string name="v6_4_1_keep_chats_clean_descr">Увімкнути зникаючі повідомлення за замовчуванням.</string>
<string name="error_changing_user">Помилка зміни профілю</string>
<string name="error_preparing_contact">Помилка відкриття чату</string>
<string name="error_preparing_group">Помилка відкриття групи</string>
<string name="error_rejecting_contact_request">Помилка відхилення запиту на контакт</string>
<string name="chat_banner_group">Група</string>
<string name="compose_view_join_group">Приєднуйтесь до групи</string>
<string name="v6_4_1_keep_chats_clean">Підтримуйте чистоту в чатах</string>
<string name="v6_4_message_delivery_descr">Менше трафіку в мобільних мережах.</string>
<string name="loading_profile">Завантаження профілю…</string>
<string name="v6_4_connect_faster_descr">Миттєве повідомлення, щойно ви натиснете \"Підключитися\".</string>
<string name="v6_4_role_moderator">Нова роль у групі: Модератор</string>
<string name="private_routing_no_session">Немає приватного сеансу маршрутизації</string>
<string name="connect_plan_open_chat">Відкритий чат</string>
<string name="connect_plan_open_new_chat">Відкрити новий чат</string>
<string name="connect_plan_open_new_group">Відкрити нову групу</string>
<string name="open_to_accept">Відкрити для прийняття</string>
<string name="open_to_connect">Відкрито для підключення</string>
<string name="group_preview_open_to_join">Відкрито для приєднання</string>
<string name="private_routing_timeout">Тайм-аут приватної маршрутизації</string>
<string name="network_option_protocol_timeout_background">Фоновий тайм-аут протоколу</string>
<string name="reject_contact_request">Відхилити запит на контакт</string>
<string name="v6_4_role_moderator_descr">Видаляє повідомлення та блокує користувачів.</string>
<string name="cant_send_message_request_is_sent">запит відправлено</string>
<string name="v6_4_review_members">Учасники групи оглядів</string>
<string name="compose_view_send_contact_request_alert_question">Надіслати запит на контакт?</string>
<string name="compose_view_send_request">Надіслати запит</string>
<string name="compose_view_send_request_without_message">Надіслати запит без повідомлення</string>
<string name="v6_4_support_chat_descr">Надсилайте свої приватні відгуки до груп.</string>
<string name="sent_to_your_contact_after_connection">Відправлено вашому контакту після з\'єднання.</string>
<string name="v6_4_1_welcome_contacts_descr">Налаштуйте біографію профілю та вітальне повідомлення.</string>
<string name="share_old_address_alert_button">Поділіться старою адресою</string>
<string name="share_old_link_alert_button">Поділіться старим посиланням</string>
<string name="v6_4_1_short_address_share">Поділіться своєю адресою</string>
<string name="group_short_descr_field">Короткий опис:</string>
<string name="v6_4_1_short_address">Коротка адреса SimpleX</string>
<string name="chat_banner_connect_to_chat">Натисніть Підключитися до чату</string>
<string name="chat_banner_send_request_to_connect">Натисніть Підключитися, щоб відправити запит</string>
<string name="chat_banner_join_group">Натисніть Приєднатися до групи</string>
<string name="network_option_tcp_connection_timeout_background">Таймаут TCP-з\'єднання bg</string>
<string name="share_profile_via_link_alert_text">Адреса буде короткою, і ваш профіль буде доступний за цією адресою.</string>
<string name="share_group_profile_via_link_alert_text">Посилання буде коротким, а профіль групи буде поширюватися за посиланням.</string>
<string name="the_sender_will_not_be_notified">Відправник НЕ буде повідомлений.</string>
<string name="time_to_disappear_is_set_only_for_new_contacts">Час зникнення встановлюється тільки для нових контактів.</string>
<string name="context_user_picker_cant_change_profile_alert_message">Щоб використовувати інший профіль після спроби з\'єднання, видаліть чат і скористайтеся посиланням знову.</string>
<string name="v6_4_1_short_address_update">Оновіть свою адресу</string>
<string name="share_profile_via_link_alert_confirm">Оновлення</string>
<string name="share_profile_via_link">Змінити адресу?</string>
<string name="upgrade_group_link">Оновити посилання на групу</string>
<string name="share_group_profile_via_link">Оновити посилання на групу?</string>
<string name="connect_use_incognito_profile">Використовуйте профіль інкогніто</string>
<string name="address_welcome_message">Вітальне повідомлення</string>
<string name="v6_4_1_welcome_contacts">Вітаємо ваші контакти 👋</string>
<string name="short_descr">Твоя біографія:</string>
<string name="chat_banner_your_business_contact">Ваш діловий контакт</string>
<string name="chat_banner_your_contact">Ваш контакт</string>
<string name="chat_banner_your_group">Ваша група</string>
<string name="context_user_picker_your_profile">Ваш профіль</string>
</resources>
@@ -183,7 +183,7 @@
<string name="group_invitation_tap_to_join_incognito">点击以加入隐身聊天</string>
<string name="group_main_profile_sent">你的聊天资料将被发送给群成员</string>
<string name="invite_prohibited_description">你正在尝试邀请与你共享隐身个人资料的联系人加入你使用主要个人资料的群</string>
<string name="incognito_info_protects">隐身模式通过为每个联系人使用新的随机配置文件来保护你的隐私。</string>
<string name="incognito_info_protects">隐身模式通过为每个联系人使用新的随机个人资料来保护你的隐私。</string>
<string name="alert_title_cant_invite_contacts_descr">你正在为该群使用隐身个人资料——为防止共享你的主要个人资料,不允许邀请联系人</string>
<string name="description_via_one_time_link_incognito">通过一次性链接隐身</string>
<string name="only_group_owners_can_enable_voice">只有群主可以启用语音信息。</string>
@@ -460,7 +460,7 @@
<string name="smp_servers_invalid_address">无效的服务器地址!</string>
<string name="button_add_members">邀请成员</string>
<string name="button_leave_group">离开群</string>
<string name="users_delete_data_only">仅本地配置文件数据</string>
<string name="users_delete_data_only">仅本地个人资料数据</string>
<string name="icon_descr_instant_notifications">即时通知</string>
<string name="service_notifications">即时通知!</string>
<string name="auth_log_in_using_credential">使用你的凭据登录</string>
@@ -853,7 +853,7 @@
<string name="icon_descr_simplex_team">SimpleX 团队</string>
<string name="group_info_section_title_num_members">%1$s 名成员</string>
<string name="chat_preferences_yes"></string>
<string name="you_will_be_connected_when_group_host_device_is_online">你将在主设备上线时连接到该群,请稍等或稍后再检查!</string>
<string name="you_will_be_connected_when_group_host_device_is_online">你将在主设备上线时连接到该群,请稍等或稍后再检查!</string>
<string name="auth_you_will_be_required_to_authenticate_when_you_start_or_resume">当你启动应用或在应用程序驻留后台超过30 秒后,你将需要进行身份验证。</string>
<string name="you_can_connect_to_simplex_chat_founder"><![CDATA[你可以 <font color="#0088ff"> 连接到 SimpleX Chat 开发者提出任何问题并接收更新 </font>。]]></string>
<string name="you_accepted_connection">你已接受连接</string>
@@ -885,7 +885,7 @@
<string name="snd_group_event_changed_member_role">你将 %s 的角色更改为 %s</string>
<string name="snd_group_event_changed_role_for_yourself">你将自己的角色更改为 %s</string>
<string name="snd_conn_event_switch_queue_phase_completed">你已更改地址</string>
<string name="you_can_share_group_link_anybody_will_be_able_to_connect">你可以共享链接或二维码——任何人都可以加入该群。如果你稍后将其删除,你不会失去该的成员。</string>
<string name="you_can_share_group_link_anybody_will_be_able_to_connect">你可以共享链接或二维码——任何人都可以加入该群。如果你稍后将其删除,你不会失去该的成员。</string>
<string name="conn_level_desc_indirect">间接(%1$s</string>
<string name="you_can_also_connect_by_clicking_the_link"><![CDATA[你也可以通过点击链接进行连接。 如果它在浏览器中打开,请单击<b>在移动应用程序中打开</b>按钮。]]></string>
<string name="app_name">SimpleX</string>
@@ -905,7 +905,7 @@
<string name="ttl_days">%d 天</string>
<string name="ttl_w">%dw</string>
<string name="you_are_invited_to_group_join_to_connect_with_group_members">你被邀请加入群。 加入以与群成员联系。</string>
<string name="youve_accepted_group_invitation_connecting_to_inviting_group_member">你加入了这个群。连接到邀请成员。</string>
<string name="youve_accepted_group_invitation_connecting_to_inviting_group_member">你加入了这个群。连接到邀请成员。</string>
<string name="snd_conn_event_switch_queue_phase_completed_for_member">你更改了 %s 的地址</string>
<string name="snd_group_event_user_left">你已离开</string>
<string name="num_contacts_selected">已选择 %d 名联系人</string>
@@ -939,7 +939,7 @@
<string name="user_hide">隐藏</string>
<string name="make_profile_private">将个人资料设置为私密!</string>
<string name="user_mute">静音</string>
<string name="save_and_update_group_profile">保存并更新组配置文件</string>
<string name="save_and_update_group_profile">保存并更新群资料</string>
<string name="dont_show_again">不再显示</string>
<string name="muted_when_inactive">不活跃时静音!</string>
<string name="v4_6_audio_video_calls">语音和视频通话</string>
@@ -969,8 +969,8 @@
<string name="v4_6_chinese_spanish_interface_descr">感谢用户——通过 Weblate 做出贡献!</string>
<string name="user_unmute">解除静音</string>
<string name="button_welcome_message">欢迎消息</string>
<string name="you_will_still_receive_calls_and_ntfs">当静音配置文件处于活动状态时,你仍会收到来自静音配置文件的电话和通知。</string>
<string name="you_can_hide_or_mute_user_profile">你可以隐藏或静音用户配置文件——长按以显示菜单。</string>
<string name="you_will_still_receive_calls_and_ntfs">当静音个人资料处于活动状态时,你仍会收到来自静音个人资料的电话和通知。</string>
<string name="you_can_hide_or_mute_user_profile">你可以隐藏或静音用户个人资料——长按以显示菜单。</string>
<string name="group_welcome_title">欢迎消息</string>
<string name="confirm_database_upgrades">确认数据库升级</string>
<string name="settings_section_title_experimenta">实验性</string>
@@ -1268,7 +1268,7 @@
<string name="connect__your_profile_will_be_shared">你的个人资料 %1$s 将被共享。</string>
<string name="sending_delivery_receipts_will_be_enabled">将为所有联系人启用送达回执功能。</string>
<string name="turn_off_system_restriction_button">打开应用程序设置</string>
<string name="receipts_groups_enable_for_all">为所有启用</string>
<string name="receipts_groups_enable_for_all">为所有启用</string>
<string name="rcv_group_event_n_members_connected">%s、%s 和 %d 其他成员已连接</string>
<string name="receipts_contacts_override_enabled">已为 %d 联系人启用送达回执功能</string>
<string name="snd_conn_event_ratchet_sync_agreed">已同意 %s 的加密</string>
@@ -1277,7 +1277,7 @@
<string name="connect_use_new_incognito_profile">使用新的隐身个人资料</string>
<string name="v5_2_favourites_filter_descr">过滤未读和收藏的聊天记录。</string>
<string name="rcv_conn_event_verification_code_reset">已更改安全密码</string>
<string name="sending_delivery_receipts_will_be_enabled_all_profiles">将为所有可见聊天配置文件中的所有联系人启用送达回执功能。</string>
<string name="sending_delivery_receipts_will_be_enabled_all_profiles">将为所有可见聊天个人资料中的所有联系人启用送达回执功能。</string>
<string name="system_restricted_background_in_call_warn"><![CDATA[要在后台拨打电话,请在应用设置中选择<b>应用电池使用情况</b> / <b>无限制</b>。]]></string>
<string name="sender_at_ts">%s 在 %s</string>
<string name="receipts_contacts_title_disable">禁用回执?</string>
@@ -1285,12 +1285,12 @@
<string name="receipts_section_description_1">可以在联系人和群设置中覆盖它们。</string>
<string name="receipts_contacts_disable_for_all">对所有联系人关闭</string>
<string name="you_can_change_it_later">随机密码以明文形式存储在设置中。 \n你可以稍后更改。</string>
<string name="receipts_groups_override_disabled">已禁用 %d 的送达回执功能</string>
<string name="receipts_groups_override_disabled">已禁用 %d 的送达回执功能</string>
<string name="snd_conn_event_ratchet_sync_required">需要为 %s 重新协商加密</string>
<string name="system_restricted_background_desc">SimpleX 无法在后台运行。只有在应用程序运行时,你才会收到通知。</string>
<string name="receipts_contacts_enable_keep_overrides">启用(保留覆盖)</string>
<string name="database_encryption_will_be_updated_in_settings">即将更新数据库加密密码并将其存储在设置中。</string>
<string name="connect_use_current_profile">使用当前配置文件</string>
<string name="connect_use_current_profile">使用当前个人资料</string>
<string name="remove_passphrase_from_settings">从设置中删除密码?</string>
<string name="conn_event_ratchet_sync_agreed">同意加密</string>
<string name="receipts_contacts_title_enable">启用回执?</string>
@@ -1309,12 +1309,12 @@
<string name="receipts_groups_title_disable">为群禁用回执吗?</string>
<string name="rcv_group_event_3_members_connected">%s、%s 和 %s 已连接</string>
<string name="fix_connection_not_supported_by_group_member">修复群成员不支持的问题</string>
<string name="receipts_groups_override_enabled">已为 %d 启用送达回执功能</string>
<string name="receipts_groups_override_enabled">已为 %d 启用送达回执功能</string>
<string name="sync_connection_force_confirm">重新协商</string>
<string name="receipts_contacts_disable_keep_overrides">禁用(保留覆盖)</string>
<string name="set_database_passphrase">设置数据库密码</string>
<string name="receipts_contacts_override_disabled">已禁用 %d 联系人的送达回执功能</string>
<string name="receipts_groups_enable_keep_overrides">启用(保留覆盖)</string>
<string name="receipts_groups_enable_keep_overrides">启用(保留覆盖)</string>
<string name="system_restricted_background_warn"><![CDATA[要启用通知,请在应用设置中选择<b>应用电池使用情况</b> / <b>无限制</b>。]]></string>
<string name="send_receipts_disabled_alert_title">送达回执已禁用</string>
<string name="open_database_folder">打开数据库文件夹</string>
@@ -1333,7 +1333,7 @@
<string name="no_selected_chat">没有选中的聊天</string>
<string name="conn_event_ratchet_sync_ok">可以加密</string>
<string name="renegotiate_encryption">重新协商加密</string>
<string name="receipts_groups_disable_keep_overrides">禁用(保留覆盖)</string>
<string name="receipts_groups_disable_keep_overrides">禁用(保留覆盖)</string>
<string name="receipts_groups_title_enable">为群启用回执吗?</string>
<string name="fix_connection_not_supported_by_contact">修复联系人不支持的问题</string>
<string name="snd_conn_event_ratchet_sync_ok">对 %s 加密正常</string>
@@ -1342,10 +1342,10 @@
<string name="disable_notifications_button">禁用通知</string>
<string name="in_reply_to">回复</string>
<string name="dont_enable_receipts">不启用</string>
<string name="connect_via_member_address_alert_desc">连接请求将发送给该成员。</string>
<string name="connect_via_member_address_alert_desc">连接请求将发送给该成员。</string>
<string name="settings_is_storing_in_clear_text">密码以明文形式存储在设置中。</string>
<string name="error_synchronizing_connection">同步连接时出错</string>
<string name="receipts_section_description">这些设置适用于你当前的配置文件</string>
<string name="receipts_section_description">这些设置适用于你当前的个人资料</string>
<string name="snd_conn_event_ratchet_sync_allowed">允许为 %s 重新协商加密</string>
<string name="receipts_contacts_enable_for_all">为所有人启用</string>
<string name="conn_event_ratchet_sync_required">需要重新协商加密</string>
@@ -1366,7 +1366,7 @@
<string name="error_creating_member_contact">创建成员联系人时出错</string>
<string name="compose_send_direct_message_to_connect">发送私信来连接</string>
<string name="member_contact_send_direct_message">发送私信来连接</string>
<string name="rcv_group_event_member_created_contact">直连</string>
<string name="rcv_group_event_member_created_contact">请求连接</string>
<string name="expand_verb">展开</string>
<string name="connect_plan_repeat_connection_request">重复连接请求吗?</string>
<string name="rcv_direct_event_contact_deleted">已删除联系人</string>
@@ -1852,7 +1852,7 @@
<string name="subscription_percentage">显示百分比</string>
<string name="member_info_member_inactive">不活跃</string>
<string name="appearance_zoom">缩放</string>
<string name="all_users">所有配置文件</string>
<string name="all_users">所有个人资料</string>
<string name="servers_info_files_tab">文件</string>
<string name="servers_info_missing">没有信息,试试重新加载</string>
<string name="servers_info">服务器信息</string>
@@ -1930,7 +1930,7 @@
<string name="subscription_results_ignored">订阅被忽略</string>
<string name="smp_servers_configured">已配置的 SMP 服务器</string>
<string name="xftp_servers_configured">已配置的 XFTP 服务器</string>
<string name="current_user">当前配置文件</string>
<string name="current_user">当前个人资料</string>
<string name="servers_info_transport_sessions_section_header">传输会话</string>
<string name="servers_info_uploaded">已上传</string>
<string name="member_info_member_disabled">已停用</string>
@@ -2046,16 +2046,16 @@
<string name="migrate_from_device_uploaded_archive_will_be_removed">上传的数据库存档将永久性从服务器被删除。</string>
<string name="network_proxy_incorrect_config_desc">确保代理配置正确</string>
<string name="delete_messages_cannot_be_undone_warning">消息将被删除 - 此操作无法撤销!</string>
<string name="switching_profile_error_message">你的连接被移动到 %s,但在切换配置文件时发生了错误。</string>
<string name="switching_profile_error_message">你的连接被移动到 %s,但在切换个人资料时发生了错误。</string>
<string name="network_proxy_auth_mode_no_auth">代理不使用身份验证凭据</string>
<string name="switching_profile_error_title">切换配置文件出错</string>
<string name="switching_profile_error_title">切换个人资料出错</string>
<string name="network_proxy_auth">代理身份验证</string>
<string name="migrate_from_device_remove_archive_question">删除存档?</string>
<string name="select_chat_profile">选择聊天配置文件</string>
<string name="select_chat_profile">选择聊天个人资料</string>
<string name="network_proxy_incorrect_config_title">保存代理出错</string>
<string name="network_proxy_password">密码</string>
<string name="network_proxy_auth_mode_isolate_by_auth_entity">每个连接使用不同的代理身份验证凭据。</string>
<string name="network_proxy_auth_mode_isolate_by_auth_user">个配置文件使用不同的代理身份验证。</string>
<string name="network_proxy_auth_mode_isolate_by_auth_user">一个人资料使用不同的代理身份验证。</string>
<string name="network_proxy_auth_mode_username_password">你的凭据可能以未经加密的方式被发送。</string>
<string name="network_proxy_random_credentials">使用随机凭据</string>
<string name="network_proxy_username">用户名</string>
@@ -2095,7 +2095,7 @@
<string name="v6_1_forward_many_messages_descr">一次转发最多20条消息。</string>
<string name="v6_1_better_security_descr">Trail of Bits 审核了 SimpleX 协议。</string>
<string name="v6_1_better_calls_descr">通话期间切换音频和视频。</string>
<string name="v6_1_switch_chat_profile_descr">对一次性邀请切换聊天配置文件</string>
<string name="v6_1_switch_chat_profile_descr">对一次性邀请切换聊天个人资料</string>
<string name="v6_1_better_calls">更佳的通话</string>
<string name="v6_1_delete_many_messages_descr">允许自行删除或管理员移除最多200条消息。</string>
<string name="failed_to_save_servers">保存服务器出错</string>
@@ -2339,7 +2339,7 @@
<string name="v6_3_faster_deletion_of_groups">更快地删除群。</string>
<string name="v6_3_faster_sending_messages">更快发送消息。</string>
<string name="v6_3_mentions_descr">被提及时收到通知。</string>
<string name="v6_3_reports_descr">帮助管理员管理群</string>
<string name="v6_3_reports_descr">帮助管理员管理群。</string>
<string name="v6_3_organize_chat_lists">将聊天组织到列表</string>
<string name="v6_3_private_media_file_names">私密媒体文件名。</string>
<string name="v6_3_reports">发送私下举报</string>
@@ -2363,7 +2363,7 @@
<string name="onboarding_conditions_privacy_policy_and_conditions_of_use">隐私政策和使用条款。</string>
<string name="onboarding_conditions_accept">接受</string>
<string name="onboarding_conditions_by_using_you_agree">使用 SimpleX Chat 代表您同意:\n- 在公开群中只发送合法内容\n- 尊重其他用户 – 没有垃圾信息。</string>
<string name="onboarding_conditions_private_chats_not_accessible">服务器运营方无法访问私密聊天、群和你的联系人。</string>
<string name="onboarding_conditions_private_chats_not_accessible">服务器运营方无法访问私密聊天、群和你的联系人。</string>
<string name="onboarding_conditions_configure_server_operators">配置服务器运营方</string>
<string name="unsupported_connection_link">不支持的连接链接</string>
<string name="simplex_link_channel">SimpleX 频道链接</string>
@@ -2499,4 +2499,8 @@
<string name="upgrade_group_link">升级群链接</string>
<string name="connect_use_incognito_profile">使用隐身个人资料</string>
<string name="v6_4_1_welcome_contacts">欢迎联系人👋</string>
<string name="rcv_direct_event_group_inv_link_received">来自%1$s群的连接请求</string>
<string name="this_setting_is_for_your_current_profile">此设置用于当前个人资料</string>
<string name="settings_section_title_contact_requests_from_groups">来自群的联络请求</string>
<string name="member_is_deleted_cant_accept_request">成员被删除——无法接受请求</string>
</resources>
@@ -31,6 +31,7 @@ actual fun CustomTimePicker(
mutableStateOf(res)
}
val values = remember(unit.value) {
// TODO replace with firstOrNull
val limit = timeUnitsLimits.first { it.timeUnit == unit.value }
val res = ArrayList<Pair<Int, String>>()
for (i in limit.minValue..limit.maxValue) {
+4 -4
View File
@@ -24,13 +24,13 @@ android.nonTransitiveRClass=true
kotlin.mpp.androidSourceSetLayoutVersion=2
kotlin.jvm.target=11
android.version_name=6.4.1
android.version_code=307
android.version_name=6.4.2
android.version_code=309
android.bundle=false
desktop.version_name=6.4.1
desktop.version_code=114
desktop.version_name=6.4.2
desktop.version_code=115
kotlin.version=1.9.23
gradle.plugin.version=8.2.0
@@ -124,13 +124,13 @@ data DirectoryCmdTag (r :: DirectoryRole) where
DCDeleteGroup_ :: DirectoryCmdTag 'DRUser
DCMemberRole_ :: DirectoryCmdTag 'DRUser
DCGroupFilter_ :: DirectoryCmdTag 'DRUser
DCShowUpgradeGroupLink_ :: DirectoryCmdTag 'DRUser
DCApproveGroup_ :: DirectoryCmdTag 'DRAdmin
DCRejectGroup_ :: DirectoryCmdTag 'DRAdmin
DCSuspendGroup_ :: DirectoryCmdTag 'DRAdmin
DCResumeGroup_ :: DirectoryCmdTag 'DRAdmin
DCListLastGroups_ :: DirectoryCmdTag 'DRAdmin
DCListPendingGroups_ :: DirectoryCmdTag 'DRAdmin
DCShowGroupLink_ :: DirectoryCmdTag 'DRAdmin
DCSendToGroupOwner_ :: DirectoryCmdTag 'DRAdmin
DCInviteOwnerToGroup_ :: DirectoryCmdTag 'DRAdmin
-- DCAddBlockedWord_ :: DirectoryCmdTag 'DRAdmin
@@ -156,13 +156,13 @@ data DirectoryCmd (r :: DirectoryRole) where
DCDeleteGroup :: UserGroupRegId -> GroupName -> DirectoryCmd 'DRUser
DCMemberRole :: UserGroupRegId -> Maybe GroupName -> Maybe GroupMemberRole -> DirectoryCmd 'DRUser
DCGroupFilter :: UserGroupRegId -> Maybe GroupName -> Maybe DirectoryMemberAcceptance -> DirectoryCmd 'DRUser
DCShowUpgradeGroupLink :: GroupId -> Maybe GroupName -> DirectoryCmd 'DRUser
DCApproveGroup :: {groupId :: GroupId, displayName :: GroupName, groupApprovalId :: GroupApprovalId} -> DirectoryCmd 'DRAdmin
DCRejectGroup :: GroupId -> GroupName -> DirectoryCmd 'DRAdmin
DCSuspendGroup :: GroupId -> GroupName -> DirectoryCmd 'DRAdmin
DCResumeGroup :: GroupId -> GroupName -> DirectoryCmd 'DRAdmin
DCListLastGroups :: Int -> DirectoryCmd 'DRAdmin
DCListPendingGroups :: Int -> DirectoryCmd 'DRAdmin
DCShowGroupLink :: GroupId -> GroupName -> DirectoryCmd 'DRAdmin
DCSendToGroupOwner :: GroupId -> GroupName -> Text -> DirectoryCmd 'DRAdmin
DCInviteOwnerToGroup :: GroupId -> GroupName -> DirectoryCmd 'DRAdmin
-- DCAddBlockedWord :: Text -> DirectoryCmd 'DRAdmin
@@ -200,13 +200,13 @@ directoryCmdP =
"delete" -> u DCDeleteGroup_
"role" -> u DCMemberRole_
"filter" -> u DCGroupFilter_
"link" -> u DCShowUpgradeGroupLink_
"approve" -> au DCApproveGroup_
"reject" -> au DCRejectGroup_
"suspend" -> au DCSuspendGroup_
"resume" -> au DCResumeGroup_
"last" -> au DCListLastGroups_
"pending" -> au DCListPendingGroups_
"link" -> au DCShowGroupLink_
"owner" -> au DCSendToGroupOwner_
"invite" -> au DCInviteOwnerToGroup_
-- "block_word" -> au DCAddBlockedWord_
@@ -266,6 +266,7 @@ directoryCmdP =
"=all" $> PCAll
<|> ("=noimage" <|> "=no_image" <|> "=no-image") $> PCNoImage
<|> pure PCAll
DCShowUpgradeGroupLink_ -> gc_ DCShowUpgradeGroupLink
DCApproveGroup_ -> do
(groupId, displayName) <- gc (,)
groupApprovalId <- A.space *> A.decimal
@@ -275,7 +276,6 @@ directoryCmdP =
DCResumeGroup_ -> gc DCResumeGroup
DCListLastGroups_ -> DCListLastGroups <$> (A.space *> A.decimal <|> pure 10)
DCListPendingGroups_ -> DCListPendingGroups <$> (A.space *> A.decimal <|> pure 10)
DCShowGroupLink_ -> gc DCShowGroupLink
DCSendToGroupOwner_ -> do
(groupId, displayName) <- gc (,)
msg <- A.space *> A.takeText
@@ -299,17 +299,17 @@ directoryCmdTag = \case
DCRecentGroups -> "new"
DCSubmitGroup _ -> "submit"
DCConfirmDuplicateGroup {} -> "confirm"
DCListUserGroups -> "list"
DCListUserGroups -> "list"
DCDeleteGroup {} -> "delete"
DCApproveGroup {} -> "approve"
DCMemberRole {} -> "role"
DCGroupFilter {} -> "filter"
DCShowUpgradeGroupLink {} -> "link"
DCRejectGroup {} -> "reject"
DCSuspendGroup {} -> "suspend"
DCResumeGroup {} -> "resume"
DCListLastGroups _ -> "last"
DCListPendingGroups _ -> "pending"
DCShowGroupLink {} -> "link"
DCSendToGroupOwner {} -> "owner"
DCInviteOwnerToGroup {} -> "invite"
-- DCAddBlockedWord _ -> "block_word"
@@ -29,7 +29,7 @@ import Control.Monad.IO.Class
import Data.List (find, intercalate)
import Data.List.NonEmpty (NonEmpty (..))
import qualified Data.Map.Strict as M
import Data.Maybe (fromMaybe, isJust, maybeToList)
import Data.Maybe (fromMaybe, isJust, isNothing, maybeToList)
import Data.Set (Set)
import qualified Data.Set as S
import Data.Text (Text)
@@ -72,7 +72,12 @@ import Simplex.Messaging.Util (safeDecodeUtf8, tshow, ($>>=), (<$$>))
import System.Directory (getAppUserDataDirectory)
import System.Process (readProcess)
data GroupProfileUpdate = GPNoServiceLink | GPServiceLinkAdded | GPServiceLinkRemoved | GPHasServiceLink | GPServiceLinkError
data GroupProfileUpdate
= GPNoServiceLink
| GPServiceLinkAdded {linkNow :: Text}
| GPServiceLinkRemoved
| GPHasServiceLink {linkBefore :: Text, linkNow :: Text}
| GPServiceLinkError
data DuplicateGroup
= DGUnique -- display name or full name is unique
@@ -223,6 +228,7 @@ directoryServiceEvent st opts@DirectoryOpts {adminUsers, superUsers, serviceName
SDRSuperUser -> deSuperUserCommand ct ciId cmd
DELogChatResponse r -> logInfo r
where
groupLinkText (CCLink cReq sLnk_) = maybe (strEncodeTxt $ simplexChatContact cReq) strEncodeTxt sLnk_
withAdminUsers action = void . forkIO $ do
forM_ superUsers $ \KnownContact {contactId} -> action contactId
forM_ adminUsers $ \KnownContact {contactId} -> action contactId
@@ -354,14 +360,14 @@ directoryServiceEvent st opts@DirectoryOpts {adminUsers, superUsers, serviceName
let GroupInfo {groupId, groupProfile = GroupProfile {displayName}} = g
notifyOwner gr $ "Joined the group " <> displayName <> ", creating the link…"
sendChatCmd cc (APICreateGroupLink groupId GRMember) >>= \case
Right CRGroupLinkCreated {groupLink = GroupLink {connLinkContact = CCLink gLink _}} -> do
Right CRGroupLinkCreated {groupLink = GroupLink {connLinkContact = gLink}} -> do
setGroupStatus st gr GRSPendingUpdate
notifyOwner
gr
"Created the public link to join the group via this directory service that is always online.\n\n\
\Please add it to the group welcome message.\n\
\For example, add:"
notifyOwner gr $ "Link to join the group " <> displayName <> ": " <> strEncodeTxt (simplexChatContact gLink)
notifyOwner gr $ "Link to join the group " <> displayName <> ": " <> groupLinkText gLink
Left (ChatError e) -> case e of
CEGroupUserRole {} -> notifyOwner gr "Failed creating group link, as service is no longer an admin."
CEGroupMemberUserRemoved -> notifyOwner gr "Failed creating group link, as service is removed from the group."
@@ -386,20 +392,20 @@ directoryServiceEvent st opts@DirectoryOpts {adminUsers, superUsers, serviceName
groupProfileUpdate >>= \case
GPNoServiceLink ->
notifyOwner gr $ "The profile updated for " <> userGroupRef <> byMember <> ", but the group link is not added to the welcome message."
GPServiceLinkAdded -> groupLinkAdded gr byMember
GPServiceLinkAdded _ -> groupLinkAdded gr byMember
GPServiceLinkRemoved ->
notifyOwner gr $
"The group link of " <> userGroupRef <> " is removed from the welcome message" <> byMember <> ", please add it."
GPHasServiceLink -> groupLinkAdded gr byMember
GPHasServiceLink {} -> groupLinkAdded gr byMember
GPServiceLinkError -> do
notifyOwner gr $
("Error: " <> serviceName <> " has no group link for " <> userGroupRef)
<> " after profile was updated" <> byMember <> ". Please report the error to the developers."
logError $ "Error: no group link for " <> userGroupRef
GRSPendingApproval n -> processProfileChange gr byMember $ n + 1
GRSActive -> processProfileChange gr byMember 1
GRSSuspended -> processProfileChange gr byMember 1
GRSSuspendedBadRoles -> processProfileChange gr byMember 1
GRSPendingApproval n -> processProfileChange gr byMember False $ n + 1
GRSActive -> processProfileChange gr byMember True 1
GRSSuspended -> processProfileChange gr byMember False 1
GRSSuspendedBadRoles -> processProfileChange gr byMember False 1
GRSRemoved -> pure ()
where
GroupInfo {groupId, groupProfile = p} = fromGroup
@@ -407,7 +413,7 @@ directoryServiceEvent st opts@DirectoryOpts {adminUsers, superUsers, serviceName
sameProfile
GroupProfile {displayName = n, fullName = fn, shortDescr = sd, image = i, description = d}
GroupProfile {displayName = n', fullName = fn', shortDescr = sd', image = i', description = d'} =
n == n' && fn == fn' && i == i' && sd == sd' && d == d'
n == n' && fn == fn' && i == i' && sd == sd' && (T.words <$> d) == (T.words <$> d')
groupLinkAdded gr byMember = do
getDuplicateGroup toGroup >>= \case
Nothing -> notifyOwner gr "Error: getDuplicateGroup. Please notify the developers."
@@ -419,53 +425,65 @@ directoryServiceEvent st opts@DirectoryOpts {adminUsers, superUsers, serviceName
("Thank you! The group link for " <> userGroupReference gr toGroup <> " is added to the welcome message" <> byMember)
<> ".\nYou will be notified once the group is added to the directory - it may take up to 48 hours."
checkRolesSendToApprove gr gaId
processProfileChange gr byMember n' = do
setGroupStatus st gr GRSPendingUpdate
processProfileChange gr byMember isActive n' = do
let userGroupRef = userGroupReference gr toGroup
groupRef = groupReference toGroup
groupProfileUpdate >>= \case
GPNoServiceLink -> do
setGroupStatus st gr GRSPendingUpdate
notifyOwner gr $
("The group profile is updated for " <> userGroupRef <> byMember <> ", but no link is added to the welcome message.\n\n")
<> "The group will remain hidden from the directory until the group link is added and the group is re-approved."
GPServiceLinkRemoved -> do
setGroupStatus st gr GRSPendingUpdate
notifyOwner gr $
("The group link for " <> userGroupRef <> " is removed from the welcome message" <> byMember)
<> ".\n\nThe group is hidden from the directory until the group link is added and the group is re-approved."
notifyAdminUsers $ "The group link is removed from " <> groupRef <> ", de-listed."
GPServiceLinkAdded -> do
GPServiceLinkAdded _ -> do
setGroupStatus st gr $ GRSPendingApproval n'
notifyOwner gr $
("The group link is added to " <> userGroupRef <> byMember)
<> "!\nIt is hidden from the directory until approved."
notifyAdminUsers $ "The group link is added to " <> groupRef <> byMember <> "."
checkRolesSendToApprove gr n'
GPHasServiceLink -> do
setGroupStatus st gr $ GRSPendingApproval n'
notifyOwner gr $
("The group " <> userGroupRef <> " is updated" <> byMember)
<> "!\nIt is hidden from the directory until approved."
notifyAdminUsers $ "The group " <> groupRef <> " is updated" <> byMember <> "."
checkRolesSendToApprove gr n'
GPHasServiceLink {linkBefore, linkNow}
| isActive && onlyLinkChanged p p' -> do
notifyOwner gr $
("The group " <> userGroupRef <> " is updated" <> byMember)
<> "!\nThe group is listed in directory."
notifyAdminUsers $ "The group " <> groupRef <> " is updated" <> byMember <> " - only link or whitespace changes.\nThe group remained listed in directory."
| otherwise -> do
setGroupStatus st gr $ GRSPendingApproval n'
notifyOwner gr $
("The group " <> userGroupRef <> " is updated" <> byMember)
<> "!\nIt is hidden from the directory until approved."
notifyAdminUsers $ "The group " <> groupRef <> " is updated" <> byMember <> "."
checkRolesSendToApprove gr n'
where
onlyLinkChanged
GroupProfile {displayName = dn, fullName = fn, shortDescr = sd, image = i, description = d}
GroupProfile {displayName = dn', fullName = fn', shortDescr = sd', image = i', description = d'} =
dn == dn' && fn == fn' && i == i' && sd == sd' && (T.words . T.replace linkBefore "" <$> d) == (T.words . T.replace linkNow "" <$> d')
GPServiceLinkError -> logError $ "Error: no group link for " <> groupRef <> " pending approval."
groupProfileUpdate = profileUpdate <$> sendChatCmd cc (APIGetGroupLink groupId)
where
profileUpdate = \case
Right CRGroupLink {groupLink = GroupLink {connLinkContact = CCLink cr sl_}} ->
let hadLinkBefore = profileHasGroupLink fromGroup
hasLinkNow = profileHasGroupLink toGroup
profileHasGroupLink GroupInfo {groupProfile = gp} =
maybe False (any ftHasLink) $ parseMaybeMarkdownList =<< description gp
let linkBefore_ = profileGroupLinkText fromGroup
linkNow_ = profileGroupLinkText toGroup
profileGroupLinkText GroupInfo {groupProfile = gp} =
maybe Nothing (fmap (\(FormattedText _ t) -> t) . find ftHasLink) $ parseMaybeMarkdownList =<< description gp
ftHasLink = \case
FormattedText (Just SimplexLink {simplexUri = ACL SCMContact cLink}) _ -> case cLink of
CLFull cr' -> sameConnReqContact cr' cr
CLShort sl' -> maybe False (sameShortLinkContact sl') sl_
_ -> False
in if
| hadLinkBefore && hasLinkNow -> GPHasServiceLink
| hadLinkBefore -> GPServiceLinkRemoved
| hasLinkNow -> GPServiceLinkAdded
| otherwise -> GPNoServiceLink
in case (linkBefore_, linkNow_) of
(Just linkBefore, Just linkNow) -> GPHasServiceLink linkBefore linkNow
(Just _, Nothing) -> GPServiceLinkRemoved
(Nothing, Just linkNow) -> GPServiceLinkAdded linkNow
(Nothing, Nothing) -> GPNoServiceLink
_ -> GPServiceLinkError
checkRolesSendToApprove gr gaId = do
(badRolesMsg <$$> getGroupRolesStatus toGroup gr) >>= \case
@@ -706,8 +724,9 @@ directoryServiceEvent st opts@DirectoryOpts {adminUsers, superUsers, serviceName
DCListUserGroups ->
getUserGroupRegs st (contactId' ct) >>= \grs -> do
sendReply $ tshow (length grs) <> " registered group(s)"
void . forkIO $ forM_ (reverse grs) $ \gr@GroupReg {userGroupRegId} ->
sendGroupInfo ct gr userGroupRegId Nothing
void . forkIO $ forM_ (reverse grs) $ \gr@GroupReg {dbGroupId, userGroupRegId} ->
let useGroupId = if isAdmin then dbGroupId else userGroupRegId
in sendGroupInfo ct gr useGroupId Nothing
DCDeleteGroup gId gName ->
(if isAdmin then withGroupAndReg sendReply else withUserGroupReg) gId gName $ \GroupInfo {groupProfile = GroupProfile {displayName}} gr -> do
delGroupReg st gr
@@ -718,7 +737,7 @@ directoryServiceEvent st opts@DirectoryOpts {adminUsers, superUsers, serviceName
case mRole_ of
Nothing ->
getGroupLink' cc user g >>= \case
Just GroupLink {connLinkContact = CCLink gLink _, acceptMemberRole} -> do
Just GroupLink {connLinkContact = gLink, acceptMemberRole} -> do
let anotherRole = case acceptMemberRole of GRObserver -> GRMember; _ -> GRObserver
sendReply $
initialRole n acceptMemberRole
@@ -731,7 +750,7 @@ directoryServiceEvent st opts@DirectoryOpts {adminUsers, superUsers, serviceName
Nothing -> sendReply $ "Error: the initial member role for the group " <> n <> " was NOT upgated."
where
initialRole n mRole = "The initial member role for the group " <> n <> " is set to *" <> strEncodeTxt mRole <> "*\n"
onlyViaLink gLink = "*Please note*: it applies only to members joining via this link: " <> strEncodeTxt (simplexChatContact gLink)
onlyViaLink gLink = "*Please note*: it applies only to members joining via this link: " <> groupLinkText gLink
DCGroupFilter gId gName_ acceptance_ ->
(if isAdmin then withGroupAndReg_ sendReply else withUserGroupReg_) gId gName_ $ \g _gr -> do
let GroupInfo {groupProfile = GroupProfile {displayName = n}} = g
@@ -760,6 +779,50 @@ directoryServiceEvent st opts@DirectoryOpts {adminUsers, superUsers, serviceName
Nothing -> "_disabled_"
Just PCAll -> "_enabled_"
Just PCNoImage -> "_enabled for profiles without image_"
DCShowUpgradeGroupLink gId gName_ ->
(if isAdmin then withGroupAndReg_ sendReply else withUserGroupReg_) gId gName_ $ \GroupInfo {groupId, localDisplayName = gName} _ -> do
let groupRef = groupReference' gId gName
withGroupLinkResult groupRef (sendChatCmd cc $ APIGetGroupLink groupId) $
\GroupLink {connLinkContact = gLink@(CCLink _ sLnk_), acceptMemberRole, shortLinkDataSet, shortLinkLargeDataSet = BoolDef slLargeDataSet} -> do
let shouldBeUpgraded = isNothing sLnk_ || not shortLinkDataSet || not slLargeDataSet
sendReply $ T.unlines $
[ "The link to join the group " <> groupRef <> ":",
groupLinkText gLink,
"New member role: " <> strEncodeTxt acceptMemberRole
]
<> ["The link is being upgraded..." | shouldBeUpgraded]
when shouldBeUpgraded $ do
let send = sendComposedMessage cc ct Nothing . MCText . T.unlines
withGroupLinkResult groupRef (sendChatCmd cc $ APIAddGroupShortLink groupId) $
\GroupLink {connLinkContact = CCLink _ sLnk_'} -> case (sLnk_, sLnk_') of
(Just _, Just _) ->
send ["The group link is upgraded for: " <> groupRef, "No changes to group needed."]
(Nothing, Just sLnk) ->
sendComposedMessages cc (SRDirect $ contactId' ct)
[ MCText $ T.unlines
[ "Please replace the old link in welcome message of your group " <> groupRef,
"If this is the only change, the group will remain listed in directory without re-approval.",
"",
"The new link:"
],
MCText $ strEncodeTxt sLnk
]
(_, Nothing) ->
send ["The short link is not created for " <> groupRef, "Please report it to the developers."]
where
withGroupLinkResult groupRef a cb =
a >>= \case
Right CRGroupLink {groupLink} -> cb groupLink
Left (ChatErrorStore (SEGroupLinkNotFound _)) ->
sendReply $ "The group " <> groupRef <> " has no public link."
Right r -> do
ts <- getCurrentTime
tz <- getCurrentTimeZone
let resp = T.pack $ serializeChatResponse (Nothing, Just user) (config cc) ts tz Nothing r
sendReply $ "Unexpected error:\n" <> resp
Left e -> do
let resp = T.pack $ serializeChatError True (config cc) e
sendReply $ "Unexpected error:\n" <> resp
DCUnknownCommand -> sendReply "Unknown command"
DCCommandError tag -> sendReply $ "Command error: " <> tshow tag
where
@@ -894,26 +957,6 @@ directoryServiceEvent st opts@DirectoryOpts {adminUsers, superUsers, serviceName
_ -> sendReply $ "The group " <> groupRef <> " is not suspended, can't be resumed."
DCListLastGroups count -> listGroups count False
DCListPendingGroups count -> listGroups count True
DCShowGroupLink groupId gName -> do
let groupRef = groupReference' groupId gName
withGroupAndReg sendReply groupId gName $ \_ _ ->
sendChatCmd cc (APIGetGroupLink groupId) >>= \case
Right CRGroupLink {groupLink = GroupLink {connLinkContact = CCLink cReq _, acceptMemberRole}} ->
sendReply $ T.unlines
[ "The link to join the group " <> groupRef <> ":",
strEncodeTxt $ simplexChatContact cReq,
"New member role: " <> strEncodeTxt acceptMemberRole
]
Left (ChatErrorStore (SEGroupLinkNotFound _)) ->
sendReply $ "The group " <> groupRef <> " has no public link."
Right r -> do
ts <- getCurrentTime
tz <- getCurrentTimeZone
let resp = T.pack $ serializeChatResponse (Nothing, Just user) (config cc) ts tz Nothing r
sendReply $ "Unexpected error:\n" <> resp
Left e -> do
let resp = T.pack $ serializeChatError True (config cc) e
sendReply $ "Unexpected error:\n" <> resp
DCSendToGroupOwner groupId gName msg -> do
let groupRef = groupReference' groupId gName
withGroupAndReg sendReply groupId gName $ \_ gr@GroupReg {dbContactId} -> do
@@ -1054,11 +1097,11 @@ getGroupLink' :: ChatController -> User -> GroupInfo -> IO (Maybe GroupLink)
getGroupLink' cc user gInfo =
withDB "getGroupLink" cc $ \db -> getGroupLink db user gInfo
setGroupLinkRole :: ChatController -> GroupInfo -> GroupMemberRole -> IO (Maybe ConnReqContact)
setGroupLinkRole :: ChatController -> GroupInfo -> GroupMemberRole -> IO (Maybe CreatedLinkContact)
setGroupLinkRole cc GroupInfo {groupId} mRole = resp <$> sendChatCmd cc (APIGroupLinkMemberRole groupId mRole)
where
resp = \case
Right (CRGroupLink {groupLink = GroupLink {connLinkContact = CCLink gLink _sLnk}}) -> Just gLink
Right (CRGroupLink {groupLink = GroupLink {connLinkContact}}) -> Just connLinkContact
_ -> Nothing
unexpectedError :: Text -> Text
@@ -2,26 +2,119 @@
layout: layouts/article.html
title: "SimpleX Chat v6.4.1: welcome your contacts, review members to protect groups, and more."
date: 2025-07-29
# previewBody: blog_previews/20250308.html
# image: images/20250308-captcha.png
# imageBottom: true
draft: true
previewBody: blog_previews/20250729.html
image: images/20250729-join2.png
imageBottom: true
permalink: "/blog/20250729-simplex-chat-v6-4-1-welcome-contacts-protect-groups-app-security.html"
---
# SimpleX Chat v6.4.1: welcome your contacts, review members to protect groups, and more.
**Will be published:** Jul 29, 2025
This is a placeholder for upcoming v6.4.1 release announcement.
**Published:** Jul 29, 2025
**What's new in v6.4.1**:
TODO
- [welcome your contacts](#welcome-your-contacts-the-new-experience-of-making-connections): set your profile bio and welcome message.
- [protect your communities](#protect-your-groups) from spam and abuse:
- review new members ("knocking"),
- moderator role to delegate message moderation to trusted members,
- receive direct feedback from your group members.
- [other improvements](#other-improvements): set default time to delete messages for new contacts.
- [improved app integrity](#improved-app-integrity).
Also, we added 3 new interface languages to Android and desktop apps: Indonesian, Romanian and Vietnamese.
Huge thanks to our users who [contributed translations](https://github.com/simplex-chat/simplex-chat#help-translating-simplex-chat).
## What's new in v6.4.1
TODO
### Welcome your contacts: the new experience of making connections
<img src="./images/20250729-connect2.png" width="288" class="float-to-right"> <img src="./images/20250729-connect1.png" width="288" class="float-to-right">
The new simple way to connect to your friends is fully available in this version.
We received many compliments from our users who started using it in beta versions and in v6.4 about how it simplifies connecting with friends. We agree - this is the biggest UX revolution since the app was released.
Instead of connecting blindly, and waiting until your contact is online, as it was before, you can now see profile and welcome message of the person you connect to, before you connect.
When you tap Open new chat you can decide which profile to use to connect or if you want to connect incognito, and in some cases you can include a message with your connection request.
This way, the conversation with your friends starts even before they connect to you!
For previously created SimpleX addresses and group links you have an option to upgrade. The links will become short, and will include profile information into link data. Old long links will continue to work, so you won't lose any contacts or members during the upgrade.
These links are now short enough to be shared in your social media profiles - they are less than 80 characters.
And as before, it is as secure - servers cannot see you profiles, unless they have the link, and cannot modify them even if they somehow get the link. You can read more about security property and other technical details in our [post about SimpleX protocols extension](./20250703-simplex-network-protocol-extension-for-securely-connecting-people.md) supporting this new user experience.
Thank you for bringing your friends to SimpleX network!
### Protect your groups
<img src="./images/20250729-join2.png" width="288" class="float-to-right"> <img src="./images/20250729-join1.png" width="288" class="float-to-right">
**Review new members**
Since v6.4 there are some major improvements in your ability to protect your group from spam and abuse.
You can enable an option to review all new group members. It is also commonly called "knocking". It allows you to:
- ask prospective members any questions,
- explain the group rules,
- make sure their profile is appropriate for the group,
- decide whether to allow them joining the group, and whether they should be able to send messages in the group.
Some small groups may enable member review permanently, while larger public groups may enable it temporarily during spam/troll attacks.
**New role for group moderators**
In addition to that, there is a new group role - moderator.
This role allows:
- to approve members in review,
- moderate messages,
- block members for all.
Unlike admins, moderators can't add new members or permanently remove members from the group. This allows you to delegate group moderation to your community members without risking that they may disrupt the group.
**Receive direct feedback from group members**
Your group members now can send messages to group admins. Each conversation with a group member is a mini-group where all group owners, admins and moderators can talk to a member. Reports that members can send [since v6.3](./20250308-simplex-chat-v6-3-new-user-experience-safety-in-public-groups.md) are also added to chat with member, allowing you to discuss the report.
### Other improvements
**Enable disappearing messages for new contacts**
Now you can enable disappearing messages for all new contacts automatically. Tap your profile image in the corner, then tap Chat preferences and set time for messages to disappear.
**Improved message delivery**
We improved networking layer by increasing request timeouts for all background requests. It substantially reduces traffic on slow networks.
### Improved app integrity
**Supply chain security**
The app security depends on security of its components and its build process, and many of these components are created by third parties. In this version we improved the build process to control the upgrades of these components:
- all 3rd party GitHub actions used during the build are now moved to [the forks we control](https://github.com/simplex-chat?q=action&type=fork&sort=name) - it prevents supply chain attacks via build actions.
- we now build VLC library for all platforms from the source code ourselves, in [this repository](https://github.com/simplex-chat/vlc).
- SQLCipher and [Haskell dependencies](https://github.com/simplex-chat/simplex-chat/blob/stable/docs/dependencies/HASKELL.md) versions were already "locked" prior to this version.
**Automatic virus scanning**
We now run automatic daily virus scanning of all apps released via GitHub using [VirusTotal.com](https://www.virustotal.com/).
You can see the scan results [here](https://github.com/simplex-chat/simplex-virutstotal-scan).
**Reproducible builds**
In addition to [server builds](https://github.com/simplex-chat/simplexmq/releases/tag/v6.4.1) that were reproducible since v6.3, the builds of Linux CLI and desktop apps are now reproducible too. You can build Linux apps from source using [this script](https://github.com/simplex-chat/simplex-chat/blob/master/scripts/simplex-chat-reproduce-builds.sh).
*Please note*: Linux package upgrades may change the build.
Stable builds of Linux apps are now independently reproduced and [signed by our and Flux teams](https://github.com/simplex-chat/simplex-chat/releases/tag/v6.4.1) - it verifies the integrity of GitHub builds.
Huge thanks to [Flux](https://runonflux.com/) for doing that and for providing their servers via the app.
## SimpleX network
+16
View File
@@ -1,5 +1,21 @@
# Blog
Jul 29, 2025 [SimpleX Chat v6.4.1: welcome your contacts, review members to protect groups, and more.](./20250729-simplex-chat-v6-4-1-welcome-contacts-protect-groups-app-security.md)
What's new in v6.4.1:
- welcome your contacts: set your profile bio and welcome message.
- protect your communities from spam and abuse:
- review new members ("knocking"),
- moderator role to delegate message moderation to trusted members,
- receive direct feedback from your group members.
- set default time to delete messages for new contacts.
- improved app integrity: Linux app builds are now reproducible.
Also, we added 3 new interface languages to Android and desktop apps, thanks to our users: Indonesian, Romanian and Vietnamese.
---
Jul 3, 2025 [SimpleX network: new experience of connecting with people &mdash; available in SimpleX Chat v6.4-beta.4](./20250703-simplex-network-protocol-extension-for-securely-connecting-people.md)
Now you can start talking to your contacts much faster, as soon as you scan the link. This technical post covers the technology that enabled this new user experience &mdash; short links and associated data of messaging queues.
Binary file not shown.

After

Width:  |  Height:  |  Size: 498 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 588 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 229 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 207 KiB

+20
View File
@@ -82,6 +82,7 @@ This file is generated automatically.
- [FullPreferences](#fullpreferences)
- [GroupChatScope](#groupchatscope)
- [GroupChatScopeInfo](#groupchatscopeinfo)
- [GroupDirectInvitation](#groupdirectinvitation)
- [GroupFeature](#groupfeature)
- [GroupFeatureEnabled](#groupfeatureenabled)
- [GroupInfo](#groupinfo)
@@ -1595,6 +1596,7 @@ Error:
- contactRequestId: int64?
- contactGroupMemberId: int64?
- contactGrpInvSent: bool
- groupDirectInv: [GroupDirectInvitation](#groupdirectinvitation)?
- chatTags: [int64]
- chatItemTTL: int64?
- uiThemes: [UIThemeEntityOverrides](#uithemeentityoverrides)?
@@ -2032,6 +2034,18 @@ MemberSupport:
- groupMember_: [GroupMember](#groupmember)?
---
## GroupDirectInvitation
**Record type**:
- groupDirectInvLink: string
- fromGroupId_: int64?
- fromGroupMemberId_: int64?
- fromGroupMemberConnId_: int64?
- groupDirectInvStartedConnection: bool
---
## GroupFeature
@@ -2080,6 +2094,7 @@ MemberSupport:
- uiThemes: [UIThemeEntityOverrides](#uithemeentityoverrides)?
- customData: JSONObject?
- membersRequireAttention: int
- viaGroupLinkUri: string?
---
@@ -2810,6 +2825,10 @@ ProfileUpdated:
- fromProfile: [Profile](#profile)
- toProfile: [Profile](#profile)
GroupInvLinkReceived:
- type: "groupInvLinkReceived"
- groupProfile: [GroupProfile](#groupprofile)
---
@@ -3601,6 +3620,7 @@ Handshake:
- showNtfs: bool
- sendRcptsContacts: bool
- sendRcptsSmallGroups: bool
- autoAcceptMemberContacts: bool
- userMemberProfileUpdatedAt: UTCTime?
- uiThemes: [UIThemeEntityOverrides](#uithemeentityoverrides)?
+5 -1
View File
@@ -245,6 +245,7 @@ cliCommands =
"SendImage",
"SendLiveMessage",
"SendMemberContactMessage",
"AcceptMemberContact",
"SendMessage",
"SendMessageBroadcast",
"SendMessageQuote",
@@ -265,6 +266,7 @@ cliCommands =
"SetUserContactReceipts",
"SetUserFeature",
"SetUserGroupReceipts",
"SetUserAutoAcceptMemberContacts",
"SetUserTimedMessages",
"ShowChatItem",
"ShowChatItemInfo",
@@ -320,6 +322,8 @@ undocumentedCommands =
"APICreateChatItems",
"APICreateChatTag",
"APICreateMemberContact",
"APISendMemberContactInvitation",
"APIAcceptMemberContact",
"APIDeleteChatTag",
"APIDeleteMemberSupportChat",
"APIDeleteReceivedReports",
@@ -370,7 +374,6 @@ undocumentedCommands =
"APISendCallExtraInfo",
"APISendCallInvitation",
"APISendCallOffer",
"APISendMemberContactInvitation",
"APISetAppFilePaths",
"APISetChatItemTTL",
"APISetChatSettings",
@@ -390,6 +393,7 @@ undocumentedCommands =
"APISetServerOperators",
"APISetUserContactReceipts",
"APISetUserGroupReceipts",
"APISetUserAutoAcceptMemberContacts",
"APISetUserServers",
"APISetUserUIThemes",
"APIStandaloneFileInfo",
+1
View File
@@ -171,6 +171,7 @@ undocumentedResponses =
"CRNetworkStatuses",
"CRNewMemberContact",
"CRNewMemberContactSentInv",
"CRMemberContactAccepted",
"CRNewPreparedChat",
"CRNtfConns",
"CRNtfToken",
+4 -1
View File
@@ -1,4 +1,5 @@
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedLists #-}
module API.Docs.Syntax.Types where
@@ -27,4 +28,6 @@ isConst = \case
instance IsString Expr where fromString = Const
instance Semigroup Expr where sconcat = Concat
instance Semigroup Expr where
sconcat = Concat
x <> y = Concat [x, y]
+3 -1
View File
@@ -255,7 +255,7 @@ chatTypesDocsData =
(sti @FileProtocol, (STEnum' $ consLower "FP"), "", [], "", ""),
(sti @FileStatus, STEnum, "FS", [], "", ""),
(sti @FileTransferMeta, STRecord, "", [], "", ""),
(sti @Format, STUnion, "", [], "", ""),
(sti @Format, STUnion, "", ["Unknown"], "", ""),
(sti @FormattedText, STRecord, "", [], "", ""),
(sti @FullGroupPreferences, STRecord, "", [], "", ""),
(sti @FullPreferences, STRecord, "", [], "", ""),
@@ -302,6 +302,7 @@ chatTypesDocsData =
(sti @PrefEnabled, STRecord, "", [], "", ""),
(sti @Preferences, STRecord, "", [], "", ""),
(sti @PreparedContact, STRecord, "", [], "", ""),
(sti @GroupDirectInvitation, STRecord, "", [], "", ""),
(sti @PreparedGroup, STRecord, "", [], "", ""),
(sti @Profile, STRecord, "", [], "", ""),
(sti @ProxyClientError, STUnion, "Proxy", [], "", ""),
@@ -492,6 +493,7 @@ deriving instance Generic PendingContactConnection
deriving instance Generic PrefEnabled
deriving instance Generic Preferences
deriving instance Generic PreparedContact
deriving instance Generic GroupDirectInvitation
deriving instance Generic PreparedGroup
deriving instance Generic Profile
deriving instance Generic ProxyClientError
+1
View File
@@ -170,6 +170,7 @@ toTypeInfo tr =
"FormatColor" -> ST "Color" []
"CustomData" -> ST "JSONObject" []
"KeyMap" -> ST "JSONObject" []
"Value" -> ST "JSONObject" []
"CIQDirection" -> ST "CIDirection" []
"SendRef" -> ST "ChatRef" []
t
+1 -1
View File
@@ -12,7 +12,7 @@ constraints: zip +disable-bzip2 +disable-zstd
source-repository-package
type: git
location: https://github.com/simplex-chat/simplexmq.git
tag: 846be50f72c1bfbbd70a98e9edf25c0a2d9d4234
tag: db325cb81f77652471a27f4331143982739f9f10
source-repository-package
type: git
@@ -0,0 +1,228 @@
# Super-peer groups MVP
## Priorities
1. migration to super-peer protocol for groups, min. protocol for choice of super-peer member
2. decrease number of connections, decrease traffic for senders - super-peer message delivery
3. optimize postgres client
4. availability of past messages, skipped messages - conversation pagination via requests to super-peers
5. \* comment threads (subchannels)
6. \* rework group links -> shared group link - ownership to owners, operation to super-peers? or point 10? (initially HA admin is ok)
7. \* multiple super-peers for redundancy, load balancing (decision to deliver based on number of super-peers)
8. \* more advanced management of super-peer list (create, add, choose, delete)
9. \* protect super-peers from abuse - rate limiting, banning (via client restrictions?)
10. \* discovery server (member) language and image recognition, pre-moderation of messages
> an advertised link to join the group should be controlled by discovery server (so that the group owners can't make discovery server see a content that is different from the actual group content).
11. \* features - ability to conceal member list, scheduled posts
12. \* automated moderation via members reputation score (observer -> member, image posts, more frequent posts)
13. \* authorization of admin changes (have owners and admins sign / wait for delivery from multiple super-peers)
14. \* super-peers to prioritize processing owner > admin > moderator commands/messages (priority to connections)
15. \* integrity of group state (member list > profile > messages) between super-peers
\* not MVP
## Design and implementation ideas
### 1. Migration to super-peer protocol for groups, min. protocol for choice of super-peer member
- Allow owner to assign member as super-peer. In practice many groups have single owner.
- Alternatively protocol to accept and approve role changes is necessary, as it should not be possible to unilaterally appoint some member to be a super-peer? Not necessary.
- Client to have choice to accept/reject becoming super-peer.
- Not necessary to do UI, as regular users aren't highly available clients anyway. They will ignore offer to be super-peer.
- Client to have configuration to auto-accept (or manually) super-peer offer. HA clients can be run with it - directory service.
- In practice to make transition we would recommend owners of current directory groups to choose directory service as super-peer. Another advantage of this approach is that directory service already hosts links.
- Possibly create a "super-peer" bot that can be chosen. Recommend (hardcode?) creating a link via it.
- Multi-host group links are not necessary initially - users will be joining directly to single super-peer.
- Remove ability to add contact via interface? Or for super-peer group it should share group link / introduce to super-peer, and allow all members to invite? Not necessarily MVP, maybe removing ability to add for admins is enough. Instead we could have super-peer link to be included in group profile / description. Pinned?
- Clients to delete connections (probably background job) once super-peer is appointed. Potentially disruptive but will greatly reduce subscription load. We could make warning to owner that it's experimental feature and it's irreversible, at least during beta. Also automatically post warning in group with super-peer's group link to rejoin in case of disruption.
### 2. Decrease number of connections, decrease traffic for senders - super-peer message delivery
- We already have group forwarding - simply have to change rules for forwarding for super-peer groups: only super-peer forwards; other admins don't forward; super-peer forwards messages always, not only for not connected members (simplifies filtering on forwarding).
- New members are never introduced to other members in order to establish connections. Instead all new members join to super-peer via its group link.
- Instead introduction (in previous sense) is replaced with sharing "member records" - profiles and member IDs. Existing members receive new "member record".
- Sub protocol for inviting new members via sharing super-peer link (same considerations as above).
- We may need more robust processing for forwarded messages - more events / edge cases.
### 3. Optimize postgres client
- Connection pool.
- Optimization of indexes (different from SQLite) may be required.
- Many small queries may have to be reworked into large queries in some cases.
### 4. Availability of past messages, skipped messages - conversation pagination via requests to super-peers
- Protocol to paginate group conversation.
- Based on shared msg id? item ts?
- Response batches messages.
- Rate limit? Probably not MVP.
## Super-peer agreement protocol
This protocol draft is for larger scope MVP that includes short links.
The main idea is that public groups should have identity, that is defined via a permanent link to them, and that only owner(s) should be able to control group identity and link. This link is a short link either to SMP blob (see simplexmq rfcs on blob extensions), or to an XFTP file (requires indefinitely long storage). For clarity, to distinguish from per super-peer group links used for establishing connections with super-peers, it will be further called "short link".
Short link points to a blob/file containing:
- Super-peer group links,
- Owners' public keys for verifying ownership transfer and other administrative actions,
- Other group metadata as required by further clarifications to protocol.
UX for creating a public group should be straightforward:
1. Select operators, whose super-peers to use, or optionally custom configured super-peers.
2. Create group, which generates short link and invites super-peers to it. Connection progress is shown for each super-peer.
3. Confirm creation, once super-peers connected. Super-peer can fail to connect, at least one connected super-peer is required for confirmation.
4. Share link for members to join.
Super-peers are pre-configured in app for preset operators. User can also add self-hosted or other known super-peers to custom configuration. Super-peer should have a SimpleX address to receive group join requests.
Protocol for creating public group (happy path):
1. Group owner's client (further owner) creates group record locally.
2. Owner sends contact requests to selected super-peers SimpleX addresses. These contact requests are essentially invitations to be super-peers in this group. ConnInfo sent in these contact requests (INV) contains group invitation details (XGrpInv with added fields, or new specific protocol message - TBC).
3. Super-peers receive these requests. They generate new group links specifically for this group, to serve as a point of connection to them for new members.
4. Super-peers accept requests, sending generated group links in confirmation (CONF) ConnInfos.
5. Owner packages super-peers group links and other group metadata into blob.
6. Owner uploads this blob to one of their SMP servers, creating short link.
7. Owner shares short link publicly or with selected new members.
8. New members retrieve blob via short link.
9. New members connect to super-peers via group links specified in the blob.
```
Owner SMP Owner Super-peers Super-peers SMP New members
| | | | |
| |1. create group| | | |
| | | | |
| |2. contact requests| | |
| | (INV, group inv.) | | |
| |------------------>| | |
| | | 3. create group | |
| | | links | |
| | |------------------>| |
| | |<------------------| |
| | | new addresses | |
| |4. accept requests | | |
| |(CONF, group links)| | |
| |<------------------| | |
| | | | |
| |5. package blob| | | |
| | | | |
| 6. upload blob | | | |
|<------------------| | | |
|------------------>| | | |
| short link | | | |
| | 7. short link (oob) |
| |~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ >|
| | | | |
| 8. retrieve blob |
|<------------------------------------------------------------------------------|
|------------------------------------------------------------------------------>|
| blob with super-peers group links |
| | | | |
| | | 9. connect via group links |
| | |<--------------------------------------|
| | | | |
* * * * *
```
On client side super-peer is a specific user profile, which can be created in a hosted CLI client, or in a highly available desktop app. Super-peer user is programmed to accept incoming requests to join groups as super-peer. It's hidden from regular user list and requires specific API and UI for management.
```sql
ALTER TABLE users ADD COLUMN superpeer INTEGER NOT NULL DEFAULT 0;
```
In user clients super-peer is an invisible group member, that is prohibited to send its own messages, but allowed to forward all messages between group members. It's also hidden from group member list.
```sql
ALTER TABLE group_members ADD COLUMN superpeer INTEGER NOT NULL DEFAULT 0;
```
If group has more than one active super-peer, owner can remove super-peer from group by removing its group link from short link's blob, which means new members will not use it to connect. Owner also should issue message to members to delete connections with removed super-peer, and to super-peer to leave group.
Problems:
- To prevent abuse from owner, super-peer can periodically or on each group join check short link for presence of its group link. If it's absent, it should delete group link, and after some time stop forwarding messages in group and leave it, see next point.
- If group has only one super-peer, fully removing it from group should not be possible until new super-peer \[fully?\] connects to \[all? active?\] existing group members. For this, current super-peer has to remain in group in order to introduce members to new super-peer. At the very least, current super-peer should forward owner's message with new super peer's group link to members. Better, to prevent downtimes or failures in delivery, current super-peer should wait for confirmations of connection from members.
- If group has a single super-peer, or only super-peers of select operators, nothing prevents these super-peers (operators) from effectively deleting group by destroying all connections with members. So if operators adhere to the same moderating/banning policies, group is not protected from censorship unless it uses self-hosted or other custom configured super-peers. Even then, if group used at least one super-peer of select operators, group owner is subject to potential client restrictions.
### Removing super-peer from group
If group has a single super-peer, owner has to add a new one before removing it. Protocol for removing single super-peer from group:
1. Owner adds new super-peer to group and connects with it (as above).
2. New super-peer connects with current super-peer and starts to synchronize its group state, including group history and member profiles.
- TBC group state to synchronize: full or partial history, additional metadata?
3. Owner updates short link: adds new super-peer group link to it, removes or marks as disabled current super-peer.
4. Owner announces deleting current and adding new super-peer to group.
- Via both super-peers - current would forward to existing members, new would forward to newly joined.
- Separate messages or single specialized message ("replace")?
5. Members that have received this message start connecting with new super-peer.
6. Once group state is synchronized, current (removed) super-peer deletes connections with members.
- To be clarified, protocol for synchronizing group state between super-peers.
7. Members that haven't received announcement via removed super-peer (for example, they were offline), receive AUTH errors on subscription to connection with it. Knowing it is a super-peer connection to a specific group, they retrieve new super-peer group link from updated blob via short link and connect to it.
```
Owner SMP Owner Current super-peer New super-peer Members
| | | | |
| | 1. connect (add to group) | |
| |-------------------------------------->| |
| |<--------------------------------------| |
| | new address for this group | |
| | | | |
| | | 2. connect, | |
| | |start synchronizing| |
| | |<----------------->| |
| 3. update blob | | | |
| by short link | | | |
| (new, disabled | | | |
| super-peers) | | | |
|<------------------| | | |
|------------------>| | | |
| OK | | | |
| | 4. announce removing current and |
| | adding new super-peer |
| |---------------------------------------------------------->|
| | | | |
| | | | 5. connect |
| | | | (members who re- |
| | | |ceived announcemnt)|
| | | |<----------------->|
| | | | |
| | [ state is synchronized ] |
| | | | |
| | |6. delete connections| | |
| | | | |
| | | 7. subscribe (members who |
| | | didn't receive announcement) |
| | |<--------------------------------------|
| | |-------------------------------------->|
| | | AUTH error (from SMP) |
| 7. retrieve updated blob |
|<------------------------------------------------------------------------------|
|------------------------------------------------------------------------------>|
| blob with new super-peer group link |
| | | | 7. connect |
| | | |<----------------->|
| | | | |
* * * * *
```
The advantage of this approach is that current super-peer doesn't have to wait for new super-peer to connect to existing members, which can take arbitrary time if they are offline, or even never complete if they don't come online.
If group has more than one active super-peer, owner can remove a super-peer from group immediately.
### Member profile accounting, group statistics
Super-peers don't broadcast all member profiles on introduction, instead they keep accounting of which member profiles were shared to which members, and when forwarding messages also send profiles to members who haven't received them before. Regular members don't see full list of member profiles, only overall number of members and list of profiles of actively participating members (who send messages).
Even without addition of new super-peer, current super-peers can synchronize state by forwarding all messages to each other.
Periodically super-peers send group statistics to owner:
- Number of actively participating members - those who send messages and whose profiles were shared to other members (known via shared profile accounting).
- Number of connected members - members to whom super-peer forwards messages.
- Number of inactive members - members to whom super-peer currently doesn't forward messages due to inactivity. Super-peer considers member inactive if it received their profile from previous super-peer and new member hasn't connected, or due to QUOTA error inactivity. These reasons could be differentiated. Perhaps number of members with QUOTA error inactivity should be a sub-count of connected members.
Owner client can show aggregated statistics and detailed statistics for each super-peer.

Some files were not shown because too many files have changed in this diff Show More