Added linting for the localized strings, updated the quote & mention behaviour for the current user
Added a script and build step to error if we have localised a string in code bug don't have an entry in the localisable files Added the logic and UI to replace the current users public key (or blinded key) with 'You' in mentions and quotes Cleaned up some duplicate & missing localised strings Fixed a bug where new closed groups weren't getting setup locally correctly Updated the id truncating behaviour to always truncate from the middle
This commit is contained in:
parent
5b6be3912d
commit
3c07a2d044
|
@ -0,0 +1,251 @@
|
|||
#!/usr/bin/xcrun --sdk macosx swift
|
||||
|
||||
//
|
||||
// ListLocalizableStrings.swift
|
||||
// Archa
|
||||
//
|
||||
// Created by Morgan Pretty on 18/5/20.
|
||||
// Copyright © 2020 Archa. All rights reserved.
|
||||
//
|
||||
// This script is based on https://github.com/ginowu7/CleanSwiftLocalizableExample the main difference
|
||||
// is canges to the localized usage regex
|
||||
|
||||
import Foundation
|
||||
|
||||
let fileManager = FileManager.default
|
||||
let currentPath = (
|
||||
ProcessInfo.processInfo.environment["PROJECT_DIR"] ?? fileManager.currentDirectoryPath
|
||||
)
|
||||
|
||||
/// List of files in currentPath - recursive
|
||||
var pathFiles: [String] = {
|
||||
guard let enumerator = fileManager.enumerator(atPath: currentPath), let files = enumerator.allObjects as? [String] else {
|
||||
fatalError("Could not locate files in path directory: \(currentPath)")
|
||||
}
|
||||
|
||||
return files
|
||||
}()
|
||||
|
||||
|
||||
/// List of localizable files - not including Localizable files in the Pods
|
||||
var localizableFiles: [String] = {
|
||||
return pathFiles
|
||||
.filter {
|
||||
$0.hasSuffix("Localizable.strings") &&
|
||||
!$0.contains(".app/") && // Exclude Built Localizable.strings files
|
||||
!$0.contains("Pods") // Exclude Pods
|
||||
}
|
||||
}()
|
||||
|
||||
|
||||
/// List of executable files
|
||||
var executableFiles: [String] = {
|
||||
return pathFiles.filter {
|
||||
!$0.localizedCaseInsensitiveContains("test") && // Exclude test files
|
||||
!$0.contains(".app/") && // Exclude Built Localizable.strings files
|
||||
!$0.contains("Pods") && // Exclude Pods
|
||||
(
|
||||
NSString(string: $0).pathExtension == "swift" ||
|
||||
NSString(string: $0).pathExtension == "m"
|
||||
)
|
||||
}
|
||||
}()
|
||||
|
||||
/// Reads contents in path
|
||||
///
|
||||
/// - Parameter path: path of file
|
||||
/// - Returns: content in file
|
||||
func contents(atPath path: String) -> String {
|
||||
print("Path: \(path)")
|
||||
guard let data = fileManager.contents(atPath: path), let content = String(data: data, encoding: .utf8) else {
|
||||
fatalError("Could not read from path: \(path)")
|
||||
}
|
||||
|
||||
return content
|
||||
}
|
||||
|
||||
/// Returns a list of strings that match regex pattern from content
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - pattern: regex pattern
|
||||
/// - content: content to match
|
||||
/// - Returns: list of results
|
||||
func regexFor(_ pattern: String, content: String) -> [String] {
|
||||
guard let regex = try? NSRegularExpression(pattern: pattern, options: []) else {
|
||||
fatalError("Regex not formatted correctly: \(pattern)")
|
||||
}
|
||||
|
||||
let matches = regex.matches(in: content, options: [], range: NSRange(location: 0, length: content.utf16.count))
|
||||
|
||||
return matches.map {
|
||||
guard let range = Range($0.range(at: 0), in: content) else {
|
||||
fatalError("Incorrect range match")
|
||||
}
|
||||
|
||||
return String(content[range])
|
||||
}
|
||||
}
|
||||
|
||||
func create() -> [LocalizationStringsFile] {
|
||||
return localizableFiles.map(LocalizationStringsFile.init(path:))
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
/// - Returns: A list of LocalizationCodeFile - contains path of file and all keys in it
|
||||
func localizedStringsInCode() -> [LocalizationCodeFile] {
|
||||
return executableFiles.compactMap {
|
||||
let content = contents(atPath: $0)
|
||||
// Note: Need to exclude escaped quotation marks from strings
|
||||
let matchesOld = regexFor("(?<=NSLocalizedString\\()\\s*\"(?!.*?%d)(.*?)\"", content: content)
|
||||
let matchesNew = regexFor("\"(?!.*?%d)([^(\\\")]*?)\"(?=\\s*)(?=\\.localized)", content: content)
|
||||
let allMatches = (matchesOld + matchesNew)
|
||||
|
||||
return allMatches.isEmpty ? nil : LocalizationCodeFile(path: $0, keys: Set(allMatches))
|
||||
}
|
||||
}
|
||||
|
||||
/// Throws error if ALL localizable files does not have matching keys
|
||||
///
|
||||
/// - Parameter files: list of localizable files to validate
|
||||
func validateMatchKeys(_ files: [LocalizationStringsFile]) {
|
||||
print("------------ Validating keys match in all localizable files ------------")
|
||||
|
||||
guard let base = files.first, files.count > 1 else { return }
|
||||
|
||||
let files = Array(files.dropFirst())
|
||||
|
||||
files.forEach {
|
||||
guard let extraKey = Set(base.keys).symmetricDifference($0.keys).first else { return }
|
||||
let incorrectFile = $0.keys.contains(extraKey) ? $0 : base
|
||||
printPretty("error: Found extra key: \(extraKey) in file: \(incorrectFile.path)")
|
||||
}
|
||||
}
|
||||
|
||||
/// Throws error if localizable files are missing keys
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - codeFiles: Array of LocalizationCodeFile
|
||||
/// - localizationFiles: Array of LocalizableStringFiles
|
||||
func validateMissingKeys(_ codeFiles: [LocalizationCodeFile], localizationFiles: [LocalizationStringsFile]) {
|
||||
print("------------ Checking for missing keys -----------")
|
||||
|
||||
guard let baseFile = localizationFiles.first else {
|
||||
fatalError("Could not locate base localization file")
|
||||
}
|
||||
|
||||
let baseKeys = Set(baseFile.keys)
|
||||
|
||||
codeFiles.forEach {
|
||||
let extraKeys = $0.keys.subtracting(baseKeys)
|
||||
if !extraKeys.isEmpty {
|
||||
printPretty("error: Found keys in code missing in strings file: \(extraKeys) from \($0.path)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Throws warning if keys exist in localizable file but are not being used
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - codeFiles: Array of LocalizationCodeFile
|
||||
/// - localizationFiles: Array of LocalizableStringFiles
|
||||
func validateDeadKeys(_ codeFiles: [LocalizationCodeFile], localizationFiles: [LocalizationStringsFile]) {
|
||||
print("------------ Checking for any dead keys in localizable file -----------")
|
||||
|
||||
guard let baseFile = localizationFiles.first else {
|
||||
fatalError("Could not locate base localization file")
|
||||
}
|
||||
|
||||
let baseKeys: Set<String> = Set(baseFile.keys)
|
||||
let allCodeFileKeys: [String] = codeFiles.flatMap { $0.keys }
|
||||
let deadKeys: [String] = Array(baseKeys.subtracting(allCodeFileKeys))
|
||||
.sorted()
|
||||
.map { $0.trimmingCharacters(in: CharacterSet(charactersIn: "\"")) }
|
||||
|
||||
if !deadKeys.isEmpty {
|
||||
printPretty("warning: \(deadKeys) - Suggest cleaning dead keys")
|
||||
}
|
||||
}
|
||||
|
||||
protocol Pathable {
|
||||
var path: String { get }
|
||||
}
|
||||
|
||||
struct LocalizationStringsFile: Pathable {
|
||||
let path: String
|
||||
let kv: [String: String]
|
||||
|
||||
var keys: [String] {
|
||||
return Array(kv.keys)
|
||||
}
|
||||
|
||||
init(path: String) {
|
||||
self.path = path
|
||||
self.kv = ContentParser.parse(path)
|
||||
}
|
||||
|
||||
/// Writes back to localizable file with sorted keys and removed whitespaces and new lines
|
||||
func cleanWrite() {
|
||||
print("------------ Sort and remove whitespaces: \(path) ------------")
|
||||
let content = kv.keys.sorted().map { "\($0) = \(kv[$0]!);" }.joined(separator: "\n")
|
||||
try! content.write(toFile: path, atomically: true, encoding: .utf8)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
struct LocalizationCodeFile: Pathable {
|
||||
let path: String
|
||||
let keys: Set<String>
|
||||
}
|
||||
|
||||
struct ContentParser {
|
||||
|
||||
/// Parses contents of a file to localizable keys and values - Throws error if localizable file have duplicated keys
|
||||
///
|
||||
/// - Parameter path: Localizable file paths
|
||||
/// - Returns: localizable key and value for content at path
|
||||
static func parse(_ path: String) -> [String: String] {
|
||||
print("------------ Checking for duplicate keys: \(path) ------------")
|
||||
|
||||
let content = contents(atPath: path)
|
||||
let trimmed = content
|
||||
.replacingOccurrences(of: "\n+", with: "", options: .regularExpression, range: nil)
|
||||
.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
let keys = regexFor("\"([^\"]*?)\"(?= =)", content: trimmed)
|
||||
let values = regexFor("(?<== )\"(.*?)\"(?=;)", content: trimmed)
|
||||
|
||||
if keys.count != values.count {
|
||||
fatalError("Error parsing contents: Make sure all keys and values are in correct format (this could be due to extra spaces between keys and values)")
|
||||
}
|
||||
|
||||
return zip(keys, values).reduce(into: [String: String]()) { results, keyValue in
|
||||
if results[keyValue.0] != nil {
|
||||
printPretty("error: Found duplicate key: \(keyValue.0) in file: \(path)")
|
||||
abort()
|
||||
}
|
||||
results[keyValue.0] = keyValue.1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func printPretty(_ string: String) {
|
||||
print(string.replacingOccurrences(of: "\\", with: ""))
|
||||
}
|
||||
|
||||
let stringFiles = create()
|
||||
|
||||
if !stringFiles.isEmpty {
|
||||
print("------------ Found \(stringFiles.count) file(s) ------------")
|
||||
|
||||
stringFiles.forEach { print($0.path) }
|
||||
validateMatchKeys(stringFiles)
|
||||
|
||||
// Note: Uncomment the below file to clean out all comments from the localizable file (we don't want this because comments make it readable...)
|
||||
// stringFiles.forEach { $0.cleanWrite() }
|
||||
|
||||
let codeFiles = localizedStringsInCode()
|
||||
validateMissingKeys(codeFiles, localizationFiles: stringFiles)
|
||||
validateDeadKeys(codeFiles, localizationFiles: stringFiles)
|
||||
}
|
||||
|
||||
print("------------ SUCCESS ------------")
|
|
@ -781,6 +781,7 @@
|
|||
FDD250702837199200198BDA /* GarbageCollectionJob.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDD2506F2837199200198BDA /* GarbageCollectionJob.swift */; };
|
||||
FDD250722837234B00198BDA /* MediaGalleryNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDD250712837234B00198BDA /* MediaGalleryNavigationController.swift */; };
|
||||
FDE72118286C156E0093DF33 /* ChatSettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDE72117286C156E0093DF33 /* ChatSettingsViewController.swift */; };
|
||||
FDE72154287FE4470093DF33 /* HighlightMentionBackgroundView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDE72153287FE4470093DF33 /* HighlightMentionBackgroundView.swift */; };
|
||||
FDE77F6B280FEB28002CFC5D /* ControlMessageProcessRecord.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDE77F6A280FEB28002CFC5D /* ControlMessageProcessRecord.swift */; };
|
||||
FDED2E3C282E1B5D00B2CD2A /* UICollectionView+ReusableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDED2E3B282E1B5D00B2CD2A /* UICollectionView+ReusableView.swift */; };
|
||||
FDF0B73C27FFD3D6004C14C5 /* LinkPreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDF0B73B27FFD3D6004C14C5 /* LinkPreview.swift */; };
|
||||
|
@ -1811,6 +1812,9 @@
|
|||
FDD2506F2837199200198BDA /* GarbageCollectionJob.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GarbageCollectionJob.swift; sourceTree = "<group>"; };
|
||||
FDD250712837234B00198BDA /* MediaGalleryNavigationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaGalleryNavigationController.swift; sourceTree = "<group>"; };
|
||||
FDE72117286C156E0093DF33 /* ChatSettingsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatSettingsViewController.swift; sourceTree = "<group>"; };
|
||||
FDE7214F287E50D50093DF33 /* ProtoWrappers.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = ProtoWrappers.py; sourceTree = "<group>"; };
|
||||
FDE72150287E50D50093DF33 /* LintLocalizableStrings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LintLocalizableStrings.swift; sourceTree = "<group>"; };
|
||||
FDE72153287FE4470093DF33 /* HighlightMentionBackgroundView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HighlightMentionBackgroundView.swift; sourceTree = "<group>"; };
|
||||
FDE77F68280F9EDA002CFC5D /* JobRunnerError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JobRunnerError.swift; sourceTree = "<group>"; };
|
||||
FDE77F6A280FEB28002CFC5D /* ControlMessageProcessRecord.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ControlMessageProcessRecord.swift; sourceTree = "<group>"; };
|
||||
FDED2E3B282E1B5D00B2CD2A /* UICollectionView+ReusableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UICollectionView+ReusableView.swift"; sourceTree = "<group>"; };
|
||||
|
@ -2436,6 +2440,7 @@
|
|||
4C4AEC4420EC343B0020E72B /* DismissableTextField.swift */,
|
||||
45E5A6981F61E6DD001E4A8A /* MarqueeLabel.swift */,
|
||||
34386A53207D271C009F5D9C /* NeverClearView.swift */,
|
||||
FDE72153287FE4470093DF33 /* HighlightMentionBackgroundView.swift */,
|
||||
34F308A01ECB469700BB7697 /* OWSBezierPathView.h */,
|
||||
34F308A11ECB469700BB7697 /* OWSBezierPathView.m */,
|
||||
34330AA11E79686200DF2FB9 /* OWSProgressView.h */,
|
||||
|
@ -3306,6 +3311,7 @@
|
|||
FD83B9BC27CF2215005E1583 /* SharedTest */,
|
||||
FDC4388F27B9FFC700C60D73 /* SessionMessagingKitTests */,
|
||||
FD83B9B027CF200A005E1583 /* SessionUtilitiesKitTests */,
|
||||
FDE7214E287E50D50093DF33 /* Scripts */,
|
||||
D221A08C169C9E5E00537ABF /* Frameworks */,
|
||||
D221A08A169C9E5E00537ABF /* Products */,
|
||||
2BADBA206E0B8D297E313FBA /* Pods */,
|
||||
|
@ -3871,6 +3877,15 @@
|
|||
path = Utilities;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
FDE7214E287E50D50093DF33 /* Scripts */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
FDE7214F287E50D50093DF33 /* ProtoWrappers.py */,
|
||||
FDE72150287E50D50093DF33 /* LintLocalizableStrings.swift */,
|
||||
);
|
||||
path = Scripts;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
FDF0B7452804F0A8004C14C5 /* Types */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -4141,6 +4156,7 @@
|
|||
buildConfigurationList = D221A0BC169C9E5F00537ABF /* Build configuration list for PBXNativeTarget "Session" */;
|
||||
buildPhases = (
|
||||
0401967CF3320CC84B175A3B /* [CP] Check Pods Manifest.lock */,
|
||||
FDE7214D287E50820093DF33 /* Lint Localizable.strings */,
|
||||
D221A085169C9E5E00537ABF /* Sources */,
|
||||
D221A086169C9E5E00537ABF /* Frameworks */,
|
||||
D221A087169C9E5E00537ABF /* Resources */,
|
||||
|
@ -4768,6 +4784,25 @@
|
|||
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
FDE7214D287E50820093DF33 /* Lint Localizable.strings */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "Lint Localizable.strings";
|
||||
outputFileListPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${SRCROOT}/Scripts/LintLocalizableStrings.swift\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
|
@ -5261,6 +5296,7 @@
|
|||
7B1581E6271FD2A100848B49 /* VideoPreviewVC.swift in Sources */,
|
||||
B83F2B88240CB75A000A54AB /* UIImage+Scaling.swift in Sources */,
|
||||
3430FE181F7751D4000EC51B /* GiphyAPI.swift in Sources */,
|
||||
FDE72154287FE4470093DF33 /* HighlightMentionBackgroundView.swift in Sources */,
|
||||
340FC8AA204DAC8D007AEB0F /* NotificationSettingsViewController.m in Sources */,
|
||||
4C090A1B210FD9C7001FD7F9 /* HapticFeedback.swift in Sources */,
|
||||
34F308A21ECB469700BB7697 /* OWSBezierPathView.m in Sources */,
|
||||
|
|
|
@ -40,8 +40,7 @@ public final class SessionCallManager: NSObject, CallManagerProtocol {
|
|||
}
|
||||
|
||||
static func buildProviderConfiguration(useSystemCallLog: Bool) -> CXProviderConfiguration {
|
||||
let localizedName = NSLocalizedString("APPLICATION_NAME", comment: "Name of application")
|
||||
let providerConfiguration = CXProviderConfiguration(localizedName: localizedName)
|
||||
let providerConfiguration = CXProviderConfiguration(localizedName: "Session")
|
||||
providerConfiguration.supportsVideo = true
|
||||
providerConfiguration.maximumCallGroups = 1
|
||||
providerConfiguration.maximumCallsPerCallGroup = 1
|
||||
|
|
|
@ -86,7 +86,10 @@ public class ConversationViewModel: OWSAudioPlayerDelegate {
|
|||
// also want to skip the initial query and trigger it async so that the push animation
|
||||
// doesn't stutter (it should load basically immediately but without this there is a
|
||||
// distinct stutter)
|
||||
self.pagedDataObserver = self.setupPagedObserver(for: threadId)
|
||||
self.pagedDataObserver = self.setupPagedObserver(
|
||||
for: threadId,
|
||||
userPublicKey: getUserHexEncodedPublicKey()
|
||||
)
|
||||
|
||||
// Run the initial query on a background thread so we don't block the push transition
|
||||
DispatchQueue.global(qos: .default).async { [weak self] in
|
||||
|
@ -164,7 +167,7 @@ public class ConversationViewModel: OWSAudioPlayerDelegate {
|
|||
}
|
||||
}
|
||||
|
||||
private func setupPagedObserver(for threadId: String) -> PagedDatabaseObserver<Interaction, MessageViewModel> {
|
||||
private func setupPagedObserver(for threadId: String, userPublicKey: String) -> PagedDatabaseObserver<Interaction, MessageViewModel> {
|
||||
return PagedDatabaseObserver(
|
||||
pagedTable: Interaction.self,
|
||||
pageSize: ConversationViewModel.pageSize,
|
||||
|
@ -201,6 +204,7 @@ public class ConversationViewModel: OWSAudioPlayerDelegate {
|
|||
groupSQL: MessageViewModel.groupSQL,
|
||||
orderSQL: MessageViewModel.orderSQL,
|
||||
dataQuery: MessageViewModel.baseQuery(
|
||||
userPublicKey: userPublicKey,
|
||||
orderSQL: MessageViewModel.orderSQL,
|
||||
groupSQL: MessageViewModel.groupSQL
|
||||
),
|
||||
|
@ -316,7 +320,8 @@ public class ConversationViewModel: OWSAudioPlayerDelegate {
|
|||
// it's the last element in the 'sortedData' array
|
||||
index == (sortedData.count - 1) &&
|
||||
pageInfo.pageOffset == 0
|
||||
)
|
||||
),
|
||||
currentUserBlindedPublicKey: threadData.currentUserBlindedPublicKey
|
||||
)
|
||||
}
|
||||
.appending(typingIndicator)
|
||||
|
@ -491,7 +496,10 @@ public class ConversationViewModel: OWSAudioPlayerDelegate {
|
|||
|
||||
self.threadId = updatedThreadId
|
||||
self.observableThreadData = self.setupObservableThreadData(for: updatedThreadId)
|
||||
self.pagedDataObserver = self.setupPagedObserver(for: updatedThreadId)
|
||||
self.pagedDataObserver = self.setupPagedObserver(
|
||||
for: updatedThreadId,
|
||||
userPublicKey: getUserHexEncodedPublicKey()
|
||||
)
|
||||
|
||||
// Try load everything up to the initial visible message, fallback to just the initial page of messages
|
||||
// if we don't have one
|
||||
|
|
|
@ -228,6 +228,8 @@ final class InputView: UIView, InputViewButtonDelegate, InputTextViewDelegate, M
|
|||
authorId: quoteDraftInfo.model.authorId,
|
||||
quotedText: quoteDraftInfo.model.body,
|
||||
threadVariant: threadVariant,
|
||||
currentUserPublicKey: nil,
|
||||
currentUserBlindedPublicKey: nil,
|
||||
direction: (quoteDraftInfo.isOutgoing ? .outgoing : .incoming),
|
||||
attachment: quoteDraftInfo.model.attachment,
|
||||
hInset: hInset,
|
||||
|
|
|
@ -28,6 +28,8 @@ final class QuoteView: UIView {
|
|||
authorId: String,
|
||||
quotedText: String?,
|
||||
threadVariant: SessionThread.Variant,
|
||||
currentUserPublicKey: String?,
|
||||
currentUserBlindedPublicKey: String?,
|
||||
direction: Direction,
|
||||
attachment: Attachment?,
|
||||
hInset: CGFloat,
|
||||
|
@ -43,6 +45,8 @@ final class QuoteView: UIView {
|
|||
authorId: authorId,
|
||||
quotedText: quotedText,
|
||||
threadVariant: threadVariant,
|
||||
currentUserPublicKey: currentUserPublicKey,
|
||||
currentUserBlindedPublicKey: currentUserBlindedPublicKey,
|
||||
direction: direction,
|
||||
attachment: attachment,
|
||||
hInset: hInset,
|
||||
|
@ -63,6 +67,8 @@ final class QuoteView: UIView {
|
|||
authorId: String,
|
||||
quotedText: String?,
|
||||
threadVariant: SessionThread.Variant,
|
||||
currentUserPublicKey: String?,
|
||||
currentUserBlindedPublicKey: String?,
|
||||
direction: Direction,
|
||||
attachment: Attachment?,
|
||||
hInset: CGFloat,
|
||||
|
@ -190,6 +196,8 @@ final class QuoteView: UIView {
|
|||
MentionUtilities.highlightMentions(
|
||||
in: $0,
|
||||
threadVariant: threadVariant,
|
||||
currentUserPublicKey: currentUserPublicKey,
|
||||
currentUserBlindedPublicKey: currentUserBlindedPublicKey,
|
||||
isOutgoingMessage: isOutgoing,
|
||||
attributes: [:]
|
||||
)
|
||||
|
@ -207,11 +215,21 @@ final class QuoteView: UIView {
|
|||
// Label stack view
|
||||
var authorLabelHeight: CGFloat?
|
||||
if threadVariant == .openGroup || threadVariant == .closedGroup {
|
||||
let isCurrentUser: Bool = [
|
||||
currentUserPublicKey,
|
||||
currentUserBlindedPublicKey,
|
||||
]
|
||||
.compactMap { $0 }
|
||||
.asSet()
|
||||
.contains(authorId)
|
||||
let authorLabel = UILabel()
|
||||
authorLabel.lineBreakMode = .byTruncatingTail
|
||||
authorLabel.text = Profile.displayName(
|
||||
id: authorId,
|
||||
threadVariant: threadVariant
|
||||
authorLabel.text = (isCurrentUser ?
|
||||
"MEDIA_GALLERY_SENDER_NAME_YOU".localized() :
|
||||
Profile.displayName(
|
||||
id: authorId,
|
||||
threadVariant: threadVariant
|
||||
)
|
||||
)
|
||||
authorLabel.textColor = textColor
|
||||
authorLabel.font = .boldSystemFont(ofSize: Values.smallFontSize)
|
||||
|
|
|
@ -459,6 +459,8 @@ final class VisibleMessageCell: MessageCell, UITextViewDelegate, BodyTextViewDel
|
|||
authorId: quote.authorId,
|
||||
quotedText: quote.body,
|
||||
threadVariant: cellViewModel.threadVariant,
|
||||
currentUserPublicKey: cellViewModel.currentUserPublicKey,
|
||||
currentUserBlindedPublicKey: cellViewModel.currentUserBlindedPublicKey,
|
||||
direction: (cellViewModel.variant == .standardOutgoing ?
|
||||
.outgoing :
|
||||
.incoming
|
||||
|
@ -956,6 +958,8 @@ final class VisibleMessageCell: MessageCell, UITextViewDelegate, BodyTextViewDel
|
|||
attributedString: MentionUtilities.highlightMentions(
|
||||
in: (cellViewModel.body ?? ""),
|
||||
threadVariant: cellViewModel.threadVariant,
|
||||
currentUserPublicKey: cellViewModel.currentUserPublicKey,
|
||||
currentUserBlindedPublicKey: cellViewModel.currentUserBlindedPublicKey,
|
||||
isOutgoingMessage: isOutgoing,
|
||||
attributes: [
|
||||
.foregroundColor : textColor,
|
||||
|
|
|
@ -9,10 +9,29 @@ import UIKit
|
|||
// • The long press interaction that shows the context menu should still work
|
||||
final class BodyTextView: UITextView {
|
||||
private let snDelegate: BodyTextViewDelegate?
|
||||
private let highlightedMentionBackgroundView: HighlightMentionBackgroundView = HighlightMentionBackgroundView()
|
||||
|
||||
override var attributedText: NSAttributedString! {
|
||||
didSet {
|
||||
guard attributedText != nil else { return }
|
||||
|
||||
highlightedMentionBackgroundView.maxPadding = highlightedMentionBackgroundView
|
||||
.calculateMaxPadding(for: attributedText)
|
||||
highlightedMentionBackgroundView.frame = self.bounds.insetBy(
|
||||
dx: -highlightedMentionBackgroundView.maxPadding,
|
||||
dy: -highlightedMentionBackgroundView.maxPadding
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
init(snDelegate: BodyTextViewDelegate?) {
|
||||
self.snDelegate = snDelegate
|
||||
|
||||
super.init(frame: CGRect.zero, textContainer: nil)
|
||||
|
||||
self.clipsToBounds = false // Needed for the 'HighlightMentionBackgroundView'
|
||||
addSubview(highlightedMentionBackgroundView)
|
||||
|
||||
setUpGestureRecognizers()
|
||||
}
|
||||
|
||||
|
@ -39,6 +58,15 @@ final class BodyTextView: UITextView {
|
|||
@objc private func handleDoubleTap() {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
override func layoutSubviews() {
|
||||
super.layoutSubviews()
|
||||
|
||||
highlightedMentionBackgroundView.frame = self.bounds.insetBy(
|
||||
dx: -highlightedMentionBackgroundView.maxPadding,
|
||||
dy: -highlightedMentionBackgroundView.maxPadding
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
protocol BodyTextViewDelegate {
|
||||
|
|
|
@ -252,6 +252,11 @@ public class HomeViewModel {
|
|||
0 :
|
||||
self.state.unreadMessageRequestThreadCount
|
||||
)
|
||||
let groupedOldData: [String: [SessionThreadViewModel]] = (self.threadData
|
||||
.first(where: { $0.model == .threads })?
|
||||
.elements)
|
||||
.defaulting(to: [])
|
||||
.grouped(by: \.threadId)
|
||||
|
||||
return [
|
||||
// If there are no unread message requests then hide the message request banner
|
||||
|
@ -275,6 +280,13 @@ public class HomeViewModel {
|
|||
|
||||
return lhs.lastInteractionDate > rhs.lastInteractionDate
|
||||
}
|
||||
.map { viewModel -> SessionThreadViewModel in
|
||||
viewModel.populatingCurrentUserBlindedKey(
|
||||
currentUserBlindedPublicKeyForThisThread: groupedOldData[viewModel.threadId]?
|
||||
.first?
|
||||
.currentUserBlindedPublicKey
|
||||
)
|
||||
}
|
||||
)
|
||||
],
|
||||
(!data.isEmpty && (pageInfo.pageOffset + pageInfo.currentCount) < pageInfo.totalCount ?
|
||||
|
|
|
@ -140,12 +140,25 @@ public class MessageRequestsViewModel {
|
|||
}
|
||||
|
||||
private func process(data: [SessionThreadViewModel], for pageInfo: PagedData.PageInfo) -> [SectionModel] {
|
||||
let groupedOldData: [String: [SessionThreadViewModel]] = (self.threadData
|
||||
.first(where: { $0.model == .threads })?
|
||||
.elements)
|
||||
.defaulting(to: [])
|
||||
.grouped(by: \.threadId)
|
||||
|
||||
return [
|
||||
[
|
||||
SectionModel(
|
||||
section: .threads,
|
||||
elements: data
|
||||
.sorted { lhs, rhs -> Bool in lhs.lastInteractionDate > rhs.lastInteractionDate }
|
||||
.map { viewModel -> SessionThreadViewModel in
|
||||
viewModel.populatingCurrentUserBlindedKey(
|
||||
currentUserBlindedPublicKeyForThisThread: groupedOldData[viewModel.threadId]?
|
||||
.first?
|
||||
.currentUserBlindedPublicKey
|
||||
)
|
||||
}
|
||||
)
|
||||
],
|
||||
(!data.isEmpty && (pageInfo.pageOffset + pageInfo.currentCount) < pageInfo.totalCount ?
|
||||
|
|
|
@ -105,7 +105,7 @@ class GifPickerViewController: OWSViewController, UISearchBarDelegate, UICollect
|
|||
|
||||
// Loki: Customize title
|
||||
let titleLabel = UILabel()
|
||||
titleLabel.text = NSLocalizedString("GIF", comment: "")
|
||||
titleLabel.text = "accessibility_gif_button".localized().uppercased()
|
||||
titleLabel.textColor = Colors.text
|
||||
titleLabel.font = .boldSystemFont(ofSize: Values.veryLargeFontSize)
|
||||
navigationItem.titleView = titleLabel
|
||||
|
|
|
@ -606,7 +606,6 @@
|
|||
"accessibility_camera_button" = "Kamera";
|
||||
"accessibility_main_button_collapse" = "Optionen für Anhänge einklappen";
|
||||
"invalid_recovery_phrase" = "Ungültige Wiederherstellungsphrase";
|
||||
"invalid_recovery_phrase" = "Ungültige Wiederherstellungsphrase";
|
||||
"DISMISS_BUTTON_TEXT" = "Verwerfen";
|
||||
/* Button text which opens the settings app */
|
||||
"OPEN_SETTINGS_BUTTON" = "Einstellungen";
|
||||
|
@ -653,10 +652,36 @@
|
|||
"modal_call_permission_request_explanation" = "You can enable the 'Voice and video calls' permission in the Privacy Settings.";
|
||||
"DEFAULT_OPEN_GROUP_LOAD_ERROR_TITLE" = "Oops, an error occurred";
|
||||
"DEFAULT_OPEN_GROUP_LOAD_ERROR_SUBTITLE" = "Please try again later";
|
||||
"ALERT_ERROR_TITLE" = "Fehler";
|
||||
"LOADING_CONVERSATIONS" = "Loading Conversations...";
|
||||
"DATABASE_MIGRATION_FAILED" = "An error occurred when optimising the database\n\nYou can export your application logs to be able to share for troubleshooting or you can restore our device\n\nWarning: Restoring your device will result in loss of any data older than two weeks";
|
||||
"CHATS_TITLE" = "Chats";
|
||||
"MESSAGE_TRIMMING_TITLE" = "Message Trimming";
|
||||
"MESSAGE_TRIMMING_OPEN_GROUP_TITLE" = "Delete Old Open Group Messages";
|
||||
"MESSAGE_TRIMMING_OPEN_GROUP_DESCRIPTION" = "Automatically delete messages which are older than 6 months from open groups with over 2,000 messages when starting the app";
|
||||
"RECOVERY_PHASE_ERROR_GENERIC" = "Something went wrong. Please check your recovery phrase and try again.";
|
||||
"RECOVERY_PHASE_ERROR_LENGTH" = "Looks like you didn't enter enough words. Please check your recovery phrase and try again.";
|
||||
"RECOVERY_PHASE_ERROR_LAST_WORD" = "You seem to be missing the last word of your recovery phrase. Please check what you entered and try again.";
|
||||
"RECOVERY_PHASE_ERROR_INVALID_WORD" = "There appears to be an invalid word in your recovery phrase. Please check what you entered and try again.";
|
||||
"RECOVERY_PHASE_ERROR_FAILED" = "Your recovery phrase couldn't be verified. Please check what you entered and try again.";
|
||||
/* Indicates that an unknown error occurred while using Touch ID/Face ID/Phone Passcode. */
|
||||
"SCREEN_LOCK_ENABLE_UNKNOWN_ERROR" = "Authentication could not be accessed.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode authentication failed. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_FAILED" = "Authentifizierung gescheitert.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode is 'locked out' on this device due to authentication failures. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_LOCKOUT" = "Zu viele gescheiterte Authentifizierungsversuche. Bitte versuche es später erneut.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode are not available on this device. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_AVAILABLE" = "Du musst einen Passcode in deinen iOS-Einstellungen festlegen, um die Bildschirmsperre zu verwenden.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode is not configured on this device. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_ENROLLED" = "Du musst einen Passcode in deinen iOS-Einstellungen festlegen, um die Bildschirmsperre zu verwenden.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode passcode is not set. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_PASSCODE_NOT_SET" = "Du musst einen Passcode in deinen iOS-Einstellungen festlegen, um die Bildschirmsperre zu verwenden.";
|
||||
/* Label for the button to send a message */
|
||||
"SEND_BUTTON_TITLE" = "Send";
|
||||
/* Generic text for button that retries whatever the last action was. */
|
||||
"RETRY_BUTTON_TEXT" = "Retry";
|
||||
/* notification action */
|
||||
"SHOW_THREAD_BUTTON_TITLE" = "Show Chat";
|
||||
/* notification body */
|
||||
"SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send.";
|
||||
"INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again.";
|
||||
"INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again.";
|
||||
|
|
|
@ -606,7 +606,6 @@
|
|||
"accessibility_camera_button" = "Camera";
|
||||
"accessibility_main_button_collapse" = "Collapse attachment options";
|
||||
"invalid_recovery_phrase" = "Invalid Recovery Phrase";
|
||||
"invalid_recovery_phrase" = "Invalid Recovery Phrase";
|
||||
"DISMISS_BUTTON_TEXT" = "Dismiss";
|
||||
/* Button text which opens the settings app */
|
||||
"OPEN_SETTINGS_BUTTON" = "Settings";
|
||||
|
@ -653,11 +652,36 @@
|
|||
"modal_call_permission_request_explanation" = "You can enable the 'Voice and video calls' permission in the Privacy Settings.";
|
||||
"DEFAULT_OPEN_GROUP_LOAD_ERROR_TITLE" = "Oops, an error occurred";
|
||||
"DEFAULT_OPEN_GROUP_LOAD_ERROR_SUBTITLE" = "Please try again later";
|
||||
"ALERT_ERROR_TITLE" = "Error";
|
||||
"LOADING_CONVERSATIONS" = "Loading Conversations...";
|
||||
"DATABASE_MIGRATION_FAILED" = "An error occurred when optimising the database\n\nYou can export your application logs to be able to share for troubleshooting or you can restore our device\n\nWarning: Restoring your device will result in loss of any data older than two weeks";
|
||||
"CHATS_TITLE" = "Chats";
|
||||
"MESSAGE_TRIMMING_TITLE" = "Message Trimming";
|
||||
"MESSAGE_TRIMMING_OPEN_GROUP_TITLE" = "Delete Old Open Group Messages";
|
||||
"MESSAGE_TRIMMING_OPEN_GROUP_DESCRIPTION" = "Automatically delete messages which are older than 6 months from open groups with over 2,000 messages when starting the app";
|
||||
|
||||
"RECOVERY_PHASE_ERROR_GENERIC" = "Something went wrong. Please check your recovery phrase and try again.";
|
||||
"RECOVERY_PHASE_ERROR_LENGTH" = "Looks like you didn't enter enough words. Please check your recovery phrase and try again.";
|
||||
"RECOVERY_PHASE_ERROR_LAST_WORD" = "You seem to be missing the last word of your recovery phrase. Please check what you entered and try again.";
|
||||
"RECOVERY_PHASE_ERROR_INVALID_WORD" = "There appears to be an invalid word in your recovery phrase. Please check what you entered and try again.";
|
||||
"RECOVERY_PHASE_ERROR_FAILED" = "Your recovery phrase couldn't be verified. Please check what you entered and try again.";
|
||||
/* Indicates that an unknown error occurred while using Touch ID/Face ID/Phone Passcode. */
|
||||
"SCREEN_LOCK_ENABLE_UNKNOWN_ERROR" = "Authentication could not be accessed.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode authentication failed. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_FAILED" = "Authentication failed.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode is 'locked out' on this device due to authentication failures. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_LOCKOUT" = "Too many failed authentication attempts. Please try again later.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode are not available on this device. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_AVAILABLE" = "You must enable a passcode in your iOS Settings in order to use Screen Lock.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode is not configured on this device. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_ENROLLED" = "You must enable a passcode in your iOS Settings in order to use Screen Lock.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode passcode is not set. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_PASSCODE_NOT_SET" = "You must enable a passcode in your iOS Settings in order to use Screen Lock.";
|
||||
/* Label for the button to send a message */
|
||||
"SEND_BUTTON_TITLE" = "Send";
|
||||
/* Generic text for button that retries whatever the last action was. */
|
||||
"RETRY_BUTTON_TEXT" = "Retry";
|
||||
/* notification action */
|
||||
"SHOW_THREAD_BUTTON_TITLE" = "Show Chat";
|
||||
/* notification body */
|
||||
"SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send.";
|
||||
"INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again.";
|
||||
"INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again.";
|
||||
|
|
|
@ -606,7 +606,6 @@
|
|||
"accessibility_camera_button" = "Cámara";
|
||||
"accessibility_main_button_collapse" = "Collapse attachment options";
|
||||
"invalid_recovery_phrase" = "Frase de Recuperación Incorrecta";
|
||||
"invalid_recovery_phrase" = "Invalid Recovery Phrase";
|
||||
"DISMISS_BUTTON_TEXT" = "Descartar";
|
||||
/* Button text which opens the settings app */
|
||||
"OPEN_SETTINGS_BUTTON" = "Ajustes";
|
||||
|
@ -653,10 +652,36 @@
|
|||
"modal_call_permission_request_explanation" = "You can enable the 'Voice and video calls' permission in the Privacy Settings.";
|
||||
"DEFAULT_OPEN_GROUP_LOAD_ERROR_TITLE" = "Oops, an error occurred";
|
||||
"DEFAULT_OPEN_GROUP_LOAD_ERROR_SUBTITLE" = "Please try again later";
|
||||
"ALERT_ERROR_TITLE" = "Fallo";
|
||||
"LOADING_CONVERSATIONS" = "Loading Conversations...";
|
||||
"DATABASE_MIGRATION_FAILED" = "An error occurred when optimising the database\n\nYou can export your application logs to be able to share for troubleshooting or you can restore our device\n\nWarning: Restoring your device will result in loss of any data older than two weeks";
|
||||
"CHATS_TITLE" = "Chats";
|
||||
"MESSAGE_TRIMMING_TITLE" = "Message Trimming";
|
||||
"MESSAGE_TRIMMING_OPEN_GROUP_TITLE" = "Delete Old Open Group Messages";
|
||||
"MESSAGE_TRIMMING_OPEN_GROUP_DESCRIPTION" = "Automatically delete messages which are older than 6 months from open groups with over 2,000 messages when starting the app";
|
||||
"RECOVERY_PHASE_ERROR_GENERIC" = "Something went wrong. Please check your recovery phrase and try again.";
|
||||
"RECOVERY_PHASE_ERROR_LENGTH" = "Looks like you didn't enter enough words. Please check your recovery phrase and try again.";
|
||||
"RECOVERY_PHASE_ERROR_LAST_WORD" = "You seem to be missing the last word of your recovery phrase. Please check what you entered and try again.";
|
||||
"RECOVERY_PHASE_ERROR_INVALID_WORD" = "There appears to be an invalid word in your recovery phrase. Please check what you entered and try again.";
|
||||
"RECOVERY_PHASE_ERROR_FAILED" = "Your recovery phrase couldn't be verified. Please check what you entered and try again.";
|
||||
/* Indicates that an unknown error occurred while using Touch ID/Face ID/Phone Passcode. */
|
||||
"SCREEN_LOCK_ENABLE_UNKNOWN_ERROR" = "Authentication could not be accessed.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode authentication failed. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_FAILED" = "Fallo en la identificación.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode is 'locked out' on this device due to authentication failures. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_LOCKOUT" = "Demasiados intentos fallidos. Prueda de nuevo más tarde.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode are not available on this device. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_AVAILABLE" = "Necesitas configurar un código en «Ajustes» de iOS para poder usar el bloqueo de acceso.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode is not configured on this device. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_ENROLLED" = "Necesitas configurar un código en «Ajustes» de iOS para poder usar el bloqueo de acceso.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode passcode is not set. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_PASSCODE_NOT_SET" = "Necesitas configurar un código en «Ajustes» de iOS para poder usar el bloqueo de acceso.";
|
||||
/* Label for the button to send a message */
|
||||
"SEND_BUTTON_TITLE" = "Send";
|
||||
/* Generic text for button that retries whatever the last action was. */
|
||||
"RETRY_BUTTON_TEXT" = "Retry";
|
||||
/* notification action */
|
||||
"SHOW_THREAD_BUTTON_TITLE" = "Show Chat";
|
||||
/* notification body */
|
||||
"SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send.";
|
||||
"INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again.";
|
||||
"INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again.";
|
||||
|
|
|
@ -606,7 +606,6 @@
|
|||
"accessibility_camera_button" = "Camera";
|
||||
"accessibility_main_button_collapse" = "Collapse attachment options";
|
||||
"invalid_recovery_phrase" = "Invalid Recovery Phrase";
|
||||
"invalid_recovery_phrase" = "Invalid Recovery Phrase";
|
||||
"DISMISS_BUTTON_TEXT" = "Dismiss";
|
||||
/* Button text which opens the settings app */
|
||||
"OPEN_SETTINGS_BUTTON" = "Settings";
|
||||
|
@ -653,10 +652,36 @@
|
|||
"modal_call_permission_request_explanation" = "You can enable the 'Voice and video calls' permission in the Privacy Settings.";
|
||||
"DEFAULT_OPEN_GROUP_LOAD_ERROR_TITLE" = "Oops, an error occurred";
|
||||
"DEFAULT_OPEN_GROUP_LOAD_ERROR_SUBTITLE" = "Please try again later";
|
||||
"ALERT_ERROR_TITLE" = "خطاء";
|
||||
"LOADING_CONVERSATIONS" = "Loading Conversations...";
|
||||
"DATABASE_MIGRATION_FAILED" = "An error occurred when optimising the database\n\nYou can export your application logs to be able to share for troubleshooting or you can restore our device\n\nWarning: Restoring your device will result in loss of any data older than two weeks";
|
||||
"CHATS_TITLE" = "Chats";
|
||||
"MESSAGE_TRIMMING_TITLE" = "Message Trimming";
|
||||
"MESSAGE_TRIMMING_OPEN_GROUP_TITLE" = "Delete Old Open Group Messages";
|
||||
"MESSAGE_TRIMMING_OPEN_GROUP_DESCRIPTION" = "Automatically delete messages which are older than 6 months from open groups with over 2,000 messages when starting the app";
|
||||
"RECOVERY_PHASE_ERROR_GENERIC" = "Something went wrong. Please check your recovery phrase and try again.";
|
||||
"RECOVERY_PHASE_ERROR_LENGTH" = "Looks like you didn't enter enough words. Please check your recovery phrase and try again.";
|
||||
"RECOVERY_PHASE_ERROR_LAST_WORD" = "You seem to be missing the last word of your recovery phrase. Please check what you entered and try again.";
|
||||
"RECOVERY_PHASE_ERROR_INVALID_WORD" = "There appears to be an invalid word in your recovery phrase. Please check what you entered and try again.";
|
||||
"RECOVERY_PHASE_ERROR_FAILED" = "Your recovery phrase couldn't be verified. Please check what you entered and try again.";
|
||||
/* Indicates that an unknown error occurred while using Touch ID/Face ID/Phone Passcode. */
|
||||
"SCREEN_LOCK_ENABLE_UNKNOWN_ERROR" = "Authentication could not be accessed.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode authentication failed. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_FAILED" = "احراز هویت ناموفق بود.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode is 'locked out' on this device due to authentication failures. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_LOCKOUT" = "چندین احراز هویت ناموفق رخ داد. لطفا بعدا تلاش کنید.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode are not available on this device. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_AVAILABLE" = "برای استفاده از قفل صفحه نمایش می بایستی یک رمزعبور از تنظیمات iOS خود فعال کنید.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode is not configured on this device. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_ENROLLED" = "شما برای استفاده از قفل صفحه نمایس می بایستی یک رمزعبور از تنظیمات iOS خود فعال کنید.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode passcode is not set. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_PASSCODE_NOT_SET" = "برای استفاده از قفل صفحه نمایش می بایستی یک رمزعبور از تنظیمات iOS فعال کنید.";
|
||||
/* Label for the button to send a message */
|
||||
"SEND_BUTTON_TITLE" = "Send";
|
||||
/* Generic text for button that retries whatever the last action was. */
|
||||
"RETRY_BUTTON_TEXT" = "Retry";
|
||||
/* notification action */
|
||||
"SHOW_THREAD_BUTTON_TITLE" = "Show Chat";
|
||||
/* notification body */
|
||||
"SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send.";
|
||||
"INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again.";
|
||||
"INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again.";
|
||||
|
|
|
@ -606,7 +606,6 @@
|
|||
"accessibility_camera_button" = "Kamera";
|
||||
"accessibility_main_button_collapse" = "Tiivistä liiteasetukset";
|
||||
"invalid_recovery_phrase" = "Virheellinen Palautuslauseke";
|
||||
"invalid_recovery_phrase" = "Virheellinen palautuslauseke";
|
||||
"DISMISS_BUTTON_TEXT" = "Hylkää";
|
||||
/* Button text which opens the settings app */
|
||||
"OPEN_SETTINGS_BUTTON" = "Asetukset";
|
||||
|
@ -653,10 +652,36 @@
|
|||
"modal_call_permission_request_explanation" = "You can enable the 'Voice and video calls' permission in the Privacy Settings.";
|
||||
"DEFAULT_OPEN_GROUP_LOAD_ERROR_TITLE" = "Oops, an error occurred";
|
||||
"DEFAULT_OPEN_GROUP_LOAD_ERROR_SUBTITLE" = "Please try again later";
|
||||
"ALERT_ERROR_TITLE" = "Error";
|
||||
"LOADING_CONVERSATIONS" = "Loading Conversations...";
|
||||
"DATABASE_MIGRATION_FAILED" = "An error occurred when optimising the database\n\nYou can export your application logs to be able to share for troubleshooting or you can restore our device\n\nWarning: Restoring your device will result in loss of any data older than two weeks";
|
||||
"CHATS_TITLE" = "Chats";
|
||||
"MESSAGE_TRIMMING_TITLE" = "Message Trimming";
|
||||
"MESSAGE_TRIMMING_OPEN_GROUP_TITLE" = "Delete Old Open Group Messages";
|
||||
"MESSAGE_TRIMMING_OPEN_GROUP_DESCRIPTION" = "Automatically delete messages which are older than 6 months from open groups with over 2,000 messages when starting the app";
|
||||
"RECOVERY_PHASE_ERROR_GENERIC" = "Something went wrong. Please check your recovery phrase and try again.";
|
||||
"RECOVERY_PHASE_ERROR_LENGTH" = "Looks like you didn't enter enough words. Please check your recovery phrase and try again.";
|
||||
"RECOVERY_PHASE_ERROR_LAST_WORD" = "You seem to be missing the last word of your recovery phrase. Please check what you entered and try again.";
|
||||
"RECOVERY_PHASE_ERROR_INVALID_WORD" = "There appears to be an invalid word in your recovery phrase. Please check what you entered and try again.";
|
||||
"RECOVERY_PHASE_ERROR_FAILED" = "Your recovery phrase couldn't be verified. Please check what you entered and try again.";
|
||||
/* Indicates that an unknown error occurred while using Touch ID/Face ID/Phone Passcode. */
|
||||
"SCREEN_LOCK_ENABLE_UNKNOWN_ERROR" = "Authentication could not be accessed.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode authentication failed. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_FAILED" = "Tunnistautuminen epäonnistui";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode is 'locked out' on this device due to authentication failures. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_LOCKOUT" = "Liian monta epäonnistunutta tunnistautumista. Yritä myöhemmin uudelleen.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode are not available on this device. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_AVAILABLE" = "Aseta pääsykoodi puhelimesi asetuksista, jotta voit käyttää näytön lukitusta.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode is not configured on this device. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_ENROLLED" = "Aseta pääsykoodi puhelimesi asetuksista, jotta voit käyttää näytön lukitusta.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode passcode is not set. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_PASSCODE_NOT_SET" = "Aseta pääsykoodi puhelimesi asetuksista, jotta voit käyttää näytön lukitusta.";
|
||||
/* Label for the button to send a message */
|
||||
"SEND_BUTTON_TITLE" = "Send";
|
||||
/* Generic text for button that retries whatever the last action was. */
|
||||
"RETRY_BUTTON_TEXT" = "Retry";
|
||||
/* notification action */
|
||||
"SHOW_THREAD_BUTTON_TITLE" = "Show Chat";
|
||||
/* notification body */
|
||||
"SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send.";
|
||||
"INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again.";
|
||||
"INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again.";
|
||||
|
|
|
@ -606,7 +606,6 @@
|
|||
"accessibility_camera_button" = "Caméra";
|
||||
"accessibility_main_button_collapse" = "Réduire les options de pièces jointes";
|
||||
"invalid_recovery_phrase" = "Phrase de récupération incorrecte";
|
||||
"invalid_recovery_phrase" = "Phrase de récupération incorrecte";
|
||||
"DISMISS_BUTTON_TEXT" = "Fermer";
|
||||
/* Button text which opens the settings app */
|
||||
"OPEN_SETTINGS_BUTTON" = "Paramètres";
|
||||
|
@ -653,10 +652,36 @@
|
|||
"modal_call_permission_request_explanation" = "Vous pouvez activer la permission \"Appels vocaux et vidéo\" dans les paramètres de confidentialité.";
|
||||
"DEFAULT_OPEN_GROUP_LOAD_ERROR_TITLE" = "Oops, an error occurred";
|
||||
"DEFAULT_OPEN_GROUP_LOAD_ERROR_SUBTITLE" = "Please try again later";
|
||||
"ALERT_ERROR_TITLE" = "Erreur";
|
||||
"LOADING_CONVERSATIONS" = "Loading Conversations...";
|
||||
"DATABASE_MIGRATION_FAILED" = "An error occurred when optimising the database\n\nYou can export your application logs to be able to share for troubleshooting or you can restore our device\n\nWarning: Restoring your device will result in loss of any data older than two weeks";
|
||||
"CHATS_TITLE" = "Chats";
|
||||
"MESSAGE_TRIMMING_TITLE" = "Message Trimming";
|
||||
"MESSAGE_TRIMMING_OPEN_GROUP_TITLE" = "Delete Old Open Group Messages";
|
||||
"MESSAGE_TRIMMING_OPEN_GROUP_DESCRIPTION" = "Automatically delete messages which are older than 6 months from open groups with over 2,000 messages when starting the app";
|
||||
"RECOVERY_PHASE_ERROR_GENERIC" = "Something went wrong. Please check your recovery phrase and try again.";
|
||||
"RECOVERY_PHASE_ERROR_LENGTH" = "Looks like you didn't enter enough words. Please check your recovery phrase and try again.";
|
||||
"RECOVERY_PHASE_ERROR_LAST_WORD" = "You seem to be missing the last word of your recovery phrase. Please check what you entered and try again.";
|
||||
"RECOVERY_PHASE_ERROR_INVALID_WORD" = "There appears to be an invalid word in your recovery phrase. Please check what you entered and try again.";
|
||||
"RECOVERY_PHASE_ERROR_FAILED" = "Your recovery phrase couldn't be verified. Please check what you entered and try again.";
|
||||
/* Indicates that an unknown error occurred while using Touch ID/Face ID/Phone Passcode. */
|
||||
"SCREEN_LOCK_ENABLE_UNKNOWN_ERROR" = "Authentication could not be accessed.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode authentication failed. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_FAILED" = "Échec d’authentification";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode is 'locked out' on this device due to authentication failures. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_LOCKOUT" = "Trop d’essais infructueux d’authentification. Veuillez réessayer plus tard.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode are not available on this device. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_AVAILABLE" = "Vous devez activer un code dans vos réglages iOS pour utiliser le verrou d’écran.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode is not configured on this device. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_ENROLLED" = "Vous devez activer un code dans vos réglages iOS pour utiliser le verrou d’écran.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode passcode is not set. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_PASSCODE_NOT_SET" = "Vous devez activer un code dans vos réglages iOS pour utiliser le verrou d’écran.";
|
||||
/* Label for the button to send a message */
|
||||
"SEND_BUTTON_TITLE" = "Send";
|
||||
/* Generic text for button that retries whatever the last action was. */
|
||||
"RETRY_BUTTON_TEXT" = "Retry";
|
||||
/* notification action */
|
||||
"SHOW_THREAD_BUTTON_TITLE" = "Show Chat";
|
||||
/* notification body */
|
||||
"SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send.";
|
||||
"INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again.";
|
||||
"INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again.";
|
||||
|
|
|
@ -606,7 +606,6 @@
|
|||
"accessibility_camera_button" = "Camera";
|
||||
"accessibility_main_button_collapse" = "Collapse attachment options";
|
||||
"invalid_recovery_phrase" = "Invalid Recovery Phrase";
|
||||
"invalid_recovery_phrase" = "Invalid Recovery Phrase";
|
||||
"DISMISS_BUTTON_TEXT" = "Dismiss";
|
||||
/* Button text which opens the settings app */
|
||||
"OPEN_SETTINGS_BUTTON" = "Settings";
|
||||
|
@ -653,10 +652,36 @@
|
|||
"modal_call_permission_request_explanation" = "You can enable the 'Voice and video calls' permission in the Privacy Settings.";
|
||||
"DEFAULT_OPEN_GROUP_LOAD_ERROR_TITLE" = "Oops, an error occurred";
|
||||
"DEFAULT_OPEN_GROUP_LOAD_ERROR_SUBTITLE" = "Please try again later";
|
||||
"ALERT_ERROR_TITLE" = "Error";
|
||||
"LOADING_CONVERSATIONS" = "Loading Conversations...";
|
||||
"DATABASE_MIGRATION_FAILED" = "An error occurred when optimising the database\n\nYou can export your application logs to be able to share for troubleshooting or you can restore our device\n\nWarning: Restoring your device will result in loss of any data older than two weeks";
|
||||
"CHATS_TITLE" = "Chats";
|
||||
"MESSAGE_TRIMMING_TITLE" = "Message Trimming";
|
||||
"MESSAGE_TRIMMING_OPEN_GROUP_TITLE" = "Delete Old Open Group Messages";
|
||||
"MESSAGE_TRIMMING_OPEN_GROUP_DESCRIPTION" = "Automatically delete messages which are older than 6 months from open groups with over 2,000 messages when starting the app";
|
||||
"RECOVERY_PHASE_ERROR_GENERIC" = "Something went wrong. Please check your recovery phrase and try again.";
|
||||
"RECOVERY_PHASE_ERROR_LENGTH" = "Looks like you didn't enter enough words. Please check your recovery phrase and try again.";
|
||||
"RECOVERY_PHASE_ERROR_LAST_WORD" = "You seem to be missing the last word of your recovery phrase. Please check what you entered and try again.";
|
||||
"RECOVERY_PHASE_ERROR_INVALID_WORD" = "There appears to be an invalid word in your recovery phrase. Please check what you entered and try again.";
|
||||
"RECOVERY_PHASE_ERROR_FAILED" = "Your recovery phrase couldn't be verified. Please check what you entered and try again.";
|
||||
/* Indicates that an unknown error occurred while using Touch ID/Face ID/Phone Passcode. */
|
||||
"SCREEN_LOCK_ENABLE_UNKNOWN_ERROR" = "Authentication could not be accessed.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode authentication failed. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_FAILED" = "प्रमाणीकरण असफल";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode is 'locked out' on this device due to authentication failures. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_LOCKOUT" = "बहुत सारी असफल प्रमाणीकरण की कोशिशें हुई हैं। कृपया थोङी देर बाद कोशिश करें।";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode are not available on this device. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_AVAILABLE" = "सक्रीन लॉक इस्तेमाल करने के लिये अपने iOS सेटिंग्स से पासकोड की अनुमति दें।";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode is not configured on this device. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_ENROLLED" = "सक्रीन लॉक इस्तेमाल करने के लिये अपने iOS सेटिंग्स से पासकोड की अनुमति दें।";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode passcode is not set. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_PASSCODE_NOT_SET" = "सक्रीन लॉक इस्तेमाल करने के लिये अपने iOS सेटिंग्स से पासकोड की अनुमति दें।";
|
||||
/* Label for the button to send a message */
|
||||
"SEND_BUTTON_TITLE" = "Send";
|
||||
/* Generic text for button that retries whatever the last action was. */
|
||||
"RETRY_BUTTON_TEXT" = "Retry";
|
||||
/* notification action */
|
||||
"SHOW_THREAD_BUTTON_TITLE" = "Show Chat";
|
||||
/* notification body */
|
||||
"SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send.";
|
||||
"INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again.";
|
||||
"INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again.";
|
||||
|
|
|
@ -606,7 +606,6 @@
|
|||
"accessibility_camera_button" = "Kamera";
|
||||
"accessibility_main_button_collapse" = "Sažmi opcije privitka";
|
||||
"invalid_recovery_phrase" = "Nevažeća fraza za oporavak";
|
||||
"invalid_recovery_phrase" = "Nevažeća fraza za oporavak";
|
||||
"DISMISS_BUTTON_TEXT" = "Odbaci";
|
||||
/* Button text which opens the settings app */
|
||||
"OPEN_SETTINGS_BUTTON" = "Postavke";
|
||||
|
@ -653,10 +652,36 @@
|
|||
"modal_call_permission_request_explanation" = "You can enable the 'Voice and video calls' permission in the Privacy Settings.";
|
||||
"DEFAULT_OPEN_GROUP_LOAD_ERROR_TITLE" = "Oops, an error occurred";
|
||||
"DEFAULT_OPEN_GROUP_LOAD_ERROR_SUBTITLE" = "Please try again later";
|
||||
"ALERT_ERROR_TITLE" = "Error";
|
||||
"LOADING_CONVERSATIONS" = "Loading Conversations...";
|
||||
"DATABASE_MIGRATION_FAILED" = "An error occurred when optimising the database\n\nYou can export your application logs to be able to share for troubleshooting or you can restore our device\n\nWarning: Restoring your device will result in loss of any data older than two weeks";
|
||||
"CHATS_TITLE" = "Chats";
|
||||
"MESSAGE_TRIMMING_TITLE" = "Message Trimming";
|
||||
"MESSAGE_TRIMMING_OPEN_GROUP_TITLE" = "Delete Old Open Group Messages";
|
||||
"MESSAGE_TRIMMING_OPEN_GROUP_DESCRIPTION" = "Automatically delete messages which are older than 6 months from open groups with over 2,000 messages when starting the app";
|
||||
"RECOVERY_PHASE_ERROR_GENERIC" = "Something went wrong. Please check your recovery phrase and try again.";
|
||||
"RECOVERY_PHASE_ERROR_LENGTH" = "Looks like you didn't enter enough words. Please check your recovery phrase and try again.";
|
||||
"RECOVERY_PHASE_ERROR_LAST_WORD" = "You seem to be missing the last word of your recovery phrase. Please check what you entered and try again.";
|
||||
"RECOVERY_PHASE_ERROR_INVALID_WORD" = "There appears to be an invalid word in your recovery phrase. Please check what you entered and try again.";
|
||||
"RECOVERY_PHASE_ERROR_FAILED" = "Your recovery phrase couldn't be verified. Please check what you entered and try again.";
|
||||
/* Indicates that an unknown error occurred while using Touch ID/Face ID/Phone Passcode. */
|
||||
"SCREEN_LOCK_ENABLE_UNKNOWN_ERROR" = "Authentication could not be accessed.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode authentication failed. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_FAILED" = "Provjera autentičnosti nije uspjela.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode is 'locked out' on this device due to authentication failures. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_LOCKOUT" = "Previše neuspjelih pokušaja provjere autentičnosti. Pokušajte ponovo kasnije.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode are not available on this device. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_AVAILABLE" = "Kako biste koristili Zaključavanje zaslona, morate omogućiti lozinku u postavkama iOS-a.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode is not configured on this device. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_ENROLLED" = "Kako biste koristili Zaključavanje zaslona, morate omogućiti lozinku u postavkama iOS-a.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode passcode is not set. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_PASSCODE_NOT_SET" = "Kako biste koristili Zaključavanje zaslona, morate omogućiti lozinku u postavkama iOS-a.";
|
||||
/* Label for the button to send a message */
|
||||
"SEND_BUTTON_TITLE" = "Send";
|
||||
/* Generic text for button that retries whatever the last action was. */
|
||||
"RETRY_BUTTON_TEXT" = "Retry";
|
||||
/* notification action */
|
||||
"SHOW_THREAD_BUTTON_TITLE" = "Show Chat";
|
||||
/* notification body */
|
||||
"SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send.";
|
||||
"INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again.";
|
||||
"INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again.";
|
||||
|
|
|
@ -606,7 +606,6 @@
|
|||
"accessibility_camera_button" = "Camera";
|
||||
"accessibility_main_button_collapse" = "Collapse attachment options";
|
||||
"invalid_recovery_phrase" = "Invalid Recovery Phrase";
|
||||
"invalid_recovery_phrase" = "Invalid Recovery Phrase";
|
||||
"DISMISS_BUTTON_TEXT" = "Dismiss";
|
||||
/* Button text which opens the settings app */
|
||||
"OPEN_SETTINGS_BUTTON" = "Settings";
|
||||
|
@ -653,10 +652,36 @@
|
|||
"modal_call_permission_request_explanation" = "You can enable the 'Voice and video calls' permission in the Privacy Settings.";
|
||||
"DEFAULT_OPEN_GROUP_LOAD_ERROR_TITLE" = "Oops, an error occurred";
|
||||
"DEFAULT_OPEN_GROUP_LOAD_ERROR_SUBTITLE" = "Please try again later";
|
||||
"ALERT_ERROR_TITLE" = "Galat";
|
||||
"LOADING_CONVERSATIONS" = "Loading Conversations...";
|
||||
"DATABASE_MIGRATION_FAILED" = "An error occurred when optimising the database\n\nYou can export your application logs to be able to share for troubleshooting or you can restore our device\n\nWarning: Restoring your device will result in loss of any data older than two weeks";
|
||||
"CHATS_TITLE" = "Chats";
|
||||
"MESSAGE_TRIMMING_TITLE" = "Message Trimming";
|
||||
"MESSAGE_TRIMMING_OPEN_GROUP_TITLE" = "Delete Old Open Group Messages";
|
||||
"MESSAGE_TRIMMING_OPEN_GROUP_DESCRIPTION" = "Automatically delete messages which are older than 6 months from open groups with over 2,000 messages when starting the app";
|
||||
"RECOVERY_PHASE_ERROR_GENERIC" = "Something went wrong. Please check your recovery phrase and try again.";
|
||||
"RECOVERY_PHASE_ERROR_LENGTH" = "Looks like you didn't enter enough words. Please check your recovery phrase and try again.";
|
||||
"RECOVERY_PHASE_ERROR_LAST_WORD" = "You seem to be missing the last word of your recovery phrase. Please check what you entered and try again.";
|
||||
"RECOVERY_PHASE_ERROR_INVALID_WORD" = "There appears to be an invalid word in your recovery phrase. Please check what you entered and try again.";
|
||||
"RECOVERY_PHASE_ERROR_FAILED" = "Your recovery phrase couldn't be verified. Please check what you entered and try again.";
|
||||
/* Indicates that an unknown error occurred while using Touch ID/Face ID/Phone Passcode. */
|
||||
"SCREEN_LOCK_ENABLE_UNKNOWN_ERROR" = "Authentication could not be accessed.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode authentication failed. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_FAILED" = "Authentication failed.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode is 'locked out' on this device due to authentication failures. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_LOCKOUT" = "Too many failed authentication attempts. Please try again later.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode are not available on this device. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_AVAILABLE" = "You must enable a passcode in your iOS Settings in order to use Screen Lock.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode is not configured on this device. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_ENROLLED" = "You must enable a passcode in your iOS Settings in order to use Screen Lock.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode passcode is not set. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_PASSCODE_NOT_SET" = "You must enable a passcode in your iOS Settings in order to use Screen Lock.";
|
||||
/* Label for the button to send a message */
|
||||
"SEND_BUTTON_TITLE" = "Send";
|
||||
/* Generic text for button that retries whatever the last action was. */
|
||||
"RETRY_BUTTON_TEXT" = "Retry";
|
||||
/* notification action */
|
||||
"SHOW_THREAD_BUTTON_TITLE" = "Show Chat";
|
||||
/* notification body */
|
||||
"SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send.";
|
||||
"INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again.";
|
||||
"INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again.";
|
||||
|
|
|
@ -606,7 +606,6 @@
|
|||
"accessibility_camera_button" = "Fotocamera";
|
||||
"accessibility_main_button_collapse" = "Comprimi opzioni allegato";
|
||||
"invalid_recovery_phrase" = "Frase Di Recupero non valida";
|
||||
"invalid_recovery_phrase" = "Frase Di Ripristino Non Valida";
|
||||
"DISMISS_BUTTON_TEXT" = "Chiudi";
|
||||
/* Button text which opens the settings app */
|
||||
"OPEN_SETTINGS_BUTTON" = "Impostazioni";
|
||||
|
@ -653,10 +652,36 @@
|
|||
"modal_call_permission_request_explanation" = "È possibile abilitare l'autorizzazione 'Voce e video chiamate' nelle Impostazioni Privacy.";
|
||||
"DEFAULT_OPEN_GROUP_LOAD_ERROR_TITLE" = "Oops, an error occurred";
|
||||
"DEFAULT_OPEN_GROUP_LOAD_ERROR_SUBTITLE" = "Please try again later";
|
||||
"ALERT_ERROR_TITLE" = "Errore";
|
||||
"LOADING_CONVERSATIONS" = "Loading Conversations...";
|
||||
"DATABASE_MIGRATION_FAILED" = "An error occurred when optimising the database\n\nYou can export your application logs to be able to share for troubleshooting or you can restore our device\n\nWarning: Restoring your device will result in loss of any data older than two weeks";
|
||||
"CHATS_TITLE" = "Chats";
|
||||
"MESSAGE_TRIMMING_TITLE" = "Message Trimming";
|
||||
"MESSAGE_TRIMMING_OPEN_GROUP_TITLE" = "Delete Old Open Group Messages";
|
||||
"MESSAGE_TRIMMING_OPEN_GROUP_DESCRIPTION" = "Automatically delete messages which are older than 6 months from open groups with over 2,000 messages when starting the app";
|
||||
"RECOVERY_PHASE_ERROR_GENERIC" = "Something went wrong. Please check your recovery phrase and try again.";
|
||||
"RECOVERY_PHASE_ERROR_LENGTH" = "Looks like you didn't enter enough words. Please check your recovery phrase and try again.";
|
||||
"RECOVERY_PHASE_ERROR_LAST_WORD" = "You seem to be missing the last word of your recovery phrase. Please check what you entered and try again.";
|
||||
"RECOVERY_PHASE_ERROR_INVALID_WORD" = "There appears to be an invalid word in your recovery phrase. Please check what you entered and try again.";
|
||||
"RECOVERY_PHASE_ERROR_FAILED" = "Your recovery phrase couldn't be verified. Please check what you entered and try again.";
|
||||
/* Indicates that an unknown error occurred while using Touch ID/Face ID/Phone Passcode. */
|
||||
"SCREEN_LOCK_ENABLE_UNKNOWN_ERROR" = "Authentication could not be accessed.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode authentication failed. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_FAILED" = "Autenticazione non riuscita.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode is 'locked out' on this device due to authentication failures. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_LOCKOUT" = "Troppi tentativi di autenticazione non riusciti. Riprova più tardi.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode are not available on this device. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_AVAILABLE" = "Devi abilitare una password nelle impostazioni di iOS per poter usare il blocco schermo.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode is not configured on this device. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_ENROLLED" = "Devi abilitare una password nelle impostazioni di iOS per poter usare il blocco schermo.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode passcode is not set. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_PASSCODE_NOT_SET" = "Devi abilitare una password nelle impostazioni di iOS per poter usare il blocco schermo.";
|
||||
/* Label for the button to send a message */
|
||||
"SEND_BUTTON_TITLE" = "Send";
|
||||
/* Generic text for button that retries whatever the last action was. */
|
||||
"RETRY_BUTTON_TEXT" = "Retry";
|
||||
/* notification action */
|
||||
"SHOW_THREAD_BUTTON_TITLE" = "Show Chat";
|
||||
/* notification body */
|
||||
"SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send.";
|
||||
"INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again.";
|
||||
"INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again.";
|
||||
|
|
|
@ -606,7 +606,6 @@
|
|||
"accessibility_camera_button" = "カメラ";
|
||||
"accessibility_main_button_collapse" = "添付ファイルのオプションを閉じる";
|
||||
"invalid_recovery_phrase" = "無効な復元フレーズ";
|
||||
"invalid_recovery_phrase" = "無効な復元フレーズ";
|
||||
"DISMISS_BUTTON_TEXT" = "中止";
|
||||
/* Button text which opens the settings app */
|
||||
"OPEN_SETTINGS_BUTTON" = "設定";
|
||||
|
@ -653,10 +652,36 @@
|
|||
"modal_call_permission_request_explanation" = "プライバシー設定から音声とビデオ通話の許可を有効にできます。";
|
||||
"DEFAULT_OPEN_GROUP_LOAD_ERROR_TITLE" = "Oops, an error occurred";
|
||||
"DEFAULT_OPEN_GROUP_LOAD_ERROR_SUBTITLE" = "Please try again later";
|
||||
"ALERT_ERROR_TITLE" = "エラー";
|
||||
"LOADING_CONVERSATIONS" = "Loading Conversations...";
|
||||
"DATABASE_MIGRATION_FAILED" = "An error occurred when optimising the database\n\nYou can export your application logs to be able to share for troubleshooting or you can restore our device\n\nWarning: Restoring your device will result in loss of any data older than two weeks";
|
||||
"CHATS_TITLE" = "Chats";
|
||||
"MESSAGE_TRIMMING_TITLE" = "Message Trimming";
|
||||
"MESSAGE_TRIMMING_OPEN_GROUP_TITLE" = "Delete Old Open Group Messages";
|
||||
"MESSAGE_TRIMMING_OPEN_GROUP_DESCRIPTION" = "Automatically delete messages which are older than 6 months from open groups with over 2,000 messages when starting the app";
|
||||
"RECOVERY_PHASE_ERROR_GENERIC" = "Something went wrong. Please check your recovery phrase and try again.";
|
||||
"RECOVERY_PHASE_ERROR_LENGTH" = "Looks like you didn't enter enough words. Please check your recovery phrase and try again.";
|
||||
"RECOVERY_PHASE_ERROR_LAST_WORD" = "You seem to be missing the last word of your recovery phrase. Please check what you entered and try again.";
|
||||
"RECOVERY_PHASE_ERROR_INVALID_WORD" = "There appears to be an invalid word in your recovery phrase. Please check what you entered and try again.";
|
||||
"RECOVERY_PHASE_ERROR_FAILED" = "Your recovery phrase couldn't be verified. Please check what you entered and try again.";
|
||||
/* Indicates that an unknown error occurred while using Touch ID/Face ID/Phone Passcode. */
|
||||
"SCREEN_LOCK_ENABLE_UNKNOWN_ERROR" = "Authentication could not be accessed.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode authentication failed. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_FAILED" = "認証に失敗しました。";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode is 'locked out' on this device due to authentication failures. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_LOCKOUT" = "認証失敗が多すぎます。あとで再度試してください。";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode are not available on this device. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_AVAILABLE" = "画面ロックを使用するには、iOSの設定でパスコードを有効にしてください。";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode is not configured on this device. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_ENROLLED" = "画面ロックを使用するには、iOSの設定でパスコードを有効にしてください。";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode passcode is not set. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_PASSCODE_NOT_SET" = "画面ロックを使用するには、iOSの設定でパスコードを有効にしてください。";
|
||||
/* Label for the button to send a message */
|
||||
"SEND_BUTTON_TITLE" = "Send";
|
||||
/* Generic text for button that retries whatever the last action was. */
|
||||
"RETRY_BUTTON_TEXT" = "Retry";
|
||||
/* notification action */
|
||||
"SHOW_THREAD_BUTTON_TITLE" = "Show Chat";
|
||||
/* notification body */
|
||||
"SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send.";
|
||||
"INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again.";
|
||||
"INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again.";
|
||||
|
|
|
@ -606,7 +606,6 @@
|
|||
"accessibility_camera_button" = "Camera";
|
||||
"accessibility_main_button_collapse" = "Bijlage-opties inklappen";
|
||||
"invalid_recovery_phrase" = "Ongeldig Herstelzin";
|
||||
"invalid_recovery_phrase" = "Ongeldig Herstelzin";
|
||||
"DISMISS_BUTTON_TEXT" = "Negeren";
|
||||
/* Button text which opens the settings app */
|
||||
"OPEN_SETTINGS_BUTTON" = "Instellingen";
|
||||
|
@ -653,10 +652,36 @@
|
|||
"modal_call_permission_request_explanation" = "You can enable the 'Voice and video calls' permission in the Privacy Settings.";
|
||||
"DEFAULT_OPEN_GROUP_LOAD_ERROR_TITLE" = "Oops, an error occurred";
|
||||
"DEFAULT_OPEN_GROUP_LOAD_ERROR_SUBTITLE" = "Please try again later";
|
||||
"ALERT_ERROR_TITLE" = "Error";
|
||||
"LOADING_CONVERSATIONS" = "Loading Conversations...";
|
||||
"DATABASE_MIGRATION_FAILED" = "An error occurred when optimising the database\n\nYou can export your application logs to be able to share for troubleshooting or you can restore our device\n\nWarning: Restoring your device will result in loss of any data older than two weeks";
|
||||
"CHATS_TITLE" = "Chats";
|
||||
"MESSAGE_TRIMMING_TITLE" = "Message Trimming";
|
||||
"MESSAGE_TRIMMING_OPEN_GROUP_TITLE" = "Delete Old Open Group Messages";
|
||||
"MESSAGE_TRIMMING_OPEN_GROUP_DESCRIPTION" = "Automatically delete messages which are older than 6 months from open groups with over 2,000 messages when starting the app";
|
||||
"RECOVERY_PHASE_ERROR_GENERIC" = "Something went wrong. Please check your recovery phrase and try again.";
|
||||
"RECOVERY_PHASE_ERROR_LENGTH" = "Looks like you didn't enter enough words. Please check your recovery phrase and try again.";
|
||||
"RECOVERY_PHASE_ERROR_LAST_WORD" = "You seem to be missing the last word of your recovery phrase. Please check what you entered and try again.";
|
||||
"RECOVERY_PHASE_ERROR_INVALID_WORD" = "There appears to be an invalid word in your recovery phrase. Please check what you entered and try again.";
|
||||
"RECOVERY_PHASE_ERROR_FAILED" = "Your recovery phrase couldn't be verified. Please check what you entered and try again.";
|
||||
/* Indicates that an unknown error occurred while using Touch ID/Face ID/Phone Passcode. */
|
||||
"SCREEN_LOCK_ENABLE_UNKNOWN_ERROR" = "Authentication could not be accessed.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode authentication failed. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_FAILED" = "Authenticatie mislukt.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode is 'locked out' on this device due to authentication failures. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_LOCKOUT" = "Te veel pogingen tot authenticatie. Probeer het later opnieuw.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode are not available on this device. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_AVAILABLE" = "Om appvergrendeling te kunnen gebruiken, moet je een toegangscode instellen in de iOS-instellingen.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode is not configured on this device. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_ENROLLED" = "Om appvergrendeling te kunnen gebruiken, moet je een toegangscode instellen in de iOS-instellingen.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode passcode is not set. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_PASSCODE_NOT_SET" = "Om appvergrendeling te kunnen gebruiken, moet je een toegangscode instellen in de iOS-instellingen.";
|
||||
/* Label for the button to send a message */
|
||||
"SEND_BUTTON_TITLE" = "Send";
|
||||
/* Generic text for button that retries whatever the last action was. */
|
||||
"RETRY_BUTTON_TEXT" = "Retry";
|
||||
/* notification action */
|
||||
"SHOW_THREAD_BUTTON_TITLE" = "Show Chat";
|
||||
/* notification body */
|
||||
"SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send.";
|
||||
"INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again.";
|
||||
"INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again.";
|
||||
|
|
|
@ -606,7 +606,6 @@
|
|||
"accessibility_camera_button" = "Aparat";
|
||||
"accessibility_main_button_collapse" = "Zwiń opcje załączników";
|
||||
"invalid_recovery_phrase" = "Nieprawidłowa fraza odzyskiwania";
|
||||
"invalid_recovery_phrase" = "Nieprawidłowa fraza odzyskiwania";
|
||||
"DISMISS_BUTTON_TEXT" = "Odrzuć";
|
||||
/* Button text which opens the settings app */
|
||||
"OPEN_SETTINGS_BUTTON" = "Ustawienia";
|
||||
|
@ -653,10 +652,36 @@
|
|||
"modal_call_permission_request_explanation" = "Możesz włączyć uprawnienie 'Połączenia głosowe i wideo' w Ustawieniach Prywatności.";
|
||||
"DEFAULT_OPEN_GROUP_LOAD_ERROR_TITLE" = "Oops, an error occurred";
|
||||
"DEFAULT_OPEN_GROUP_LOAD_ERROR_SUBTITLE" = "Please try again later";
|
||||
"ALERT_ERROR_TITLE" = "Błąd";
|
||||
"LOADING_CONVERSATIONS" = "Loading Conversations...";
|
||||
"DATABASE_MIGRATION_FAILED" = "An error occurred when optimising the database\n\nYou can export your application logs to be able to share for troubleshooting or you can restore our device\n\nWarning: Restoring your device will result in loss of any data older than two weeks";
|
||||
"CHATS_TITLE" = "Chats";
|
||||
"MESSAGE_TRIMMING_TITLE" = "Message Trimming";
|
||||
"MESSAGE_TRIMMING_OPEN_GROUP_TITLE" = "Delete Old Open Group Messages";
|
||||
"MESSAGE_TRIMMING_OPEN_GROUP_DESCRIPTION" = "Automatically delete messages which are older than 6 months from open groups with over 2,000 messages when starting the app";
|
||||
"RECOVERY_PHASE_ERROR_GENERIC" = "Something went wrong. Please check your recovery phrase and try again.";
|
||||
"RECOVERY_PHASE_ERROR_LENGTH" = "Looks like you didn't enter enough words. Please check your recovery phrase and try again.";
|
||||
"RECOVERY_PHASE_ERROR_LAST_WORD" = "You seem to be missing the last word of your recovery phrase. Please check what you entered and try again.";
|
||||
"RECOVERY_PHASE_ERROR_INVALID_WORD" = "There appears to be an invalid word in your recovery phrase. Please check what you entered and try again.";
|
||||
"RECOVERY_PHASE_ERROR_FAILED" = "Your recovery phrase couldn't be verified. Please check what you entered and try again.";
|
||||
/* Indicates that an unknown error occurred while using Touch ID/Face ID/Phone Passcode. */
|
||||
"SCREEN_LOCK_ENABLE_UNKNOWN_ERROR" = "Authentication could not be accessed.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode authentication failed. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_FAILED" = "Uwierzytelnianie nie powiodło się.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode is 'locked out' on this device due to authentication failures. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_LOCKOUT" = "Zbyt wiele błędnych logowań. Spróbuj później.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode are not available on this device. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_AVAILABLE" = "Musisz włączyć kod dostępu w Ustawieniach systemu iOS, aby korzystać z blokady ekranu.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode is not configured on this device. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_ENROLLED" = "Musisz włączyć kod dostępu w Ustawieniach systemu iOS, aby korzystać z blokady ekranu.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode passcode is not set. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_PASSCODE_NOT_SET" = "Musisz włączyć kod dostępu w Ustawieniach systemu iOS, aby korzystać z blokady ekranu.";
|
||||
/* Label for the button to send a message */
|
||||
"SEND_BUTTON_TITLE" = "Send";
|
||||
/* Generic text for button that retries whatever the last action was. */
|
||||
"RETRY_BUTTON_TEXT" = "Retry";
|
||||
/* notification action */
|
||||
"SHOW_THREAD_BUTTON_TITLE" = "Show Chat";
|
||||
/* notification body */
|
||||
"SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send.";
|
||||
"INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again.";
|
||||
"INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again.";
|
||||
|
|
|
@ -606,7 +606,6 @@
|
|||
"accessibility_camera_button" = "Câmera";
|
||||
"accessibility_main_button_collapse" = "Recolher opções de anexo";
|
||||
"invalid_recovery_phrase" = "Frase de Recuperação inválida";
|
||||
"invalid_recovery_phrase" = "Frase de Recuperação inválida";
|
||||
"DISMISS_BUTTON_TEXT" = "Ignorar";
|
||||
/* Button text which opens the settings app */
|
||||
"OPEN_SETTINGS_BUTTON" = "Configurações";
|
||||
|
@ -653,10 +652,36 @@
|
|||
"modal_call_permission_request_explanation" = "You can enable the 'Voice and video calls' permission in the Privacy Settings.";
|
||||
"DEFAULT_OPEN_GROUP_LOAD_ERROR_TITLE" = "Oops, an error occurred";
|
||||
"DEFAULT_OPEN_GROUP_LOAD_ERROR_SUBTITLE" = "Please try again later";
|
||||
"ALERT_ERROR_TITLE" = "Erro";
|
||||
"LOADING_CONVERSATIONS" = "Loading Conversations...";
|
||||
"DATABASE_MIGRATION_FAILED" = "An error occurred when optimising the database\n\nYou can export your application logs to be able to share for troubleshooting or you can restore our device\n\nWarning: Restoring your device will result in loss of any data older than two weeks";
|
||||
"CHATS_TITLE" = "Chats";
|
||||
"MESSAGE_TRIMMING_TITLE" = "Message Trimming";
|
||||
"MESSAGE_TRIMMING_OPEN_GROUP_TITLE" = "Delete Old Open Group Messages";
|
||||
"MESSAGE_TRIMMING_OPEN_GROUP_DESCRIPTION" = "Automatically delete messages which are older than 6 months from open groups with over 2,000 messages when starting the app";
|
||||
"RECOVERY_PHASE_ERROR_GENERIC" = "Something went wrong. Please check your recovery phrase and try again.";
|
||||
"RECOVERY_PHASE_ERROR_LENGTH" = "Looks like you didn't enter enough words. Please check your recovery phrase and try again.";
|
||||
"RECOVERY_PHASE_ERROR_LAST_WORD" = "You seem to be missing the last word of your recovery phrase. Please check what you entered and try again.";
|
||||
"RECOVERY_PHASE_ERROR_INVALID_WORD" = "There appears to be an invalid word in your recovery phrase. Please check what you entered and try again.";
|
||||
"RECOVERY_PHASE_ERROR_FAILED" = "Your recovery phrase couldn't be verified. Please check what you entered and try again.";
|
||||
/* Indicates that an unknown error occurred while using Touch ID/Face ID/Phone Passcode. */
|
||||
"SCREEN_LOCK_ENABLE_UNKNOWN_ERROR" = "Authentication could not be accessed.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode authentication failed. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_FAILED" = "Falha na autenticação.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode is 'locked out' on this device due to authentication failures. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_LOCKOUT" = "Você excedeu o número máximo permitido de tentativas de autenticação. Por favor, tente novamente mais tarde.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode are not available on this device. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_AVAILABLE" = "Você deve criar uma senha no app Ajustes do iOS para usar bloqueio de tela.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode is not configured on this device. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_ENROLLED" = "Você deve criar uma senha no app Ajustes do iOS para usar o bloqueio de tela.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode passcode is not set. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_PASSCODE_NOT_SET" = "Você deve criar uma senha no app Ajustes do iOS para usar o bloqueio de tela.";
|
||||
/* Label for the button to send a message */
|
||||
"SEND_BUTTON_TITLE" = "Send";
|
||||
/* Generic text for button that retries whatever the last action was. */
|
||||
"RETRY_BUTTON_TEXT" = "Retry";
|
||||
/* notification action */
|
||||
"SHOW_THREAD_BUTTON_TITLE" = "Show Chat";
|
||||
/* notification body */
|
||||
"SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send.";
|
||||
"INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again.";
|
||||
"INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again.";
|
||||
|
|
|
@ -606,7 +606,6 @@
|
|||
"accessibility_camera_button" = "Камера";
|
||||
"accessibility_main_button_collapse" = "Свернуть параметры вложений";
|
||||
"invalid_recovery_phrase" = "Неверная секретная фраза";
|
||||
"invalid_recovery_phrase" = "Неверная секретная фраза";
|
||||
"DISMISS_BUTTON_TEXT" = "Закрыть";
|
||||
/* Button text which opens the settings app */
|
||||
"OPEN_SETTINGS_BUTTON" = "Настройки";
|
||||
|
@ -653,10 +652,36 @@
|
|||
"modal_call_permission_request_explanation" = "You can enable the 'Voice and video calls' permission in the Privacy Settings.";
|
||||
"DEFAULT_OPEN_GROUP_LOAD_ERROR_TITLE" = "Oops, an error occurred";
|
||||
"DEFAULT_OPEN_GROUP_LOAD_ERROR_SUBTITLE" = "Please try again later";
|
||||
"ALERT_ERROR_TITLE" = "Ошибка";
|
||||
"LOADING_CONVERSATIONS" = "Loading Conversations...";
|
||||
"DATABASE_MIGRATION_FAILED" = "An error occurred when optimising the database\n\nYou can export your application logs to be able to share for troubleshooting or you can restore our device\n\nWarning: Restoring your device will result in loss of any data older than two weeks";
|
||||
"CHATS_TITLE" = "Chats";
|
||||
"MESSAGE_TRIMMING_TITLE" = "Message Trimming";
|
||||
"MESSAGE_TRIMMING_OPEN_GROUP_TITLE" = "Delete Old Open Group Messages";
|
||||
"MESSAGE_TRIMMING_OPEN_GROUP_DESCRIPTION" = "Automatically delete messages which are older than 6 months from open groups with over 2,000 messages when starting the app";
|
||||
"RECOVERY_PHASE_ERROR_GENERIC" = "Something went wrong. Please check your recovery phrase and try again.";
|
||||
"RECOVERY_PHASE_ERROR_LENGTH" = "Looks like you didn't enter enough words. Please check your recovery phrase and try again.";
|
||||
"RECOVERY_PHASE_ERROR_LAST_WORD" = "You seem to be missing the last word of your recovery phrase. Please check what you entered and try again.";
|
||||
"RECOVERY_PHASE_ERROR_INVALID_WORD" = "There appears to be an invalid word in your recovery phrase. Please check what you entered and try again.";
|
||||
"RECOVERY_PHASE_ERROR_FAILED" = "Your recovery phrase couldn't be verified. Please check what you entered and try again.";
|
||||
/* Indicates that an unknown error occurred while using Touch ID/Face ID/Phone Passcode. */
|
||||
"SCREEN_LOCK_ENABLE_UNKNOWN_ERROR" = "Authentication could not be accessed.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode authentication failed. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_FAILED" = "Ошибка аутентификации.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode is 'locked out' on this device due to authentication failures. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_LOCKOUT" = "Слишком много неудачных попыток аутентификации. Пожалуйста, повторите попытку позже.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode are not available on this device. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_AVAILABLE" = "Вы должны включить код доступа в приложении «Настройки», чтобы использовать блокировку экрана.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode is not configured on this device. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_ENROLLED" = "Вы должны включить код доступа в приложении «Настройки», чтобы использовать блокировку экрана.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode passcode is not set. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_PASSCODE_NOT_SET" = "Вы должны включить код доступа в приложении «Настройки», чтобы использовать блокировку экрана.";
|
||||
/* Label for the button to send a message */
|
||||
"SEND_BUTTON_TITLE" = "Send";
|
||||
/* Generic text for button that retries whatever the last action was. */
|
||||
"RETRY_BUTTON_TEXT" = "Retry";
|
||||
/* notification action */
|
||||
"SHOW_THREAD_BUTTON_TITLE" = "Show Chat";
|
||||
/* notification body */
|
||||
"SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send.";
|
||||
"INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again.";
|
||||
"INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again.";
|
||||
|
|
|
@ -606,7 +606,6 @@
|
|||
"accessibility_camera_button" = "Camera";
|
||||
"accessibility_main_button_collapse" = "Collapse attachment options";
|
||||
"invalid_recovery_phrase" = "Invalid Recovery Phrase";
|
||||
"invalid_recovery_phrase" = "Invalid Recovery Phrase";
|
||||
"DISMISS_BUTTON_TEXT" = "Dismiss";
|
||||
/* Button text which opens the settings app */
|
||||
"OPEN_SETTINGS_BUTTON" = "සැකසුම්";
|
||||
|
@ -653,10 +652,36 @@
|
|||
"modal_call_permission_request_explanation" = "You can enable the 'Voice and video calls' permission in the Privacy Settings.";
|
||||
"DEFAULT_OPEN_GROUP_LOAD_ERROR_TITLE" = "Oops, an error occurred";
|
||||
"DEFAULT_OPEN_GROUP_LOAD_ERROR_SUBTITLE" = "Please try again later";
|
||||
"ALERT_ERROR_TITLE" = "Error";
|
||||
"LOADING_CONVERSATIONS" = "Loading Conversations...";
|
||||
"DATABASE_MIGRATION_FAILED" = "An error occurred when optimising the database\n\nYou can export your application logs to be able to share for troubleshooting or you can restore our device\n\nWarning: Restoring your device will result in loss of any data older than two weeks";
|
||||
"CHATS_TITLE" = "Chats";
|
||||
"MESSAGE_TRIMMING_TITLE" = "Message Trimming";
|
||||
"MESSAGE_TRIMMING_OPEN_GROUP_TITLE" = "Delete Old Open Group Messages";
|
||||
"MESSAGE_TRIMMING_OPEN_GROUP_DESCRIPTION" = "Automatically delete messages which are older than 6 months from open groups with over 2,000 messages when starting the app";
|
||||
"RECOVERY_PHASE_ERROR_GENERIC" = "Something went wrong. Please check your recovery phrase and try again.";
|
||||
"RECOVERY_PHASE_ERROR_LENGTH" = "Looks like you didn't enter enough words. Please check your recovery phrase and try again.";
|
||||
"RECOVERY_PHASE_ERROR_LAST_WORD" = "You seem to be missing the last word of your recovery phrase. Please check what you entered and try again.";
|
||||
"RECOVERY_PHASE_ERROR_INVALID_WORD" = "There appears to be an invalid word in your recovery phrase. Please check what you entered and try again.";
|
||||
"RECOVERY_PHASE_ERROR_FAILED" = "Your recovery phrase couldn't be verified. Please check what you entered and try again.";
|
||||
/* Indicates that an unknown error occurred while using Touch ID/Face ID/Phone Passcode. */
|
||||
"SCREEN_LOCK_ENABLE_UNKNOWN_ERROR" = "Authentication could not be accessed.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode authentication failed. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_FAILED" = "Authentication failed.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode is 'locked out' on this device due to authentication failures. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_LOCKOUT" = "Too many failed authentication attempts. Please try again later.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode are not available on this device. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_AVAILABLE" = "You must enable a passcode in your iOS Settings in order to use Screen Lock.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode is not configured on this device. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_ENROLLED" = "You must enable a passcode in your iOS Settings in order to use Screen Lock.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode passcode is not set. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_PASSCODE_NOT_SET" = "You must enable a passcode in your iOS Settings in order to use Screen Lock.";
|
||||
/* Label for the button to send a message */
|
||||
"SEND_BUTTON_TITLE" = "Send";
|
||||
/* Generic text for button that retries whatever the last action was. */
|
||||
"RETRY_BUTTON_TEXT" = "Retry";
|
||||
/* notification action */
|
||||
"SHOW_THREAD_BUTTON_TITLE" = "Show Chat";
|
||||
/* notification body */
|
||||
"SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send.";
|
||||
"INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again.";
|
||||
"INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again.";
|
||||
|
|
|
@ -606,7 +606,6 @@
|
|||
"accessibility_camera_button" = "Kamera";
|
||||
"accessibility_main_button_collapse" = "Uzatvor možnosti prípon";
|
||||
"invalid_recovery_phrase" = "Neplatná Obnovovacia Fráza";
|
||||
"invalid_recovery_phrase" = "Neplatná Obnovovacia Fráza";
|
||||
"DISMISS_BUTTON_TEXT" = "Zrušiť";
|
||||
/* Button text which opens the settings app */
|
||||
"OPEN_SETTINGS_BUTTON" = "Nastavenia";
|
||||
|
@ -653,10 +652,36 @@
|
|||
"modal_call_permission_request_explanation" = "You can enable the 'Voice and video calls' permission in the Privacy Settings.";
|
||||
"DEFAULT_OPEN_GROUP_LOAD_ERROR_TITLE" = "Oops, an error occurred";
|
||||
"DEFAULT_OPEN_GROUP_LOAD_ERROR_SUBTITLE" = "Please try again later";
|
||||
"ALERT_ERROR_TITLE" = "Error";
|
||||
"LOADING_CONVERSATIONS" = "Loading Conversations...";
|
||||
"DATABASE_MIGRATION_FAILED" = "An error occurred when optimising the database\n\nYou can export your application logs to be able to share for troubleshooting or you can restore our device\n\nWarning: Restoring your device will result in loss of any data older than two weeks";
|
||||
"CHATS_TITLE" = "Chats";
|
||||
"MESSAGE_TRIMMING_TITLE" = "Message Trimming";
|
||||
"MESSAGE_TRIMMING_OPEN_GROUP_TITLE" = "Delete Old Open Group Messages";
|
||||
"MESSAGE_TRIMMING_OPEN_GROUP_DESCRIPTION" = "Automatically delete messages which are older than 6 months from open groups with over 2,000 messages when starting the app";
|
||||
"RECOVERY_PHASE_ERROR_GENERIC" = "Something went wrong. Please check your recovery phrase and try again.";
|
||||
"RECOVERY_PHASE_ERROR_LENGTH" = "Looks like you didn't enter enough words. Please check your recovery phrase and try again.";
|
||||
"RECOVERY_PHASE_ERROR_LAST_WORD" = "You seem to be missing the last word of your recovery phrase. Please check what you entered and try again.";
|
||||
"RECOVERY_PHASE_ERROR_INVALID_WORD" = "There appears to be an invalid word in your recovery phrase. Please check what you entered and try again.";
|
||||
"RECOVERY_PHASE_ERROR_FAILED" = "Your recovery phrase couldn't be verified. Please check what you entered and try again.";
|
||||
/* Indicates that an unknown error occurred while using Touch ID/Face ID/Phone Passcode. */
|
||||
"SCREEN_LOCK_ENABLE_UNKNOWN_ERROR" = "Authentication could not be accessed.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode authentication failed. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_FAILED" = "Autentifikácia zlyhala";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode is 'locked out' on this device due to authentication failures. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_LOCKOUT" = "Priveľa nepodarených pokusov o autentifikáciu. Prosím, skúste to znovu neskôr.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode are not available on this device. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_AVAILABLE" = "Pre používanie zámku obrazovky, zapnite kódový zámok v nastaveniach iOS.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode is not configured on this device. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_ENROLLED" = "Pre používanie zámku obrazovky, zapnite kódový zámok v nastaveniach iOS.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode passcode is not set. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_PASSCODE_NOT_SET" = "Pre používanie zámku obrazovky, zapnite kódový zámok v nastaveniach iOS.";
|
||||
/* Label for the button to send a message */
|
||||
"SEND_BUTTON_TITLE" = "Send";
|
||||
/* Generic text for button that retries whatever the last action was. */
|
||||
"RETRY_BUTTON_TEXT" = "Retry";
|
||||
/* notification action */
|
||||
"SHOW_THREAD_BUTTON_TITLE" = "Show Chat";
|
||||
/* notification body */
|
||||
"SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send.";
|
||||
"INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again.";
|
||||
"INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again.";
|
||||
|
|
|
@ -606,7 +606,6 @@
|
|||
"accessibility_camera_button" = "Kamera";
|
||||
"accessibility_main_button_collapse" = "Collapse attachment options";
|
||||
"invalid_recovery_phrase" = "Invalid Recovery Phrase";
|
||||
"invalid_recovery_phrase" = "Invalid Recovery Phrase";
|
||||
"DISMISS_BUTTON_TEXT" = "Dismiss";
|
||||
/* Button text which opens the settings app */
|
||||
"OPEN_SETTINGS_BUTTON" = "Inställningar";
|
||||
|
@ -653,10 +652,36 @@
|
|||
"modal_call_permission_request_explanation" = "You can enable the 'Voice and video calls' permission in the Privacy Settings.";
|
||||
"DEFAULT_OPEN_GROUP_LOAD_ERROR_TITLE" = "Oops, an error occurred";
|
||||
"DEFAULT_OPEN_GROUP_LOAD_ERROR_SUBTITLE" = "Please try again later";
|
||||
"ALERT_ERROR_TITLE" = "Error";
|
||||
"LOADING_CONVERSATIONS" = "Loading Conversations...";
|
||||
"DATABASE_MIGRATION_FAILED" = "An error occurred when optimising the database\n\nYou can export your application logs to be able to share for troubleshooting or you can restore our device\n\nWarning: Restoring your device will result in loss of any data older than two weeks";
|
||||
"CHATS_TITLE" = "Chats";
|
||||
"MESSAGE_TRIMMING_TITLE" = "Message Trimming";
|
||||
"MESSAGE_TRIMMING_OPEN_GROUP_TITLE" = "Delete Old Open Group Messages";
|
||||
"MESSAGE_TRIMMING_OPEN_GROUP_DESCRIPTION" = "Automatically delete messages which are older than 6 months from open groups with over 2,000 messages when starting the app";
|
||||
"RECOVERY_PHASE_ERROR_GENERIC" = "Something went wrong. Please check your recovery phrase and try again.";
|
||||
"RECOVERY_PHASE_ERROR_LENGTH" = "Looks like you didn't enter enough words. Please check your recovery phrase and try again.";
|
||||
"RECOVERY_PHASE_ERROR_LAST_WORD" = "You seem to be missing the last word of your recovery phrase. Please check what you entered and try again.";
|
||||
"RECOVERY_PHASE_ERROR_INVALID_WORD" = "There appears to be an invalid word in your recovery phrase. Please check what you entered and try again.";
|
||||
"RECOVERY_PHASE_ERROR_FAILED" = "Your recovery phrase couldn't be verified. Please check what you entered and try again.";
|
||||
/* Indicates that an unknown error occurred while using Touch ID/Face ID/Phone Passcode. */
|
||||
"SCREEN_LOCK_ENABLE_UNKNOWN_ERROR" = "Authentication could not be accessed.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode authentication failed. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_FAILED" = "Autentisering misslyckades.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode is 'locked out' on this device due to authentication failures. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_LOCKOUT" = "För många misslyckade autentiseringsförsök. Försök igen senare.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode are not available on this device. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_AVAILABLE" = "Du måste aktivera en lösenkod i dina iOS-inställningar för att använda Skärmlås.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode is not configured on this device. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_ENROLLED" = "Du måste aktivera en lösenkod i dina iOS-inställningar för att använda Skärmlås.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode passcode is not set. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_PASSCODE_NOT_SET" = "Du måste aktivera en lösenkod i dina iOS-inställningar för att använda Skärmlås.";
|
||||
/* Label for the button to send a message */
|
||||
"SEND_BUTTON_TITLE" = "Send";
|
||||
/* Generic text for button that retries whatever the last action was. */
|
||||
"RETRY_BUTTON_TEXT" = "Retry";
|
||||
/* notification action */
|
||||
"SHOW_THREAD_BUTTON_TITLE" = "Show Chat";
|
||||
/* notification body */
|
||||
"SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send.";
|
||||
"INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again.";
|
||||
"INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again.";
|
||||
|
|
|
@ -606,7 +606,6 @@
|
|||
"accessibility_camera_button" = "Camera";
|
||||
"accessibility_main_button_collapse" = "Collapse attachment options";
|
||||
"invalid_recovery_phrase" = "Invalid Recovery Phrase";
|
||||
"invalid_recovery_phrase" = "Invalid Recovery Phrase";
|
||||
"DISMISS_BUTTON_TEXT" = "Dismiss";
|
||||
/* Button text which opens the settings app */
|
||||
"OPEN_SETTINGS_BUTTON" = "Settings";
|
||||
|
@ -653,10 +652,36 @@
|
|||
"modal_call_permission_request_explanation" = "You can enable the 'Voice and video calls' permission in the Privacy Settings.";
|
||||
"DEFAULT_OPEN_GROUP_LOAD_ERROR_TITLE" = "Oops, an error occurred";
|
||||
"DEFAULT_OPEN_GROUP_LOAD_ERROR_SUBTITLE" = "Please try again later";
|
||||
"ALERT_ERROR_TITLE" = "Error";
|
||||
"LOADING_CONVERSATIONS" = "Loading Conversations...";
|
||||
"DATABASE_MIGRATION_FAILED" = "An error occurred when optimising the database\n\nYou can export your application logs to be able to share for troubleshooting or you can restore our device\n\nWarning: Restoring your device will result in loss of any data older than two weeks";
|
||||
"CHATS_TITLE" = "Chats";
|
||||
"MESSAGE_TRIMMING_TITLE" = "Message Trimming";
|
||||
"MESSAGE_TRIMMING_OPEN_GROUP_TITLE" = "Delete Old Open Group Messages";
|
||||
"MESSAGE_TRIMMING_OPEN_GROUP_DESCRIPTION" = "Automatically delete messages which are older than 6 months from open groups with over 2,000 messages when starting the app";
|
||||
"RECOVERY_PHASE_ERROR_GENERIC" = "Something went wrong. Please check your recovery phrase and try again.";
|
||||
"RECOVERY_PHASE_ERROR_LENGTH" = "Looks like you didn't enter enough words. Please check your recovery phrase and try again.";
|
||||
"RECOVERY_PHASE_ERROR_LAST_WORD" = "You seem to be missing the last word of your recovery phrase. Please check what you entered and try again.";
|
||||
"RECOVERY_PHASE_ERROR_INVALID_WORD" = "There appears to be an invalid word in your recovery phrase. Please check what you entered and try again.";
|
||||
"RECOVERY_PHASE_ERROR_FAILED" = "Your recovery phrase couldn't be verified. Please check what you entered and try again.";
|
||||
/* Indicates that an unknown error occurred while using Touch ID/Face ID/Phone Passcode. */
|
||||
"SCREEN_LOCK_ENABLE_UNKNOWN_ERROR" = "Authentication could not be accessed.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode authentication failed. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_FAILED" = "การรับรองความถูกต้องไม่สำเร็จ";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode is 'locked out' on this device due to authentication failures. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_LOCKOUT" = "รับรองความถูกต้องไม่สำเร็จหลายครั้งเกินไป โปรดลองใหม่ในภายหลัง";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode are not available on this device. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_AVAILABLE" = "คุณต้องเปิดใช้งานรหัสผ่านในการตั้งค่า iOS ของคุณเพื่อใช้งานการล็อกหน้าจอ";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode is not configured on this device. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_ENROLLED" = "คุณต้องเปิดใช้งานรหัสผ่านในการตั้งค่า iOS ของคุณเพื่อใช้งานการล็อกหน้าจอ";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode passcode is not set. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_PASSCODE_NOT_SET" = "คุณต้องเปิดใช้งานรหัสผ่านในการตั้งค่า iOS ของคุณเพื่อใช้งานการล็อกหน้าจอ";
|
||||
/* Label for the button to send a message */
|
||||
"SEND_BUTTON_TITLE" = "Send";
|
||||
/* Generic text for button that retries whatever the last action was. */
|
||||
"RETRY_BUTTON_TEXT" = "Retry";
|
||||
/* notification action */
|
||||
"SHOW_THREAD_BUTTON_TITLE" = "Show Chat";
|
||||
/* notification body */
|
||||
"SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send.";
|
||||
"INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again.";
|
||||
"INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again.";
|
||||
|
|
|
@ -606,7 +606,6 @@
|
|||
"accessibility_camera_button" = "Camera";
|
||||
"accessibility_main_button_collapse" = "Collapse attachment options";
|
||||
"invalid_recovery_phrase" = "Invalid Recovery Phrase";
|
||||
"invalid_recovery_phrase" = "Invalid Recovery Phrase";
|
||||
"DISMISS_BUTTON_TEXT" = "Dismiss";
|
||||
/* Button text which opens the settings app */
|
||||
"OPEN_SETTINGS_BUTTON" = "Settings";
|
||||
|
@ -653,10 +652,36 @@
|
|||
"modal_call_permission_request_explanation" = "You can enable the 'Voice and video calls' permission in the Privacy Settings.";
|
||||
"DEFAULT_OPEN_GROUP_LOAD_ERROR_TITLE" = "Oops, an error occurred";
|
||||
"DEFAULT_OPEN_GROUP_LOAD_ERROR_SUBTITLE" = "Please try again later";
|
||||
"ALERT_ERROR_TITLE" = "Error";
|
||||
"LOADING_CONVERSATIONS" = "Loading Conversations...";
|
||||
"DATABASE_MIGRATION_FAILED" = "An error occurred when optimising the database\n\nYou can export your application logs to be able to share for troubleshooting or you can restore our device\n\nWarning: Restoring your device will result in loss of any data older than two weeks";
|
||||
"CHATS_TITLE" = "Chats";
|
||||
"MESSAGE_TRIMMING_TITLE" = "Message Trimming";
|
||||
"MESSAGE_TRIMMING_OPEN_GROUP_TITLE" = "Delete Old Open Group Messages";
|
||||
"MESSAGE_TRIMMING_OPEN_GROUP_DESCRIPTION" = "Automatically delete messages which are older than 6 months from open groups with over 2,000 messages when starting the app";
|
||||
"RECOVERY_PHASE_ERROR_GENERIC" = "Something went wrong. Please check your recovery phrase and try again.";
|
||||
"RECOVERY_PHASE_ERROR_LENGTH" = "Looks like you didn't enter enough words. Please check your recovery phrase and try again.";
|
||||
"RECOVERY_PHASE_ERROR_LAST_WORD" = "You seem to be missing the last word of your recovery phrase. Please check what you entered and try again.";
|
||||
"RECOVERY_PHASE_ERROR_INVALID_WORD" = "There appears to be an invalid word in your recovery phrase. Please check what you entered and try again.";
|
||||
"RECOVERY_PHASE_ERROR_FAILED" = "Your recovery phrase couldn't be verified. Please check what you entered and try again.";
|
||||
/* Indicates that an unknown error occurred while using Touch ID/Face ID/Phone Passcode. */
|
||||
"SCREEN_LOCK_ENABLE_UNKNOWN_ERROR" = "Authentication could not be accessed.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode authentication failed. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_FAILED" = "Authentication failed.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode is 'locked out' on this device due to authentication failures. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_LOCKOUT" = "Too many failed authentication attempts. Please try again later.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode are not available on this device. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_AVAILABLE" = "You must enable a passcode in your iOS Settings in order to use Screen Lock.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode is not configured on this device. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_ENROLLED" = "You must enable a passcode in your iOS Settings in order to use Screen Lock.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode passcode is not set. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_PASSCODE_NOT_SET" = "You must enable a passcode in your iOS Settings in order to use Screen Lock.";
|
||||
/* Label for the button to send a message */
|
||||
"SEND_BUTTON_TITLE" = "Send";
|
||||
/* Generic text for button that retries whatever the last action was. */
|
||||
"RETRY_BUTTON_TEXT" = "Retry";
|
||||
/* notification action */
|
||||
"SHOW_THREAD_BUTTON_TITLE" = "Show Chat";
|
||||
/* notification body */
|
||||
"SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send.";
|
||||
"INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again.";
|
||||
"INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again.";
|
||||
|
|
|
@ -606,7 +606,6 @@
|
|||
"accessibility_camera_button" = "相機";
|
||||
"accessibility_main_button_collapse" = "摺疊附件選項";
|
||||
"invalid_recovery_phrase" = "備援暗語無效";
|
||||
"invalid_recovery_phrase" = "恢復短語無效";
|
||||
"DISMISS_BUTTON_TEXT" = "關閉";
|
||||
/* Button text which opens the settings app */
|
||||
"OPEN_SETTINGS_BUTTON" = "設定";
|
||||
|
@ -653,10 +652,36 @@
|
|||
"modal_call_permission_request_explanation" = "You can enable the 'Voice and video calls' permission in the Privacy Settings.";
|
||||
"DEFAULT_OPEN_GROUP_LOAD_ERROR_TITLE" = "Oops, an error occurred";
|
||||
"DEFAULT_OPEN_GROUP_LOAD_ERROR_SUBTITLE" = "Please try again later";
|
||||
"ALERT_ERROR_TITLE" = "Error";
|
||||
"LOADING_CONVERSATIONS" = "Loading Conversations...";
|
||||
"DATABASE_MIGRATION_FAILED" = "An error occurred when optimising the database\n\nYou can export your application logs to be able to share for troubleshooting or you can restore our device\n\nWarning: Restoring your device will result in loss of any data older than two weeks";
|
||||
"CHATS_TITLE" = "Chats";
|
||||
"MESSAGE_TRIMMING_TITLE" = "Message Trimming";
|
||||
"MESSAGE_TRIMMING_OPEN_GROUP_TITLE" = "Delete Old Open Group Messages";
|
||||
"MESSAGE_TRIMMING_OPEN_GROUP_DESCRIPTION" = "Automatically delete messages which are older than 6 months from open groups with over 2,000 messages when starting the app";
|
||||
"RECOVERY_PHASE_ERROR_GENERIC" = "Something went wrong. Please check your recovery phrase and try again.";
|
||||
"RECOVERY_PHASE_ERROR_LENGTH" = "Looks like you didn't enter enough words. Please check your recovery phrase and try again.";
|
||||
"RECOVERY_PHASE_ERROR_LAST_WORD" = "You seem to be missing the last word of your recovery phrase. Please check what you entered and try again.";
|
||||
"RECOVERY_PHASE_ERROR_INVALID_WORD" = "There appears to be an invalid word in your recovery phrase. Please check what you entered and try again.";
|
||||
"RECOVERY_PHASE_ERROR_FAILED" = "Your recovery phrase couldn't be verified. Please check what you entered and try again.";
|
||||
/* Indicates that an unknown error occurred while using Touch ID/Face ID/Phone Passcode. */
|
||||
"SCREEN_LOCK_ENABLE_UNKNOWN_ERROR" = "Authentication could not be accessed.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode authentication failed. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_FAILED" = "Authentication failed.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode is 'locked out' on this device due to authentication failures. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_LOCKOUT" = "Too many failed authentication attempts. Please try again later.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode are not available on this device. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_AVAILABLE" = "You must enable a passcode in your iOS Settings in order to use Screen Lock.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode is not configured on this device. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_ENROLLED" = "You must enable a passcode in your iOS Settings in order to use Screen Lock.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode passcode is not set. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_PASSCODE_NOT_SET" = "You must enable a passcode in your iOS Settings in order to use Screen Lock.";
|
||||
/* Label for the button to send a message */
|
||||
"SEND_BUTTON_TITLE" = "Send";
|
||||
/* Generic text for button that retries whatever the last action was. */
|
||||
"RETRY_BUTTON_TEXT" = "Retry";
|
||||
/* notification action */
|
||||
"SHOW_THREAD_BUTTON_TITLE" = "Show Chat";
|
||||
/* notification body */
|
||||
"SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send.";
|
||||
"INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again.";
|
||||
"INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again.";
|
||||
|
|
|
@ -606,7 +606,6 @@
|
|||
"accessibility_camera_button" = "相机";
|
||||
"accessibility_main_button_collapse" = "收起附件选项";
|
||||
"invalid_recovery_phrase" = "恢复口令无效";
|
||||
"invalid_recovery_phrase" = "恢复口令无效";
|
||||
"DISMISS_BUTTON_TEXT" = "取消";
|
||||
/* Button text which opens the settings app */
|
||||
"OPEN_SETTINGS_BUTTON" = "设置";
|
||||
|
@ -653,10 +652,36 @@
|
|||
"modal_call_permission_request_explanation" = "您可以在隐私设置中启用“语音和视频通话”权限。";
|
||||
"DEFAULT_OPEN_GROUP_LOAD_ERROR_TITLE" = "Oops, an error occurred";
|
||||
"DEFAULT_OPEN_GROUP_LOAD_ERROR_SUBTITLE" = "Please try again later";
|
||||
"ALERT_ERROR_TITLE" = "错误";
|
||||
"LOADING_CONVERSATIONS" = "Loading Conversations...";
|
||||
"DATABASE_MIGRATION_FAILED" = "An error occurred when optimising the database\n\nYou can export your application logs to be able to share for troubleshooting or you can restore our device\n\nWarning: Restoring your device will result in loss of any data older than two weeks";
|
||||
"CHATS_TITLE" = "Chats";
|
||||
"MESSAGE_TRIMMING_TITLE" = "Message Trimming";
|
||||
"MESSAGE_TRIMMING_OPEN_GROUP_TITLE" = "Delete Old Open Group Messages";
|
||||
"MESSAGE_TRIMMING_OPEN_GROUP_DESCRIPTION" = "Automatically delete messages which are older than 6 months from open groups with over 2,000 messages when starting the app";
|
||||
"RECOVERY_PHASE_ERROR_GENERIC" = "Something went wrong. Please check your recovery phrase and try again.";
|
||||
"RECOVERY_PHASE_ERROR_LENGTH" = "Looks like you didn't enter enough words. Please check your recovery phrase and try again.";
|
||||
"RECOVERY_PHASE_ERROR_LAST_WORD" = "You seem to be missing the last word of your recovery phrase. Please check what you entered and try again.";
|
||||
"RECOVERY_PHASE_ERROR_INVALID_WORD" = "There appears to be an invalid word in your recovery phrase. Please check what you entered and try again.";
|
||||
"RECOVERY_PHASE_ERROR_FAILED" = "Your recovery phrase couldn't be verified. Please check what you entered and try again.";
|
||||
/* Indicates that an unknown error occurred while using Touch ID/Face ID/Phone Passcode. */
|
||||
"SCREEN_LOCK_ENABLE_UNKNOWN_ERROR" = "Authentication could not be accessed.";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode authentication failed. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_FAILED" = "认证失败。";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode is 'locked out' on this device due to authentication failures. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_LOCKOUT" = "认证失败次数太多,请稍后再试。";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode are not available on this device. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_AVAILABLE" = "您需要先设置您的密码来开启屏幕锁功能。";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode is not configured on this device. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_ENROLLED" = "您需要先设置您的密码来开启屏幕锁功能。";
|
||||
/* Indicates that Touch ID/Face ID/Phone Passcode passcode is not set. */
|
||||
"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_PASSCODE_NOT_SET" = "您需要先设置您的密码来开启屏幕锁功能。";
|
||||
/* Label for the button to send a message */
|
||||
"SEND_BUTTON_TITLE" = "Send";
|
||||
/* Generic text for button that retries whatever the last action was. */
|
||||
"RETRY_BUTTON_TEXT" = "Retry";
|
||||
/* notification action */
|
||||
"SHOW_THREAD_BUTTON_TITLE" = "Show Chat";
|
||||
/* notification body */
|
||||
"SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send.";
|
||||
"INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again.";
|
||||
"INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again.";
|
||||
|
|
|
@ -224,11 +224,19 @@ public class NotificationPresenter: NSObject, NotificationsProtocol {
|
|||
let userInfo = [
|
||||
AppNotificationUserInfoKey.threadId: thread.id
|
||||
]
|
||||
|
||||
let userPublicKey: String = getUserHexEncodedPublicKey(db)
|
||||
let userBlindedKey: String? = SessionThread.getUserHexEncodedBlindedKey(
|
||||
threadId: thread.id,
|
||||
threadVariant: thread.variant
|
||||
)
|
||||
|
||||
DispatchQueue.main.async {
|
||||
notificationBody = MentionUtilities.highlightMentions(
|
||||
in: (notificationBody ?? ""),
|
||||
threadVariant: thread.variant
|
||||
threadVariant: thread.variant,
|
||||
currentUserPublicKey: userPublicKey,
|
||||
currentUserBlindedPublicKey: userBlindedKey
|
||||
)
|
||||
let sound: Preferences.Sound? = self.requestSound(thread: thread)
|
||||
|
||||
|
|
|
@ -128,7 +128,11 @@ final class LinkDeviceVC : BaseVC, UIPageViewControllerDataSource, UIPageViewCon
|
|||
|
||||
func continueWithSeed(_ seed: Data) {
|
||||
if (seed.count != 16) {
|
||||
let alert = UIAlertController(title: NSLocalizedString("invalid_recovery_phrase", comment: ""), message: NSLocalizedString("Please check the Recovery Phrase and try again.", comment: ""), preferredStyle: .alert)
|
||||
let alert = UIAlertController(
|
||||
title: "invalid_recovery_phrase".localized(),
|
||||
message: "INVALID_RECOVERY_PHRASE_MESSAGE".localized(),
|
||||
preferredStyle: .alert
|
||||
)
|
||||
alert.addAction(UIAlertAction(title: NSLocalizedString("BUTTON_OK", comment: ""), style: .default, handler: { _ in
|
||||
self.scanQRCodeWrapperVC.startCapture()
|
||||
}))
|
||||
|
|
|
@ -121,7 +121,9 @@ final class QRCodeVC : BaseVC, UIPageViewControllerDataSource, UIPageViewControl
|
|||
|
||||
fileprivate func startNewPrivateChatIfPossible(with hexEncodedPublicKey: String) {
|
||||
if !ECKeyPair.isValidHexEncodedPublicKey(candidate: hexEncodedPublicKey) {
|
||||
let alert = UIAlertController(title: NSLocalizedString("invalid_session_id", comment: ""), message: NSLocalizedString("Please check the Session ID and try again.", comment: ""), preferredStyle: .alert)
|
||||
let alert = UIAlertController(
|
||||
title: "invalid_session_id".localized(),
|
||||
message: "INVALID_SESSION_ID_MESSAGE".localized(), preferredStyle: .alert)
|
||||
alert.addAction(UIAlertAction(title: NSLocalizedString("BUTTON_OK", comment: ""), style: .default, handler: nil))
|
||||
presentAlert(alert)
|
||||
}
|
||||
|
|
|
@ -267,6 +267,8 @@ public final class FullConversationCell: UITableViewCell {
|
|||
cellViewModel.authorName(for: .contact) :
|
||||
nil
|
||||
),
|
||||
currentUserPublicKey: cellViewModel.currentUserPublicKey,
|
||||
currentUserBlindedPublicKey: cellViewModel.currentUserBlindedPublicKey,
|
||||
searchText: searchText.lowercased(),
|
||||
fontSize: Values.smallFontSize
|
||||
)
|
||||
|
@ -288,6 +290,8 @@ public final class FullConversationCell: UITableViewCell {
|
|||
timestampLabel.isHidden = true
|
||||
displayNameLabel.attributedText = getHighlightedSnippet(
|
||||
content: cellViewModel.displayName,
|
||||
currentUserPublicKey: cellViewModel.currentUserPublicKey,
|
||||
currentUserBlindedPublicKey: cellViewModel.currentUserBlindedPublicKey,
|
||||
searchText: searchText.lowercased(),
|
||||
fontSize: Values.mediumFontSize
|
||||
)
|
||||
|
@ -299,6 +303,8 @@ public final class FullConversationCell: UITableViewCell {
|
|||
bottomLabelStackView.isHidden = (cellViewModel.threadMemberNames ?? "").isEmpty
|
||||
snippetLabel.attributedText = getHighlightedSnippet(
|
||||
content: (cellViewModel.threadMemberNames ?? ""),
|
||||
currentUserPublicKey: cellViewModel.currentUserPublicKey,
|
||||
currentUserBlindedPublicKey: cellViewModel.currentUserBlindedPublicKey,
|
||||
searchText: searchText.lowercased(),
|
||||
fontSize: Values.smallFontSize
|
||||
)
|
||||
|
@ -440,7 +446,9 @@ public final class FullConversationCell: UITableViewCell {
|
|||
attachmentCount: cellViewModel.interactionAttachmentCount,
|
||||
isOpenGroupInvitation: (cellViewModel.interactionIsOpenGroupInvitation == true)
|
||||
),
|
||||
threadVariant: cellViewModel.threadVariant
|
||||
threadVariant: cellViewModel.threadVariant,
|
||||
currentUserPublicKey: cellViewModel.currentUserPublicKey,
|
||||
currentUserBlindedPublicKey: cellViewModel.currentUserBlindedPublicKey
|
||||
),
|
||||
attributes: [
|
||||
.font: font,
|
||||
|
@ -454,6 +462,8 @@ public final class FullConversationCell: UITableViewCell {
|
|||
private func getHighlightedSnippet(
|
||||
content: String,
|
||||
authorName: String? = nil,
|
||||
currentUserPublicKey: String,
|
||||
currentUserBlindedPublicKey: String?,
|
||||
searchText: String,
|
||||
fontSize: CGFloat
|
||||
) -> NSAttributedString {
|
||||
|
@ -473,7 +483,9 @@ public final class FullConversationCell: UITableViewCell {
|
|||
// we don't want to include the truncated id as part of the name so we exclude it
|
||||
let mentionReplacedContent: String = MentionUtilities.highlightMentions(
|
||||
in: content,
|
||||
threadVariant: .contact
|
||||
threadVariant: .contact,
|
||||
currentUserPublicKey: currentUserPublicKey,
|
||||
currentUserBlindedPublicKey: currentUserBlindedPublicKey
|
||||
)
|
||||
let result: NSMutableAttributedString = NSMutableAttributedString(
|
||||
string: mentionReplacedContent,
|
||||
|
|
|
@ -0,0 +1,161 @@
|
|||
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
||||
|
||||
import UIKit
|
||||
|
||||
public extension NSAttributedString.Key {
|
||||
static let currentUserMentionBackgroundColor: NSAttributedString.Key = NSAttributedString.Key(rawValue: "currentUserMentionBackgroundColor")
|
||||
static let currentUserMentionBackgroundCornerRadius: NSAttributedString.Key = NSAttributedString.Key(rawValue: "currentUserMentionBackgroundCornerRadius")
|
||||
static let currentUserMentionBackgroundPadding: NSAttributedString.Key = NSAttributedString.Key(rawValue: "currentUserMentionBackgroundPadding")
|
||||
}
|
||||
|
||||
class HighlightMentionBackgroundView: UIView {
|
||||
var maxPadding: CGFloat = 0
|
||||
|
||||
init() {
|
||||
super.init(frame: .zero)
|
||||
|
||||
self.isOpaque = false
|
||||
self.layer.zPosition = -1
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
// MARK: - Functions
|
||||
|
||||
public func calculateMaxPadding(for attributedText: NSAttributedString) -> CGFloat {
|
||||
var allMentionRadii: [CGFloat?] = []
|
||||
let path: CGMutablePath = CGMutablePath()
|
||||
path.addRect(CGRect(
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: CGFloat.greatestFiniteMagnitude,
|
||||
height: CGFloat.greatestFiniteMagnitude
|
||||
))
|
||||
|
||||
let framesetter = CTFramesetterCreateWithAttributedString(attributedText as CFAttributedString)
|
||||
let frame: CTFrame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, attributedText.length), path, nil)
|
||||
let lines: [CTLine] = frame.lines
|
||||
|
||||
lines.forEach { line in
|
||||
let runs: [CTRun] = line.ctruns
|
||||
|
||||
runs.forEach { run in
|
||||
let attributes: NSDictionary = CTRunGetAttributes(run)
|
||||
allMentionRadii.append(
|
||||
attributes
|
||||
.value(forKey: NSAttributedString.Key.currentUserMentionBackgroundPadding.rawValue) as? CGFloat
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return allMentionRadii
|
||||
.compactMap { $0 }
|
||||
.max()
|
||||
.defaulting(to: 0)
|
||||
}
|
||||
|
||||
// MARK: - Drawing
|
||||
|
||||
override func draw(_ rect: CGRect) {
|
||||
guard
|
||||
let superview: UITextView = (self.superview as? UITextView),
|
||||
let context = UIGraphicsGetCurrentContext()
|
||||
else { return }
|
||||
|
||||
// Need to invery the Y axis because iOS likes to render from the bottom left instead of the top left
|
||||
context.textMatrix = .identity
|
||||
context.translateBy(x: 0, y: bounds.size.height)
|
||||
context.scaleBy(x: 1.0, y: -1.0)
|
||||
|
||||
// Note: Calculations MUST happen based on the 'superview' size as this class has extra padding which
|
||||
// can result in calculations being off
|
||||
let path = CGMutablePath()
|
||||
let size = superview.sizeThatFits(CGSize(width: superview.bounds.width, height: .greatestFiniteMagnitude))
|
||||
path.addRect(CGRect(x: 0, y: 0, width: size.width, height: size.height), transform: .identity)
|
||||
|
||||
let framesetter = CTFramesetterCreateWithAttributedString(superview.attributedText as CFAttributedString)
|
||||
let frame: CTFrame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, superview.attributedText.length), path, nil)
|
||||
let lines: [CTLine] = frame.lines
|
||||
|
||||
var origins = [CGPoint](repeating: .zero, count: lines.count)
|
||||
CTFrameGetLineOrigins(frame, CFRangeMake(0, 0), &origins)
|
||||
|
||||
for lineIndex in 0..<lines.count {
|
||||
let line = lines[lineIndex]
|
||||
let runs: [CTRun] = line.ctruns
|
||||
var ascent: CGFloat = 0
|
||||
var descent: CGFloat = 0
|
||||
var leading: CGFloat = 0
|
||||
let lineWidth = CGFloat(CTLineGetTypographicBounds(line, &ascent, &descent, &leading))
|
||||
|
||||
for run in runs {
|
||||
let attributes: NSDictionary = CTRunGetAttributes(run)
|
||||
|
||||
guard let mentionBackgroundColor: UIColor = attributes.value(forKey: NSAttributedString.Key.currentUserMentionBackgroundColor.rawValue) as? UIColor else {
|
||||
continue
|
||||
}
|
||||
|
||||
let cornerRadius: CGFloat = (attributes
|
||||
.value(forKey: NSAttributedString.Key.currentUserMentionBackgroundCornerRadius.rawValue) as? CGFloat)
|
||||
.defaulting(to: 0)
|
||||
let padding: CGFloat = (attributes
|
||||
.value(forKey: NSAttributedString.Key.currentUserMentionBackgroundPadding.rawValue) as? CGFloat)
|
||||
.defaulting(to: 0)
|
||||
|
||||
let range = CTRunGetStringRange(run)
|
||||
var runBounds: CGRect = .zero
|
||||
var runAscent: CGFloat = 0
|
||||
var runDescent: CGFloat = 0
|
||||
runBounds.size.width = CGFloat(CTRunGetTypographicBounds(run, CFRangeMake(0, 0), &runAscent, &runDescent, nil) + (padding * 2))
|
||||
runBounds.size.height = (runAscent + runDescent + (padding * 2))
|
||||
|
||||
let xOffset: CGFloat = {
|
||||
switch CTRunGetStatus(run) {
|
||||
case .rightToLeft:
|
||||
return CTLineGetOffsetForStringIndex(line, range.location + range.length, nil)
|
||||
|
||||
default:
|
||||
return CTLineGetOffsetForStringIndex(line, range.location, nil)
|
||||
}
|
||||
}()
|
||||
|
||||
// HACK: This `extraYOffset` value is a hack to resolve a weird issue where the positioning
|
||||
// seems to be slightly off every additional line of text we add (it doesn't seem to be related
|
||||
// to line spacing or anything, more related to the bold mention text being positioned slightly
|
||||
// differently from the non-bold text)
|
||||
let extraYOffset: CGFloat = (CGFloat(lineIndex) * (runDescent / 12))
|
||||
|
||||
// Note: Changes to `origin.y` need to be inverted since the context has been flipped
|
||||
runBounds.origin.x = origins[lineIndex].x + rect.origin.x + self.maxPadding + xOffset - padding
|
||||
runBounds.origin.y = (
|
||||
origins[lineIndex].y + rect.origin.y +
|
||||
self.maxPadding -
|
||||
padding -
|
||||
runDescent -
|
||||
extraYOffset
|
||||
)
|
||||
|
||||
// We don't want to draw too far to the right
|
||||
runBounds.size.width = (runBounds.width > lineWidth ? lineWidth : runBounds.width)
|
||||
|
||||
let path = UIBezierPath(roundedRect: runBounds, cornerRadius: cornerRadius)
|
||||
mentionBackgroundColor.setFill()
|
||||
path.fill()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension CTFrame {
|
||||
var lines: [CTLine] {
|
||||
return ((CTFrameGetLines(self) as [AnyObject] as? [CTLine]) ?? [])
|
||||
}
|
||||
}
|
||||
|
||||
extension CTLine {
|
||||
var ctruns: [CTRun] {
|
||||
return ((CTLineGetGlyphRuns(self) as [AnyObject] as? [CTRun]) ?? [])
|
||||
}
|
||||
}
|
|
@ -56,7 +56,7 @@ final class ScanQRCodeWrapperVC : BaseVC {
|
|||
explanationLabel.autoPinWidthToSuperview(withMargin: 32)
|
||||
explanationLabel.autoPinHeightToSuperview(withMargin: 32)
|
||||
// Title
|
||||
title = NSLocalizedString("Scan QR Code", comment: "")
|
||||
title = "Scan QR Code"
|
||||
}
|
||||
|
||||
override func viewDidAppear(_ animated: Bool) {
|
||||
|
|
|
@ -6,10 +6,17 @@ import SessionUIKit
|
|||
import SessionMessagingKit
|
||||
|
||||
public enum MentionUtilities {
|
||||
public static func highlightMentions(in string: String, threadVariant: SessionThread.Variant) -> String {
|
||||
public static func highlightMentions(
|
||||
in string: String,
|
||||
threadVariant: SessionThread.Variant,
|
||||
currentUserPublicKey: String,
|
||||
currentUserBlindedPublicKey: String?
|
||||
) -> String {
|
||||
return highlightMentions(
|
||||
in: string,
|
||||
threadVariant: threadVariant,
|
||||
currentUserPublicKey: currentUserPublicKey,
|
||||
currentUserBlindedPublicKey: currentUserBlindedPublicKey,
|
||||
isOutgoingMessage: false,
|
||||
attributes: [:]
|
||||
).string // isOutgoingMessage and attributes are irrelevant
|
||||
|
@ -18,6 +25,8 @@ public enum MentionUtilities {
|
|||
public static func highlightMentions(
|
||||
in string: String,
|
||||
threadVariant: SessionThread.Variant,
|
||||
currentUserPublicKey: String?,
|
||||
currentUserBlindedPublicKey: String?,
|
||||
isOutgoingMessage: Bool,
|
||||
attributes: [NSAttributedString.Key: Any]
|
||||
) -> NSAttributedString {
|
||||
|
@ -29,7 +38,13 @@ public enum MentionUtilities {
|
|||
|
||||
var string = string
|
||||
var lastMatchEnd: Int = 0
|
||||
var mentions: [(range: NSRange, publicKey: String)] = []
|
||||
var mentions: [(range: NSRange, isCurrentUser: Bool)] = []
|
||||
let currentUserPublicKeys: Set<String> = [
|
||||
currentUserPublicKey,
|
||||
currentUserBlindedPublicKey
|
||||
]
|
||||
.compactMap { $0 }
|
||||
.asSet()
|
||||
|
||||
while let match: NSTextCheckingResult = regex.firstMatch(
|
||||
in: string,
|
||||
|
@ -39,28 +54,52 @@ public enum MentionUtilities {
|
|||
guard let range: Range = Range(match.range, in: string) else { break }
|
||||
|
||||
let publicKey: String = String(string[range].dropFirst()) // Drop the @
|
||||
let isCurrentUser: Bool = currentUserPublicKeys.contains(publicKey)
|
||||
|
||||
guard let displayName: String = Profile.displayNameNoFallback(id: publicKey, threadVariant: threadVariant) else {
|
||||
lastMatchEnd = (match.range.location + match.range.length)
|
||||
continue
|
||||
}
|
||||
guard let targetString: String = {
|
||||
guard !isCurrentUser else { return "MEDIA_GALLERY_SENDER_NAME_YOU".localized() }
|
||||
guard let displayName: String = Profile.displayNameNoFallback(id: publicKey, threadVariant: threadVariant) else {
|
||||
lastMatchEnd = (match.range.location + match.range.length)
|
||||
return nil
|
||||
}
|
||||
|
||||
return displayName
|
||||
}()
|
||||
else { continue }
|
||||
|
||||
string = string.replacingCharacters(in: range, with: "@\(displayName)")
|
||||
lastMatchEnd = (match.range.location + displayName.utf16.count)
|
||||
string = string.replacingCharacters(in: range, with: "@\(targetString)")
|
||||
lastMatchEnd = (match.range.location + targetString.utf16.count)
|
||||
|
||||
mentions.append((
|
||||
// + 1 to include the @
|
||||
range: NSRange(location: match.range.location, length: displayName.utf16.count + 1),
|
||||
publicKey: publicKey
|
||||
range: NSRange(location: match.range.location, length: targetString.utf16.count + 1),
|
||||
isCurrentUser: isCurrentUser
|
||||
))
|
||||
}
|
||||
|
||||
let sizeDiff: CGFloat = (Values.smallFontSize / Values.mediumFontSize)
|
||||
let result: NSMutableAttributedString = NSMutableAttributedString(string: string, attributes: attributes)
|
||||
mentions.forEach { mention in
|
||||
// FIXME: This might break when swapping between themes
|
||||
let color = isOutgoingMessage ? (isLightMode ? .white : .black) : Colors.accent
|
||||
result.addAttribute(.foregroundColor, value: color, range: mention.range)
|
||||
result.addAttribute(.font, value: UIFont.boldSystemFont(ofSize: Values.smallFontSize), range: mention.range)
|
||||
|
||||
if mention.isCurrentUser {
|
||||
// Note: The designs don't match with the dynamic sizing so these values need to be calculated
|
||||
// to maintain a "rounded rect" effect rather than a "pill" effect
|
||||
result.addAttribute(.currentUserMentionBackgroundCornerRadius, value: (8 * sizeDiff), range: mention.range)
|
||||
result.addAttribute(.currentUserMentionBackgroundPadding, value: (3 * sizeDiff), range: mention.range)
|
||||
result.addAttribute(.currentUserMentionBackgroundColor, value: Colors.accent, range: mention.range)
|
||||
result.addAttribute(.foregroundColor, value: UIColor.black, range: mention.range)
|
||||
}
|
||||
else {
|
||||
let color: UIColor = {
|
||||
switch (isLightMode, isOutgoingMessage) {
|
||||
case (_, true): return .black
|
||||
case (true, false): return .black
|
||||
case (false, false): return Colors.accent
|
||||
}
|
||||
}()
|
||||
result.addAttribute(.foregroundColor, value: color, range: mention.range)
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
|
|
|
@ -314,14 +314,11 @@ public extension Profile {
|
|||
|
||||
/// A standardised mechanism for truncating a user id for a given thread
|
||||
static func truncated(id: String, threadVariant: SessionThread.Variant = .contact) -> String {
|
||||
switch threadVariant {
|
||||
case .openGroup: return truncated(id: id, truncating: .start)
|
||||
default: return truncated(id: id, truncating: .middle)
|
||||
}
|
||||
return truncated(id: id, truncating: .middle)
|
||||
}
|
||||
|
||||
/// A standardised mechanism for truncating a user id
|
||||
static func truncated(id: String, truncating: Truncation = .start) -> String {
|
||||
static func truncated(id: String, truncating: Truncation = .middle) -> String {
|
||||
guard id.count > 8 else { return id }
|
||||
|
||||
switch truncating {
|
||||
|
@ -355,7 +352,7 @@ public extension Profile {
|
|||
case .openGroup:
|
||||
// In open groups, where it's more likely that multiple users have the same name,
|
||||
// we display a bit of the Session ID after a user's display name for added context
|
||||
return "\(name) (\(Profile.truncated(id: id, truncating: .start)))"
|
||||
return "\(name) (\(Profile.truncated(id: id, truncating: .middle)))"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
import Foundation
|
||||
import GRDB
|
||||
import Sodium
|
||||
import SessionUtilitiesKit
|
||||
|
||||
public struct SessionThread: Codable, Identifiable, Equatable, FetchableRecord, PersistableRecord, TableRecord, ColumnExpressible {
|
||||
|
@ -314,6 +315,39 @@ public extension SessionThread {
|
|||
return profile.displayName()
|
||||
}
|
||||
}
|
||||
|
||||
static func getUserHexEncodedBlindedKey(
|
||||
threadId: String,
|
||||
threadVariant: Variant
|
||||
) -> String? {
|
||||
guard
|
||||
threadVariant == .openGroup,
|
||||
let blindingInfo: (edkeyPair: Box.KeyPair?, publicKey: String?) = Storage.shared.read({ db in
|
||||
return (
|
||||
Identity.fetchUserEd25519KeyPair(db),
|
||||
try OpenGroup
|
||||
.filter(id: threadId)
|
||||
.select(.publicKey)
|
||||
.asRequest(of: String.self)
|
||||
.fetchOne(db)
|
||||
)
|
||||
}),
|
||||
let userEdKeyPair: Box.KeyPair = blindingInfo.edkeyPair,
|
||||
let publicKey: String = blindingInfo.publicKey
|
||||
else { return nil }
|
||||
|
||||
let sodium: Sodium = Sodium()
|
||||
|
||||
let blindedKeyPair: Box.KeyPair? = sodium.blindedKeyPair(
|
||||
serverPublicKey: publicKey,
|
||||
edKeyPair: userEdKeyPair,
|
||||
genericHash: sodium.getGenericHash()
|
||||
)
|
||||
|
||||
return blindedKeyPair.map { keyPair -> String in
|
||||
SessionId(.blinded, publicKey: keyPair.publicKey).hexString
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Objective-C Support
|
||||
|
|
|
@ -44,11 +44,11 @@ extension MessageSender {
|
|||
// Send a closed group update message to all members individually
|
||||
var promises: [Promise<Void>] = []
|
||||
|
||||
try members.forEach { adminId in
|
||||
try members.forEach { memberId in
|
||||
try GroupMember(
|
||||
groupId: groupPublicKey,
|
||||
profileId: adminId,
|
||||
role: .admin
|
||||
profileId: memberId,
|
||||
role: .standard
|
||||
).insert(db)
|
||||
}
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@ public struct MessageViewModel: FetchableRecordWithRowId, Decodable, Equatable,
|
|||
public static let quoteAttachmentKey: SQL = SQL(stringLiteral: CodingKeys.quoteAttachment.stringValue)
|
||||
public static let linkPreviewKey: SQL = SQL(stringLiteral: CodingKeys.linkPreview.stringValue)
|
||||
public static let linkPreviewAttachmentKey: SQL = SQL(stringLiteral: CodingKeys.linkPreviewAttachment.stringValue)
|
||||
public static let currentUserPublicKeyKey: SQL = SQL(stringLiteral: CodingKeys.currentUserPublicKey.stringValue)
|
||||
public static let cellTypeKey: SQL = SQL(stringLiteral: CodingKeys.cellType.stringValue)
|
||||
public static let authorNameKey: SQL = SQL(stringLiteral: CodingKeys.authorName.stringValue)
|
||||
public static let shouldShowProfileKey: SQL = SQL(stringLiteral: CodingKeys.shouldShowProfile.stringValue)
|
||||
|
@ -92,6 +93,8 @@ public struct MessageViewModel: FetchableRecordWithRowId, Decodable, Equatable,
|
|||
public let linkPreview: LinkPreview?
|
||||
public let linkPreviewAttachment: Attachment?
|
||||
|
||||
public let currentUserPublicKey: String
|
||||
|
||||
// Post-Query Processing Data
|
||||
|
||||
/// This value includes the associated attachments
|
||||
|
@ -132,6 +135,9 @@ public struct MessageViewModel: FetchableRecordWithRowId, Decodable, Equatable,
|
|||
|
||||
/// This value indicates whether this is the last message in the thread
|
||||
public let isLast: Bool
|
||||
|
||||
/// This is the users blinded key (will only be set for messages within open groups)
|
||||
public let currentUserBlindedPublicKey: String?
|
||||
|
||||
// MARK: - Mutation
|
||||
|
||||
|
@ -164,6 +170,7 @@ public struct MessageViewModel: FetchableRecordWithRowId, Decodable, Equatable,
|
|||
quoteAttachment: self.quoteAttachment,
|
||||
linkPreview: self.linkPreview,
|
||||
linkPreviewAttachment: self.linkPreviewAttachment,
|
||||
currentUserPublicKey: self.currentUserPublicKey,
|
||||
attachments: attachments,
|
||||
cellType: self.cellType,
|
||||
authorName: self.authorName,
|
||||
|
@ -175,14 +182,16 @@ public struct MessageViewModel: FetchableRecordWithRowId, Decodable, Equatable,
|
|||
previousVariant: self.previousVariant,
|
||||
positionInCluster: self.positionInCluster,
|
||||
isOnlyMessageInCluster: self.isOnlyMessageInCluster,
|
||||
isLast: self.isLast
|
||||
isLast: self.isLast,
|
||||
currentUserBlindedPublicKey: self.currentUserBlindedPublicKey
|
||||
)
|
||||
}
|
||||
|
||||
public func withClusteringChanges(
|
||||
prevModel: MessageViewModel?,
|
||||
nextModel: MessageViewModel?,
|
||||
isLast: Bool
|
||||
isLast: Bool,
|
||||
currentUserBlindedPublicKey: String?
|
||||
) -> MessageViewModel {
|
||||
let cellType: CellType = {
|
||||
guard self.isTypingIndicator != true else { return .typingIndicator }
|
||||
|
@ -338,6 +347,7 @@ public struct MessageViewModel: FetchableRecordWithRowId, Decodable, Equatable,
|
|||
quoteAttachment: self.quoteAttachment,
|
||||
linkPreview: self.linkPreview,
|
||||
linkPreviewAttachment: self.linkPreviewAttachment,
|
||||
currentUserPublicKey: self.currentUserPublicKey,
|
||||
attachments: self.attachments,
|
||||
cellType: cellType,
|
||||
authorName: authorDisplayName,
|
||||
|
@ -385,7 +395,8 @@ public struct MessageViewModel: FetchableRecordWithRowId, Decodable, Equatable,
|
|||
previousVariant: prevModel?.variant,
|
||||
positionInCluster: positionInCluster,
|
||||
isOnlyMessageInCluster: isOnlyMessageInCluster,
|
||||
isLast: isLast
|
||||
isLast: isLast,
|
||||
currentUserBlindedPublicKey: currentUserBlindedPublicKey
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -478,6 +489,7 @@ public extension MessageViewModel {
|
|||
self.quoteAttachment = nil
|
||||
self.linkPreview = nil
|
||||
self.linkPreviewAttachment = nil
|
||||
self.currentUserPublicKey = ""
|
||||
|
||||
// Post-Query Processing Data
|
||||
|
||||
|
@ -493,6 +505,7 @@ public extension MessageViewModel {
|
|||
self.positionInCluster = .middle
|
||||
self.isOnlyMessageInCluster = true
|
||||
self.isLast = true
|
||||
self.currentUserBlindedPublicKey = nil
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -557,7 +570,11 @@ public extension MessageViewModel {
|
|||
return SQL("\(interaction[.timestampMs].desc)")
|
||||
}()
|
||||
|
||||
static func baseQuery(orderSQL: SQL, groupSQL: SQL?) -> (([Int64]) -> AdaptedFetchRequest<SQLRequest<MessageViewModel>>) {
|
||||
static func baseQuery(
|
||||
userPublicKey: String,
|
||||
orderSQL: SQL,
|
||||
groupSQL: SQL?
|
||||
) -> (([Int64]) -> AdaptedFetchRequest<SQLRequest<MessageViewModel>>) {
|
||||
return { rowIds -> AdaptedFetchRequest<SQLRequest<ViewModel>> in
|
||||
let interaction: TypedTableAlias<Interaction> = TypedTableAlias()
|
||||
let thread: TypedTableAlias<SessionThread> = TypedTableAlias()
|
||||
|
@ -621,6 +638,8 @@ public extension MessageViewModel {
|
|||
\(ViewModel.linkPreviewKey).*,
|
||||
\(ViewModel.linkPreviewAttachmentKey).*,
|
||||
|
||||
\(SQL("\(userPublicKey)")) AS \(ViewModel.currentUserPublicKeyKey),
|
||||
|
||||
-- All of the below properties are set in post-query processing but to prevent the
|
||||
-- query from crashing when decoding we need to provide default values
|
||||
\(CellType.textOnlyMessage) AS \(ViewModel.cellTypeKey),
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
import Foundation
|
||||
import GRDB
|
||||
import Sodium
|
||||
import DifferenceKit
|
||||
import SessionUtilitiesKit
|
||||
|
||||
|
@ -124,6 +125,7 @@ public struct SessionThreadViewModel: FetchableRecordWithRowId, Decodable, Equat
|
|||
private let threadContactNameInternal: String?
|
||||
private let authorNameInternal: String?
|
||||
public let currentUserPublicKey: String
|
||||
public let currentUserBlindedPublicKey: String?
|
||||
|
||||
// UI specific logic
|
||||
|
||||
|
@ -275,6 +277,67 @@ public extension SessionThreadViewModel {
|
|||
self.threadContactNameInternal = nil
|
||||
self.authorNameInternal = nil
|
||||
self.currentUserPublicKey = getUserHexEncodedPublicKey()
|
||||
self.currentUserBlindedPublicKey = nil
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Mutation
|
||||
|
||||
public extension SessionThreadViewModel {
|
||||
func populatingCurrentUserBlindedKey(
|
||||
currentUserBlindedPublicKeyForThisThread: String? = nil
|
||||
) -> SessionThreadViewModel {
|
||||
return SessionThreadViewModel(
|
||||
rowId: self.rowId,
|
||||
threadId: self.threadId,
|
||||
threadVariant: self.threadVariant,
|
||||
threadCreationDateTimestamp: self.threadCreationDateTimestamp,
|
||||
threadMemberNames: self.threadMemberNames,
|
||||
threadIsNoteToSelf: self.threadIsNoteToSelf,
|
||||
threadIsMessageRequest: self.threadIsMessageRequest,
|
||||
threadRequiresApproval: self.threadRequiresApproval,
|
||||
threadShouldBeVisible: self.threadShouldBeVisible,
|
||||
threadIsPinned: self.threadIsPinned,
|
||||
threadIsBlocked: self.threadIsBlocked,
|
||||
threadMutedUntilTimestamp: self.threadMutedUntilTimestamp,
|
||||
threadOnlyNotifyForMentions: self.threadOnlyNotifyForMentions,
|
||||
threadMessageDraft: self.threadMessageDraft,
|
||||
threadContactIsTyping: self.threadContactIsTyping,
|
||||
threadUnreadCount: self.threadUnreadCount,
|
||||
threadUnreadMentionCount: self.threadUnreadMentionCount,
|
||||
contactProfile: self.contactProfile,
|
||||
closedGroupProfileFront: self.closedGroupProfileFront,
|
||||
closedGroupProfileBack: self.closedGroupProfileBack,
|
||||
closedGroupProfileBackFallback: self.closedGroupProfileBackFallback,
|
||||
closedGroupName: self.closedGroupName,
|
||||
closedGroupUserCount: self.closedGroupUserCount,
|
||||
currentUserIsClosedGroupMember: self.currentUserIsClosedGroupMember,
|
||||
currentUserIsClosedGroupAdmin: self.currentUserIsClosedGroupAdmin,
|
||||
openGroupName: self.openGroupName,
|
||||
openGroupServer: self.openGroupServer,
|
||||
openGroupRoomToken: self.openGroupRoomToken,
|
||||
openGroupProfilePictureData: self.openGroupProfilePictureData,
|
||||
openGroupUserCount: self.openGroupUserCount,
|
||||
interactionId: self.interactionId,
|
||||
interactionVariant: self.interactionVariant,
|
||||
interactionTimestampMs: self.interactionTimestampMs,
|
||||
interactionBody: self.interactionBody,
|
||||
interactionState: self.interactionState,
|
||||
interactionIsOpenGroupInvitation: self.interactionIsOpenGroupInvitation,
|
||||
interactionAttachmentDescriptionInfo: self.interactionAttachmentDescriptionInfo,
|
||||
interactionAttachmentCount: self.interactionAttachmentCount,
|
||||
authorId: self.authorId,
|
||||
threadContactNameInternal: self.threadContactNameInternal,
|
||||
authorNameInternal: self.authorNameInternal,
|
||||
currentUserPublicKey: self.currentUserPublicKey,
|
||||
currentUserBlindedPublicKey: (
|
||||
currentUserBlindedPublicKeyForThisThread ??
|
||||
SessionThread.getUserHexEncodedBlindedKey(
|
||||
threadId: self.threadId,
|
||||
threadVariant: self.threadVariant
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -11,4 +11,6 @@ public enum SnodeAPIEndpoint: String {
|
|||
case getInfo = "info"
|
||||
case clearAllData = "delete_all"
|
||||
case expire = "expire"
|
||||
case batch = "batch"
|
||||
case sequence = "sequence"
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ public extension UISearchBar {
|
|||
let searchTextField: UITextField = self.searchTextField
|
||||
searchTextField.backgroundColor = Colors.searchBarBackground // The search bar background color
|
||||
searchTextField.textColor = Colors.text
|
||||
searchTextField.attributedPlaceholder = NSAttributedString(string: NSLocalizedString("Search", comment: ""), attributes: [ .foregroundColor : Colors.searchBarPlaceholder ])
|
||||
searchTextField.attributedPlaceholder = NSAttributedString(string: "Search", attributes: [ .foregroundColor : Colors.searchBarPlaceholder ])
|
||||
setPositionAdjustment(UIOffset(horizontal: 4, vertical: 0), for: UISearchBar.Icon.search)
|
||||
searchTextPositionAdjustment = UIOffset(horizontal: 2, vertical: 0)
|
||||
setPositionAdjustment(UIOffset(horizontal: -4, vertical: 0), for: UISearchBar.Icon.clear)
|
||||
|
|
|
@ -48,11 +48,11 @@ public enum Mnemonic {
|
|||
|
||||
public var errorDescription: String? {
|
||||
switch self {
|
||||
case .generic: return NSLocalizedString("Something went wrong. Please check your recovery phrase and try again.", comment: "")
|
||||
case .inputTooShort: return NSLocalizedString("Looks like you didn't enter enough words. Please check your recovery phrase and try again.", comment: "")
|
||||
case .missingLastWord: return NSLocalizedString("You seem to be missing the last word of your recovery phrase. Please check what you entered and try again.", comment: "")
|
||||
case .invalidWord: return NSLocalizedString("There appears to be an invalid word in your recovery phrase. Please check what you entered and try again.", comment: "")
|
||||
case .verificationFailed: return NSLocalizedString("Your recovery phrase couldn't be verified. Please check what you entered and try again.", comment: "")
|
||||
case .generic: return "RECOVERY_PHASE_ERROR_GENERIC".localized()
|
||||
case .inputTooShort: return "RECOVERY_PHASE_ERROR_LENGTH".localized()
|
||||
case .missingLastWord: return "RECOVERY_PHASE_ERROR_LAST_WORD".localized()
|
||||
case .invalidWord: return "RECOVERY_PHASE_ERROR_INVALID_WORD".localized()
|
||||
case .verificationFailed: return "RECOVERY_PHASE_ERROR_FAILED".localized()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -164,7 +164,7 @@ class AttachmentTextToolbar: UIView, UITextViewDelegate {
|
|||
private lazy var placeholderTextView: UITextView = {
|
||||
let placeholderTextView = buildTextView()
|
||||
|
||||
placeholderTextView.text = NSLocalizedString("Message", comment: "")
|
||||
placeholderTextView.text = "Message"
|
||||
placeholderTextView.isEditable = false
|
||||
|
||||
return placeholderTextView
|
||||
|
|
|
@ -118,8 +118,7 @@ import SessionMessagingKit
|
|||
completion completionParam: @escaping ((OWSScreenLockOutcome) -> Void)) {
|
||||
AssertIsOnMainThread()
|
||||
|
||||
let defaultErrorDescription = NSLocalizedString("SCREEN_LOCK_ENABLE_UNKNOWN_ERROR",
|
||||
comment: "Indicates that an unknown error occurred while using Touch ID/Face ID/Phone Passcode.")
|
||||
let defaultErrorDescription = "SCREEN_LOCK_ENABLE_UNKNOWN_ERROR".localized()
|
||||
|
||||
// Ensure completion is always called on the main thread.
|
||||
let completion = { (outcome: OWSScreenLockOutcome) in
|
||||
|
@ -140,7 +139,7 @@ import SessionMessagingKit
|
|||
switch outcome {
|
||||
case .success:
|
||||
owsFailDebug("local authentication unexpected success")
|
||||
completion(.failure(error:defaultErrorDescription))
|
||||
completion(.failure(error: defaultErrorDescription))
|
||||
case .cancel, .failure, .unexpectedFailure:
|
||||
completion(outcome)
|
||||
}
|
||||
|
@ -177,16 +176,13 @@ import SessionMessagingKit
|
|||
switch laError.code {
|
||||
case .biometryNotAvailable:
|
||||
Logger.error("local authentication error: biometryNotAvailable.")
|
||||
return .failure(error: NSLocalizedString("SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_AVAILABLE",
|
||||
comment: "Indicates that Touch ID/Face ID/Phone Passcode are not available on this device."))
|
||||
return .failure(error: "SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_AVAILABLE".localized())
|
||||
case .biometryNotEnrolled:
|
||||
Logger.error("local authentication error: biometryNotEnrolled.")
|
||||
return .failure(error: NSLocalizedString("SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_ENROLLED",
|
||||
comment: "Indicates that Touch ID/Face ID/Phone Passcode is not configured on this device."))
|
||||
return .failure(error: "SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_ENROLLED".localized())
|
||||
case .biometryLockout:
|
||||
Logger.error("local authentication error: biometryLockout.")
|
||||
return .failure(error: NSLocalizedString("SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_LOCKOUT",
|
||||
comment: "Indicates that Touch ID/Face ID/Phone Passcode is 'locked out' on this device due to authentication failures."))
|
||||
return .failure(error: "SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_LOCKOUT".localized())
|
||||
default:
|
||||
// Fall through to second switch
|
||||
break
|
||||
|
@ -195,27 +191,22 @@ import SessionMessagingKit
|
|||
switch laError.code {
|
||||
case .authenticationFailed:
|
||||
Logger.error("local authentication error: authenticationFailed.")
|
||||
return .failure(error: NSLocalizedString("SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_FAILED",
|
||||
comment: "Indicates that Touch ID/Face ID/Phone Passcode authentication failed."))
|
||||
return .failure(error: "SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_FAILED".localized())
|
||||
case .userCancel, .userFallback, .systemCancel, .appCancel:
|
||||
Logger.info("local authentication cancelled.")
|
||||
return .cancel
|
||||
case .passcodeNotSet:
|
||||
Logger.error("local authentication error: passcodeNotSet.")
|
||||
return .failure(error: NSLocalizedString("SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_PASSCODE_NOT_SET",
|
||||
comment: "Indicates that Touch ID/Face ID/Phone Passcode passcode is not set."))
|
||||
return .failure(error: "SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_PASSCODE_NOT_SET".localized())
|
||||
case .touchIDNotAvailable:
|
||||
Logger.error("local authentication error: touchIDNotAvailable.")
|
||||
return .failure(error: NSLocalizedString("SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_AVAILABLE",
|
||||
comment: "Indicates that Touch ID/Face ID/Phone Passcode are not available on this device."))
|
||||
return .failure(error: "SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_AVAILABLE".localized())
|
||||
case .touchIDNotEnrolled:
|
||||
Logger.error("local authentication error: touchIDNotEnrolled.")
|
||||
return .failure(error: NSLocalizedString("SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_ENROLLED",
|
||||
comment: "Indicates that Touch ID/Face ID/Phone Passcode is not configured on this device."))
|
||||
return .failure(error: "SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_ENROLLED".localized())
|
||||
case .touchIDLockout:
|
||||
Logger.error("local authentication error: touchIDLockout.")
|
||||
return .failure(error: NSLocalizedString("SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_LOCKOUT",
|
||||
comment: "Indicates that Touch ID/Face ID/Phone Passcode is 'locked out' on this device due to authentication failures."))
|
||||
return .failure(error: "SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_LOCKOUT".localized())
|
||||
case .invalidContext:
|
||||
owsFailDebug("context not valid.")
|
||||
return .unexpectedFailure(error:defaultErrorDescription)
|
||||
|
|
|
@ -16,7 +16,7 @@ import Foundation
|
|||
@objc
|
||||
static public let doneButton = NSLocalizedString("BUTTON_DONE", comment: "Label for generic done button.")
|
||||
@objc
|
||||
static public let retryButton = NSLocalizedString("RETRY_BUTTON_TEXT", comment: "Generic text for button that retries whatever the last action was.")
|
||||
static public let retryButton = "RETRY_BUTTON_TEXT".localized()
|
||||
@objc
|
||||
static public let openSettingsButton = NSLocalizedString("OPEN_SETTINGS_BUTTON", comment: "Button text which opens the settings app")
|
||||
@objc
|
||||
|
@ -31,20 +31,11 @@ import Foundation
|
|||
static public let markAsReadNotificationAction = NSLocalizedString("PUSH_MANAGER_MARKREAD", comment: "Notification action button title")
|
||||
|
||||
@objc
|
||||
static public let sendButton = NSLocalizedString("SEND_BUTTON_TITLE", comment: "Label for the button to send a message")
|
||||
static public let sendButton = "SEND_BUTTON_TITLE".localized()
|
||||
}
|
||||
|
||||
@objc
|
||||
public class NotificationStrings: NSObject {
|
||||
@objc
|
||||
static public let incomingCallBody = NSLocalizedString("CALL_INCOMING_NOTIFICATION_BODY", comment: "notification body")
|
||||
|
||||
@objc
|
||||
static public let missedCallBody = NSLocalizedString("CALL_MISSED_NOTIFICATION_BODY", comment: "notification body")
|
||||
|
||||
@objc
|
||||
static public let missedCallBecauseOfIdentityChangeBody = NSLocalizedString("CALL_MISSED_BECAUSE_OF_IDENTITY_CHANGE_NOTIFICATION_BODY", comment: "notification body")
|
||||
|
||||
@objc
|
||||
static public let incomingMessageBody = NSLocalizedString("APN_Message", comment: "notification body")
|
||||
|
||||
|
@ -55,41 +46,16 @@ public class NotificationStrings: NSObject {
|
|||
static public let incomingGroupMessageTitleFormat = NSLocalizedString("NEW_GROUP_MESSAGE_NOTIFICATION_TITLE", comment: "notification title. Embeds {{author name}} and {{group name}}")
|
||||
|
||||
@objc
|
||||
static public let failedToSendBody = NSLocalizedString("SEND_FAILED_NOTIFICATION_BODY", comment: "notification body")
|
||||
static public let failedToSendBody = "SEND_FAILED_NOTIFICATION_BODY".localized()
|
||||
}
|
||||
|
||||
@objc public class CallStrings: NSObject {
|
||||
@objc
|
||||
static public let callStatusFormat = NSLocalizedString("CALL_STATUS_FORMAT", comment: "embeds {{Call Status}} in call screen label. For ongoing calls, {{Call Status}} is a seconds timer like 01:23, otherwise {{Call Status}} is a short text like 'Ringing', 'Busy', or 'Failed Call'")
|
||||
|
||||
@objc
|
||||
static public let confirmAndCallButtonTitle = NSLocalizedString("SAFETY_NUMBER_CHANGED_CONFIRM_CALL_ACTION", comment: "alert button text to confirm placing an outgoing call after the recipients Safety Number has changed.")
|
||||
|
||||
@objc
|
||||
static public let callBackAlertTitle = NSLocalizedString("CALL_USER_ALERT_TITLE", comment: "Title for alert offering to call a user.")
|
||||
@objc
|
||||
static public let callBackAlertMessageFormat = NSLocalizedString("CALL_USER_ALERT_MESSAGE_FORMAT", comment: "Message format for alert offering to call a user. Embeds {{the user's display name or phone number}}.")
|
||||
@objc
|
||||
static public let callBackAlertCallButton = NSLocalizedString("CALL_USER_ALERT_CALL_BUTTON", comment: "Label for call button for alert offering to call a user.")
|
||||
|
||||
// MARK: Notification actions
|
||||
@objc
|
||||
static public let callBackButtonTitle = NSLocalizedString("CALLBACK_BUTTON_TITLE", comment: "notification action")
|
||||
@objc
|
||||
static public let showThreadButtonTitle = NSLocalizedString("SHOW_THREAD_BUTTON_TITLE", comment: "notification action")
|
||||
@objc
|
||||
static public let answerCallButtonTitle = NSLocalizedString("ANSWER_CALL_BUTTON_TITLE", comment: "notification action")
|
||||
@objc
|
||||
static public let declineCallButtonTitle = NSLocalizedString("REJECT_CALL_BUTTON_TITLE", comment: "notification action")
|
||||
static public let showThreadButtonTitle = "SHOW_THREAD_BUTTON_TITLE".localized()
|
||||
}
|
||||
|
||||
@objc public class MediaStrings: NSObject {
|
||||
@objc
|
||||
static public let allMedia = NSLocalizedString("MEDIA_DETAIL_VIEW_ALL_MEDIA_BUTTON", comment: "nav bar button item")
|
||||
}
|
||||
|
||||
@objc public class SafetyNumberStrings: NSObject {
|
||||
@objc
|
||||
static public let confirmSendButton = NSLocalizedString("SAFETY_NUMBER_CHANGED_CONFIRM_SEND_ACTION",
|
||||
comment: "button title to confirm sending to a recipient whose safety number recently changed")
|
||||
}
|
||||
|
|
|
@ -6,25 +6,6 @@ import Foundation
|
|||
import SessionUtilitiesKit
|
||||
|
||||
@objc public class OWSAlerts: NSObject {
|
||||
|
||||
/// Cleanup and present alert for no permissions
|
||||
@objc
|
||||
public class func showNoMicrophonePermissionAlert() {
|
||||
let alertTitle = NSLocalizedString("CALL_AUDIO_PERMISSION_TITLE", comment: "Alert title when calling and permissions for microphone are missing")
|
||||
let alertMessage = NSLocalizedString("CALL_AUDIO_PERMISSION_MESSAGE", comment: "Alert message when calling and permissions for microphone are missing")
|
||||
let alert = UIAlertController(title: alertTitle, message: alertMessage, preferredStyle: .alert)
|
||||
|
||||
let dismissAction = UIAlertAction(title: CommonStrings.dismissButton, style: .cancel)
|
||||
dismissAction.accessibilityIdentifier = "OWSAlerts.\("dismiss")"
|
||||
alert.addAction(dismissAction)
|
||||
|
||||
if let settingsAction = CurrentAppContext().openSystemSettingsAction {
|
||||
settingsAction.accessibilityIdentifier = "OWSAlerts.\("settings")"
|
||||
alert.addAction(settingsAction)
|
||||
}
|
||||
CurrentAppContext().frontmostViewController()?.presentAlert(alert)
|
||||
}
|
||||
|
||||
@objc
|
||||
public class func showAlert(_ alert: UIAlertController) {
|
||||
guard let frontmostViewController = CurrentAppContext().frontmostViewController() else {
|
||||
|
|
Loading…
Reference in New Issue