Merge branch 'release/v2.8.0'

This commit is contained in:
Arnfried Griesert
2023-08-10 17:03:54 +02:00
118 changed files with 2125 additions and 1369 deletions
+30
View File
@@ -0,0 +1,30 @@
//
// Copyright 2023 Vector Creations Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Configuration settings file format documentation can be found at:
// https://help.apple.com/xcode/#/dev745c5c974
#include "Config/AppIdentifiers.xcconfig"
#include "Config/AppVersion.xcconfig"
PRODUCT_NAME = BroadcastUploadExtension
PRODUCT_BUNDLE_IDENTIFIER = $(BROADCAST_UPLOAD_EXTENSION_BUNDLE_IDENTIFIER)
INFOPLIST_FILE = BroadcastUploadExtension/SupportingFiles/Info.plist
CODE_SIGN_ENTITLEMENTS = BroadcastUploadExtension/SupportingFiles/BroadcastUploadExtension.entitlements
SKIP_INSTALL = YES
+21
View File
@@ -0,0 +1,21 @@
//
// Copyright 2020 Vector Creations Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Configuration settings file format documentation can be found at:
// https://help.apple.com/xcode/#/dev745c5c974
#include "Common.xcconfig"
#include "Pods/Target Support Files/Pods-RiotPods-BroadcastUploadExtension/Pods-RiotPods-BroadcastUploadExtension.debug.xcconfig"
+26
View File
@@ -0,0 +1,26 @@
//
// Copyright 2020 Vector Creations Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Configuration settings file format documentation can be found at:
// https://help.apple.com/xcode/#/dev745c5c974
#include "Common.xcconfig"
#include "Pods/Target Support Files/Pods-RiotPods-BroadcastUploadExtension/Pods-RiotPods-BroadcastUploadExtension.release.xcconfig"
PROVISIONING_PROFILE = $(BROADCAST_UPLOAD_EXTENSION_PROVISIONING_PROFILE)
PROVISIONING_PROFILE_SPECIFIER = $(BROADCAST_UPLOAD_EXTENSION_PROVISIONING_PROFILE_SPECIFIER)
COPY_PHASE_STRIP = NO
@@ -0,0 +1,41 @@
//
// License from the original repository:
// https://github.com/jitsi/jitsi-meet-sdk-samples/blob/master/LICENSE
//
// Atomic.swift
// Broadcast Extension
//
// Created by Maksym Shcheglov.
// https://www.onswiftwings.com/posts/atomic-property-wrapper/
//
import Foundation
@propertyWrapper
struct Atomic<Value> {
private var value: Value
private let lock = NSLock()
init(wrappedValue value: Value) {
self.value = value
}
var wrappedValue: Value {
get { load() }
set { store(newValue: newValue) }
}
func load() -> Value {
lock.lock()
defer { lock.unlock() }
return value
}
mutating func store(newValue: Value) {
lock.lock()
defer { lock.unlock() }
value = newValue
}
}
@@ -0,0 +1,33 @@
//
// License from the original repository:
// https://github.com/jitsi/jitsi-meet-sdk-samples/blob/master/LICENSE
//
// DarwinNotificationCenter.swift
// Broadcast Extension
//
// Created by Alex-Dan Bumbu on 23/03/2021.
// Copyright © 2021 8x8, Inc. All rights reserved.
//
import Foundation
enum DarwinNotification: String {
case broadcastStarted = "iOS_BroadcastStarted"
case broadcastStopped = "iOS_BroadcastStopped"
}
class DarwinNotificationCenter {
static let shared = DarwinNotificationCenter()
private let notificationCenter: CFNotificationCenter
init() {
notificationCenter = CFNotificationCenterGetDarwinNotifyCenter()
}
func postNotification(_ name: DarwinNotification) {
CFNotificationCenterPostNotification(notificationCenter, CFNotificationName(rawValue: name.rawValue as CFString), nil, nil, true)
}
}
@@ -0,0 +1,125 @@
//
// License from the original repository:
// https://github.com/jitsi/jitsi-meet-sdk-samples/blob/master/LICENSE
//
// SampleHandler.swift
// Broadcast Extension
//
// Created by Alex-Dan Bumbu on 04.06.2021.
//
import ReplayKit
import MatrixSDK
private enum Constants {
// the App Group ID value that the app and the broadcast extension targets are setup with. It differs for each app.
static let appGroupIdentifier = BuildSettings.applicationGroupIdentifier
}
class SampleHandler: RPBroadcastSampleHandler {
private var clientConnection: SocketConnection?
private var uploader: SampleUploader?
private var frameCount: Int = 0
private var socketFilePath: String {
let sharedContainer = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: Constants.appGroupIdentifier)
return sharedContainer?.appendingPathComponent("rtc_SSFD").path ?? ""
}
override init() {
super.init()
setupLogger()
if let connection = SocketConnection(filePath: socketFilePath) {
clientConnection = connection
setupConnection()
uploader = SampleUploader(connection: connection)
}
}
override func broadcastStarted(withSetupInfo setupInfo: [String: NSObject]?) {
// User has requested to start the broadcast. Setup info from the UI extension can be supplied but optional.
frameCount = 0
DarwinNotificationCenter.shared.postNotification(.broadcastStarted)
openConnection()
}
override func broadcastPaused() {
// User has requested to pause the broadcast. Samples will stop being delivered.
}
override func broadcastResumed() {
// User has requested to resume the broadcast. Samples delivery will resume.
}
override func broadcastFinished() {
// User has requested to finish the broadcast.
DarwinNotificationCenter.shared.postNotification(.broadcastStopped)
clientConnection?.close()
}
override func processSampleBuffer(_ sampleBuffer: CMSampleBuffer, with sampleBufferType: RPSampleBufferType) {
switch sampleBufferType {
case RPSampleBufferType.video:
// very simple mechanism for adjusting frame rate by using every third frame
frameCount += 1
if frameCount % 3 == 0 {
uploader?.send(sample: sampleBuffer)
}
default:
break
}
}
}
private extension SampleHandler {
func setupConnection() {
clientConnection?.didClose = { [weak self] error in
MXLog.error("client connection did close", context: error)
if let error = error {
self?.finishBroadcastWithError(error)
} else {
// the displayed failure message is more user friendly when using NSError instead of Error
let JMScreenSharingStopped = 10001
let customError = NSError(domain: RPRecordingErrorDomain, code: JMScreenSharingStopped, userInfo: [NSLocalizedDescriptionKey: "Screen sharing stopped"])
self?.finishBroadcastWithError(customError)
}
}
}
func openConnection() {
let queue = DispatchQueue(label: "broadcast.connectTimer")
let timer = DispatchSource.makeTimerSource(queue: queue)
timer.schedule(deadline: .now(), repeating: .milliseconds(100), leeway: .milliseconds(500))
timer.setEventHandler { [weak self] in
guard self?.clientConnection?.open() == true else {
return
}
timer.cancel()
}
timer.resume()
}
func setupLogger() {
let configuration = MXLogConfiguration()
configuration.logLevel = .verbose
configuration.maxLogFilesCount = 100
configuration.logFilesSizeLimit = 10 * 1024 * 1024; // 10MB
configuration.subLogName = "broadcastUploadExtension"
if isatty(STDERR_FILENO) == 0 {
configuration.redirectLogsToFiles = true
}
MXLog.configure(configuration)
}
}
@@ -0,0 +1,151 @@
//
// License from the original repository:
// https://github.com/jitsi/jitsi-meet-sdk-samples/blob/master/LICENSE
//
// SampleUploader.swift
// Broadcast Extension
//
// Created by Alex-Dan Bumbu on 22/03/2021.
// Copyright © 2021 8x8, Inc. All rights reserved.
//
import Foundation
import ReplayKit
import MatrixSDK
private enum Constants {
static let bufferMaxLength = 10240
}
class SampleUploader {
private static var imageContext = CIContext(options: nil)
@Atomic private var isReady = false
private var connection: SocketConnection
private var dataToSend: Data?
private var byteIndex = 0
private let serialQueue: DispatchQueue
init(connection: SocketConnection) {
self.connection = connection
self.serialQueue = DispatchQueue(label: "org.jitsi.meet.broadcast.sampleUploader")
setupConnection()
}
@discardableResult func send(sample buffer: CMSampleBuffer) -> Bool {
guard isReady else {
return false
}
isReady = false
dataToSend = prepare(sample: buffer)
byteIndex = 0
serialQueue.async { [weak self] in
self?.sendDataChunk()
}
return true
}
}
private extension SampleUploader {
func setupConnection() {
connection.didOpen = { [weak self] in
self?.isReady = true
}
connection.streamHasSpaceAvailable = { [weak self] in
self?.serialQueue.async {
if let success = self?.sendDataChunk() {
self?.isReady = !success
}
}
}
}
@discardableResult func sendDataChunk() -> Bool {
guard let dataToSend = dataToSend else {
return false
}
var bytesLeft = dataToSend.count - byteIndex
var length = bytesLeft > Constants.bufferMaxLength ? Constants.bufferMaxLength : bytesLeft
length = dataToSend[byteIndex..<(byteIndex + length)].withUnsafeBytes {
guard let ptr = $0.bindMemory(to: UInt8.self).baseAddress else {
return 0
}
return connection.writeToStream(buffer: ptr, maxLength: length)
}
if length > 0 {
byteIndex += length
bytesLeft -= length
if bytesLeft == 0 {
self.dataToSend = nil
byteIndex = 0
}
} else {
MXLog.error("writeBufferToStream failure")
}
return true
}
func prepare(sample buffer: CMSampleBuffer) -> Data? {
guard let imageBuffer = CMSampleBufferGetImageBuffer(buffer) else {
MXLog.error("image buffer not available")
return nil
}
CVPixelBufferLockBaseAddress(imageBuffer, .readOnly)
let scaleFactor = 2.0
let width = CVPixelBufferGetWidth(imageBuffer)/Int(scaleFactor)
let height = CVPixelBufferGetHeight(imageBuffer)/Int(scaleFactor)
let orientation = CMGetAttachment(buffer, key: RPVideoSampleOrientationKey as CFString, attachmentModeOut: nil)?.uintValue ?? 0
let scaleTransform = CGAffineTransform(scaleX: CGFloat(1.0/scaleFactor), y: CGFloat(1.0/scaleFactor))
let bufferData = self.jpegData(from: imageBuffer, scale: scaleTransform)
CVPixelBufferUnlockBaseAddress(imageBuffer, .readOnly)
guard let messageData = bufferData else {
MXLog.error("corrupted image buffer")
return nil
}
let httpResponse = CFHTTPMessageCreateResponse(nil, 200, nil, kCFHTTPVersion1_1).takeRetainedValue()
CFHTTPMessageSetHeaderFieldValue(httpResponse, "Content-Length" as CFString, String(messageData.count) as CFString)
CFHTTPMessageSetHeaderFieldValue(httpResponse, "Buffer-Width" as CFString, String(width) as CFString)
CFHTTPMessageSetHeaderFieldValue(httpResponse, "Buffer-Height" as CFString, String(height) as CFString)
CFHTTPMessageSetHeaderFieldValue(httpResponse, "Buffer-Orientation" as CFString, String(orientation) as CFString)
CFHTTPMessageSetBody(httpResponse, messageData as CFData)
let serializedMessage = CFHTTPMessageCopySerializedMessage(httpResponse)?.takeRetainedValue() as Data?
return serializedMessage
}
func jpegData(from buffer: CVPixelBuffer, scale scaleTransform: CGAffineTransform) -> Data? {
let image = CIImage(cvPixelBuffer: buffer).transformed(by: scaleTransform)
guard let colorSpace = image.colorSpace else {
return nil
}
let options: [CIImageRepresentationOption: Float] = [kCGImageDestinationLossyCompressionQuality as CIImageRepresentationOption: 1.0]
return SampleUploader.imageContext.jpegRepresentation(of: image, colorSpace: colorSpace, options: options)
}
}
@@ -0,0 +1,203 @@
//
// License from the original repository:
// https://github.com/jitsi/jitsi-meet-sdk-samples/blob/master/LICENSE
//
// SocketConnection.swift
// Broadcast Extension
//
// Created by Alex-Dan Bumbu on 22/03/2021.
// Copyright © 2021 Atlassian Inc. All rights reserved.
//
import Foundation
import MatrixSDK
class SocketConnection: NSObject {
var didOpen: (() -> Void)?
var didClose: ((Error?) -> Void)?
var streamHasSpaceAvailable: (() -> Void)?
private let filePath: String
private var socketHandle: Int32 = -1
private var address: sockaddr_un?
private var inputStream: InputStream?
private var outputStream: OutputStream?
private var networkQueue: DispatchQueue?
private var shouldKeepRunning = false
init?(filePath path: String) {
filePath = path
socketHandle = Darwin.socket(AF_UNIX, SOCK_STREAM, 0)
guard socketHandle != -1 else {
MXLog.error("failure: create socket")
return nil
}
}
func open() -> Bool {
MXLog.info("open socket connection")
guard FileManager.default.fileExists(atPath: filePath) else {
MXLog.error("failure: socket file missing")
return false
}
guard setupAddress() == true else {
return false
}
guard connectSocket() == true else {
return false
}
setupStreams()
inputStream?.open()
outputStream?.open()
return true
}
func close() {
unscheduleStreams()
inputStream?.delegate = nil
outputStream?.delegate = nil
inputStream?.close()
outputStream?.close()
inputStream = nil
outputStream = nil
}
func writeToStream(buffer: UnsafePointer<UInt8>, maxLength length: Int) -> Int {
outputStream?.write(buffer, maxLength: length) ?? 0
}
}
extension SocketConnection: StreamDelegate {
func stream(_ aStream: Stream, handle eventCode: Stream.Event) {
switch eventCode {
case .openCompleted:
MXLog.info("client stream open completed")
if aStream == outputStream {
didOpen?()
}
case .hasBytesAvailable:
if aStream == inputStream {
var buffer: UInt8 = 0
let numberOfBytesRead = inputStream?.read(&buffer, maxLength: 1)
if numberOfBytesRead == 0 && aStream.streamStatus == .atEnd {
MXLog.info("server socket closed")
close()
notifyDidClose(error: nil)
}
}
case .hasSpaceAvailable:
if aStream == outputStream {
streamHasSpaceAvailable?()
}
case .errorOccurred:
MXLog.error("client stream error occured", context: aStream.streamError)
close()
notifyDidClose(error: aStream.streamError)
default:
break
}
}
}
private extension SocketConnection {
func setupAddress() -> Bool {
var addr = sockaddr_un()
guard filePath.count < MemoryLayout.size(ofValue: addr.sun_path) else {
MXLog.error("failure: fd path is too long")
return false
}
_ = withUnsafeMutablePointer(to: &addr.sun_path.0) { ptr in
filePath.withCString {
strncpy(ptr, $0, filePath.count)
}
}
address = addr
return true
}
func connectSocket() -> Bool {
guard var addr = address else {
return false
}
let status = withUnsafePointer(to: &addr) { ptr in
ptr.withMemoryRebound(to: sockaddr.self, capacity: 1) {
Darwin.connect(socketHandle, $0, socklen_t(MemoryLayout<sockaddr_un>.size))
}
}
guard status == noErr else {
MXLog.error("connect socket failure", context: status)
return false
}
return true
}
func setupStreams() {
var readStream: Unmanaged<CFReadStream>?
var writeStream: Unmanaged<CFWriteStream>?
CFStreamCreatePairWithSocket(kCFAllocatorDefault, socketHandle, &readStream, &writeStream)
inputStream = readStream?.takeRetainedValue()
inputStream?.delegate = self
inputStream?.setProperty(kCFBooleanTrue, forKey: Stream.PropertyKey(kCFStreamPropertyShouldCloseNativeSocket as String))
outputStream = writeStream?.takeRetainedValue()
outputStream?.delegate = self
outputStream?.setProperty(kCFBooleanTrue, forKey: Stream.PropertyKey(kCFStreamPropertyShouldCloseNativeSocket as String))
scheduleStreams()
}
func scheduleStreams() {
shouldKeepRunning = true
networkQueue = DispatchQueue.global(qos: .userInitiated)
networkQueue?.async { [weak self] in
self?.inputStream?.schedule(in: .current, forMode: .common)
self?.outputStream?.schedule(in: .current, forMode: .common)
RunLoop.current.run()
var isRunning = false
repeat {
isRunning = self?.shouldKeepRunning ?? false && RunLoop.current.run(mode: .default, before: .distantFuture)
} while (isRunning)
}
}
func unscheduleStreams() {
networkQueue?.sync { [weak self] in
self?.inputStream?.remove(from: .current, forMode: .common)
self?.outputStream?.remove(from: .current, forMode: .common)
}
shouldKeepRunning = false
}
func notifyDidClose(error: Error?) {
if didClose != nil {
didClose?(error)
}
}
}
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.application-groups</key>
<array>
<string>$(APPLICATION_GROUP_IDENTIFIER)</string>
</array>
</dict>
</plist>
@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>CFBundleShortVersionString</key>
<string>$(MARKETING_VERSION)</string>
<key>CFBundlePackageType</key>
<string>XPC!</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleDisplayName</key>
<string>$(BUNDLE_DISPLAY_NAME)</string>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>NSExtension</key>
<dict>
<key>NSExtensionPointIdentifier</key>
<string>com.apple.broadcast-services-upload</string>
<key>NSExtensionPrincipalClass</key>
<string>$(PRODUCT_MODULE_NAME).SampleHandler</string>
<key>RPBroadcastProcessMode</key>
<string>RPBroadcastProcessModeSampleBuffer</string>
</dict>
</dict>
</plist>
+42
View File
@@ -0,0 +1,42 @@
name: BroadcastUploadExtension
schemes:
BroadcastUploadExtension:
analyze:
config: Debug
archive:
config: Release
build:
targets:
BroadcastUploadExtension:
- running
- testing
- profiling
- analyzing
- archiving
profile:
config: Release
run:
askForAppToLaunch: true
config: Debug
debugEnabled: false
disableMainThreadChecker: true
launchAutomaticallySubstyle: 2
test:
config: Debug
disableMainThreadChecker: true
targets:
BroadcastUploadExtension:
platform: iOS
type: app-extension
configFiles:
Debug: Debug.xcconfig
Release: Release.xcconfig
sources:
- path: .
- path: ../Config/BuildSettings.swift
- path: ../Riot/Categories/Bundle.swift
- path: ../Riot/Modules/Room/TimelineCells/Styles/RoomTimelineStyleIdentifier.swift
+31
View File
@@ -1,3 +1,34 @@
## Changes in 1.10.14 (2023-06-21)
🙌 Improvements
- Upgrade MatrixSDK version ([v0.26.12](https://github.com/matrix-org/matrix-ios-sdk/releases/tag/v0.26.12)).
## Changes in 1.10.13 (2023-06-13)
✨ Features
- Increase max. length of voice message recordings to 5m ([#7582](https://github.com/vector-im/element-ios/pull/7582))
- Broadcast Upload Extension added to the app targets to allow Jitsi screen sharing feature. ([#7566](https://github.com/vector-im/element-ios/issues/7566))
🙌 Improvements
- Upgrade MatrixSDK version ([v0.26.11](https://github.com/matrix-org/matrix-ios-sdk/releases/tag/v0.26.11)).
- Prompt the user when the invited MatrixId is not recognized ([#7558](https://github.com/vector-im/element-ios/issues/7558))
- MSC3987 implementation: the 'dont_notify' action for a push_rule is now deprecated and replaced by an empty action list. ([#7576](https://github.com/vector-im/element-ios/issues/7576))
🐛 Bugfixes
- Device manager: fix offline state for user's sessions overview. ([#7562](https://github.com/vector-im/element-ios/pull/7562))
- Prevents user avatar from disappearing due to incorrect width. ([#7587](https://github.com/vector-im/element-ios/pull/7587))
- App crashes when we make audio and video calls ([#7529](https://github.com/vector-im/element-ios/issues/7529))
- Timeline: Room creation intro cell now correctly adjusts to light / dark theme changes. ([#7554](https://github.com/vector-im/element-ios/issues/7554))
- Labs: Fix RTE sometimes inserting characters in wrong locations after multiple new lines ([#7570](https://github.com/vector-im/element-ios/issues/7570))
- Labs: RTE: Fix a crash when creating a new direct chat ([#7577](https://github.com/vector-im/element-ios/issues/7577))
- Fixed crashes when mentioning users without display names ([#7579](https://github.com/vector-im/element-ios/issues/7579))
## Changes in 1.10.12 (2023-05-16)
✨ Features
+25 -1
View File
@@ -1,3 +1,27 @@
Changes in BWI project 2.8.0 (2023-08-03)
===================================================
Upstream merge ✨:
- v1.10.14
Features ✨:
- New show participants toggle for polls (#4393)
Improvements 🙌:
- Migration progress information (#4905)
- Additional information for maintance (#4295)
- Poll history information (#4484)
- Notification times (#3580)
Bugfix 🐛:
Translations 🗣 :
SDK API changes ⚠️:
Build 🧱:
Changes in BWI project 2.7.0 (2023-07-04)
===================================================
@@ -27,7 +51,7 @@ Bugfix 🐛:
- Show app logo in pin code screen (#4828)
- Update "all chats" filter on logout/login (#4573)
Translations 🗣 :
Translations 🗣 :
- English translations passphrase (#4706)
SDK API changes ⚠️:
+3
View File
@@ -37,3 +37,6 @@ SHARE_EXTENSION_PROVISIONING_PROFILE = 8c797ca0-0440-49bd-be8d-11d761152995
SIRI_INTENTS_PROVISIONING_PROFILE_SPECIFIER = "Vector Siri Intents: App Store"
SIRI_INTENTS_PROVISIONING_PROFILE = 1690e81a-5ad3-4d99-b578-02693579be71
BROADCAST_UPLOAD_EXTENSION_PROVISIONING_PROFILE_SPECIFIER = "Vector Broadcast Upload Extension: App Store"
BROADCAST_UPLOAD_EXTENSION_PROVISIONING_PROFILE = c86239f4-0d3a-47f4-a5f2-9f4763c42b5d
+1 -1
View File
@@ -16,5 +16,5 @@
//
// Version
MARKETING_VERSION = 2.7.0
MARKETING_VERSION = 2.8.0
CURRENT_PROJECT_VERSION = 20220714163152
+7 -2
View File
@@ -126,6 +126,9 @@ class BWIBuildSettings: NSObject {
var bwiShowClosedPolls = true
var bwiPollShowParticipantsToggle = true
var bwiPollVisibleVotes = 5
var bwiPollParticipantsInHistory = true
var bwiShowThreads = false
var bwiShowRoomCreationSectionFooter = false
@@ -196,7 +199,8 @@ class BWIBuildSettings: NSObject {
"160c35279484a027031b131583f3f203b1166306bab214355b00cf28502bce11",
"d5a7298dde23aa0269c4cbd3b1a543e6ede94ce78fc20e4bfb888eb6057b5c52",
"00136d830dd2acd5047efcf8429e939ef7ef97a84bef1930df86aace3f855265",
"64cbbeea37237814445b65c941d010b9d5d024e4c584a476864b00c7c9909bce"
"64cbbeea37237814445b65c941d010b9d5d024e4c584a476864b00c7c9909bce",
"e79f4ce0f3c2772b45fd492a9c12e4e10e869ca21af68f13ff48c9c3bbd446ea"
]
// use a different badge color if the user was mentioned in a room
@@ -501,7 +505,7 @@ class BWIBuildSettings: NSObject {
var passwordIndicatorOnLogin = true
// MARK: Displays the element base version on the settings screen
var elementBaseVersion = "1.10.12"
var elementBaseVersion = "1.10.14"
var showElementBaseVersion = true
@@ -612,6 +616,7 @@ class BWIBuildSettings: NSObject {
// MARK: - Maintenance
var enableMaintenanceInfoOnWelcomeScreen = false
var showMaintenanceInfoMessageType = false
// MARK: User Search
var sortUserSearchResultsAlphabetically = true
@@ -33,10 +33,11 @@ extension BWIBuildSettings {
bwiLocationShareButtonVisible = false
bwiLoginFlowLayout = false
useRustEncryption = true
bwiNotificationTimes = true
enableLabFeatureVoiceBroadcasts = true
enableNewSessionManagerByDefault = true
enableLabFeatureWYSIWYG = true
showMaintenanceInfoMessageType = true
}
}
+1 -1
View File
@@ -25,7 +25,7 @@ extension BWIBuildSettings {
bwiLocationShareButtonVisible = false
bwiLoginFlowLayout = false
authScreenShowTestServerOptions = false
bwiNotificationTimes = true
enableNewSessionManagerByDefault = true
}
+13 -12
View File
@@ -91,8 +91,7 @@ class CommonConfiguration: NSObject, Configurable {
sdkOptions.enableNewClientInformationFeature = RiotSettings.shared.enableClientInformationFeature
// Configure Crypto SDK feature deciding which crypto module to use
sdkOptions.cryptoSDKFeature = CryptoSDKFeature.shared
sdkOptions.cryptoMigrationDelegate = self
}
private func makeASCIIUserAgent() -> String? {
@@ -168,14 +167,16 @@ class CommonConfiguration: NSObject, Configurable {
if RiotSettings.shared.allowStunServerFallback, let stunServerFallback = BWIBuildSettings.shared.stunServerFallbackUrlString {
callManager.fallbackSTUNServer = stunServerFallback
}
}
// MARK: - Per loaded matrix session settings
func setupSettingsWhenLoaded(for matrixSession: MXSession) {
// Do not warn for unknown devices. We have cross-signing now
(matrixSession.crypto as? MXLegacyCrypto)?.warnOnUnknowDevices = false
}
}
}
extension CommonConfiguration: MXCryptoV2MigrationDelegate {
var needsVerificationUpgrade: Bool {
get {
RiotSettings.shared.showVerificationUpgradeAlert
}
set {
RiotSettings.shared.showVerificationUpgradeAlert = newValue
}
}
}
-3
View File
@@ -24,7 +24,4 @@ import MatrixSDK
// MARK: - Per matrix session settings
func setupSettings(for matrixSession: MXSession)
// MARK: - Per loaded matrix session settings
func setupSettingsWhenLoaded(for matrixSession: MXSession)
}
+1
View File
@@ -23,6 +23,7 @@
// Application constants
KEYCHAIN_ACCESS_GROUP = $(AppIdentifierPrefix)$(BASE_BUNDLE_IDENTIFIER).keychain.shared
BROADCAST_UPLOAD_EXTENSION_BUNDLE_IDENTIFIER = $(BASE_BUNDLE_IDENTIFIER).broadcastUploadExtension
// Build settings
IPHONEOS_DEPLOYMENT_TARGET = 14.0
@@ -21,7 +21,8 @@ import SwiftUI
/// Dark theme colors.
public class DarkColors {
private static let values = ColorValues(
accent: UIColor(rgb:0x0DBD8B),
// bwi: BUM accent color 108194
accent: UIColor(rgb:0x108194),
alert: UIColor(rgb:0xFF4B55),
primaryContent: UIColor(rgb:0xFFFFFF),
secondaryContent: UIColor(rgb:0xA9B2BC),
@@ -22,7 +22,8 @@ import SwiftUI
/// Light theme colors.
public class LightColors {
private static let values = ColorValues(
accent: UIColor(rgb:0x0DBD8B),
// bwi: BUM accent color 108194
accent: UIColor(rgb:0x108194),
alert: UIColor(rgb:0xFF4B55),
primaryContent: UIColor(rgb:0x17191C),
secondaryContent: UIColor(rgb:0x737D8C),
+44 -49
View File
@@ -1,15 +1,21 @@
GIT
remote: https://github.com/mhtranbn/fastlane-plugin-diawi.git
revision: 6ca982cd41e7c315290240cd4570d5d7b799db38
specs:
fastlane-plugin-diawi (0.1.3)
GEM
remote: https://rubygems.org/
specs:
CFPropertyList (3.0.5)
CFPropertyList (3.0.6)
rexml
activesupport (6.1.7)
activesupport (6.1.7.3)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 1.6, < 2)
minitest (>= 5.1)
tzinfo (~> 2.0)
zeitwerk (~> 2.3)
addressable (2.8.1)
addressable (2.8.4)
public_suffix (>= 2.0.2, < 6.0)
algoliasearch (1.27.5)
httpclient (~> 2.8, >= 2.8.3)
@@ -17,16 +23,16 @@ GEM
artifactory (3.0.15)
atomos (0.1.3)
aws-eventstream (1.2.0)
aws-partitions (1.674.0)
aws-sdk-core (3.168.4)
aws-partitions (1.770.0)
aws-sdk-core (3.173.1)
aws-eventstream (~> 1, >= 1.0.2)
aws-partitions (~> 1, >= 1.651.0)
aws-sigv4 (~> 1.5)
jmespath (~> 1, >= 1.6.1)
aws-sdk-kms (1.61.0)
aws-sdk-kms (1.64.0)
aws-sdk-core (~> 3, >= 3.165.0)
aws-sigv4 (~> 1.1)
aws-sdk-s3 (1.117.2)
aws-sdk-s3 (1.122.0)
aws-sdk-core (~> 3, >= 3.165.0)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.4)
@@ -76,7 +82,7 @@ GEM
colored2 (3.1.2)
commander (4.6.0)
highline (~> 2.0.0)
concurrent-ruby (1.1.10)
concurrent-ruby (1.2.2)
declarative (0.0.20)
digest-crc (0.6.4)
rake (>= 12.0.0, < 14.0.0)
@@ -87,8 +93,8 @@ GEM
escape (0.0.4)
ethon (0.16.0)
ffi (>= 1.15.0)
excon (0.94.0)
faraday (1.10.2)
excon (0.99.0)
faraday (1.10.3)
faraday-em_http (~> 1.0)
faraday-em_synchrony (~> 1.0)
faraday-excon (~> 1.1)
@@ -116,8 +122,8 @@ GEM
faraday-retry (1.0.3)
faraday_middleware (1.2.0)
faraday (~> 1.0)
fastimage (2.2.6)
fastlane (2.211.0)
fastimage (2.2.7)
fastlane (2.213.0)
CFPropertyList (>= 2.3, < 4.0.0)
addressable (>= 2.8, < 3.0.0)
artifactory (~> 3.0)
@@ -141,7 +147,7 @@ GEM
json (< 3.0.0)
jwt (>= 2.1.0, < 3)
mini_magick (>= 4.9.4, < 5.0.0)
multipart-post (~> 2.0.0)
multipart-post (>= 2.0.0, < 3.0.0)
naturally (~> 2.2)
optparse (~> 0.1.1)
plist (>= 3.1.0, < 4.0.0)
@@ -157,9 +163,7 @@ GEM
xcpretty (~> 0.3.0)
xcpretty-travis-formatter (>= 0.0.3)
fastlane-plugin-brew (0.1.1)
fastlane-plugin-diawi (2.1.0)
rest-client (>= 2.0.0)
fastlane-plugin-sentry (1.14.0)
fastlane-plugin-sentry (1.15.0)
os (~> 1.1, >= 1.1.4)
fastlane-plugin-versioning (0.5.1)
fastlane-plugin-xcodegen (1.1.0)
@@ -168,9 +172,9 @@ GEM
fourflusher (2.3.1)
fuzzy_match (2.0.4)
gh_inspector (1.1.3)
google-apis-androidpublisher_v3 (0.31.0)
google-apis-core (>= 0.9.1, < 2.a)
google-apis-core (0.9.1)
google-apis-androidpublisher_v3 (0.42.0)
google-apis-core (>= 0.11.0, < 2.a)
google-apis-core (0.11.0)
addressable (~> 2.5, >= 2.5.1)
googleauth (>= 0.16.2, < 2.a)
httpclient (>= 2.8.1, < 3.a)
@@ -179,10 +183,10 @@ GEM
retriable (>= 2.0, < 4.a)
rexml
webrick
google-apis-iamcredentials_v1 (0.16.0)
google-apis-core (>= 0.9.1, < 2.a)
google-apis-playcustomapp_v1 (0.12.0)
google-apis-core (>= 0.9.1, < 2.a)
google-apis-iamcredentials_v1 (0.17.0)
google-apis-core (>= 0.11.0, < 2.a)
google-apis-playcustomapp_v1 (0.13.0)
google-apis-core (>= 0.11.0, < 2.a)
google-apis-storage_v1 (0.19.0)
google-apis-core (>= 0.9.0, < 2.a)
google-cloud-core (1.6.0)
@@ -190,7 +194,7 @@ GEM
google-cloud-errors (~> 1.0)
google-cloud-env (1.6.0)
faraday (>= 0.17.3, < 3.0)
google-cloud-errors (1.3.0)
google-cloud-errors (1.3.1)
google-cloud-storage (1.44.0)
addressable (~> 2.8)
digest-crc (~> 0.4)
@@ -199,7 +203,7 @@ GEM
google-cloud-core (~> 1.6)
googleauth (>= 0.16.2, < 2.a)
mini_mime (~> 1.0)
googleauth (1.3.0)
googleauth (1.5.2)
faraday (>= 0.17.3, < 3.a)
jwt (>= 1.4, < 3.0)
memoist (~> 0.16)
@@ -207,48 +211,39 @@ GEM
os (>= 0.9, < 2.0)
signet (>= 0.16, < 2.a)
highline (2.0.3)
http-accept (1.7.0)
http-cookie (1.0.5)
domain_name (~> 0.5)
httpclient (2.8.3)
i18n (1.12.0)
i18n (1.13.0)
concurrent-ruby (~> 1.0)
jmespath (1.6.2)
json (2.6.3)
jwt (2.5.0)
jwt (2.7.0)
memoist (0.16.2)
mime-types (3.4.1)
mime-types-data (~> 3.2015)
mime-types-data (3.2022.0105)
mini_magick (4.12.0)
mini_mime (1.1.2)
mini_portile2 (2.8.0)
minitest (5.16.3)
mini_portile2 (2.8.2)
minitest (5.18.0)
molinillo (0.8.0)
multi_json (1.15.0)
multipart-post (2.0.0)
multipart-post (2.3.0)
nanaimo (0.3.0)
nap (1.1.0)
naturally (2.2.1)
netrc (0.11.0)
nokogiri (1.13.10)
mini_portile2 (~> 2.8.0)
nokogiri (1.15.2)
mini_portile2 (~> 2.8.2)
racc (~> 1.4)
optparse (0.1.1)
os (1.1.4)
plist (3.6.0)
plist (3.7.0)
public_suffix (4.0.7)
racc (1.6.1)
racc (1.6.2)
rake (13.0.6)
representable (3.2.0)
declarative (< 0.1.0)
trailblazer-option (>= 0.1.1, < 0.2.0)
uber (< 0.2.0)
rest-client (2.1.0)
http-accept (>= 1.7.0, < 2.0)
http-cookie (>= 1.0.2, < 2.0)
mime-types (>= 1.16, < 4.0)
netrc (~> 0.8)
retriable (3.1.2)
rexml (3.2.5)
rouge (2.0.7)
@@ -261,10 +256,10 @@ GEM
faraday (>= 0.17.5, < 3.a)
jwt (>= 1.5, < 3.0)
multi_json (~> 1.10)
simctl (1.6.8)
simctl (1.6.10)
CFPropertyList
naturally
slather (2.7.3)
slather (2.7.4)
CFPropertyList (>= 2.2, < 4)
activesupport
clamp (~> 1.3)
@@ -280,14 +275,14 @@ GEM
tty-cursor (~> 0.7)
typhoeus (1.4.0)
ethon (>= 0.9.0)
tzinfo (2.0.5)
tzinfo (2.0.6)
concurrent-ruby (~> 1.0)
uber (0.1.0)
unf (0.1.4)
unf_ext
unf_ext (0.0.8.2)
unicode-display_width (1.8.0)
webrick (1.7.0)
webrick (1.8.1)
word_wrap (1.0.0)
xcode-install (2.8.1)
claide (>= 0.9.1)
@@ -303,7 +298,7 @@ GEM
rouge (~> 2.0.7)
xcpretty-travis-formatter (1.0.1)
xcpretty (~> 0.2, >= 0.0.7)
zeitwerk (2.6.6)
zeitwerk (2.6.8)
PLATFORMS
ruby
@@ -311,7 +306,7 @@ PLATFORMS
DEPENDENCIES
cocoapods (~> 1.11.2)
fastlane
fastlane-plugin-diawi
fastlane-plugin-diawi!
fastlane-plugin-sentry
fastlane-plugin-versioning
fastlane-plugin-xcodegen
+6 -2
View File
@@ -16,7 +16,7 @@ use_frameworks!
# - `{ :specHash => {sdk spec hash}` to depend on specific pod options (:git => …, :podspec => …) for MatrixSDK repo. Used by Fastfile during CI
#
# Warning: our internal tooling depends on the name of this variable name, so be sure not to change it
$matrixSDKVersion = '= 0.26.10'
$matrixSDKVersion = '= 0.26.12'
# $matrixSDKVersion = :local
# $matrixSDKVersion = { :branch => 'develop'}
# $matrixSDKVersion = { :specHash => { git: 'https://git.io/fork123', branch: 'fix' } }
@@ -43,7 +43,7 @@ when String # specific MatrixSDK released version
$matrixSDKVersionSpec = $matrixSDKVersion
end
$matrixSDKVersionSpec = { :git => 'https://dl-gitlab.example.com/bwmessenger/bundesmessenger/bundesmessenger-ios-sdk', :tag => 'v0.26.10_bwi' }
$matrixSDKVersionSpec = { :git => 'https://dl-gitlab.example.com/bwmessenger/bundesmessenger/bundesmessenger-ios-sdk', :tag => 'v0.26.12_bwi' }
# Method to import the MatrixSDK
def import_MatrixSDK
@@ -189,6 +189,10 @@ abstract_target 'RiotPods' do
import_MatrixKit_pods
end
target "BroadcastUploadExtension" do
import_MatrixSDK
end
end
post_install do |installer|
+23 -65
View File
@@ -20,24 +20,6 @@ PODS:
- Down (0.11.0)
- DSBottomSheet (0.3.0)
- DSWaveformImage (6.1.1)
- DTCoreText (1.6.26):
- DTCoreText/Core (= 1.6.26)
- DTFoundation/Core (~> 1.7.5)
- DTFoundation/DTAnimatedGIF (~> 1.7.5)
- DTFoundation/DTHTMLParser (~> 1.7.5)
- DTFoundation/UIKit (~> 1.7.5)
- DTCoreText/Core (1.6.26):
- DTFoundation/Core (~> 1.7.5)
- DTFoundation/DTAnimatedGIF (~> 1.7.5)
- DTFoundation/DTHTMLParser (~> 1.7.5)
- DTFoundation/UIKit (~> 1.7.5)
- DTFoundation/Core (1.7.18)
- DTFoundation/DTAnimatedGIF (1.7.18)
- DTFoundation/DTHTMLParser (1.7.18):
- DTFoundation/Core
- DTFoundation/UIKit (1.7.18):
- DTFoundation/Core
- DTTJailbreakDetection (0.4.0)
- FLEX (4.5.0)
- FlowCommoniOS (1.12.2)
- GBDeviceInfo (7.1.0):
@@ -45,9 +27,9 @@ PODS:
- GBDeviceInfo/Core (7.1.0)
- GZIP (1.3.0)
- Introspect (0.1.4)
- JitsiMeetSDKLite (7.0.1-lite):
- JitsiWebRTC (~> 106.0)
- JitsiWebRTC (106.0.0)
- JitsiMeetSDKLite (8.1.2-lite):
- JitsiWebRTC (~> 111.0)
- JitsiWebRTC (111.0.2)
- KeychainAccess (4.2.2)
- KituraContracts (1.2.1):
- LoggerAPI (~> 1.7)
@@ -57,12 +39,9 @@ PODS:
- LoggerAPI (1.9.200):
- Logging (~> 1.1)
- Logging (1.4.0)
- MatomoTracker (7.5.2):
- MatomoTracker/Core (= 7.5.2)
- MatomoTracker/Core (7.5.2)
- MatrixSDK (0.26.10):
- MatrixSDK/Core (= 0.26.10)
- MatrixSDK/Core (0.26.10):
- MatrixSDK (0.26.12):
- MatrixSDK/Core (= 0.26.12)
- MatrixSDK/Core (0.26.12):
- AFNetworking (~> 4.0.0)
- GZIP (~> 1.3.0)
- libbase58 (~> 0.1.4)
@@ -70,8 +49,8 @@ PODS:
- OLMKit (~> 3.2.5)
- Realm (= 10.27.0)
- SwiftyBeaver (= 1.9.5)
- MatrixSDK/JingleCallStack (0.26.10):
- JitsiMeetSDKLite (= 7.0.1-lite)
- MatrixSDK/JingleCallStack (0.26.12):
- JitsiMeetSDKLite (= 8.1.2-lite)
- MatrixSDK/Core
- MatrixSDKCrypto (0.3.4)
- OLMKit (3.2.12):
@@ -116,8 +95,6 @@ DEPENDENCIES:
- Down (~> 0.11.0)
- DSBottomSheet (~> 0.3)
- DSWaveformImage (~> 6.1.1)
- DTCoreText (= 1.6.26)
- DTTJailbreakDetection (~> 0.4.0)
- FLEX (~> 4.5.0)
- FlowCommoniOS (~> 1.12.0)
- GBDeviceInfo (~> 7.1.0)
@@ -125,9 +102,8 @@ DEPENDENCIES:
- KeychainAccess (~> 4.2.2)
- KTCenterFlowLayout (~> 1.3.1)
- libPhoneNumber-iOS (~> 0.9.13)
- MatomoTracker (~> 7.5.2)
- MatrixSDK (from `https://dl-gitlab.example.com/bwmessenger/bundesmessenger/bundesmessenger-ios-sdk`, tag `v0.26.10_bwi_beta`)
- MatrixSDK/JingleCallStack (from `https://dl-gitlab.example.com/bwmessenger/bundesmessenger/bundesmessenger-ios-sdk`, tag `v0.26.10_bwi_beta`)
- MatrixSDK (= 0.26.12)
- MatrixSDK/JingleCallStack (= 0.26.12)
- OLMKit
- PostHog (~> 2.0.0)
- ReadMoreTextView (~> 3.0.1)
@@ -146,20 +122,8 @@ DEPENDENCIES:
- ZXingObjC (~> 3.6.5)
SPEC REPOS:
https://github.com/CocoaPods/Specs.git:
- AFNetworking
- DTCoreText
- DTFoundation
- DTTJailbreakDetection
- GZIP
- JitsiMeetSDKLite
- JitsiWebRTC
- libbase58
- MatomoTracker
- MatrixSDKCrypto
- Realm
- SwiftyBeaver
trunk:
- AFNetworking
- BlueCryptor
- BlueECC
- BlueRSA
@@ -169,16 +133,23 @@ SPEC REPOS:
- FLEX
- FlowCommoniOS
- GBDeviceInfo
- GZIP
- Introspect
- JitsiMeetSDKLite
- JitsiWebRTC
- KeychainAccess
- KituraContracts
- KTCenterFlowLayout
- libbase58
- libPhoneNumber-iOS
- LoggerAPI
- Logging
- MatrixSDK
- MatrixSDKCrypto
- OLMKit
- PostHog
- ReadMoreTextView
- Realm
- Reusable
- Sentry
- SideMenu
@@ -187,22 +158,13 @@ SPEC REPOS:
- SwiftGen
- SwiftJWT
- SwiftLint
- SwiftyBeaver
- UICollectionViewLeftAlignedLayout
- UICollectionViewRightAlignedLayout
- WeakDictionary
- zxcvbn-ios
- ZXingObjC
EXTERNAL SOURCES:
MatrixSDK:
:git: https://dl-gitlab.example.com/bwmessenger/bundesmessenger/bundesmessenger-ios-sdk
:tag: v0.26.10_bwi_beta
CHECKOUT OPTIONS:
MatrixSDK:
:git: https://dl-gitlab.example.com/bwmessenger/bundesmessenger/bundesmessenger-ios-sdk
:tag: v0.26.10_bwi_beta
SPEC CHECKSUMS:
AFNetworking: 3bd23d814e976cd148d7d44c3ab78017b744cd58
BlueCryptor: b0aee3d9b8f367b49b30de11cda90e1735571c24
@@ -211,16 +173,13 @@ SPEC CHECKSUMS:
Down: b6ba1bc985c9d2f4e15e3b293d2207766fa12612
DSBottomSheet: ca0ac37eb5af2dd54663f86b84382ed90a59be2a
DSWaveformImage: 3c718a0cf99291887ee70d1d0c18d80101d3d9ce
DTCoreText: ec749e013f2e1f76de5e7c7634642e600a7467ce
DTFoundation: a53f8cda2489208cbc71c648be177f902ee17536
DTTJailbreakDetection: 5e356c5badc17995f65a83ed9483f787a0057b71
FLEX: e51461dd6f0bfb00643c262acdfea5d5d12c596b
FlowCommoniOS: ca92071ab526dc89905495a37844fd7e78d1a7f2
GBDeviceInfo: 5d62fa85bdcce3ed288d83c28789adf1173e4376
GZIP: 416858efbe66b41b206895ac6dfd5493200d95b3
Introspect: b62c4dd2063072327c21d618ef2bedc3c87bc366
JitsiMeetSDKLite: d59573336ce887ec52327a9927aa8443f560d0b9
JitsiWebRTC: f441eb0e2d67f0588bf24e21c5162e97342714fb
JitsiMeetSDKLite: 895213158cf62342069a10634a41d2f1c00057f7
JitsiWebRTC: 80f62908fcf2a1160e0d14b584323fb6e6be630b
KeychainAccess: c0c4f7f38f6fc7bbe58f5702e25f7bd2f65abf51
KituraContracts: e845e60dc8627ad0a76fa55ef20a45451d8f830b
KTCenterFlowLayout: 6e02b50ab2bd865025ae82fe266ed13b6d9eaf97
@@ -228,8 +187,7 @@ SPEC CHECKSUMS:
libPhoneNumber-iOS: 0a32a9525cf8744fe02c5206eb30d571e38f7d75
LoggerAPI: ad9c4a6f1e32f518fdb43a1347ac14d765ab5e3d
Logging: beeb016c9c80cf77042d62e83495816847ef108b
MatomoTracker: 1d98ddc58322fd9d65e1a6886b8e41363047bd13
MatrixSDK: 68e39c246ff8d80c5788d5fc46e93fcbb24703fa
MatrixSDK: 0af737bc461b82d0ec9edd6fdf8f70b02771ebd3
MatrixSDKCrypto: ac805c22c24f79f349cdbfa065855c73a4c81b51
OLMKit: da115f16582e47626616874e20f7bb92222c7a51
PostHog: 660ec6c9d80cec17b685e148f17f6785a88b597d
@@ -250,6 +208,6 @@ SPEC CHECKSUMS:
zxcvbn-ios: fef98b7c80f1512ff0eec47ac1fa399fc00f7e3c
ZXingObjC: fdbb269f25dd2032da343e06f10224d62f537bdb
PODFILE CHECKSUM: 6bd4e9aff1b435c22f06ad6a4497af49acca8a27
PODFILE CHECKSUM: 0e7e10f516d40d9df60cb874170b91603c632118
COCOAPODS: 1.11.3
@@ -59,8 +59,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/matrix-org/matrix-wysiwyg-composer-swift",
"state" : {
"revision" : "ff5e8054da60212051cb0dec244500ca0f441bac",
"version" : "2.1.0"
"revision" : "1100b217c04d096dfe072afb4484660ff794d805",
"version" : "2.2.2"
}
},
{
+7 -2
View File
@@ -30,7 +30,8 @@
"downtime_title" = "⚠ Server nicht erreichbar";
"downtime_default_message" = "Wir führen gerade Wartungsarbeiten durch. Bitte versuche es später erneut.";
"downtime_alert_dismiss_button" = "Zurück";
"downtime_alert_dismiss_button" = "Ok";
"blocking_downtime_alert_dismiss_button" = "Zurück";
"settings_downtime_message_same_day" = "Der %@ steht am %@, %@ von %@ bis %@ Uhr (UTC%@) nicht zur Verfügung. Nachrichten können in dieser Zeit nicht verschickt oder empfangen werden.";
"settings_downtime_message_different_days" = "Der %@ steht von %@, %@ Uhr (UTC%@) bis %@, %@ Uhr (UTC%@) nicht zur Verfügung. Nachrichten können in dieser Zeit nicht verschickt oder empfangen werden.";
"settings_copyright" = "Copyright";
@@ -521,7 +522,7 @@
"bwi_settings_new_features_show_features" = "Neue Funktionen anzeigen";
"bwi_feature_banner_header" = "Neue Funktionen";
"bwi_feature_banner_show_more_button" = "Erfahre mehr";
"bwi_feature_banner_advertisement_text" = "Neue Umfragen können vom Ersteller so konfiguriert werden, dass angezeigt wird, wer für welche Option gestimmt hat.";
"bwi_feature_banner_advertisement_text" = "Mit dem neuen Feature Ruhezeiteneinstellung lassen sich Benachrichtigungen nach Wochentag und Uhrzeit ein- bzw stummschalten.";
// MARK: - Onboarding
"onboarding_splash_login_button_title" = "Loslegen";
@@ -628,3 +629,7 @@
// MARK: - Accessibility declaration
"bwi_accessibility_declaration_button_title" = "Barrierefreiheitserklärung";
// MARK: - Crypto Store migration
"bwi_launch_loading_crypto_store_migration_info" = "Die Ver-/Entschlüsselung von Nachrichten wird verbessert, dies kann ein paar Minuten dauern, bitte schließe die App nicht. Verbesserung läuft.";
+17
View File
@@ -2754,3 +2754,20 @@
"key_verification_self_verify_security_upgrade_alert_title" = "App aktualisiert";
"settings_acceptable_use" = "Nutzungsbedingungen";
"room_command_emote_description" = "Zeigt Aktionen";
"room_command_error_unknown_command" = "Ungültige oder nicht verarbeitete Eingabe";
"room_command_change_room_topic_description" = "Ändert das Raumthema";
"room_command_reset_user_power_level_description" = "Setzt das Berechtigungslevel beim Benutzer mit der angegebenen ID zurück";
"room_command_set_user_power_level_description" = "Bestimmt das Berechtigungslevel des Benutzers";
"room_command_unban_user_description" = "Entbannt den Benutzer mit der angegebenen ID";
"room_command_ban_user_description" = "Verbannt den Benutzer mit der angegebenen ID";
"room_command_kick_user_description" = "Entfernt den Benutzer mit der angegebenen ID aus diesem Raum";
"room_command_invite_user_description" = "Lädt den Benutzer mit der angegebenen ID in den aktuellen Raum ein";
"room_command_part_room_description" = "Raum verlassen";
"room_command_join_room_description" = "Raum mit angegebener Adresse betreten";
// Room commands descriptions
"room_command_change_display_name_description" = "Ändert deinen Anzeigenamen";
"notice_display_name_changed_to" = "%@ hat den Anzeigenamen zu %@ geändert";
"poll_timeline_loading" = "Lade …";
"room_command_discard_session_description" = "Erzwingt das Verferfen der aktuell ausgehende Gruppensitzung in einem verschlüsseltem Raum";
+6 -2
View File
@@ -30,7 +30,8 @@
"downtime_title" = "⚠ Server not available";
"downtime_default_message" = "We are working on our maintenance. Please try again later.";
"downtime_alert_dismiss_button" = "Back";
"downtime_alert_dismiss_button" = "Ok";
"blocking_downtime_alert_dismiss_button" = "Back";
"settings_downtime_message_same_day" = "The %@ is not available on %@, %@ between %@ and %@ (UTC%@). Messages may not be sent or received during that time.";
"settings_downtime_message_different_days" = "The %@ is not available from %@, %@ (UTC%@) to %@, %@ (UTC%@). Messages may not be sent or received during that time.";
"settings_copyright" = "Copyright";
@@ -430,7 +431,7 @@
"bwi_settings_new_features_show_features" = "Show new features";
"bwi_feature_banner_header" = "New Features";
"bwi_feature_banner_show_more_button" = "Learn more";
"bwi_feature_banner_advertisement_text" = "New polls can be configured by the creator to show who voted for which option.";
"bwi_feature_banner_advertisement_text" = "A new feature for notifications times allows you to define time intervals for filtering incoming push notifications.";
// MARK: - Onboarding
"onboarding_splash_login_button_title" = "Let's go";
@@ -538,3 +539,6 @@
// MARK: - Accessibility declaration
"bwi_accessibility_declaration_button_title" = "Accessibility declaration";
// MARK: - Crypto Store migration
"bwi_launch_loading_crypto_store_migration_info" = "Message encryption/decryption has been updated to improve app performance, this may take a few minutes. Please do not close the app during the update. The update is running.";
+5 -3
View File
@@ -366,6 +366,9 @@
"room_creation_error_invite_user_by_email_without_identity_server" = "No identity server is configured so you cannot add a participant with an email.";
"room_creation_dm_error" = "We couldn't create your DM. Please check the users you want to invite and try again.";
"room_creation_only_one_email_invite" = "You can only invite one email at a time";
"room_creation_user_not_found_prompt_title" = "Confirmation";
"room_creation_user_not_found_prompt_message" = "Unable to find profiles for this Matrix ID. Would you like to start a DM anyway?";
"room_creation_user_not_found_prompt_invite_action" = "Start DM anyway";
// Room recents
"room_recents_directory_section" = "ROOM DIRECTORY";
@@ -459,6 +462,8 @@ Tap the + to start adding people.";
"room_participants_invite_prompt_title" = "Confirmation";
"room_participants_invite_prompt_msg" = "Are you sure you want to invite %@ to this chat?";
"room_participants_invite_prompt_to_msg" = "Are you sure you want to invite %@ to %@?";
"room_participants_invite_unknown_participant_prompt_to_msg" = "Unable to find profiles for this Matrix ID. Are you sure you want to invite %@ to %@?";
"room_participants_invite_anyway" = "Invite anyway";
"room_participants_filter_room_members" = "Filter room members";
"room_participants_filter_room_members_for_dm" = "Filter members";
"room_participants_invite_another_user" = "Search / invite by User ID, Name or email";
@@ -822,9 +827,6 @@ Tap the + to start adding people.";
"settings_labs_enable_new_app_layout" = "New Application Layout";
"settings_labs_enable_wysiwyg_composer" = "Try out the rich text editor";
"settings_labs_enable_voice_broadcast" = "Voice broadcast";
"settings_labs_enable_crypto_sdk" = "Rust end-to-end encryption";
"settings_labs_confirm_crypto_sdk" = "Please be advised that as this feature is still in its experimental stage, it may not function as expected and could potentially have unintended consequences. To revert the feature, simply log out and log back in. Use at your own discretion and with caution.";
"settings_labs_disable_crypto_sdk" = "Rust end-to-end encryption (log out to disable)";
"settings_version" = "Version %@";
"settings_olm_version" = "Olm Version %@";
+17
View File
@@ -2692,3 +2692,20 @@
// Legacy to Rust security upgrade
"key_verification_self_verify_security_upgrade_alert_title" = "Rakendus on uuendatud";
"room_command_error_unknown_command" = "Vigane või määratlemata käsk";
"room_command_discard_session_description" = "Sunnib loobuma praeguse krüptitud jututoa rühmavestluse seansist";
"room_command_change_room_topic_description" = "Määra jututoa teema";
"room_command_reset_user_power_level_description" = "Eemalda antud tunnusega kasutajalt haldusõigused selles jututoas";
"room_command_set_user_power_level_description" = "Määra kasutaja õigused";
"room_command_unban_user_description" = "Taasta ligipääs antud tunnusega kasutajale";
"room_command_ban_user_description" = "Keela ligipääs antud tunnusega kasutajale";
"room_command_kick_user_description" = "Müksa selle tunnusega kasutaja jututoast välja";
"room_command_invite_user_description" = "Kutsub nimetatud kasutajatunnusega kasutaja sellesse jututuppa";
"room_command_part_room_description" = "Lahku jututoast";
"room_command_join_room_description" = "Liitu sellise aadressiga jututoaga";
"room_command_emote_description" = "Näitab tegevusi";
// Room commands descriptions
"room_command_change_display_name_description" = "Muudab sinu kuvatavat nime";
"notice_display_name_changed_to" = "%@ muutis oma kuvatavaks nimeks %@";
"poll_timeline_loading" = "Laadin...";
+20 -1
View File
@@ -54,7 +54,6 @@
// MARK: - MatrixKit
"matrix" = "Matrix";
// Login Screen
"login_create_account" = "Luo tili:";
@@ -197,3 +196,23 @@
"ssl_could_not_verify" = "Etäpalvelimen identiteetin vahvistaminen epäonnistui.";
"login_user_id_placeholder" = "Matrix ID (esim. @matti:matrix.org tai pelkästään matti)";
"login_identity_server_info" = "Matrix tarjoaa identiteettipalvelimen joka osaa kertaa mikä sähköpostiosoite tai puhelinnumero vastaa mitäkin Matrix ID:tä. Vain https://matrix.org on tällä hetkellä käytettävissä.";
"suggest" = "Ehdota";
"add" = "Lisää";
"existing" = "Nykyinen";
"new_word" = "Uusi";
"stop" = "Seis";
"done" = "Valmis";
"open" = "Avaa";
"less" = "Vähemmän";
"more" = "Lisää";
"switch" = "Vaihda";
"joined" = "Liittyi";
"skip" = "Ohita";
"send_to" = "Lähetä käyttäjälle %@";
"collapse" = "Näytä vähemmän";
"rename" = "Nimeä uudelleen";
"later" = "Myöhemmin";
"active_call_details" = "Aktiivinen puhelu (%@)";
"active_call" = "Aktiivinen puhelu";
"enable" = "Ota käyttöön";
"store_promotional_text" = "Yksityisyyttä varjeleva chat ja yhteistyösovellus, avoimessa verkossa. Hajautettu hallintaa varten. Ei datalouhintaa, takaovia tai kolmannen osapuolen pääsyä.";
+17
View File
@@ -2947,3 +2947,20 @@
"key_verification_self_verify_security_upgrade_alert_title" = "Aplikasi diperbarui";
"settings_acceptable_use" = "Kebijakan Penggunaan yang Dapat Diterima";
"room_command_error_unknown_command" = "Perintah tidak valid atau tidak ditangani";
"room_command_discard_session_description" = "Memaksa sesi kelompok outbound saat ini di ruang terenkripsi untuk dihapus";
"room_command_change_room_topic_description" = "Menetapkan topik ruangan";
"room_command_reset_user_power_level_description" = "Menurunkan pengguna dengan ID yang ditetapkan";
"room_command_set_user_power_level_description" = "Definisikan tingkat daya pengguna";
"room_command_unban_user_description" = "Menghilangkan cekalan pengguna dengan ID yang ditetapkan";
"room_command_ban_user_description" = "Mencekal pengguna dengan ID yang ditetapkan";
"room_command_kick_user_description" = "Mengeluarkan pengguna dengan ID yang ditetapkan dari ruangan ini";
"room_command_invite_user_description" = "Mengundang pengguna dengan OD yang ditetapkan ke ruangan saat ini";
"room_command_part_room_description" = "Tinggalkan ruangan";
"room_command_join_room_description" = "Bergabung dengan ruangan dengan alamat yang ditetapkan";
"room_command_emote_description" = "Menampilkan tindakan";
// Room commands descriptions
"room_command_change_display_name_description" = "Mengubah nama tampilan Anda";
"notice_display_name_changed_to" = "%@ mengubah nama tampilannya menjadi %@";
"poll_timeline_loading" = "Memuat...";
+17
View File
@@ -2720,3 +2720,20 @@
"key_verification_self_verify_security_upgrade_alert_title" = "App aggiornata";
"settings_acceptable_use" = "Politica di utilizzo accettabile";
"room_command_error_unknown_command" = "Comando non valido o non gestito";
"room_command_discard_session_description" = "Forza l'eliminazione dell'attuale sessione di gruppo in uscita in una stanza criptata";
"room_command_change_room_topic_description" = "Imposta l'argomento della stanza";
"room_command_kick_user_description" = "Rimuove l'utente per ID da questa stanza";
"room_command_reset_user_power_level_description" = "Toglie privilegi all'utente per ID";
"room_command_set_user_power_level_description" = "Definisci il livello di poteri di un utente";
"room_command_unban_user_description" = "Riammette l'utente per ID";
"room_command_ban_user_description" = "Bandisce l'utente per ID";
"room_command_invite_user_description" = "Invita l'utente per ID alla stanza attuale";
"room_command_part_room_description" = "Esci dalla stanza";
"room_command_join_room_description" = "Entra nella stanza con l'indirizzo scelto";
"room_command_emote_description" = "Mostra l'azione";
// Room commands descriptions
"room_command_change_display_name_description" = "Cambia il tuo nome visualizzato";
"notice_display_name_changed_to" = "%@ ha cambiato il suo nome visualizzato in %@";
"poll_timeline_loading" = "Caricamento...";
+6 -4
View File
@@ -3,8 +3,10 @@
"NSFaceIDUsageDescription" = "Face ID brukes til å få tilgang til appen din.";
"NSCalendarsUsageDescription" = "Se de planlagte møtene dine i appen.";
"NSContactsUsageDescription" = "For å oppdage kontakter som allerede bruker Matrix, kan Element sende e-postadresser og telefonnummer i adresseboken til den valgte Matrix-identitetsserveren. Der det støttes, hasheres personlige data før sending - vennligst sjekk identitetsserverens personvernregler for mer informasjon.";
"NSMicrophoneUsageDescription" = "Mikrofonen brukes til å ta videoer, ringe.";
"NSPhotoLibraryUsageDescription" = "Fotobiblioteket brukes til å sende bilder og videoer.";
"NSContactsUsageDescription" = "De vil bli delt med din identitets-tjener for hjelpe å finne dine kontakter.";
"NSMicrophoneUsageDescription" = "Appen trenger tilgang til mikrofonen for samtaler, og for å spille inn video og lydmeldinger.";
"NSPhotoLibraryUsageDescription" = "Tillat tilgang til å laste opp bilder og videoer fra fotobiblioteket.";
// Permissions usage explanations
"NSCameraUsageDescription" = "Kameraet brukes til å ta bilder og videoer, ringe videosamtaler.";
"NSCameraUsageDescription" = "Kameraet brukes til videosamtaler, og til å ta og laste opp bilder og videoer.";
"NSLocationAlwaysAndWhenInUseUsageDescription" = "Når du deler din lokasjon men noen trenger appen tilganger til å vise dem et kart.";
"NSLocationWhenInUseUsageDescription" = "Når du deler din lokasjon men noen trenger appen tilganger til å vise dem et kart.";
+26
View File
@@ -26,6 +26,32 @@
</style>
</head>
<body>
<div>
<p>
<b>Version 2.8.0</b>
</p>
<p>
<b>Neue Funktionen</b>
<ul>
<li/>Mit dem neuen Feature Ruhezeiteneinstellung lassen sich Benachrichtigungen nach Wochentag und Uhrzeit ein- bzw stummschalten.
</ul>
</p>
<p>
<b>Verbesserungen</b>
<ul>
<li/>Der Code zur Verschlüsselung von Nachrichten wurde komplett neu geschrieben, was die Performance und Stabilität verbessert.
</ul>
</p>
<p>
<b>Behobene Bugs</b>
<ul>
<li/>Die App informiert jetzt zuverlässiger über bevorstehende Wartungsfenster.
</ul>
</p>
</div>
<div>
<p>
<b>Version 2.7.0</b>
+3
View File
@@ -118,3 +118,6 @@
/* New file message from a specific person, not referencing a room. */
"LOCATION_FROM_USER" = "%@ udostępnił(-a) swoją lokację";
/* New voice broadcast from a specific person, not referencing a room. */
"VOICE_BROADCAST_FROM_USER" = "%@ rozpoczął transmisję głosową";
+347 -73
View File
@@ -1,5 +1,5 @@
// Titles
"title_home" = "Strona startowa";
"title_home" = "Strona główna";
"title_favourites" = "Ulubione";
"title_people" = "Osoby";
"title_rooms" = "Pokoje";
@@ -65,9 +65,9 @@
"auth_username_in_use" = "Nazwa użytkownika jest już używana";
"auth_use_server_options" = "Użyj niestandardowych ustawień serwera (zaawansowane)";
"auth_email_validation_message" = "Sprawdź swój e-mail, aby kontynuować rejestrację";
"auth_msisdn_validation_title" = "Oczekiwanie na weryfikację";
"auth_msisdn_validation_message" = "Wysłaliśmy SMS z kodem aktywacyjnym. Podaj ten kod poniżej.";
"auth_recaptcha_message" = "Ten serwer domowy chciałby się upewnić, że nie jesteś robotem";
"auth_msisdn_validation_title" = "Oczekiwanie weryfikacji";
"auth_msisdn_validation_message" = "Wysłaliśmy SMS-a z kodem aktywacyjnym. Wpisz otrzymany kod poniżej.";
"auth_recaptcha_message" = "Serwer domowy prosi o potwierdzenie, że nie jesteś robotem";
"auth_reset_password_message" = "Aby zresetować swoje hasło, wprowadź adres e-mail powiązany z twoim kontem:";
"auth_reset_password_missing_password" = "Należy wprowadzić nowe hasło.";
"auth_reset_password_next_step_button" = "Zweryfikowałem(-am) swój adres e-mail";
@@ -165,8 +165,8 @@
"room_event_action_more" = "Więcej";
"room_event_action_share" = "Udostępnij";
"room_event_action_permalink" = "Skopiuj link do wiadomości";
"room_event_action_view_source" = "Pokaż źródło";
"room_event_action_view_decrypted_source" = "Pokaż odszyfrowane źródło";
"room_event_action_view_source" = "Wyświetl źródło";
"room_event_action_view_decrypted_source" = "Pokaż rozszyfrowane źródło";
"room_event_action_report" = "Zgłoś zawartość";
"room_event_action_report_prompt_reason" = "Powód zgłoszenia zawartości";
"room_event_action_save" = "Zapisz";
@@ -443,7 +443,7 @@
"widget_integration_failed_to_send_request" = "Nie udało się wysłać żądania.";
"widget_integration_unable_to_create" = "Nie można utworzyć widżetu.";
// Widget Integration Manager
"widget_integration_need_to_be_able_to_invite" = "Aby to zrobić musisz mieć możliwość zapraszania użytkowników.";
"widget_integration_need_to_be_able_to_invite" = "Aby to zrobić, musisz mieć możliwość zapraszania użytkowników.";
"widget_sticker_picker_no_stickerpacks_alert" = "Nie masz obecnie włączonych żadnych pakietów naklejek.";
"widget_sticker_picker_no_stickerpacks_alert_add_now" = "Czy chcesz dodać teraz kilka?";
"widget_creation_failure" = "Utworzenie widżetu nie powiodło się";
@@ -522,7 +522,7 @@
"settings_key_backup_button_delete" = "Usuń kopię zapasową";
"settings_key_backup_delete_confirmation_prompt_title" = "Usuń kopię zapasową";
"auth_login_single_sign_on" = "Zaloguj się";
"auth_autodiscover_invalid_response" = "Nie udało się odnaleźć serwera domowego";
"auth_autodiscover_invalid_response" = "Nieprawidłowa odpowiedź na wykrycie serwera domowego";
"settings_key_backup_button_create" = "Zacznij korzystać z kopii zapasowej kluczy";
"settings_key_backup_button_restore" = "Przywróć z kopii zapasowej";
"room_details_fail_to_update_avatar" = "Nie udało się zaaktualizować zdjęcia pokoju";
@@ -538,7 +538,7 @@
"room_details_fail_to_update_room_communities" = "Nie udało się zaaktualizować powiązanych społeczności";
"room_details_fail_to_update_room_direct" = "Nie udało się zaaktualizować flagi tego pokoju";
"room_details_fail_to_enable_encryption" = "Nie udało się włączyć szyfrowania w tym pokoju";
"group_details_home" = "Strona startowa";
"group_details_home" = "Strona główna";
"key_backup_setup_intro_setup_action_without_existing_backup" = "Zacznij korzystać z Bezpiecznej Kopii Kluczy";
"key_backup_setup_intro_setup_connect_action_with_existing_backup" = "Podłącz tę sesję do Bezpiecznej Kopii Kluczy";
"key_backup_setup_intro_manual_export_info" = "(Zaawansowane)";
@@ -567,10 +567,10 @@
"key_backup_setup_success_from_recovery_key_make_copy_action" = "Zrób kopię";
"key_backup_setup_success_from_recovery_key_made_copy_action" = "Zrobiłem(-am) kopię";
"key_backup_recover_title" = "Bezpieczne wiadomości";
"key_backup_recover_invalid_passphrase_title" = "Nieprawidłowe hasło odzyskiwania";
"key_backup_recover_invalid_passphrase" = "Nie można odszyfrować kopii zapasowej przy użyciu tego hasła: sprawdź, czy zostało wprowadzone prawidłowe hasło odzyskiwania.";
"key_backup_recover_invalid_recovery_key_title" = "Niezgodność klucza odzyskiwania";
"key_backup_recover_invalid_recovery_key" = "Nie można odszyfrować kopii zapasowej za pomocą tego klucza: sprawdź, czy został wprowadzony prawidłowy klucz odzyskiwania.";
"key_backup_recover_invalid_passphrase_title" = "Nieprawidłowe hasło bezpieczeństwa";
"key_backup_recover_invalid_passphrase" = "Kopia zapasowa nie mogła zostać rozszyfrowana za pomocą tego Hasła: upewnij się, że wprowadzono prawidłowe Hasło bezpieczeństwa.";
"key_backup_recover_invalid_recovery_key_title" = "Klucze bezpieczeństwa nie pasują do siebie";
"key_backup_recover_invalid_recovery_key" = "Kopia zapasowa nie mogła zostać rozszyfrowana za pomocą tego Klucza: upewnij się, że wprowadzono prawidłowy Klucz bezpieczeństwa.";
"key_backup_recover_from_passphrase_info" = "Użyj hasło odzyskiwania, aby odszyfrować historyczne wiadomości";
"key_backup_recover_from_passphrase_passphrase_title" = "Wprowadź";
"key_backup_recover_from_passphrase_passphrase_placeholder" = "Wprowadź hasło";
@@ -609,7 +609,7 @@
"device_verification_error_cannot_load_device" = "Nie można załadować informacji dotyczących sesji.";
// Mark: Incoming
"device_verification_incoming_title" = "Przychodząca prośba o weryfikację";
"device_verification_incoming_description_1" = "Zweryfikuj tą sesję, aby oznaczyć ją jako zaufaną. Zaufane sesje dają Twoim rozmówcom dodatkowe poczucie spokoju, podczas konwersacji w pokojach z włączonym szyfrowaniem wiadomości end-to-end.";
"device_verification_incoming_description_1" = "Zweryfikuj tę sesję, aby oznaczyć ją jako zaufaną. Dodawanie sesji parterów do zaufanych, daje większej pewności, gdy korzystasz z wiadomości szyfrowanych end-to-end.";
"device_verification_incoming_description_2" = "Weryfikacja tej sesji spowoduje oznaczenie jej, jako zaufanej. Dodatkowo zostanie ona oznaczona jako zaufana również dla Twojego rozmówcy.";
// MARK: Start
"device_verification_start_title" = "Zweryfikuj, porównując krótki tekst";
@@ -707,7 +707,7 @@
// MARK: Reaction history
"reaction_history_title" = "Reakcje";
"auth_forgot_password_error_no_configured_identity_server" = "Brak skonfigurowanego serwera tożsamości: dodaj serwer tożsamości, aby zresetować hasło.";
"auth_softlogout_signed_out" = "Zostałeś(-aś) wylogowany(-a)";
"auth_softlogout_signed_out" = "Zostałeś wylogowany";
"auth_softlogout_reason" = "Administrator serwera domowego (%1$@) wylogował Cię z Twojego konta %2$@ (%3$@).";
"auth_softlogout_recover_encryption_keys" = "Zaloguj się aby odzyskać klucze szyfrujące zapisane na tym urządzeniu. Potrzebujesz ich aby odczytać wszystkie swoje zaszyfrowane wiadomości na którymkolwiek z Twoich urządzeń.";
"auth_softlogout_clear_data" = "Wyczyść prywatne dane";
@@ -1010,9 +1010,9 @@
// MARK: - Secrets reset
"secrets_reset_title" = "Zresetuj wszystko";
"secrets_setup_recovery_passphrase_summary_information" = "Zapamiętaj swoje hasło odzyskiwania. Możesz go użyć do odszyfrowania zaszyfrowanych wiadomości i danych.";
"secrets_setup_recovery_passphrase_summary_title" = "Zapisz swoje hasło odzyskiwania";
"secrets_reset_title" = "Resetuj wszystko";
"secrets_setup_recovery_passphrase_summary_information" = "Zapamiętaj swoje hasło bezpieczeństwa. Można go użyć do rozszyfrowania wiadomości szyfrowanych i różnych danych.";
"secrets_setup_recovery_passphrase_summary_title" = "Zapisz swoje hasło bezpieczeństwa";
"secrets_setup_recovery_passphrase_confirm_passphrase_placeholder" = "Potwierdź hasło";
"secrets_setup_recovery_passphrase_confirm_passphrase_title" = "Potwierdź";
"secrets_setup_recovery_passphrase_confirm_information" = "Wprowadź ponownie swoje hasło odzyskiwania.";
@@ -1021,19 +1021,19 @@
// Recovery passphrase
"secrets_setup_recovery_passphrase_title" = "Ustaw hasło odzyskiwania";
"secrets_setup_recovery_passphrase_title" = "Ustaw hasło bezpieczeństwa";
"secrets_setup_recovery_key_storage_alert_title" = "Dbaj o bezpieczeństwo";
"secrets_setup_recovery_key_done_action" = "Gotowe";
"secrets_setup_recovery_key_export_action" = "Zapisz";
"secrets_setup_recovery_key_loading" = "Ładowanie…";
"secrets_setup_recovery_key_information" = "Zapisz klucz odzyskiwania i przechowuj go w bezpiecznym miejscu. Będzie Ci on potrzebny, aby uzyskać dostęp do kopii kluczy zaszyfrowanych wiadomości przechowywanych na serwerze.";
"secrets_setup_recovery_key_information" = "Przechowuj swój klucz bezpieczeństwa w bezpiecznym miejscu. Można go użyć do rozszyfrowania wiadomości szyfrowanych i różnych danych.";
// MARK: - Secrets set up
// Recovery Key
"secrets_setup_recovery_key_title" = "Zapisz swój klucz odzyskiwania";
"secrets_recovery_with_key_invalid_recovery_key_title" = "Nie można uzyskać dostępu do kopii bezpieczeństwa";
"secrets_recovery_with_key_invalid_recovery_key_title" = "Nie można uzyskać dostępu do sekretnego magazynu";
"secrets_recovery_with_key_recover_action" = "Użyj klucz odzyskiwania";
"secrets_recovery_with_key_recovery_key_placeholder" = "Wprowadź klucz odzyskiwania";
"secrets_recovery_with_key_recovery_key_title" = "Wprowadź";
@@ -1044,26 +1044,26 @@
"secrets_recovery_with_key_title" = "Klucz odzyskiwania";
"secrets_recovery_with_passphrase_invalid_passphrase_message" = "Sprawdź, czy zostało wprowadzone prawidłowe hasło odzyskiwania.";
"secrets_recovery_with_passphrase_invalid_passphrase_title" = "Nie można uzyskać dostępu do kopii bezpieczeństwa";
"secrets_recovery_with_passphrase_invalid_passphrase_title" = "Nie można uzyskać dostępu do sekretnego magazynu";
"secrets_recovery_with_passphrase_lost_passphrase_action_part3" = ".";
"secrets_recovery_with_passphrase_lost_passphrase_action_part2" = "użyć klucz odzyskiwania";
"secrets_recovery_with_passphrase_lost_passphrase_action_part1" = "Nie znasz swojego hasła odzyskiwania? Możesz ";
"secrets_recovery_with_passphrase_recover_action" = "Użyj hasło odzyskiwania";
"secrets_recovery_with_passphrase_passphrase_placeholder" = "Wprowadź hasło odzyskiwania";
"secrets_recovery_with_passphrase_lost_passphrase_action_part2" = "użyj swojego Klucza bezpieczeństwa";
"secrets_recovery_with_passphrase_lost_passphrase_action_part1" = "Nie znasz swojego hasła bezpieczeństwa? Możesz ";
"secrets_recovery_with_passphrase_recover_action" = "Użyj hasła bezpieczeństwa";
"secrets_recovery_with_passphrase_passphrase_placeholder" = "Wprowadź hasło bezpieczeństwa";
"secrets_recovery_with_passphrase_passphrase_title" = "Wprowadź";
"secrets_recovery_with_passphrase_information_verify_device" = "Użyj hasło odzyskiwania, aby zweryfikować tę sesję.";
"secrets_recovery_with_passphrase_information_default" = "Uzyskaj dostęp do swoich zaszyfrowanych wiadomości i swojej tożsamości umożliwiającej weryfikację innych twoich sesji, wprowadzając swoje hasło odzyskiwania.";
// Recover with passphrase
"secrets_recovery_with_passphrase_title" = "Hasło odzyskiwania";
"secrets_recovery_reset_action_part_2" = "Zresetuj wszystko";
"secrets_recovery_with_passphrase_title" = "Hasło bezpieczeństwa";
"secrets_recovery_reset_action_part_2" = "Resetuj wszystko";
// MARK: - Secrets recovery
"secrets_recovery_reset_action_part_1" = "Zapomniałeś(-aś) lub straciłeś(-aś) wszystkie opcje odzyskiwania? ";
"user_verification_session_details_verify_action_other_user" = "Manualna weryfikacja";
"user_verification_session_details_verify_action_current_user_manually" = "Manualna weryfikacja za pomocą tekstu";
"secrets_recovery_reset_action_part_1" = "Zapomniałeś lub straciłeś wszystkie opcje odzyskiwania? ";
"user_verification_session_details_verify_action_other_user" = "Weryfikuj ręcznie";
"user_verification_session_details_verify_action_current_user_manually" = "Zweryfikuj manualnie za pomocą tekstu";
"user_verification_session_details_verify_action_current_user" = "Interaktywna weryfikacja";
"user_verification_session_details_additional_information_untrusted_current_user" = "Jeśli nie rozpoznajesz tej sesji to może oznaczać, że ktoś inny logował się na Twoje konto.";
"user_verification_session_details_additional_information_untrusted_other_user" = "Dopóki ten użytkownik nie zaufa tej sesji, wiadomości wysyłane do niej i z niej są oznaczane ostrzeżeniami. Alternatywnie możesz ją zweryfikować ręcznie.";
@@ -1123,9 +1123,9 @@
"key_verification_tile_conclusion_done_title" = "Zweryfikowano";
"key_verification_tile_request_incoming_approval_decline" = "Odmów";
"key_verification_tile_request_incoming_approval_accept" = "Zaakceptuj";
"key_verification_tile_request_status_accepted" = "Zaakceptowałeś(-aś)";
"key_verification_tile_request_status_accepted" = "Zaakceptowano";
"key_verification_tile_request_status_cancelled" = "%@ odrzucił(-a)";
"key_verification_tile_request_status_cancelled_by_me" = "Anulowałeś(-aś)";
"key_verification_tile_request_status_cancelled_by_me" = "Anulowałeś";
"key_verification_tile_request_status_expired" = "Wygasło";
"key_verification_tile_request_status_waiting" = "Oczekiwanie…";
"key_verification_tile_request_status_data_loading" = "Ładowanie danych…";
@@ -1147,20 +1147,20 @@
// User
"key_verification_verified_user_information" = "Wiadomości wysyłane do tego użytkownika są szyfrowane metodą end-to-end i nie mogą być odczytywane przez osoby trzecie.";
"key_verification_verified_user_information" = "Wiadomości z tym użytkownikiem są szyfrowane end-to-end i nie mogą zostać odczytane przez osoby trzecie.";
"key_verification_verified_this_session_information" = "Uzyskałeś(-aś) dostęp do zaszyfrowanych wiadomości w tej sesji. Dodatkowo użytkownicy będą ufać tej sesji.";
"key_verification_verified_new_session_information" = "Uzyskałeś(-aś) dostęp do zaszyfrowanych wiadomości w nowej sesji. Dodatkowo użytkownicy będą ufać tej sesji.";
"key_verification_verified_other_session_information" = "Uzyskałeś(-aś) dostęp do zaszyfrowanych wiadomości w swojej drugiej sesji. Dodatkowo użytkownicy będą ufać tej sesji.";
"key_verification_verified_new_session_title" = "Nowa sesja zweryfikowana!";
"key_verification_manually_verify_device_validate_action" = "Zweryfikuj";
"key_verification_manually_verify_device_additional_information" = "Jeżeli te dane się nie zgadzają to może oznaczać, że bezpieczeństwo komunikacji mogło zostać skompromitowane.";
"key_verification_manually_verify_device_additional_information" = "Jeśli nie pasują, bezpieczeństwo twojego konta mogło zostać zdradzone.";
"key_verification_manually_verify_device_key_title" = "Klucz sesji";
"key_verification_manually_verify_device_id_title" = "Identyfikator sesji";
"key_verification_manually_verify_device_name_title" = "Nazwa sesji";
// MARK: Manually Verify Device
"key_verification_manually_verify_device_title" = "Manualna weryfikacja za pomocą tekstu";
"key_verification_manually_verify_device_title" = "Zweryfikuj ręcznie za pomocą tekstu";
"key_verification_verify_sas_additional_information" = "Aby zapewnić maksymalne bezpieczeństwo, użyj innego zaufanego środka komunikacji lub zrób to osobiście.";
"key_verification_verify_sas_validate_action" = "Pasują";
"key_verification_verify_sas_cancel_action" = "Nie pasują";
@@ -1206,10 +1206,10 @@
"device_verification_security_advice_emoji" = "Porównaj unikalne emotikony, upewniając się, że pojawiają się w tej samej kolejności.";
"key_verification_user_title" = "Weryfikacja";
"key_verification_this_session_title" = "Weryfikacja bieżącej sesji";
"key_verification_new_session_title" = "Weryfikacja nowej sesji";
"key_verification_new_session_title" = "Weryfikuj nową sesję";
// MARK: - Device Verification
"key_verification_other_session_title" = "Weryfikacja istniejącej sesji";
"key_verification_other_session_title" = "Weryfikuj sesję";
"sign_out_non_existing_key_backup_alert_setup_secure_backup_action" = "Zacznij korzystać z bezpiecznej kopii zapasowej";
// Recover from private key
@@ -1229,7 +1229,7 @@
"secure_key_backup_setup_existing_backup_error_unlock_it" = "Odblokuj starą kopię";
"secure_key_backup_setup_existing_backup_error_info" = "Odblokuj ją, aby ponownie użyć jej w bezpiecznej kopii zapasowej lub usuń, aby utworzyć nową kopię zapasową wiadomości w bezpiecznej kopii zapasowej.";
"secure_key_backup_setup_existing_backup_error_title" = "Kopia zapasowa wiadomości już istnieje";
"secure_key_backup_setup_intro_use_security_passphrase_title" = "Ustaw hasło odzyskiwania";
"secure_key_backup_setup_intro_use_security_passphrase_title" = "Użyj hasła bezpieczeństwa";
"secure_key_backup_setup_intro_use_security_key_info" = "Wygeneruj klucz odzyskiwania. Następnie zdeponuj go w bezpiecznym miejscu.";
"secure_key_backup_setup_intro_use_security_key_title" = "Ustaw klucz odzyskiwania";
"secure_key_backup_setup_intro_info" = "Zabezpiecz się przed utratą dostępu do zaszyfrowanych wiadomości wykonując kopię zapasową kluczy szyfrowania na Twoim serwerze domowym.";
@@ -1269,7 +1269,7 @@
"bug_report_background_mode" = "Kontynuuj w tle";
"call_actions_unhold" = "Wznów połączenie";
"call_no_stun_server_error_use_fallback_button" = "Spróbuj użyć %@";
"call_no_stun_server_error_message_2" = "Alternatywnie możesz spróbować użyć serwera publicznego pod adresem %@, ale nie będzie to tak niezawodne i będzie udostępni Twój adres IP temu serwerowi. Możesz również zarządzać tym w Ustawieniach";
"call_no_stun_server_error_message_2" = "Alternatywnie możesz spróbować użyć serwera publicznego %@, ale mogą wystąpić problemy i zostanie udostępniony Twój adres IP z serwerem. Zarządzaj tym również w Ustawieniach";
"call_no_stun_server_error_message_1" = "Poproś administratora swojego serwera domowego %@ o skonfigurowanie serwera TURN, aby połączenia działały niezawodnie.";
"call_no_stun_server_error_title" = "Połączenie nie powiodło się z powodu błędnej konfiguracji serwera";
@@ -1292,7 +1292,7 @@
"room_details_access_section_anyone_for_dm" = "Każdy kto zna link pokoju, razem z gośćmi";
"room_details_access_section_anyone_apart_from_guest_for_dm" = "Każdy kto zna link pokoju, poza gośćmi";
"room_details_access_section_for_dm" = "Kto może dołączyć do pokoju?";
"room_details_room_name_for_dm" = "Nazwa Pokoju";
"room_details_room_name_for_dm" = "Nazwa";
"room_details_photo_for_dm" = "Obraz pokoju";
"room_details_integrations" = "Integracje";
"room_details_search" = "Wyszukaj w pokoju";
@@ -1301,10 +1301,10 @@
"identity_server_settings_alert_error_terms_not_accepted" = "Musisz zaakceptować warunki %@, aby ustawić go jako serwer tożsamości.";
"identity_server_settings_alert_disconnect_still_sharing_3pid_button" = "Odłącz mimo wszystko";
"identity_server_settings_alert_disconnect_still_sharing_3pid" = "Nadal udostępniasz swoje dane personalne na serwerze tożsamości %@. \n\nZalecamy usunięcie adresów e-mail i numerów telefonów z serwera tożsamości przed rozłączeniem.";
"identity_server_settings_alert_disconnect_button" = "Odłącz";
"identity_server_settings_alert_disconnect" = "Odłączyć się od serwera tożsamości %@?";
"identity_server_settings_alert_disconnect_title" = "Odłącz serwer tożsamości";
"identity_server_settings_alert_change" = "Odłączyć się od serwera tożsamości %1$@ i zamiast tego połączyć się z %2$@?";
"identity_server_settings_alert_disconnect_button" = "Rozłącz";
"identity_server_settings_alert_disconnect" = "Rozłączyć się z serwerem tożsamości %@?";
"identity_server_settings_alert_disconnect_title" = "Rozłącz serwer tożsamości";
"identity_server_settings_alert_change" = "Rozłączyć się z bieżącym serwerem tożsamości %1$@ i połączyć się z %2$@?";
"identity_server_settings_alert_change_title" = "Zmień serwer tożsamości";
"identity_server_settings_alert_no_terms" = "Wybrany serwer tożsamości nie ma żadnych warunków korzystania z usługi. Kontynuuj tylko wtedy, gdy ufasz właścicielowi serwera.";
"identity_server_settings_alert_no_terms_title" = "Serwer tożsamości nie ma warunków świadczenia usług";
@@ -1348,7 +1348,7 @@
"security_settings_crypto_sessions_description_2" = "Jeśli nie rozpoznajesz którejś z sesji to zmień hasło i zresetuj bezpieczną kopię zapasową.";
"settings_show_NSFW_public_rooms" = "Pokaż publiczne pokoje NSFW";
"secrets_setup_recovery_key_storage_alert_message" = "✓ Wydrukuj klucz i przechowuj go w bezpiecznym miejscu\n✓ Zapisz klucz na pendrive lub dysku zapasowym\n✓ Skopiuj klucz na prywatnym dysku w chmurze";
"user_verification_sessions_list_information" = "Konwersacja z tym użytkownikiem w tym pokoju jest szyfrowana end-to-end i nie może być odczytana przez osoby trzecie.";
"user_verification_sessions_list_information" = "Wiadomości z tym użytkownikiem szyfrowane end-to-end i nie mogą zostać odczytane przez osoby trzecie.";
"service_terms_modal_description_for_identity_server_2" = "Daj się znaleźć na podstawie numeru telefonu lub adresu e-mail";
"secrets_setup_recovery_passphrase_information" = "Wprowadź unikalne hasło odzyskiwania. Będzie ono używane do zabezpieczenia Twojej kopii kluczy przechowywanej na serwerze.";
"secrets_recovery_with_key_invalid_recovery_key_message" = "Sprawdź, czy wprowadziłeś(-aś) poprawny klucz odzyskiwania.";
@@ -1448,7 +1448,7 @@
"voice_message_release_to_send" = "Przytrzymaj, aby nagrać, zwolnij, aby wysłać";
"side_menu_app_version" = "Wersja %@";
"side_menu_action_feedback" = "Feedback";
"side_menu_action_feedback" = "Opinia użytkownika";
"side_menu_action_help" = "Pomoc";
"side_menu_action_settings" = "Ustawienia";
"side_menu_action_invite_friends" = "Zaproś przyjaciół";
@@ -1998,7 +1998,7 @@
// Room members
"room_member_ignore_prompt" = "Czy na pewno chcesz ukryć wszystkie wiadomości od tego użytkownika?";
"message_reply_to_message_to_reply_to_prefix" = "W odpowiedzi na";
"message_reply_to_message_to_reply_to_prefix" = "W odpowiedzi do";
"message_reply_to_sender_sent_a_file" = "wysłał(-a) plik.";
"message_reply_to_sender_sent_a_video" = "wysłał(-a) plik wideo.";
"message_reply_to_sender_sent_an_audio_file" = "wysłał(-a) plik audio.";
@@ -2038,10 +2038,10 @@
"account_error_display_name_change_failed" = "Zmiana wyświetlanej nazwy nie powiodła się";
"account_msisdn_validation_error" = "Nie można zweryfikować numeru telefonu.";
"account_msisdn_validation_message" = "Wysłaliśmy SMS-a z kodem aktywacyjnym. Wpisz otrzymany kod poniżej.";
"account_msisdn_validation_title" = "Oczekiwanie na weryfikację";
"account_msisdn_validation_title" = "Oczekiwanie weryfikacji";
"account_email_validation_error" = "Nie można zweryfikować adresu e-mail. Sprawdź swoją skrzynkę e-mail i kliknij zawarte w niej łącze. Gdy to zrobisz, kliknij kontynuuj";
"account_email_validation_message" = "Sprawdź swoją skrzynkę e-mail i kliknij zawarte w niej łącze. Gdy to zrobisz, kliknij kontynuuj.";
"account_email_validation_title" = "Oczekiwanie na weryfikację";
"account_email_validation_title" = "Oczekiwanie weryfikacji";
"account_linked_emails" = "Połączone adresy e-mail";
"account_link_email" = "Połącz adres e-mail";
@@ -2133,10 +2133,10 @@
"poll_timeline_not_closed_subtitle" = "Proszę spróbuj ponownie";
"poll_timeline_not_closed_title" = "Nie udało się zakończyć ankiety";
"poll_timeline_vote_not_registered_subtitle" = "Przepraszamy, Twój głos nie został zarejestrowany, spróbuj ponownie";
"poll_timeline_vote_not_registered_title" = "Głos niezarejestrowany";
"poll_timeline_vote_not_registered_title" = "Głos nie został zarejestrowany";
"poll_timeline_total_final_results" = "Ostateczne wyniki na podstawie %lu głosów";
"poll_timeline_total_final_results_one_vote" = "Wyniki końcowe na podstawie 1 głosu";
"poll_timeline_total_votes_not_voted" = "%lu oddane/ych głosy/ów. Zagłosuj, aby zobaczyć wyniki";
"poll_timeline_total_votes_not_voted" = "Oddano %lu głosów. Zagłosuj, aby zobaczyć wyniki";
"poll_timeline_total_one_vote_not_voted" = "1 oddany głos. Zagłosuj, aby zobaczyć wyniki";
"poll_timeline_total_votes" = "%lu głosy/ów";
"poll_timeline_total_one_vote" = "1 głos";
@@ -2169,11 +2169,11 @@
// Mark: Avatar
"space_avatar_view_accessibility_label" = "avatar";
"space_avatar_view_accessibility_label" = "awatar";
// MARK: Reactions
"room_event_action_reaction_more" = "%@ jeszcze";
"room_event_action_reaction_more" = "%@ więcej";
"leave_space_selection_no_rooms" = "Nie zaznaczaj pokoi";
"leave_space_selection_all_rooms" = "Wybierz wszystkie pokoje";
"leave_space_selection_title" = "WYBIERZ POKOJE";
@@ -2196,7 +2196,7 @@
"spaces_creation_post_process_creating_space_task" = "Tworzę %@";
"spaces_creation_post_process_creating_space" = "Tworzenie przestrzeni";
"spaces_creation_invite_by_username_message" = "Możesz ich też zaprosić później.";
"spaces_creation_invite_by_username" = "Zaproś według nazwy użytkownika";
"spaces_creation_invite_by_username" = "Zaproś przez nazwę użytkownika";
"spaces_creation_add_rooms_message" = "Ponieważ ta przestrzeń jest tylko dla Ciebie, nikt nie zostanie o tym poinformowany. Możesz dodać więcej później.";
"spaces_creation_add_rooms_title" = "Co chcesz dodać?";
"spaces_creation_sharing_type_me_and_teammates_detail" = "Prywatna przestrzeń dla Ciebie i Twoich kolegów z drużyny";
@@ -2208,11 +2208,11 @@
"spaces_creation_email_invites_email_title" = "Email";
"spaces_creation_email_invites_message" = "Możesz ich też zaprosić później.";
"spaces_creation_email_invites_title" = "Zaproś swój zespół";
"spaces_creation_new_rooms_support" = "Wspierać się";
"spaces_creation_new_rooms_random" = "Losowy";
"spaces_creation_new_rooms_support" = "Wsparcie";
"spaces_creation_new_rooms_random" = "Losowe";
"spaces_creation_new_rooms_general" = "Ogólny";
"spaces_creation_new_rooms_room_name_title" = "Nazwa pokoju";
"spaces_creation_new_rooms_message" = "Dla każdego stworzymy pokój.";
"spaces_creation_new_rooms_message" = "Utworzymy pokój dla każdego z nich.";
"spaces_creation_new_rooms_title" = "Jakie dyskusje będziesz mieć?";
"spaces_creation_cancel_message" = "Twoje postępy zostaną utracone.";
"spaces_creation_cancel_title" = "Przestać tworzyć przestrzeń?";
@@ -2237,15 +2237,15 @@
"space_settings_access_section" = "Kto ma dostęp do tej przestrzeni?";
"space_topic" = "Opis";
"space_public_join_rule_detail" = "Otwarty dla każdego, najlepszy dla społeczności";
"spaces_add_space" = "Dodaj miejsce";
"spaces_add_space" = "Dodaj przestrzeń";
"spaces_add_room" = "Dodaj pokój";
"spaces_invite_people" = "Zaproś ludzi";
"space_public_join_rule" = "Miejsce publiczne";
"space_public_join_rule" = "Przestrzeń publiczna";
"space_private_join_rule_detail" = "Tylko zapraszaj, najlepiej dla siebie lub zespołów";
"space_private_join_rule" = "Prywatna przestrzeń";
"space_private_join_rule" = "Przestrzeń prywatna";
"space_home_show_all_rooms" = "Pokaż wszystkie pokoje";
"space_participants_action_ban" = "Zakaz z tej przestrzeni";
"space_participants_action_remove" = "Usuń z tego miejsca";
"space_participants_action_ban" = "Zbanuj z tej przestrzeni";
"space_participants_action_remove" = "Usuń z tej przestrzeni";
"spaces_coming_soon_detail" = "Ta funkcja nie została tutaj zaimplementowana, ale jest w drodze. Na razie możesz to zrobić za pomocą %@ na swoim komputerze.";
"spaces_invites_coming_soon_title" = "Zaproszenia już wkrótce";
"spaces_add_rooms_coming_soon_title" = "Wkrótce dodam pokoje";
@@ -2302,11 +2302,11 @@
"create_room_suggest_room" = "Zaproponuj członkom przestrzeni";
"create_room_show_in_directory_footer" = "Pomoże to ludziom znaleźć i dołączyć do pokoju.";
"create_room_promotion_header" = "AWANS";
"create_room_section_footer_type_public" = "Tylko zaproszone osoby mogą znajdować i dołączać, a nie tylko osoby o nazwie Space.";
"create_room_section_footer_type_public" = "Tylko zaproszone osoby mogą Cię znaleźć i dołączyć, a nie tylko osoby w tej samej przestrzeni.";
"create_room_section_footer_type_restricted" = "Każda osoba w Przestrzeni może wyszukiwać i dołączać.";
"create_room_section_footer_type_private" = "Tylko zaproszone osoby mogą znaleźć i dołączyć do tego pokoju.";
"create_room_type_restricted" = "Członkowie przestrzeni";
"key_verification_manually_verify_device_instruction" = "Potwierdź zgodność poniższych informacji porównując następujące elementy z ustawieniami użytkownika w drugiej sesji:";
"key_verification_manually_verify_device_instruction" = "Potwierdź porównując następujące elementy w ustawieniach użytkownika w drugiej sesji:";
"service_terms_modal_information_description_integration_manager" = "Menedżer integracji umożliwia dodawanie funkcji od stron trzecich.";
"service_terms_modal_information_description_identity_server" = "Serwer tożsamości pomaga znaleźć kontakty, wyszukując ich numer telefonu lub adres e-mail, aby sprawdzić, czy mają już konto.";
"service_terms_modal_information_title_integration_manager" = "Menedżer integracji";
@@ -2315,7 +2315,7 @@
"service_terms_modal_information_title_identity_server" = "Serwer Tożsamości";
"service_terms_modal_description_integration_manager" = "Umożliwi to korzystanie z botów, mostów, widżetów i pakietów naklejek.";
"service_terms_modal_description_identity_server" = "Umożliwi to komuś znalezienie Cię, jeśli ma Twój numer telefonu lub adres e-mail zapisany w swoich kontaktach telefonicznych.";
"analytics_prompt_message_new_user" = "Pomóż nam zidentyfikować problemy i ulepszyć %@, udostępniając anonimowe dane o użytkowaniu. Aby zrozumieć, w jaki sposób ludzie korzystają z wielu urządzeń, wygenerujemy losowy identyfikator udostępniany przez Twoje urządzenia.";
"analytics_prompt_message_new_user" = "Pomóż nam zidentyfikować problemy i ulepszyć %@, udostępniając anonimowe dane o użytkowaniu. Aby zrozumieć, w jaki sposób użytkownicy korzystają z wielu urządzeń, wygenerujemy losowy identyfikator dzielony pomiędzy Twoimi urządzeniami.";
"network_offline_message" = "Jesteś offline, sprawdź swoje połączenie.";
"network_offline_title" = "Jesteś offline";
"event_formatter_message_deleted" = "Wiadomość usunięta";
@@ -2375,7 +2375,7 @@
"threads_empty_show_all_threads" = "Pokaż wszystkie wątki";
"threads_empty_tip" = "Wskazówka: dotknij wiadomości i użyj „Nowy wątek”, aby go utworzyć.";
"threads_empty_info_my" = "Odpowiedz w danym wątku lub dotknij wiadomości i użyj „Nowy wątek”, aby go rozpocząć.";
"threads_empty_info_all" = "Wątki umożliwiają łatwiejsze wyszukiwanie i agregowanie wiadomości dotyczących danego tematu.";
"threads_empty_info_all" = "Dzięki wątkom Twoje rozmowy są zorganizowane i łatwe do śledzenia.";
"threads_empty_title" = "Organizuj dyskusje za pomocą wątków";
"threads_action_my_threads" = "Moje wątki";
"threads_action_all_threads" = "Wszystkie wątki";
@@ -2390,7 +2390,7 @@
"room_accessibility_threads" = "Wątki";
"room_event_copy_link_info" = "Link skopiowany do schowka.";
"room_event_action_reply_in_thread" = "Wątek";
"room_event_action_view_in_room" = "Zobacz w pokoju";
"room_event_action_view_in_room" = "Wyświetl w pokoju";
"room_participants_invite_prompt_to_msg" = "Czy na pewno chcesz zaprosić %@ do %@?";
"room_participants_leave_success" = "Opuszczono pokój";
"room_participants_leave_processing" = "Opuszczanie";
@@ -2424,7 +2424,7 @@
"authentication_verify_msisdn_text_field_placeholder" = "Numer telefonu";
"authentication_verify_msisdn_input_message" = "%@ musi zweryfikować Twoje konto";
"authentication_verify_msisdn_input_title" = "Wprowadź swój numer telefonu";
"authentication_choose_password_submit_button" = "Zresetuj hasło";
"authentication_choose_password_submit_button" = "Resetuj hasło";
"authentication_choose_password_signout_all_devices" = "Wyloguj się ze wszystkich urządzeń";
"authentication_choose_password_text_field_placeholder" = "Nowe Hasło";
"authentication_choose_password_input_message" = "Upewnij się, że ma 8 znaków lub więcej";
@@ -2497,7 +2497,7 @@
"onboarding_splash_page_3_title" = "Bezpieczne przesyłanie wiadomości.";
"onboarding_splash_page_2_message" = "Wybierz, gdzie chcesz przechowywać swoje rozmowy. Połączenie ustanowione poprzez Matrix.";
"onboarding_splash_page_2_title" = "Masz kontrolę.";
"onboarding_splash_page_1_title" = "Zarządzaj swoimi rozmowami.";
"onboarding_splash_page_1_title" = "Bądź właścicielem swoich konwersacji.";
"saving" = "Zapisywanie";
// Activities
@@ -2510,10 +2510,10 @@
"new_word" = "Nowy";
"stop" = "Stop";
"joining" = "Dołączanie";
"location_sharing_invalid_power_level_message" = "Aby udostępniać lokalizację na żywo w tym pokoju, musisz mieć odpowiednie uprawnienia.";
"location_sharing_invalid_power_level_message" = "Musisz mieć odpowiednie uprawnienia, aby udostępniać lokalizację na żywo w tym pokoju.";
"location_sharing_invalid_power_level_title" = "Nie masz uprawnień do udostępniania lokalizacji na żywo";
"authentication_choose_password_not_verified_message" = "Sprawdź swoją skrzynkę odbiorczą";
"authentication_choose_password_not_verified_title" = "E-mail niezweryfikowany";
"authentication_choose_password_not_verified_title" = "E-mail nie został zweryfikowany";
"authentication_server_info_title_login" = "Miejsce twoich konwersacji";
// MARK: User sessions management
@@ -2539,7 +2539,7 @@
"room_recents_recently_viewed_section" = "Ostatnio wyświetlane";
"all_chats_nothing_found_placeholder_message" = "Spróbuj poprawić swoje wyszukiwanie.";
"all_chats_nothing_found_placeholder_title" = "Nic nie znaleziono.";
"all_chats_empty_unreads_placeholder_message" = "W tym miejscu pojawią się nieprzeczytane wiadomości, gdy będziesz takie mieć.";
"all_chats_empty_unreads_placeholder_message" = "W tym miejscu pojawią się nieprzeczytane wiadomości, jeśli jakieś dostaniesz.";
"all_chats_empty_list_placeholder_title" = "Jesteś na bieżąco.";
"all_chats_empty_view_information" = "Bezpieczny, wielofunkcyjny komunikator dla zespołów, znajomych i organizacji. Utwórz rozmowę, lub dołącz do istniejącego pokoju, aby rozpocząć.";
"all_chats_empty_space_information" = "Przestrzenie to nowy sposób na grupowanie pokojów i osób. Dodaj istniejący pokój, lub utwórz nowy, korzystając z przycisku w prawym dolnym rogu.";
@@ -2577,3 +2577,277 @@
"authentication_qr_login_start_title" = "Zeskanuj kod QR";
"authentication_login_with_qr" = "Zaloguj się za pomocą kodu QR";
"accessibility_selected" = "wybrane";
"authentication_qr_login_start_step2" = "Przejdź do Ustawień -> Bezpieczeństwo i prywatność";
"user_other_session_verified_sessions_header_subtitle" = "Dla najlepszego bezpieczeństwa, wyloguj się ze wszystkich sesji, których nie rozpoznajesz lub nie używasz.";
"user_sessions_overview_other_sessions_section_info" = "Dla najlepszego bezpieczeństwa, zweryfikuj swoje sesje i wyloguj się ze wszystkich sesji, których nie rozpoznajesz lub nie używasz.";
"poll_history_no_past_poll_period_text" = "Nie znaleziono przeszłych ankiet w ostatnich %@ dniach. Wczytaj więcej ankiet, aby wyświetlić ankiety z poprzednich miesięcy";
"poll_history_no_active_poll_period_text" = "Nie znaleziono aktywnych ankiet w ostatnich %@ dniach. Wczytaj więcej ankiet, aby wyświetlić ankiety z poprzednich miesięcy";
/* The placeholder will be replaces with manage_session_name_info_link */
"manage_session_name_info" = "Bądź świadom, że nazwy sesji są również widoczne dla ludzi, z którymi się komunikujesz. %@";
"settings_acceptable_use" = "Akceptowalna polityka użytkowania";
// First item is client name and second item is session display name
"user_session_name" = "%@: %@";
/* %1$@ will be the verification state and %2$@ will be user_session_item_details_verification_unknown or user_other_session_current_session_details */
"user_session_item_details" = "%1$@ · %2$@";
"device_name_web" = "%@ Web";
"device_name_mobile" = "%@ Mobile";
"device_type_name_web" = "Web";
"device_type_name_desktop" = "Desktop";
"device_type_name_mobile" = "Mobile";
"room_waiting_other_participants_message" = "Jak tylko zaproszeni użytkownicy dołączą do %@, będziesz mógł czatować w pokoju szyfrowanym end-to-end";
"room_waiting_other_participants_title" = "Czekanie na użytkowników %@";
"all_chats_user_menu_accessibility_label" = "Menu użytkownika";
"voice_broadcast_playback_unable_to_decrypt" = "Nie można rozszyfrować tej transmisji głosowej.";
"voice_broadcast_recorder_connection_error" = "Błąd połączenia - Nagrywanie wstrzymane";
"voice_broadcast_connection_error_message" = "Niestety, nie jesteśmy w stanie rozpocząć nowego nagrania. Spróbuj ponownie później.";
"voice_broadcast_playback_loading_error" = "Nie można odtworzyć tej transmisji głosowej.";
"voice_broadcast_already_in_progress_message" = "Już nagrywasz transmisję głosową. Zakończ bieżącą transmisję głosową, aby rozpocząć nową.";
"voice_broadcast_blocked_by_someone_else_message" = "Ktoś już nagrywa transmisję głosową. Aby rozpocząć nową, poczekaj aż bieżąca się skończy.";
"key_verification_scan_qr_code_information_other_user" = "Ustaw kamerę na kod QR wyświetlony na ich urządzeniu, aby zweryfikować ich sesję";
"key_verification_scan_qr_code_information_other_device" = "Ustaw kamerę na kod QR wyświetlony na swoim drugim urządzeniu, aby zweryfikować tę sesję";
"key_verification_scan_qr_code_information_other_session" = "Ustaw kamerę na kod QR wyświetlony na swoim drugim urządzeniu, aby zweryfikować swoją sesję";
"key_verification_scan_qr_code_information_new_session" = "Ustaw kamerę na kod QR wyświetlony na swoim drugim urządzeniu, aby zweryfikować swoją nową sesję";
"device_verification_self_verify_wait_recover_secrets_additional_help" = "Nie możesz dostać się do istniejącej %@ sesji?";
"poll_timeline_decryption_error" = "Ze względu na błędy rozszyfrowywania, niektóre głosy mogły nie zostać policzone";
"user_sessions_overview_security_recommendations_section_info" = "Zwiększ bezpieczeństwo swojego konta kierując się tymi rekomendacjami.";
"user_other_session_current_session_details" = "Twoja bieżąca sesja";
"user_other_session_security_recommendation_title" = "Inne sesje";
"user_session_rename_session_title" = "Zmienianie nazwy sesji";
"user_session_inactive_session_title" = "Sesje nieaktywne";
"user_session_unverified_session_title" = "Sesja niezweryfikowana";
"user_session_verified_session_title" = "Sesje zweryfikowane";
"user_session_got_it" = "Rozumiem";
"user_session_push_notifications_message" = "Po włączeniu, ta sesja zacznie otrzymywać powiadomienia push.";
"user_session_push_notifications" = "Powiadomienia push";
"user_other_session_verified_additional_info" = "Sesja jest gotowa do wysyłania bezpiecznych wiadomości.";
"user_other_session_permanently_unverified_additional_info" = "Ta sesja nie wspiera szyfrowania, dlatego nie może zostać zweryfikowana.";
"user_other_session_unverified_additional_info" = "Zweryfikuj lub wyloguj się z tej sesji dla zapewnienia najlepszego bezpieczeństwa.";
"user_session_verification_unknown_additional_info" = "Zweryfikuj swoją bieżącą sesję, aby odsłonić status weryfikacji tej sesji.";
"user_session_unverified_additional_info" = "Zweryfikuj swoją bieżącą sesję dla wzmocnienia bezpiecznych wiadomości.";
"user_session_verified_additional_info" = "Twoja bieżąca sesja jest gotowa do wysyłania bezpiecznych wiadomości.";
"user_session_learn_more" = "Dowiedz się więcej";
"user_session_view_details" = "Wyświetl szczegóły";
"user_session_verify_action" = "Zweryfikuj sesję";
"user_session_verification_unknown_short" = "Nieznana";
"user_session_unverified_short" = "Niezweryfikowano";
"user_session_verified_short" = "Zweryfikowano";
"user_session_verification_unknown" = "Nieznany status weryfikacji";
"user_session_unverified" = "Sesja niezweryfikowana";
"user_session_verified" = "Sesja zweryfikowana";
"user_sessions_view_all_action" = "Wyświetl wszystko (%d)";
"user_sessions_overview_link_device" = "Powiąż urządzenie";
"user_sessions_overview_current_session_section_title" = "Bieżąca sesja";
"user_sessions_hide_location_info" = "Ukryj adres IP";
"user_sessions_show_location_info" = "Pokaż adres IP";
"user_sessions_overview_security_recommendations_inactive_info" = "Rozważ wylogowanie się ze starych sesji (90 dni lub starsze), jeśli już z nich nie korzystasz.";
"user_sessions_overview_other_sessions_section_title" = "Inne sesje";
"user_sessions_overview_security_recommendations_inactive_title" = "Sesje nieaktywne";
"user_sessions_overview_security_recommendations_unverified_info" = "Zweryfikuj lub wyloguj się z niezweryfikowanych sesji.";
"user_sessions_overview_security_recommendations_unverified_title" = "Sesje niezweryfikowane";
"user_sessions_overview_security_recommendations_section_title" = "Rekomendacje bezpieczeństwa";
// MARK: User sessions management
// Parameter is the application display name (e.g. "Element")
"user_sessions_default_session_display_name" = "%@ iOS";
"poll_timeline_loading" = "Wczytywanie...";
"poll_timeline_reply_ended_poll" = "Zakończył ankietę";
"poll_timeline_ended_text" = "Zakończył ankietę";
"poll_history_fetching_error" = "Błąd podczas pobierania ankiet.";
"poll_history_load_more" = "Wczytaj więcej ankiet";
"poll_history_detail_view_in_timeline" = "Wyświetl ankietę na osi czasu";
"poll_history_no_past_poll_text" = "Brak przeszłych ankiet w tym pokoju";
"poll_history_no_active_poll_text" = "Brak aktywnych ankiet w tym pokoju";
"poll_history_past_segment_title" = "Przeszłe ankiety";
"poll_history_active_segment_title" = "Aktywne ankiety";
"poll_history_loading_text" = "Wyświetlanie ankiet";
// MARK: - Polls history
"poll_history_title" = "Historia ankiet";
"user_other_session_filter" = "Filtr";
"user_other_session_no_unverified_sessions" = "Nie znaleziono niezweryfikowanych sesji.";
"pill_message_in" = "Wiadomość w %@";
"pill_message_from" = "Wiadomość od %@";
"pill_message" = "Wiadomość";
// Pills
"pill_room_fallback_display_name" = "Przestrzeń/Pokój";
"notice_display_name_changed_to" = "%@ zmienił swoją wyświetlaną nazwę %@";
"room_event_encryption_info_key_authenticity_not_guaranteed" = "Autentyczność tej wiadomości szyfrowanej nie jest gwarantowana na tym urządzeniu.";
"notice_voice_broadcast_ended_by_you" = "Zakończyłeś transmisje na żywo.";
"notice_voice_broadcast_ended" = "%@ zakończył transmisje na żywo.";
"notice_voice_broadcast_live" = "Transmisja na żywo";
"deselect_all" = "Odznacz wszystko";
"wysiwyg_composer_link_action_edit_title" = "Edytuj link";
"wysiwyg_composer_link_action_create_title" = "Utwórz link";
"wysiwyg_composer_link_action_link" = "Link";
// Links
"wysiwyg_composer_link_action_text" = "Tekst";
"wysiwyg_composer_format_action_un_indent" = "Zmniejsz wcięcie";
"wysiwyg_composer_format_action_indent" = "Zwiększ wcięcie";
"wysiwyg_composer_format_action_quote" = "Przełącz cytat";
"wysiwyg_composer_format_action_code_block" = "Przełącz blok kodu";
"wysiwyg_composer_format_action_ordered_list" = "Przełącz listę numerowaną";
"wysiwyg_composer_format_action_unordered_list" = "Przełącz listę punktorów";
"wysiwyg_composer_format_action_inline_code" = "Zastosuj kod w tekście";
"wysiwyg_composer_format_action_link" = "Zastosuj link";
"wysiwyg_composer_format_action_strikethrough" = "Zastosuj podkreślenie";
"wysiwyg_composer_format_action_underline" = "Zastosuj przekreślenie";
"wysiwyg_composer_format_action_italic" = "Zastosuj kursywę";
// Formatting Actions
"wysiwyg_composer_format_action_bold" = "Zastosuj pogrubienie";
"wysiwyg_composer_start_action_voice_broadcast" = "Transmisja głosowa";
"wysiwyg_composer_start_action_text_formatting" = "Formatowanie tekstu";
"wysiwyg_composer_start_action_camera" = "Kamera";
"wysiwyg_composer_start_action_location" = "Lokalizacja";
"wysiwyg_composer_start_action_polls" = "Ankiety";
"wysiwyg_composer_start_action_attachments" = "Załączniki";
"wysiwyg_composer_start_action_stickers" = "Naklejki";
// MARK: - WYSIWYG Composer
// Send Media Actions
"wysiwyg_composer_start_action_media_picker" = "Biblioteka zdjęć";
"user_session_overview_session_details_button_title" = "Szczegóły sesji";
"user_session_overview_session_title" = "Sesja";
"user_session_overview_current_session_title" = "Bieżąca sesja";
"user_session_details_application_url" = "URL";
"user_session_details_application_version" = "Wersja";
"user_session_details_application_name" = "Nazwa";
"user_session_details_device_os" = "System operacyjny";
"user_session_details_device_browser" = "Przeglądarka";
"user_session_details_device_model" = "Model";
"user_session_details_device_ip_location" = "Lokalizacja IP";
"user_session_details_device_ip_address" = "Adres IP";
"user_session_details_last_activity" = "Ostatnia aktywność";
"user_session_details_session_id" = "ID sesji";
"user_session_details_session_name" = "Nazwa sesji";
"user_session_details_device_section_header" = "Urządzenie";
"user_session_details_application_section_header" = "Aplikacja";
"user_session_details_session_section_header" = "Sesja";
"user_session_details_title" = "Szczegóły sesji";
"device_type_name_unknown" = "Nieznany";
"device_name_unknown" = "Nieznany klient";
"device_name_desktop" = "%@ Desktop";
"user_inactive_session_item_with_date" = "Nieaktywny przez 90+ dni (%@)";
"user_inactive_session_item" = "Nieaktywny przez 90+ dni";
"user_session_item_details_last_activity" = "Ostatnia aktywność %@";
"user_other_session_menu_sign_out_sessions" = "Wyloguj z %@ sesji";
"user_other_session_menu_select_sessions" = "Zaznacz sesje";
"user_other_session_selected_count" = "%@ zaznaczono";
"user_other_session_clear_filter" = "Wyczyść filtry";
"user_other_session_no_verified_sessions" = "Nie znaleziono zweryfikowanych sesji.";
"user_other_session_no_inactive_sessions" = "Nie znaleziono nieaktywnych sesji.";
"user_other_session_filter_menu_inactive" = "Nieaktywny";
"user_other_session_filter_menu_unverified" = "Niezweryfikowano";
"user_other_session_filter_menu_verified" = "Zweryfikowano";
"user_other_session_filter_menu_all" = "Wszystkie sesje";
"voice_broadcast_voip_cannot_start_description" = "Nie możesz rozpocząć połączenia, ponieważ już nagrywasz transmisję na żywo.";
"voice_broadcast_connection_error_title" = "Błąd połączenia";
"voice_broadcast_voip_cannot_start_title" = "Nie można rozpocząć połączenia";
"voice_broadcast_stop_alert_agree_button" = "Tak, zatrzymaj";
"voice_broadcast_stop_alert_description" = "Czy na pewno chcesz zakończyć transmisję na żywo? Transmisja zostanie zakończona, a całe nagranie będzie dostępne w pokoju.";
"voice_broadcast_stop_alert_title" = "Zakończyć transmisję na żywo?";
"voice_broadcast_buffering" = "Buforowanie...";
"voice_broadcast_time_left" = "%@ wyszedł";
"voice_broadcast_tile" = "Transmisja głosowa";
"voice_broadcast_live" = "Na żywo";
"voice_broadcast_playback_lock_screen_placeholder" = "Transmisja głosowa";
"voice_broadcast_permission_denied_message" = "Nie posiadasz wymaganych uprawnień, aby rozpocząć transmisję głosową w tym pokoju. Skontaktuj się z administratorem pokoju, aby zwiększyć swoje uprawnienia.";
"voice_message_broadcast_in_progress_message" = "Nie możesz rozpocząć wiadomości głosowej, ponieważ już nagrywasz transmisję na żywo. Zakończ transmisję na żywo, aby rozpocząć nagrywanie wiadomości głosowej";
// MARK: - Voice Broadcast
"voice_broadcast_unauthorized_title" = "Nie można rozpocząć nowej transmisji głosowej";
"voice_message_broadcast_in_progress_title" = "Nie można rozpocząć wiadomości głosowej";
"home_context_menu_mark_as_unread" = "Oznacz jako nieprzeczytane";
"launch_loading_delay_warning" = "Może to chwilę potrwać. \nDziękujemy za Twoją cierpliwość.";
// MARK: - Launch loading
"launch_loading_generic" = "Synchronizowanie Twoich konwersacji";
"key_verification_scan_qr_code_title" = "Skanuj kod QR";
"device_verification_self_verify_open_on_other_device_information" = "Musisz zweryfikować tę sesję, aby przeglądać swoją bezpieczną historię rozmów.\n\nOtwórz Element na jednym z twoich innych urządzeń i podążaj za instrukcjami.";
"device_verification_self_verify_open_on_other_device_title" = "Otwórz %@ na swoim drugim urządzeniu";
"key_verification_alert_body" = "Przejrzyj, aby upewnić się, że twoje konto jest bezpieczne.";
// Unverified sessions
"key_verification_alert_title" = "Posiadasz niezweryfikowane sesje";
"key_verification_self_verify_security_upgrade_alert_message" = "Bezpieczne wysyłanie wiadomości zostało usprawnione z najnowszą aktualizacją. Zweryfikuj swoje urządzenie ponownie.";
// Legacy to Rust security upgrade
"key_verification_self_verify_security_upgrade_alert_title" = "Zaktualizowano aplikację";
"sign_out_confirmation_message" = "Czy na pewno chcesz się wylogować?";
// MARK: Sign out warning
"sign_out" = "Wyloguj";
"key_backup_recover_from_private_key_progress" = "%@%% Zakończone";
"room_details_polls" = "Historia ankiet";
"manage_session_sign_out_other_sessions" = "Wyloguj z wszystkich pozostałych sesji";
"manage_session_rename" = "Zmień nazwę sesji";
"manage_session_name_info_link" = "Dowiedz się więcej";
"manage_session_name_hint" = "Własne nazwy sesji pomogą Ci łatwiej rozpoznać swoje urządzenia.";
"settings_labs_enable_voice_broadcast" = "Transmisja głosowa";
"settings_labs_enable_wysiwyg_composer" = "Wypróbuj w bogatym edytorze tekstu";
"settings_labs_enable_new_app_layout" = "Nowy układ aplikacji";
"settings_labs_enable_new_client_info_feature" = "Zapisz nazwę klienta, wersję i URL, aby łatwiej rozpoznawać sesje w menedżerze sesji";
"settings_labs_enable_new_session_manager" = "Nowy menedżer sesji";
"room_command_error_unknown_command" = "Komenda jest nieprawidłowa lub nieobsługiwana";
"settings_push_rules_error" = "Wystąpił błąd podczas aktualizowania Twoich preferencji powiadomień. Przełącz opcję ponownie.";
"room_command_change_room_topic_description" = "Ustawia temat pokoju";
"room_command_reset_user_power_level_description" = "Usuwa uprawnienia administratora z danym ID";
"room_command_set_user_power_level_description" = "Ustal poziom uprawnień użytkownika";
"room_command_unban_user_description" = "Odbanowuje użytkownika z danym ID";
"room_command_ban_user_description" = "Banuje użytkownika z danym ID";
"room_command_kick_user_description" = "Usuwa użytkownika danym ID z tego pokoju";
"room_command_invite_user_description" = "Zaprasza użytkownika z danym ID do bieżącego pokoju";
"room_command_part_room_description" = "Opuść pokój";
"room_command_join_room_description" = "Dołącza do pokoju z podanego adresu";
// Room commands descriptions
"room_command_change_display_name_description" = "Zmienia twój wyświetlany pseudonim";
"room_command_emote_description" = "Wyświetla akcję";
"room_first_message_placeholder" = "Wyślij swoją pierwszą wiadomość…";
"room_creation_only_one_email_invite" = "Możesz zaprosić tylko jeden e-mail jednocześnie";
"password_policy_pwd_in_dict_error" = "Hasło zostało znalezione w słowniku, dlatego nie można go użyć.";
"password_policy_weak_pwd_error" = "Hasło jest za słabe. Musi zawierać co najmniej 8 znaków wraz z jednym z każdego typu: duże litery, małe litery, cyfry i znaki specjalne.";
// MARK: Password policy errors
"password_policy_too_short_pwd_error" = "Hasło jest za krótkie";
"authentication_qr_login_failure_retry" = "Spróbuj ponownie";
"authentication_qr_login_failure_request_timed_out" = "Wiązanie nie zostało zakończone w ustalonym czasie.";
"authentication_qr_login_failure_request_denied" = "Żądanie zostało odrzucone przez drugie urządzenie.";
"authentication_qr_login_failure_invalid_qr" = "Kod QR jest nieprawidłowy.";
"authentication_qr_login_failure_device_not_supported" = "Wiązanie z tym urządzeniem nie jest wspierane.";
"authentication_qr_login_confirm_alert" = "Upewnij się, że znasz pochodzenie tego kodu. Poprzez powiązanie urządzeń udostępniasz pełny dostęp do Twojego konta.";
"authentication_qr_login_failure_title" = "Nie udało się powiązać";
"authentication_qr_login_loading_signed_in" = "Jesteś teraz zalogowany na swoim drugim urządzeniu.";
"authentication_qr_login_loading_waiting_signin" = "Oczekiwanie na logowanie urządzenia.";
"authentication_qr_login_loading_connecting_device" = "Łączenie z urządzeniem";
"authentication_qr_login_confirm_subtitle" = "Potwierdź, że kod poniżej pasuje z Twoim drugim urządzeniem:";
"authentication_qr_login_confirm_title" = "Bezpieczne połączenie ustanowione";
"authentication_qr_login_scan_subtitle" = "Ustaw kod QR w obrębie kwadratu poniżej";
"authentication_qr_login_scan_title" = "Skanuj kod QR";
"authentication_qr_login_display_step2" = "Wybierz 'Zaloguj za pomocą kodu QR'";
"authentication_qr_login_display_subtitle" = "Zeskanuj kod QR na Twoim urządzeniu, które jest wylogowane.";
"authentication_qr_login_display_step1" = "Otwórz Element na innym urządzeniu";
"authentication_qr_login_display_title" = "Powiąż urządzenie";
"authentication_qr_login_start_need_alternative" = "Szukasz innej metody?";
"authentication_qr_login_start_display_qr" = "Pokaż kod QR na tym urządzeniu";
"authentication_qr_login_start_step4" = "Wybierz 'Pokaż kod QR na tym urządzeniu'";
"authentication_qr_login_start_step3" = "Wybierz 'powiąż urządzenie'";
"room_command_discard_session_description" = "Wymusza usunięcie bieżącej sesji grupowej wychodzącej z zaszyfrowanego pokoju";
"user_session_details_session_section_footer" = "Aby skopiować dane, przytrzymaj na nich stuknięcie.";
"user_session_inactive_session_description" = "Sesje nieaktywne to sesje, które nie były używane przez dłuższy czas, ale wciąż otrzymują klucze szyfrujące.\n\nRegularne usuwanie sesji nieaktywnych poprawia bezpieczeństwo, wydajność i upraszcza Tobie detekcje podejrzanych sesji.";
"user_session_rename_session_description" = "Inni użytkownicy w wiadomościach bezpośrednich i pokojach, do których dołączyłeś, mogą wyświetlić całą listę Twoich sesji.\n\nOznacza to dla nich pewność, że rzeczywiście rozmawiają z Tobą, ale jednocześnie oznacza, że widzą nazwę sesji, którą tutaj wpiszesz.";
"user_session_permanently_unverified_session_description" = "Ta sesja nie wspiera szyfrowania, więc nie może zostać zweryfikowana. \n\nNie będziesz w stanie uczestniczyć w pokojach, gdzie szyfrowane jest włączone.\n\nDla najlepszego bezpieczeństwa i prywatności zaleca się korzystania z klientów Matrix, które wspierają szyfrowanie.";
"user_session_unverified_session_description" = "Sesje niezweryfikowane to sesje, w których zalogowano się za pomocą Twoich danych, lecz nie zostały zweryfikowane inną sesją.\n\nW tym przypadku dokładnie się upewnij, że rozpoznajesz takie sesje, ponieważ mogą ujawnić nieautoryzowane użycie Twojego konta.";
"user_session_verified_session_description" = "Sesje zweryfikowane są wszędzie, gdzie korzystasz z Element po wprowadzeniu swojego hasła lub zweryfikowaniu swojej tożsamości za pomocą innej sesji zweryfikowanej.\n\nTo oznacza, że posiadasz wszystkie niezbędne klucze wymagane do odblokowania swoich zaszyfrowanych wiadomości i oznajmiasz innym użytkownikom, że ufasz tej sesji.";
"space_invite_nav_title" = "Zaproszenie do przestrzeni";
"user_other_session_unverified_sessions_header_subtitle" = "Dla wzmocnienia bezpiecznych wiadomości, zweryfikuj swoje sesje i wyloguj się ze wszystkich sesji, których nie rozpoznajesz lub nie używasz.";
+2 -1
View File
@@ -2626,7 +2626,6 @@
"user_session_got_it" = "Entendido";
"user_other_session_permanently_unverified_additional_info" = "Esta sessão não suporta encriptação e assim não pode ser verificada.";
"voice_broadcast_time_left" = "%@ restando";
"key_verification_alert_body" = "Revise para assegurar que sua conta está segura.";
// Unverified sessions
@@ -2653,3 +2652,5 @@
"wysiwyg_composer_format_action_inline_code" = "Aplicar formato de código inline";
"wysiwyg_composer_format_action_link" = "Aplicar formato de link";
"user_other_session_security_recommendation_title" = "Outras sessões";
"room_creation_only_one_email_invite" = "Você só pode convidar um e-mail de cada vez";
"accessibility_selected" = "selecionado";
+11 -7
View File
@@ -915,7 +915,7 @@
"security_settings_title" = "Безопасность";
"security_settings_crypto_sessions" = "МОИ СЕАНСЫ";
"security_settings_crypto_sessions_loading" = "Загрузка сеансов…";
"security_settings_crypto_sessions_description_2" = "Если вы не узнали логин, измените пароль аккаунта Matrix и сбросьте Безопасное резервное копирование.";
"security_settings_crypto_sessions_description_2" = "Если вы не узнаете логин, измените пароль учётной записи Matrix и сбросьте Secure Backup.";
"security_settings_secure_backup" = "БЕЗОПАСНОЕ РЕЗЕРВНОЕ КОПИРОВАНИЕ";
"security_settings_secure_backup_description" = "Сделайте резервную копию ключей шифрования с данными вашей учетной записи на случай, если вы потеряете доступ к своим сеансам. Ваши ключи будут защищены уникальным электронным ключом.";
"security_settings_secure_backup_setup" = "Настроить";
@@ -1186,16 +1186,16 @@
"create_room_section_header_name" = "НАЗВАНИЕ";
"create_room_placeholder_name" = "Имя";
"create_room_section_header_topic" = "Тема комнаты (опционально)";
"create_room_placeholder_topic" = "Тема";
"create_room_section_header_encryption" = "Шифрование комнаты";
"create_room_placeholder_topic" = "О чём эта комната?";
"create_room_section_header_encryption" = "ШИФРОВАНИЕ";
"create_room_enable_encryption" = "Включено шифрование";
"create_room_section_footer_encryption" = "После этого шифрование отключить нельзя.";
"create_room_section_header_type" = "Тип комнаты";
"create_room_type_private" = "Приватная комната";
"create_room_type_public" = "Публичная комната";
"create_room_section_header_type" = "КТО ИМЕЕТ ДОСТУП";
"create_room_type_private" = "Приватная комната (только по приглашению)";
"create_room_type_public" = "Публичная комната (для каждого)";
"create_room_section_footer_type" = "Люди присоединяются к приватной комнате только по приглашению в комнату.";
"create_room_show_in_directory" = "Показать комнату в списке";
"create_room_section_header_address" = "Адрес комнаты";
"create_room_section_header_address" = "АДРЕС";
"create_room_placeholder_address" = "#testroom:matrix.org";
"room_info_list_room_encrypted" = "Сообщения в этой комнате зашифрованы сквозным шифрованием";
"room_info_list_one_member" = "1 пользователь";
@@ -2261,3 +2261,7 @@
"room_access_settings_screen_private_message" = "Только приглашенные люди могут найти и присоединиться.";
"manage_session_name_hint" = "Индивидуальные имена сеансов помогут Вам легче распознавать свои устройства.";
"settings_labs_confirm_crypto_sdk" = "Имейте ввиду, что эта функция все ещё на экспериментальной стадии, поэтому она может работать не так, как ожидается, и потенциально может иметь непредвиденные последствия. Для отмены функции выйдите из системы и войдите снова. Используйте её по своему усмотрению и с осторожностью.";
// Room Access Settings
"room_access_settings_screen_nav_title" = "Доступ к комнате";
"spaces_coming_soon_detail" = "Эта функция еще не реализована здесь, но она в разработке. На данный момент вы можете сделать это с помощью %@ на своем компьютере.";
+17
View File
@@ -2943,3 +2943,20 @@
"key_verification_self_verify_security_upgrade_alert_title" = "Aplikácia bola aktualizovaná";
"settings_acceptable_use" = "Zásady prijateľného používania";
"room_command_error_unknown_command" = "Neplatný alebo nespracovaný príkaz";
"room_command_discard_session_description" = "Vynúti zrušenie aktuálnej relácie odchádzajúcej skupiny v zašifrovanej miestnosti";
"room_command_change_room_topic_description" = "Nastaví tému aktuálnej miestnosti";
"room_command_reset_user_power_level_description" = "Zruší stav moderátora používateľovi so zadaným ID";
"room_command_set_user_power_level_description" = "Určuje úroveň oprávnenia pre zadaného používateľa";
"room_command_unban_user_description" = "Zruší zákaz vstúpiť používateľovi so zadaným ID";
"room_command_ban_user_description" = "Zakáže vstup používateľovi so zadaným ID";
"room_command_kick_user_description" = "Odstráni používateľa s daným ID z tejto miestnosti";
"room_command_invite_user_description" = "Pozve zadaného používateľa do aktuálnej miestnosti";
"room_command_part_room_description" = "Opustiť miestnosť";
"room_command_join_room_description" = "Pripojí sa do miestnosti s danou adresou";
"room_command_emote_description" = "Zobrazí akciu";
// Room commands descriptions
"room_command_change_display_name_description" = "Mení vaše zobrazované meno / prezývku";
"notice_display_name_changed_to" = "%@ zmenil/a svoje zobrazované meno na %@";
"poll_timeline_loading" = "Načítavanie…";
+15
View File
@@ -2731,3 +2731,18 @@
"key_verification_self_verify_security_upgrade_alert_title" = "Aplikacioni u përditësua";
"settings_acceptable_use" = "Rregull Përdorimi të Pranueshëm";
"accessibility_selected" = "përzgjedhur";
"notice_display_name_changed_to" = "%@ ndërroi emrin e vet për në ekran si %@";
"room_command_error_unknown_command" = "Urdhër i pavlefshëm ose i patrajtuar";
"room_command_change_room_topic_description" = "Cakton temën e dhomës";
"room_command_reset_user_power_level_description" = "I heq gjendjen e operatorit përdoruesit me ID-në e dhënë";
"room_command_set_user_power_level_description" = "Përcaktoni shkallën e pushtetit së një përdoruesi";
"room_command_unban_user_description" = "Heq dëbimin për përdoruesin me ID-në e dhënë";
"room_command_ban_user_description" = "Dëbon përdoruesin me ID-në e dhënë";
"room_command_kick_user_description" = "Heq nga dhoma aktuale përdoruesin me ID-në e dhënë";
"room_command_invite_user_description" = "Fton në dhomën aktuale përdoruesin me ID-në e dhënë";
"room_command_part_room_description" = "Dil nga dhoma";
"room_command_join_room_description" = "Hyhet në dhomën me adresën e dhënë";
"room_command_emote_description" = "Veprim shfaqjeje";
// Room commands descriptions
"room_command_change_display_name_description" = "Kjo ndryshon nofkën tuaj në ekran";
+17 -2
View File
@@ -2409,7 +2409,6 @@
"spaces_explore_rooms_format" = "Utforska %@";
"spaces_create_subspace_title" = "Skapa ett underutrymme";
"spaces_add_subspace_title" = "Skapa utrymme inuti %@";
"key_verification_alert_body" = "Granska för att försäkra att ditt konto är säkert.";
// Unverified sessions
@@ -2647,7 +2646,6 @@
"voice_broadcast_connection_error_message" = "Tyvärr kan vi inte starta en röstsändning för tillfället. Vänligen pröva igen senare.";
"voice_broadcast_connection_error_title" = "Anslutningsfel";
"voice_broadcast_playback_lock_screen_placeholder" = "Röstsändning";
"room_details_polls" = "Omröstningshistorik";
"settings_labs_disable_crypto_sdk" = "Totalsträckskryptering i Rust (logga ut för att stänga av)";
"settings_labs_confirm_crypto_sdk" = "Vänligen observera att den här funktionen fortfarande ska anses vara experimentell, den kanske inte fungerar som förväntat eller kan leda till okända konsekvenser. För att återgå, logga ut och logga sedan in igen. Använd på egen risk.";
@@ -2661,3 +2659,20 @@
"home_context_menu_mark_as_unread" = "Markera som oläst";
"key_backup_recover_from_private_key_progress" = "%@%% Färdig";
"authentication_qr_login_failure_device_not_supported" = "Det finns inget stöd för att länka denna enhet.";
"room_command_emote_description" = "Visa åtgärd";
// Room commands descriptions
"room_command_change_display_name_description" = "Byter ditt visningsnamn";
"room_creation_only_one_email_invite" = "Du kan bara bjuda in en e-postadress åt gången";
"settings_acceptable_use" = "Policy för acceptabel användning";
"room_command_join_room_description" = "Går med i rummet med den angivna adressen";
"room_command_part_room_description" = "Lämna rummet";
"room_command_invite_user_description" = "Bjuder in användaren med angivet ID till aktuellt rum";
"room_command_kick_user_description" = "Tar bort användaren med angivet ID från det här rummet";
"room_command_ban_user_description" = "Bannar användaren med angivet ID";
"room_command_unban_user_description" = "Avbannar användaren med angivet ID";
"room_command_set_user_power_level_description" = "Definiera behörighetsnivån för en användare";
"room_command_reset_user_power_level_description" = "Avoppar användaren med angivet ID";
"room_command_change_room_topic_description" = "Sätter rummets ämne";
"room_command_discard_session_description" = "Tvingar den aktuella utgående gruppsessionen i ett krypterat rum att kasseras";
"room_command_error_unknown_command" = "Ogiltigt eller obehandlat kommando";
+17
View File
@@ -2945,3 +2945,20 @@
"key_verification_self_verify_security_upgrade_alert_title" = "Застосунок оновлено";
"settings_acceptable_use" = "Політика прийнятного користування";
"room_command_error_unknown_command" = "Недійсна і необроблена команда";
"room_command_discard_session_description" = "Примусово відхиляє поточний вихідний сеанс групи в зашифрованій кімнаті";
"room_command_change_room_topic_description" = "Встановлює тему кімнати";
"room_command_reset_user_power_level_description" = "Скинути рівень доступу користувача із вказаним ID";
"room_command_set_user_power_level_description" = "Визначити рівень повноважень користувача";
"room_command_unban_user_description" = "Розблоковує користувача з указаним ID";
"room_command_ban_user_description" = "Блокує користувача з указаним ID";
"room_command_kick_user_description" = "Вилучає користувача з указаним ID з цієї кімнати";
"room_command_invite_user_description" = "Запрошує користувача зі вказаним ID до кімнати";
"room_command_part_room_description" = "Вийти з кімнати";
"room_command_join_room_description" = "Приєднується до кімнати із вказаною адресою";
"room_command_emote_description" = "Показує дію";
// Room commands descriptions
"room_command_change_display_name_description" = "Змінює ваш нік";
"notice_display_name_changed_to" = "%@ змінили своє показуване ім'я на %@";
"poll_timeline_loading" = "Завантаження...";
+95 -31
View File
@@ -68,14 +68,14 @@
"auth_msisdn_validation_title" = "等待验证中";
"auth_msisdn_validation_message" = "我们通过短信向您发送了一条验证码,请在下方输入它。";
"auth_msisdn_validation_error" = "无法验证此手机号。";
"auth_recaptcha_message" = "此服务器想确定您不是机器人";
"auth_recaptcha_message" = "此服务器想确定您不是机器人";
"auth_reset_password_message" = "为了重置您的Matrix账户密码,请输入与您账户关联的邮箱地址:";
"auth_reset_password_missing_email" = "必须输入与您的账户关联的邮箱地址。";
"auth_reset_password_missing_password" = "必须输入新的密码。";
"auth_reset_password_email_validation_message" = "一封邮件已经发送到 %@。当您已经按照其中的链接操作以后,请点下面。";
"auth_reset_password_next_step_button" = "我已经验证了我的邮箱地址";
"auth_reset_password_error_unauthorized" = "验证邮箱地址失败:请确认您已经点击了邮件里的链接";
"auth_reset_password_error_not_found" = "您的邮箱地址可能没有与此服务器上的 Matrix ID 绑定。";
"auth_reset_password_error_not_found" = "您的邮箱地址可能没有与此服务器上的 Matrix ID 绑定。";
"auth_reset_password_success_message" = "您的Matrix账户密码已重置。\n\n您的所有会话都会被登出并且不会收到推送通知。要想重新收到通知,请在每个设备上重新登录。";
"auth_add_email_and_phone_warning" = "在 API 出现之前,还不支持使用邮箱地址或手机号码直接注册。只有手机号码会和此账户绑定。您可以在设置中添加邮箱地址。";
// Chat creation
@@ -237,7 +237,7 @@
"settings_config_no_build_info" = "没有编译信息";
"settings_mark_all_as_read" = "将所有消息标记为已读";
"settings_report_bug" = "报告 bug";
"settings_config_home_server" = "服务器为 %@";
"settings_config_home_server" = "服务器为 %@";
"settings_config_identity_server" = "身份认证服务器为 %@";
"settings_config_user_id" = "以 %@ 登录";
"settings_user_settings" = "用户设置";
@@ -258,12 +258,12 @@
"settings_surname" = "姓氏";
"settings_remove_prompt_title" = "确认";
"settings_remove_email_prompt_msg" = "你确定要移除邮箱地址 %@";
"settings_remove_phone_prompt_msg" = "你确定要移除手机号码地址 %@";
"settings_remove_phone_prompt_msg" = "你确定要移除电话号码%@";
"settings_email_address" = "电子邮件";
"settings_email_address_placeholder" = "输入您的邮箱地址";
"settings_add_email_address" = "添加邮箱地址";
"settings_phone_number" = "手机号码";
"settings_add_phone_number" = "添加手机号码";
"settings_phone_number" = "电话";
"settings_add_phone_number" = "添加电话号码";
"settings_night_mode" = "夜间模式";
"settings_fail_to_update_profile" = "个人档案更新失败";
"settings_enable_push_notif" = "在此设备上发送通知";
@@ -362,7 +362,7 @@
"directory_server_picker_title" = "选择一个目录";
"directory_server_all_rooms" = "%@ 服务器上的所有房间";
"directory_server_all_native_rooms" = "所有本地 Matrix 房间";
"directory_server_type_homeserver" = "输入一个服务器来列出公共房间";
"directory_server_type_homeserver" = "输入一个服务器来列出公共房间";
"directory_server_placeholder" = "matrix.org";
// Others
"or" = "或";
@@ -385,7 +385,7 @@
// Crash report
// Crypto
"e2e_enabling_on_app_update" = "%@ 现在支持端到端加密,但是您需要重新登录以启用它。\n\n您可以现在重新登录,也可以之后从应用程序设置中选择开启。";
"e2e_need_log_in_again" = "您需要登录回来以便为此会话生成端对端加密密钥并提交公钥到您的服务器。\n这只需要做一次;很抱歉造成打扰。";
"e2e_need_log_in_again" = "您需要登录回来以便为此会话生成端对端加密密钥并提交公钥到您的服务器。\n这只需要做一次;很抱歉造成打扰。";
// Bug report
"bug_report_title" = "Bug 报告";
"bug_report_description" = "请描述此 bug。您做了什么?本来应该发生什么?以及实际发生了什么?";
@@ -505,7 +505,7 @@
"event_formatter_jitsi_widget_added" = "VoIP 会议已被 %@ 添加";
"event_formatter_rerequest_keys_part1_link" = "重新请求加密密钥";
"event_formatter_rerequest_keys_part2" = " (从您的其他会话中)。";
"homeserver_connection_lost" = "无法连接至服务器。";
"homeserver_connection_lost" = "无法连接至服务器。";
"call_jitsi_error" = "电话会议加入失败。";
"deactivate_account_forget_messages_information_part2_emphasize" = "警告";
"deactivate_account_validate_action" = "停用账户";
@@ -516,12 +516,12 @@
"room_replacement_link" = "对话自此继续。";
"room_predecessor_information" = "这个房间是另一个对话的延续。";
"room_predecessor_link" = "点击此处查看更早的消息。";
"room_resource_usage_limit_reached_message_1_default" = "此服务器某资源已超出使用限制,导致 ";
"room_resource_usage_limit_reached_message_1_monthly_active_user" = "此服务器已达到月活跃用户限制,导致 ";
"room_resource_usage_limit_reached_message_1_default" = "此服务器某资源已超出使用限制,导致 ";
"room_resource_usage_limit_reached_message_1_monthly_active_user" = "此服务器已达到月活跃用户限制,导致 ";
"room_resource_usage_limit_reached_message_2" = "部分用户将无法登录。";
"room_resource_usage_limit_reached_message_contact_3" = " 以提高限制。";
// String for App Store
"store_short_description" = "安全、去中心化的聊天VoIP 应用";
"store_short_description" = "安全、去中心化的聊天/VoIP";
"store_full_description" = "Element 是一种新型的通讯与协作应用:\n\n1. 使您可以掌控您的隐私\n2. 使您与 Matrix 网络中的任何人交流,甚至可以通过集成功能与如 Slack 之类的其他应用通讯\n3. 保护您免受广告,大数据挖掘和封闭服务的侵害\n4. 通过端到端加密保证安全,通过交叉签名验证其他人\n\nElement 与其他通讯与协作应用完全不同,因为它是去中心化且开源的。\n\nElement 允许您自托管——或者选择托管商——因此,您能拥有数据和会话的隐私权,所有权和控制权。它允许您访问开放网络;因此,您可以与 Element 用户以外的人交流。并且它非常安全。\n\nElement 之所以可以做到这些,是因为它在 Matrix 上运行——开放,去中心化通讯的标准。\n\n通过让您选择由谁来托管您的会话,Element 让您掌控一切。在 Element 应用中,您可以选择不同的托管方式:\n\n1. 在由 Matrix 开发者托管的 matrix.org 公共服务器上获取免费账户,或从志愿者托管的上千个公共服务器中选择\n2. 在您自己的硬件上运行服务器,自托管您的会话\n3. 通过订阅 Element Matrix Services 托管平台,简单地在自定义服务器上注册账户\n\n为什么选择 Element?\n\n掌控您的数据:您来决定存放您的数据和消息的位置。拥有并控制它的是您,而不是挖掘您的数据或与第三方分享的巨型企业。\n\n开放通讯与协作:您可以与 Matrix 网络中的任何人聊天,不论他们使用 Element 还是其他 Matrix 应用,甚至/即使他们在使用不同的通讯系统,例如 Slack、IRC 或 XMPP。\n\n超级安全:支持真正的端到端加密(仅有会话中的人可以解密消息),还有能够验证会话参与方的设备的交叉签名。\n\n完善的通讯方式:消息,语音和视频通话,文件共享,屏幕共享和大量集成功能,机器人和挂件。建立房间与社区,保持联系并完成工作。\n\n随时随地:消息历史可在您的全部设备和 https://app.element.io 网页端之间完全同步,无论您在哪里,都可以保持联系。";
"auth_accept_policies" = "请查看并接受此主页服务器的服务条款:";
"room_replacement_information" = "这个房间已被替换,不再有效。";
@@ -572,7 +572,7 @@
"e2e_room_key_request_message_new_device" = "您添加了一个新会话 '%@' ,它正在请求加密密钥。";
"e2e_room_key_request_message" = "您的未验证会话 '%@' 正在请求加密密钥。";
// GDPR
"gdpr_consent_not_given_alert_message" = "要继续使用该 %@ 服务器,您必须查看并同意其服务条款和条件。";
"gdpr_consent_not_given_alert_message" = "要继续使用该 %@ 服务器,您必须查看并同意其服务条款和条件。";
"gdpr_consent_not_given_alert_review_now_action" = "立即查看";
"deactivate_account_title" = "停用账户";
"deactivate_account_informations_part1" = "这将使您的账户永久无法使用。 您将无法登录,也无法重新注册相同的用户 ID 。 这将导致您的账户离开其参与的所有房间,并且会从您的身份服务器中删除您的账户详细信息。 ";
@@ -595,7 +595,7 @@
"key_backup_setup_intro_manual_export_info" = "(高级)";
"key_backup_setup_intro_manual_export_action" = "手动导出密钥";
"key_backup_setup_passphrase_title" = "使用一段安全词组保护您的备份";
"key_backup_setup_passphrase_info" = "我们将会在服务器上保存一份您的密钥的加密拷贝。设置一个词组来保护您的备份的安全。\n\n为了最大的安全性,它应当与您的Matrix账户密码不同。";
"key_backup_setup_passphrase_info" = "我们将会在服务器上保存一份您的密钥的加密拷贝。设置一个词组来保护您的备份的安全。\n\n为了最大的安全性,它应当与您的Matrix账户密码不同。";
"key_backup_setup_passphrase_passphrase_title" = "输入";
"key_backup_setup_passphrase_passphrase_placeholder" = "输入词组";
"key_backup_setup_passphrase_passphrase_valid" = "太棒了!";
@@ -654,7 +654,7 @@
"sign_out_key_backup_in_progress_alert_cancel_action" = "等待";
"auth_login_single_sign_on" = "使用单点登录方式登入";
"room_message_unable_open_link_error_message" = "无法打开链接。";
"auth_autodiscover_invalid_response" = "服务器探测响应无效";
"auth_autodiscover_invalid_response" = "服务器探测响应无效";
"close" = "关闭";
// Accessibility
"accessibility_checkbox_label" = "多选框";
@@ -667,7 +667,7 @@
"auth_reset_password_error_is_required" = "未配置身份服务器:在服务器选项中添加以便重设你的Matrix账户密码。";
"auth_softlogout_signed_out" = "你已登出";
"auth_softlogout_sign_in" = "登录";
"auth_softlogout_reason" = "你的服务器(%1$@)管理员已将你的账户%2$@%3$@)登出。";
"auth_softlogout_reason" = "你的服务器(%1$@)管理员已将你的账户%2$@%3$@)登出。";
"auth_softlogout_recover_encryption_keys" = "登录以恢复单独保存在此设备上的加密密钥。你需要它们才能阅读任何设备上的安全消息。";
"auth_softlogout_clear_data" = "清空个人信息";
"auth_softlogout_clear_data_message_1" = "警告:你的个人信息(包括加密密钥)仍将保存在这台设备上。";
@@ -677,7 +677,7 @@
"auth_softlogout_clear_data_sign_out_msg" = "你确定希望清空所有当前保存在此设备上数据吗?再次登录可以获取你的账户数据和消息。";
"auth_softlogout_clear_data_sign_out" = "登出";
// Errors
"error_user_already_logged_in" = "您似乎正在尝试连接另一个服务器。您想要登出吗?";
"error_user_already_logged_in" = "您似乎正在尝试连接另一个服务器。您想要登出吗?";
"room_creation_error_invite_user_by_email_without_identity_server" = "未设置身份认证服务器,所以你不能用邮箱添加参与者。";
"contacts_address_book_no_identity_server" = "未设置身份认证服务器";
"room_participants_remove_third_party_invite_prompt_msg" = "你确定想撤回这个邀请吗?";
@@ -718,7 +718,7 @@
"settings_three_pids_management_information_part3" = "。";
"settings_security" = "安全";
"settings_calls_stun_server_fallback_button" = "允许使用通话辅助服务器作为备用手段";
"settings_calls_stun_server_fallback_description" = "允许在你的服务器不能提供时使用通话辅助服务器 %@ 作为备用手段(你的IP地址在通话时会被分享)。";
"settings_calls_stun_server_fallback_description" = "允许在你的服务器不能提供时使用通话辅助服务器 %@ 作为备用手段(你的IP地址在通话时会被分享)。";
"settings_integrations_allow_button" = "管理集成";
"settings_integrations_allow_description" = "使用集成管理器(%@)来管理机器人,桥接,小插件和贴纸包。\n\n集成管理器会收到设置数据,而且能修改小插件,发送房间邀请以及代表你设置权力级别。";
"settings_labs_message_reaction" = "用emoji表情回应消息";
@@ -792,7 +792,7 @@
"camera_unavailable" = "此摄像头在你的设备上无效";
"photo_library_access_not_granted" = "%@没有权限获取你的照片库,请更改隐私设置";
"call_no_stun_server_error_title" = "由于错误设置服务器,通话失败";
"call_no_stun_server_error_message_1" = "请让你的服务器%@的管理员设置一个TURN服务器以便通话能可靠运行。";
"call_no_stun_server_error_message_1" = "请让你的服务器%@的管理员设置一个TURN服务器以便通话能可靠运行。";
"call_no_stun_server_error_message_2" = "此外,你可以尝试使用在%@的公共服务器,但这将减少可靠性,而且它会把你的IP地址分享给那个服务器。你也可以在设置中管理这个选项";
"call_no_stun_server_error_use_fallback_button" = "尝试使用%@";
// Widget
@@ -1088,7 +1088,7 @@
"people_empty_view_title" = "用户";
"less" = "较小地";
"more" = "更多";
"switch" = "开关";
"switch" = "切换";
"joined" = "已加入";
"store_promotional_text" = "在开放网络上保护隐私的聊天和协作应用程序。去中心化让你掌控一切。没有数据挖掘,没有后门,也没有第三方访问。";
"social_login_button_title_sign_up" = "使用 %@ 注册";
@@ -1376,7 +1376,7 @@
"room_details_title_for_dm" = "详细信息";
// AuthenticatedSessionViewControllerFactory
"authenticated_session_flow_not_supported" = "此应用并不支持你的服务器的认证机制。";
"authenticated_session_flow_not_supported" = "此应用并不支持你的服务器的认证机制。";
"settings_labs_enable_ringing_for_group_calls" = "群组通话铃声";
"room_multiple_typing_notification" = "%@ 和其他人";
"room_no_privileges_to_create_group_call" = "你需要成为管理员或协管员以开始通话。";
@@ -1612,8 +1612,8 @@
// Login Screen
"login_create_account" = "创建账户:";
"login_server_url_placeholder" = "网址(例如 https://matrix.org";
"login_home_server_title" = "服务器网址:";
"login_home_server_info" = "您的服务器存储了您所有的对话和账户数据";
"login_home_server_title" = "服务器网址:";
"login_home_server_info" = "您的服务器存储了您所有的对话和账户数据";
"login_identity_server_title" = "身份认证服务器网址:";
"login_identity_server_info" = "Matrix 提供了身份认证服务器以验证邮箱地址等是否属于某个 Matrix ID。目前只有 https://matrix.org 支持。";
"login_user_id_placeholder" = "Matrix ID(例如 @bob:matrix.org 或 bob";
@@ -1690,8 +1690,8 @@
"notice_invalid_attachment" = "无效附件";
"notice_unsupported_attachment" = "不支持的附件:%@";
"login_email_info" = "指定邮箱地址可以让其他 Matrix 用户更容易找到您,并允许您可以在未来重置密码。";
"login_error_no_login_flow" = "我们未能从此服务器获取认证信息";
"login_error_do_not_support_login_flows" = "当前我们不支持此服务器定义的任何或者所有登录流";
"login_error_no_login_flow" = "我们未能从此服务器获取认证信息";
"login_error_do_not_support_login_flows" = "当前我们不支持此服务器定义的任何或者所有登录流";
"notice_feedback" = "反馈事件 (id: %@)%@";
"notice_redaction" = "%@ 取消了一个事件 (id: %@)";
"notice_error_unsupported_event" = "不支持的事件";
@@ -1790,7 +1790,7 @@
"power_level" = "权力级别";
"network_error_not_reachable" = "请检查你的网络连接";
"user_id_placeholder" = "例如:@bob:homeserver";
"ssl_homeserver_url" = "服务器网址:%@";
"ssl_homeserver_url" = "服务器网址:%@";
// Country picker
"country_picker_title" = "请选择国家";
// Language picker
@@ -1915,8 +1915,8 @@
"account_email_validation_error" = "无法验证邮箱地址。请检查你的电子邮箱并点击邮件中的链接。完成后,请点击继续";
"login_error_resource_limit_exceeded_title" = "超出资源使用限制";
"login_error_resource_limit_exceeded_contact_button" = "联系管理员";
"login_error_resource_limit_exceeded_message_default" = "此服务器已超出某资源的使用限制。";
"login_error_resource_limit_exceeded_message_monthly_active_user" = "此服务器已达到月活跃用户限制。";
"login_error_resource_limit_exceeded_message_default" = "此服务器已超出某资源的使用限制。";
"login_error_resource_limit_exceeded_message_monthly_active_user" = "此服务器已达到月活跃用户限制。";
"login_error_resource_limit_exceeded_message_contact" = "\n\n请联系管理员以继续使用本服务。";
"account_msisdn_validation_message" = "我们通过短信向您发送了一条验证码,请在下方输入它。";
"room_error_timeline_event_not_found" = "应用程序试图加载此房间时间线中的特定点,但无法找到该时间点";
@@ -2135,11 +2135,11 @@
"authentication_verify_email_input_title" = "输入你的电子邮件";
"authentication_cancel_flow_confirmation_message" = "账户还未创建。停止注册流程吗?";
"authentication_server_selection_generic_error" = "无法在这个URL上找到服务器,请检查其是否正确。";
"authentication_server_selection_server_url" = "服务器URL";
"authentication_server_selection_server_url" = "服务器URL";
"authentication_server_selection_register_message" = "你服务器的地址是什么?它就像你全部数据的家";
"authentication_server_selection_register_title" = "选择你的服务器";
"authentication_server_selection_register_title" = "选择你的服务器";
"authentication_server_selection_login_message" = "你服务器的地址是什么?";
"authentication_server_selection_login_title" = "连接到服务器";
"authentication_server_selection_login_title" = "连接到服务器";
"authentication_server_info_title_login" = "你的对话发生的地方";
"authentication_login_forgot_password" = "忘记密码";
"authentication_login_username" = "用户名/电子邮件/电话";
@@ -2285,3 +2285,67 @@
"deselect_all" = "取消全选";
"notice_voice_broadcast_ended" = "%@结束了一个语音广播。";
"notice_voice_broadcast_ended_by_you" = "你结束了一个语音广播。";
"threads_beta_cancel" = "先不了";
"threads_beta_enable" = "尝试一下";
"threads_beta_information" = "使用消息列使讨论保持有序。\n\n消息列帮助你保持聊天不跑题,且易于回溯。 ";
"threads_beta_title" = "消息列";
"threads_notice_information" = "实验期间创建的所有消息列会被 <b>显示为普通回复</b>。<br/><br/>这是个一次性的转变,因为消息列现在是Matrix标准的一部分了。";
"threads_notice_title" = "消息列不再是实验性功能了🎉";
"threads_empty_show_all_threads" = "显示所有消息列";
"threads_empty_tip" = "提示:点击一条消息然后点击“消息列”来新建一个消息列。";
"threads_empty_info_my" = "回复到一个消息列,或者点击一条消息然后点击“消息列”来新建消息列。";
"room_command_error_unknown_command" = "命令无效或未处理";
"room_command_change_room_topic_description" = "设置房间话题";
"room_command_set_user_power_level_description" = "设置用户权限级别";
"room_command_unban_user_description" = "取消封禁指定id的用户";
"room_command_invite_user_description" = "邀请指定id用户进入此房间";
"room_command_kick_user_description" = "从此房间移除指定id用户";
"room_command_ban_user_description" = "封禁指定id的用户";
"room_command_part_room_description" = "离开房间";
"room_command_join_room_description" = "根据地址加入房间";
// Room commands descriptions
"room_command_change_display_name_description" = "更改显示的昵称";
"room_creation_only_one_email_invite" = "一次性只能邀请一个邮箱地址";
"authentication_qr_login_failure_device_not_supported" = "不支持链接到此设备。";
"all_chats_edit_layout_alphabetical_order" = "按照字母顺序排序";
"all_chats_edit_layout_show_filters" = "显示过滤器";
"all_chats_edit_layout_show_recents" = "显示最近项目";
// MARK: - Space Selector
"space_selector_title" = "我的空间";
// MARK: - All Chats
"all_chats_title" = "所有聊天";
"settings_labs_enable_voice_broadcast" = "语音广播";
"settings_labs_enable_wysiwyg_composer" = "尝试富文本编辑器";
"settings_labs_enable_new_client_info_feature" = "记录客户端名字、版本和URL来在会话管理器中更方便地分辨会话";
"settings_labs_enable_new_session_manager" = "新会话管理器";
"location_sharing_live_error" = "实时位置共享错误";
"location_sharing_live_loading" = "正在加载实时位置……";
"location_sharing_live_timer_incoming" = "共享到%@";
"location_sharing_live_list_item_stop_sharing_action" = "停止";
"location_sharing_live_list_item_last_update" = "在%@之前更新";
"location_sharing_live_list_item_sharing_expired" = "共享已过期";
"location_sharing_live_viewer_title" = "位置";
"location_sharing_live_map_callout_title" = "共享位置";
"live_location_sharing_banner_stop" = "停止";
"live_location_sharing_ended" = "实时位置共享已结束";
"live_location_sharing_banner_title" = "实时位置共享已开启";
// MARK: Live location sharing
"location_sharing_live_share_title" = "共享实时位置";
"location_sharing_allow_background_location_message" = "如果你想要实时共享你的位置,Element需要在后台访问你的位置信息。要允许访问,点击设置>位置,然后选择“总是”";
"location_sharing_invalid_power_level_message" = "要在此房间中实时共享位置,你需要有对应的权限。";
"settings_labs_enable_live_location_sharing" = "实时位置共享——共享当前位置(活跃开发中,位置暂时还会留在房间历史记录中)";
"poll_timeline_decryption_error" = "因为解密错误,有的投票可能没有被算进去";
"settings_labs_enable_auto_report_decryption_errors" = "自动报告解密错误";
"settings_ui_show_redactions_in_room_history" = "为已被删除的消息显示占位符";
"settings_enable_room_message_bubbles" = "消息气泡";
"all_chats_user_menu_settings" = "用户设置";
// User sessions management
"user_sessions_settings" = "管理登陆会话";
"settings_presence_offline_mode_description" = "如果开启此选项,对其他用户来说,你看起来就会像下线了一样,即使你正在使用此软件。";
+20 -3
View File
@@ -619,10 +619,10 @@
"skip" = "略過";
"close" = "關閉";
"store_promotional_text" = "開放網路上的隱私保護聊天和協作應用程式。去中心化機制讓您可自行管控。沒有資料探勘、沒有後門,也不會被第三方存取。";
"store_full_description" = "Element 是一套新型的通訊和協作應用程式,它提供下列功能:\n\n1. 您可以自行掌控隱私\n2. 可以與 Matrix 網路中的任何人進行通訊,甚至可以與 Slack 等應用程式整合\n3. 保護您免受廣告、資料探勘、後門和封閉平台的侵害\n4. 透過端到端加密和交叉簽署來驗證彼此,互相確保安全\n\nElement 是去中心化的開軟體,因此與其他通訊和協作應用程式完全不同。\n\nElement 允許您自行架設(或選擇託管)伺服器,使您可針對隱私權,所有權以及對資料和對話內容的完整控制權。您可以連線到所有開放的網路,所以您不是只能與其他 Element 使用者聊天。而且還非常安全。\n\nElement 之所以能夠做到所有這些目標,是因為它使用 Matrix(一套開放、去中心化的通訊標準)運作。\n\nElement 讓您可以自行選擇要將對話放在哪一台伺服器來讓您可自行控制自己的訊息和資料。在 Element 應用程式中,您可以選擇以不同方式託管您的訊息:\n\n1. 在 matrix.org 公開伺服器註冊免費帳號\n2. 使用自行架設的硬體主機上的伺服器來註冊帳號\n3. 訂閱 Element Matrix Services 代管平台,註冊自己的伺服器\n\n為什麼要選擇 Element?\n\n自己擁有自己資料:由您決定將資料與訊息保留在何處。您自己擁有並管理這些資料,而不用讓某些「超大型企業」來探勘您的資料,或將資料提供給第三方。\n\n開放的通訊與協作機制:您可以與 Matrix 網路中的任何人聊天,不管他們使用的是 Element 還是其他 Matrix 應用程式,甚至他們也可以使用像 Slack 、IRC 或 XMPP 之類的其他通訊系統。\n\n超級安全:真正的端對端加密(只有對話中的人才能解開訊息內容),並進行交叉簽署以驗證對話參與者的設備。\n\n完整的通訊:傳訊息、進行語音或視訊通話、分享檔案、畫面,還有大量整合、機器人與小工具。建立聊天室、社群,保持聯繫並完成工作。\n\n無論您身在何處都可保持聯繫:無論您身在何處,都可以透過 https://element.io/app 在所有裝置與網路取得完全同步的訊息記錄來保持聯繫。";
"store_full_description" = "Element 是一套新型的通訊和協作應用程式,它提供下列功能:\n\n1. 您可以自行掌控隱私\n2. 可以與 Matrix 網路中的任何人進行通訊,甚至可以與 Slack 等應用程式整合\n3. 保護您免受廣告、資料探勘、後門和封閉平台的侵害\n4. 透過端到端加密和交叉簽署來驗證彼此,互相確保安全\n\nElement 是去中心化的開放原始碼軟體,因此與其他通訊和協作應用程式完全不同。\n\nElement 允許您自行架設(或選擇託管)伺服器,使您可針對隱私權,所有權以及對資料和對話內容的完整控制權。您可以連線到所有開放的網路,所以您不是只能與其他 Element 使用者聊天。而且還非常安全。\n\nElement 之所以能夠做到所有這些目標,是因為它使用 Matrix(一套開放、去中心化的通訊標準)運作。\n\nElement 讓您可以自行選擇要將對話放在哪一台伺服器來讓您可自行控制自己的訊息和資料。在 Element 應用程式中,您可以選擇以不同方式託管您的訊息:\n\n1. 在 matrix.org 公開伺服器註冊免費帳號\n2. 使用自行架設的硬體主機上的伺服器來註冊帳號\n3. 訂閱 Element Matrix Services 代管平台,註冊自己的伺服器\n\n為什麼要選擇 Element?\n\n自己擁有自己資料:由您決定將資料與訊息保留在何處。您自己擁有並管理這些資料,而不用讓某些「超大型企業」來探勘您的資料,或將資料提供給第三方。\n\n開放的通訊與協作機制:您可以與 Matrix 網路中的任何人聊天,不管他們使用的是 Element 還是其他 Matrix 應用程式,甚至他們也可以使用像 Slack 、IRC 或 XMPP 之類的其他通訊系統。\n\n超級安全:真正的端對端加密(只有對話中的人才能解開訊息內容),並進行交叉簽署以驗證對話參與者的設備。\n\n完整的通訊:傳訊息、進行語音或視訊通話、分享檔案、畫面,還有大量整合、機器人與小工具。建立聊天室、社群,保持聯繫並完成工作。\n\n無論您身在何處都可保持聯繫:無論您身在何處,都可以透過 https://element.io/app 在所有裝置與網路取得完全同步的訊息記錄來保持聯繫。";
// String for App Store
"store_short_description" = "去中心化的安全通訊/VoIP 軟體";
"settings_three_pids_management_information_part1" = "您可以在 ";
"settings_three_pids_management_information_part1" = "在此管理你可以用作登入或回復帳戶的電郵地址或電話號碼。你也可控制誰可以用這些資料找到你。 ";
"external_link_confirmation_message" = "此連結 %@ 將帶您到另一網頁:%@\n\n確定要前往嗎?";
"external_link_confirmation_title" = "請確認此連結";
"media_type_accessibility_sticker" = "貼圖";
@@ -2406,7 +2406,7 @@
// Analytics
"analytics_prompt_title" = "協助改善 %@";
"call_no_stun_server_error_use_fallback_button" = "嘗試使用 %@";
"call_no_stun_server_error_message_2" = "或是您也可以試著使用公開伺服器 %@,但可能不夠可靠,而且會跟該伺服器分享您的 IP 位址。您也可以在設定中管理這個";
"call_no_stun_server_error_message_2" = "或是您也可以試著使用公開伺服器 %@,但可能不夠可靠,而且會跟該伺服器分享您的 IP 位址。您也可以在設定中管理此設定";
"call_no_stun_server_error_message_1" = "請聯繫您家伺服器 %@ 的管理員建立一套 TURN 伺服器,使通話能更穩定運作。";
"call_no_stun_server_error_title" = "由於伺服器設定錯誤,無法通話";
"call_jitsi_unable_to_start" = "無法建立會議通話";
@@ -2868,3 +2868,20 @@
"key_verification_self_verify_security_upgrade_alert_title" = "已更新程式";
"settings_acceptable_use" = "可接受使用政策";
"room_command_error_unknown_command" = "無效或是無法處理的指令";
"room_command_discard_session_description" = "強制使現行在已加密聊天室的外部工作階段失效";
"room_command_change_room_topic_description" = "設定聊天室主題";
"room_command_reset_user_power_level_description" = "使用 ID 降級超級使用者";
"room_command_set_user_power_level_description" = "定義超級權限使用者";
"room_command_unban_user_description" = "使用 ID 解除已禁止使用者";
"room_command_ban_user_description" = "使用 ID 來禁止使用者";
"room_command_kick_user_description" = "使用 ID 移除使用者離開此聊天室";
"room_command_invite_user_description" = "使用 ID 邀請成員加入此聊天室";
"room_command_part_room_description" = "離開聊天室";
"room_command_join_room_description" = "使用網址位置加入聊天室";
"room_command_emote_description" = "顯示動作";
// Room commands descriptions
"room_command_change_display_name_description" = "變更您的顯示名稱";
"notice_display_name_changed_to" = "%@ 將顯示名稱變更為 %@";
"poll_timeline_loading" = "載入中 ...";
@@ -70,7 +70,6 @@ extension MXBugReportRestClient {
// SDKs
userInfo["matrix_sdk_version"] = MatrixSDKVersion
userInfo["crypto_module"] = MXSDKOptions.sharedInstance().cryptoModuleId
if let crypto = mainAccount?.mxSession?.crypto {
userInfo["crypto_module_version"] = crypto.version
}
+44 -12
View File
@@ -80,8 +80,15 @@
// Check whether an override rule has been defined with the roomm id as rule id.
// This kind of rule is created to mute the room
MXPushRule* rule = [self getOverrideRoomPushRule];
if (rule)
if (rule && rule.enabled)
{
// Support for MSC3987: The dont_notify push rule action is deprecated.
if (rule.actions.count == 0)
{
return true;
}
// Support deprecated dont_notify push rule action for compatibility purposes.
for (MXPushRuleAction *ruleAction in rule.actions)
{
if (ruleAction.actionType == MXPushRuleActionTypeDontNotify)
@@ -98,7 +105,7 @@
if (key && pattern && [key isEqualToString:@"room_id"] && [pattern isEqualToString:self.roomId])
{
return rule.enabled;
return true;
}
}
}
@@ -113,13 +120,20 @@
{
// Check push rules at room level
MXPushRule *rule = [self getRoomPushRule];
if (rule)
if (rule && rule.enabled)
{
// Support for MSC3987: The dont_notify push rule action is deprecated.
if (rule.actions.count == 0)
{
return true;
}
// Support deprecated dont_notify push rule action for compatibility purposes.
for (MXPushRuleAction *ruleAction in rule.actions)
{
if (ruleAction.actionType == MXPushRuleActionTypeDontNotify)
{
return rule.enabled;
return true;
}
}
}
@@ -178,12 +192,21 @@
// check if the user did not define one
BOOL hasDontNotifyRule = NO;
for (MXPushRuleAction *ruleAction in rule.actions)
// Support for MSC3987: The dont_notify push rule action is deprecated.
if (rule.actions.count == 0)
{
if (ruleAction.actionType == MXPushRuleActionTypeDontNotify)
hasDontNotifyRule = YES;
}
else
{
// Support deprecated dont_notify push rule action for compatibility purposes.
for (MXPushRuleAction *ruleAction in rule.actions)
{
hasDontNotifyRule = YES;
break;
if (ruleAction.actionType == MXPushRuleActionTypeDontNotify)
{
hasDontNotifyRule = YES;
break;
}
}
}
@@ -256,12 +279,21 @@
// check if the user did not define one
BOOL hasDontNotifyRule = NO;
for (MXPushRuleAction *ruleAction in rule.actions)
// Support for MSC3987: The dont_notify push rule action is deprecated.
if (rule.actions.count == 0)
{
if (ruleAction.actionType == MXPushRuleActionTypeDontNotify)
hasDontNotifyRule = YES;
}
else
{
// Support deprecated dont_notify push rule action for compatibility purposes.
for (MXPushRuleAction *ruleAction in rule.actions)
{
hasDontNotifyRule = YES;
break;
if (ruleAction.actionType == MXPushRuleActionTypeDontNotify)
{
hasDontNotifyRule = YES;
break;
}
}
}
-120
View File
@@ -1,120 +0,0 @@
//
// Copyright 2023 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
import Foundation
import MatrixSDKCrypto
/// An implementation of `MXCryptoV2Feature` which uses `UserDefaults` to persist the enabled status
/// of `CryptoSDK`, and which uses feature flags to control rollout availability.
///
/// The implementation uses both remote and local feature flags to control the availability of `CryptoSDK`.
/// Whilst remote is more convenient in that it allows changes to the rollout without new app releases,
/// it is not available to all users because it requires data tracking user consent. Remote therefore
/// represents the safer, albeit limited rollout strategy, whereas the local feature flags allows eventually
/// targetting all users, but each target change requires new app release.
///
/// Additionally users can manually enable this feature from the settings if they are not already in the
/// feature group.
@objc class CryptoSDKFeature: NSObject, MXCryptoV2Feature {
@objc static let shared = CryptoSDKFeature()
var isEnabled: Bool {
BWIBuildSettings.shared.useRustEncryption
}
var needsVerificationUpgrade: Bool {
get {
return RiotSettings.shared.showVerificationUpgradeAlert
}
set {
RiotSettings.shared.showVerificationUpgradeAlert = newValue
}
}
private static let FeatureName = "ios-crypto-sdk"
private static let FeatureNameV2 = "ios-crypto-sdk-v2"
private let remoteFeature: RemoteFeaturesClientProtocol
private let localFeature: PhasedRolloutFeature
init(
remoteFeature: RemoteFeaturesClientProtocol = PostHogAnalyticsClient.shared,
localTargetPercentage: Double = 1
) {
var targetPercentage = 0.0
if BWIBuildSettings.shared.useRustEncryption {
targetPercentage = 1.0
}
self.remoteFeature = remoteFeature
self.localFeature = PhasedRolloutFeature(
name: Self.FeatureName,
targetPercentage: targetPercentage
)
}
func enable() {
RiotSettings.shared.enableCryptoSDK = true
Analytics.shared.trackCryptoSDKEnabled()
MXLog.debug("[CryptoSDKFeature] Crypto SDK enabled")
}
func enableIfAvailable(forUserId userId: String!) {
guard !isEnabled else {
MXLog.debug("[CryptoSDKFeature] enableIfAvailable: Feature is already enabled")
return
}
guard let userId else {
MXLog.failure("[CryptoSDKFeature] enableIfAvailable: Missing user id")
return
}
guard isFeatureEnabled(userId: userId) else {
MXLog.debug("[CryptoSDKFeature] enableIfAvailable: Feature is currently not available for this user")
return
}
MXLog.debug("[CryptoSDKFeature] enableIfAvailable: Feature has become available for this user and will be enabled")
enable()
}
@objc func canManuallyEnable(forUserId userId: String!) -> Bool {
guard let userId else {
MXLog.failure("[CryptoSDKFeature] canManuallyEnable: Missing user id")
return false
}
// User can manually enable only if not already within the automatic feature group
return !isFeatureEnabled(userId: userId)
}
@objc func reset() {
RiotSettings.shared.enableCryptoSDK = false
MXLog.debug("[CryptoSDKFeature] Crypto SDK disabled")
}
private func isFeatureEnabled(userId: String) -> Bool {
// This feature includes app version with a bug, and thus will not be rolled out to 100% users
remoteFeature.isFeatureEnabled(Self.FeatureName)
// Second version of the remote feature with a bugfix and released eventually to 100% users
|| remoteFeature.isFeatureEnabled(Self.FeatureNameV2)
// Local feature
|| localFeature.isEnabled(userId: userId)
}
}
+20 -12
View File
@@ -5371,6 +5371,18 @@ public class VectorL10n: NSObject {
public static var roomCreationTitle: String {
return VectorL10n.tr("Vector", "room_creation_title")
}
/// Start DM anyway
public static var roomCreationUserNotFoundPromptInviteAction: String {
return VectorL10n.tr("Vector", "room_creation_user_not_found_prompt_invite_action")
}
/// Unable to find profiles for this Matrix ID. Would you like to start a DM anyway?
public static var roomCreationUserNotFoundPromptMessage: String {
return VectorL10n.tr("Vector", "room_creation_user_not_found_prompt_message")
}
/// Confirmation
public static var roomCreationUserNotFoundPromptTitle: String {
return VectorL10n.tr("Vector", "room_creation_user_not_found_prompt_title")
}
/// A room is already being created. Please wait.
public static var roomCreationWaitForCreation: String {
return VectorL10n.tr("Vector", "room_creation_wait_for_creation")
@@ -6375,6 +6387,10 @@ public class VectorL10n: NSObject {
public static var roomParticipantsInviteAnotherUser: String {
return VectorL10n.tr("Vector", "room_participants_invite_another_user")
}
/// Invite anyway
public static var roomParticipantsInviteAnyway: String {
return VectorL10n.tr("Vector", "room_participants_invite_anyway")
}
/// Malformed ID. Should be an email address or a Matrix ID like '@localpart:domain'
public static var roomParticipantsInviteMalformedId: String {
return VectorL10n.tr("Vector", "room_participants_invite_malformed_id")
@@ -6395,6 +6411,10 @@ public class VectorL10n: NSObject {
public static func roomParticipantsInvitePromptToMsg(_ p1: String, _ p2: String) -> String {
return VectorL10n.tr("Vector", "room_participants_invite_prompt_to_msg", p1, p2)
}
/// Unable to find profiles for this Matrix ID. Are you sure you want to invite %@ to %@?
public static func roomParticipantsInviteUnknownParticipantPromptToMsg(_ p1: String, _ p2: String) -> String {
return VectorL10n.tr("Vector", "room_participants_invite_unknown_participant_prompt_to_msg", p1, p2)
}
/// INVITED
public static var roomParticipantsInvitedSection: String {
return VectorL10n.tr("Vector", "room_participants_invited_section")
@@ -7707,18 +7727,10 @@ public class VectorL10n: NSObject {
public static var settingsLabs: String {
return VectorL10n.tr("Vector", "settings_labs")
}
/// Please be advised that as this feature is still in its experimental stage, it may not function as expected and could potentially have unintended consequences. To revert the feature, simply log out and log back in. Use at your own discretion and with caution.
public static var settingsLabsConfirmCryptoSdk: String {
return VectorL10n.tr("Vector", "settings_labs_confirm_crypto_sdk")
}
/// Create conference calls with jitsi
public static var settingsLabsCreateConferenceWithJitsi: String {
return VectorL10n.tr("Vector", "settings_labs_create_conference_with_jitsi")
}
/// Rust end-to-end encryption (log out to disable)
public static var settingsLabsDisableCryptoSdk: String {
return VectorL10n.tr("Vector", "settings_labs_disable_crypto_sdk")
}
/// End-to-End Encryption
public static var settingsLabsE2eEncryption: String {
return VectorL10n.tr("Vector", "settings_labs_e2e_encryption")
@@ -7731,10 +7743,6 @@ public class VectorL10n: NSObject {
public static var settingsLabsEnableAutoReportDecryptionErrors: String {
return VectorL10n.tr("Vector", "settings_labs_enable_auto_report_decryption_errors")
}
/// Rust end-to-end encryption
public static var settingsLabsEnableCryptoSdk: String {
return VectorL10n.tr("Vector", "settings_labs_enable_crypto_sdk")
}
/// Live location sharing - share current location (active development, and temporarily, locations persist in room history)
public static var settingsLabsEnableLiveLocationSharing: String {
return VectorL10n.tr("Vector", "settings_labs_enable_live_location_sharing")
+11 -11
View File
@@ -834,7 +834,7 @@ extension CallPresenter: JMCallKitListener {
}
func performAnswerCall(UUID: UUID) {
func performAnswerCall(with UUID: UUID) {
guard let widget = jitsiCalls[UUID] else {
return
}
@@ -842,7 +842,7 @@ extension CallPresenter: JMCallKitListener {
displayJitsiCall(withWidget: widget)
}
func performEndCall(UUID: UUID) {
func performEndCall(with UUID: UUID) {
guard let widget = jitsiCalls[UUID] else {
return
}
@@ -857,7 +857,7 @@ extension CallPresenter: JMCallKitListener {
}
}
func performSetMutedCall(UUID: UUID, isMuted: Bool) {
func performSetMutedCall(with UUID: UUID, isMuted: Bool) {
guard let widget = jitsiCalls[UUID] else {
return
}
@@ -868,20 +868,20 @@ extension CallPresenter: JMCallKitListener {
}
}
func performStartCall(UUID: UUID, isVideo: Bool) {
func performStartCall(with UUID: UUID, isVideo: Bool) {
}
func providerDidActivateAudioSession(sessionInfo: AVAudioSession) {
func providerDidActivateAudioSession(with session: AVAudioSession) {
}
func providerDidDeactivateAudioSession(sessionInfo: AVAudioSession) {
func providerDidDeactivateAudioSession(with session: AVAudioSession) {
}
func providerTimedOutPerformingAction(action: CXAction) {
func providerTimedOutPerformingAction(with action: CXAction) {
}
}
@@ -242,7 +242,7 @@ class RiotSharedSettings: NSObject {
let toHour = calender.component(.hour, from: weekday.endTime)
let toMinute = calender.component(.minute, from: weekday.endTime)
let entry: [String: Any] = ["is_enabled": weekday.isEnabled, "from_our": fromHour, "from_minute": fromMinute, "to_hour": toHour, "to_minute": toMinute]
let entry: [String: Any] = ["is_enabled": weekday.isEnabled, "from_hour": fromHour, "from_minute": fromMinute, "to_hour": toHour, "to_minute": toMinute]
entries.append(entry)
}
+1 -1
View File
@@ -274,7 +274,7 @@ extension Analytics {
func trackE2EEError(_ reason: DecryptionFailureReason, context: String) {
let event = AnalyticsEvent.Error(
context: context,
cryptoModule: MXSDKOptions.sharedInstance().enableCryptoSDK ? .Rust : .Native,
cryptoModule: .Rust,
domain: .E2EE,
name: reason.errorName
)
@@ -46,9 +46,6 @@ struct SentryMonitoringClient {
if let message = event.message?.formatted {
event.fingerprint = [message]
}
event.tags = [
"crypto_module": MXSDKOptions.sharedInstance().cryptoModuleId
]
MXLog.debug("[SentryMonitoringClient] Issue detected: \(event)")
return event
}
+23 -245
View File
@@ -34,7 +34,6 @@
#import "ContactDetailsViewController.h"
#import "BugReportViewController.h"
#import "RoomKeyRequestViewController.h"
#import "DecryptionFailureTracker.h"
#import "Tools.h"
@@ -115,11 +114,6 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
id roomKeyRequestObserver;
id roomKeyRequestCancellationObserver;
/**
If any the currently displayed sharing key dialog
*/
RoomKeyRequestViewController *roomKeyRequestViewController;
/**
Incoming key verification requests observers
*/
@@ -580,6 +574,15 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
// bwi: could be a system alert wait for diEnter background
self.isApplicationActiveFromSystemAlert = YES;
// bwi: make sure that the shared user defaults have the current notification times settings before the nse is called
MXSession *session = [AppDelegate theDelegate].mxSessions.firstObject;
if(session) {
RiotSharedSettings *sharedSettings = [[RiotSharedSettings alloc] initWithSession:session];
[sharedSettings fetchNotificationTimes];
[NotificationTimes storeToSharedUserDefaults];
}
}
- (void)applicationDidEnterBackground:(UIApplication *)application
@@ -1888,8 +1891,6 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
// start the call service
[self.callPresenter start];
[self.configuration setupSettingsWhenLoadedFor:mxSession];
// Register to user new device sign in notification
[self registerUserDidSignInOnNewDeviceNotificationForSession:mxSession];
@@ -1898,8 +1899,6 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
// Register to new key verification request
[self registerNewRequestNotificationForSession:mxSession];
[self checkLocalPrivateKeysInSession:mxSession];
[self.pushNotificationService checkPushKitPushersInSession:mxSession];
}
else if (mxSession.state == MXSessionStateRunning)
@@ -2127,9 +2126,6 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
// If any, disable the no VoIP support workaround
[self disableNoVoIPOnMatrixSession:mxSession];
// Disable listening of incoming key share requests
[self disableRoomKeyRequestObserver:mxSession];
// Disable listening of incoming key verification requests
[self disableIncomingKeyVerificationObserver:mxSession];
@@ -2372,9 +2368,6 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
// Clear cache
[self clearCache];
// Reset Crypto SDK configuration (labs flag for which crypto module to use)
[CryptoSDKFeature.shared reset];
// Reset key backup banner preferences
[SecureBackupBannerPreferences.shared reset];
@@ -2488,11 +2481,6 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
case MXSessionStateSyncInProgress:
// Stay in launching during the first server sync if the store is empty.
isLaunching = (mainSession.rooms.count == 0 && launchAnimationContainerView);
if (mainSession.crypto.crossSigning && mainSession.crypto.crossSigning.state == MXCrossSigningStateCrossSigningExists && [mainSession.crypto isKindOfClass:[MXLegacyCrypto class]])
{
[(MXLegacyCrypto *)mainSession.crypto setOutgoingKeyRequestsEnabled:NO onComplete:nil];
}
break;
case MXSessionStateRunning:
self.clearingCache = NO;
@@ -2552,7 +2540,6 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
// This is the time to check existing requests
MXLogDebug(@"[AppDelegate] handleAppState: Check pending verification requests");
[self checkPendingRoomKeyRequests];
[self checkPendingIncomingKeyVerificationsInSession:mainSession];
// TODO: When we will have an application state, we will do all of this in a dedicated initialisation state
@@ -2561,9 +2548,6 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
{
MXLogDebug(@"[AppDelegate] handleAppState: Set up observers for the crypto module");
// Enable listening of incoming key share requests
[self enableRoomKeyRequestObserver:mainSession];
// Enable listening of incoming key verification requests
[self enableIncomingKeyVerificationObserver:mainSession];
}
@@ -2589,25 +2573,24 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
{
MXLogDebug(@"[AppDelegate] showLaunchAnimation");
/* bwi: 4782 removed by nv
// bwi: #4905 show loading animation
UIView *launchLoadingView;
if (MXSDKOptions.sharedInstance.enableStartupProgress)
if (BWIBuildSettings.shared.showBUMLottieAnimation)
{
if (BWIBuildSettings.shared.showBUMLottieAnimation)
{
launchLoadingView = [BUMLaunchLoadingViewController makeView];
} else {
MXSession *mainSession = self.mxSessions.firstObject;
launchLoadingView = [LaunchLoadingView instantiateWithStartupProgress:mainSession.startupProgress];
[(LaunchLoadingView *) launchLoadingView updateWithTheme:ThemeService.shared.theme];
}
launchLoadingView = [BUMLaunchLoadingViewController makeView];
launchLoadingView.frame = window.bounds;
launchLoadingView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[window addSubview:launchLoadingView];
} else {
MXSession *mainSession = self.mxSessions.firstObject;
launchLoadingView = [LaunchLoadingView instantiateWithStartupProgress:mainSession.startupProgress];
[(LaunchLoadingView *) launchLoadingView updateWithTheme:ThemeService.shared.theme];
}
*/
launchLoadingView.frame = window.bounds;
launchLoadingView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[window addSubview:launchLoadingView];
launchAnimationContainerView = launchLoadingView;
/* bwi: 4782 - new code from nv
MXSession *mainSession = self.mxSessions.firstObject;
@@ -2727,38 +2710,6 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
#endif
}
- (void)checkLocalPrivateKeysInSession:(MXSession*)mxSession
{
if (![mxSession.crypto isKindOfClass:[MXLegacyCrypto class]])
{
return;
}
MXLegacyCrypto *crypto = (MXLegacyCrypto *)mxSession.crypto;
MXRecoveryService *recoveryService = mxSession.crypto.recoveryService;
NSUInteger keysCount = 0;
if ([recoveryService hasSecretWithSecretId:MXSecretId.keyBackup])
{
keysCount++;
}
if ([recoveryService hasSecretWithSecretId:MXSecretId.crossSigningUserSigning])
{
keysCount++;
}
if ([recoveryService hasSecretWithSecretId:MXSecretId.crossSigningSelfSigning])
{
keysCount++;
}
if ((keysCount > 0 && keysCount < 3)
|| (mxSession.crypto.crossSigning.canTrustCrossSigning && !mxSession.crypto.crossSigning.canCrossSign))
{
// We should have 3 of them. If not, request them again as mitigation
MXLogDebug(@"[AppDelegate] checkLocalPrivateKeysInSession: request keys because keysCount = %@", @(keysCount));
[crypto requestAllPrivateKeys];
}
}
- (void)authenticationDidComplete
{
[self handleAppState];
@@ -3672,173 +3623,6 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
}
}
#pragma mark - Incoming room key requests handling
- (void)enableRoomKeyRequestObserver:(MXSession*)mxSession
{
roomKeyRequestObserver =
[[NSNotificationCenter defaultCenter] addObserverForName:kMXCryptoRoomKeyRequestNotification
object:mxSession.crypto
queue:[NSOperationQueue mainQueue]
usingBlock:^(NSNotification *notif)
{
[self checkPendingRoomKeyRequestsInSession:mxSession];
}];
roomKeyRequestCancellationObserver =
[[NSNotificationCenter defaultCenter] addObserverForName:kMXCryptoRoomKeyRequestCancellationNotification
object:mxSession.crypto
queue:[NSOperationQueue mainQueue]
usingBlock:^(NSNotification *notif)
{
[self checkPendingRoomKeyRequestsInSession:mxSession];
}];
}
- (void)disableRoomKeyRequestObserver:(MXSession*)mxSession
{
if (roomKeyRequestObserver)
{
[[NSNotificationCenter defaultCenter] removeObserver:roomKeyRequestObserver];
roomKeyRequestObserver = nil;
}
if (roomKeyRequestCancellationObserver)
{
[[NSNotificationCenter defaultCenter] removeObserver:roomKeyRequestCancellationObserver];
roomKeyRequestCancellationObserver = nil;
}
}
// Check if a key share dialog must be displayed for the given session
- (void)checkPendingRoomKeyRequestsInSession:(MXSession*)mxSession
{
if ([UIApplication sharedApplication].applicationState != UIApplicationStateActive)
{
MXLogDebug(@"[AppDelegate] checkPendingRoomKeyRequestsInSession called while the app is not active. Ignore it.");
return;
}
if (![mxSession.crypto isKindOfClass:[MXLegacyCrypto class]])
{
MXLogDebug(@"[AppDelegate] checkPendingRoomKeyRequestsInSession: Only legacy crypto allows manually accepting/rejecting key requests");
return;
}
MXLegacyCrypto *crypto = (MXLegacyCrypto *)mxSession.crypto;
MXWeakify(self);
[crypto pendingKeyRequests:^(MXUsersDevicesMap<NSArray<MXIncomingRoomKeyRequest *> *> *pendingKeyRequests) {
MXStrongifyAndReturnIfNil(self);
MXLogDebug(@"[AppDelegate] checkPendingRoomKeyRequestsInSession: cross-signing state: %ld, pendingKeyRequests.count: %@. Already displayed: %@",
crypto.crossSigning.state,
@(pendingKeyRequests.count),
self->roomKeyRequestViewController ? @"YES" : @"NO");
if (!crypto.crossSigning || crypto.crossSigning.state == MXCrossSigningStateNotBootstrapped)
{
if (self->roomKeyRequestViewController)
{
// Check if the current RoomKeyRequestViewController is still valid
MXSession *currentMXSession = self->roomKeyRequestViewController.mxSession;
NSString *currentUser = self->roomKeyRequestViewController.device.userId;
NSString *currentDevice = self->roomKeyRequestViewController.device.deviceId;
NSArray<MXIncomingRoomKeyRequest *> *currentPendingRequest = [pendingKeyRequests objectForDevice:currentDevice forUser:currentUser];
if (currentMXSession == mxSession && currentPendingRequest.count == 0)
{
MXLogDebug(@"[AppDelegate] checkPendingRoomKeyRequestsInSession: Cancel current dialog");
// The key request has been probably cancelled, remove the popup
[self->roomKeyRequestViewController hide];
self->roomKeyRequestViewController = nil;
}
}
}
if (!self->roomKeyRequestViewController && pendingKeyRequests.count)
{
// Pick the first coming user/device pair
NSString *userId = pendingKeyRequests.userIds.firstObject;
NSString *deviceId = [pendingKeyRequests deviceIdsForUser:userId].firstObject;
// Give the client a chance to refresh the device list
MXWeakify(self);
[crypto downloadKeys:@[userId] forceDownload:NO success:^(MXUsersDevicesMap<MXDeviceInfo *> *usersDevicesInfoMap, NSDictionary<NSString *,MXCrossSigningInfo *> *crossSigningKeysMap) {
MXStrongifyAndReturnIfNil(self);
MXDeviceInfo *deviceInfo = [usersDevicesInfoMap objectForDevice:deviceId forUser:userId];
if (deviceInfo)
{
if (!crypto.crossSigning || crypto.crossSigning.state == MXCrossSigningStateNotBootstrapped)
{
BOOL wasNewDevice = (deviceInfo.trustLevel.localVerificationStatus == MXDeviceUnknown);
void (^openDialog)(void) = ^void()
{
MXLogDebug(@"[AppDelegate] checkPendingRoomKeyRequestsInSession: Open dialog for %@", deviceInfo);
self->roomKeyRequestViewController = [[RoomKeyRequestViewController alloc] initWithDeviceInfo:deviceInfo wasNewDevice:wasNewDevice andMatrixSession:mxSession crypto:crypto onComplete:^{
self->roomKeyRequestViewController = nil;
// Check next pending key request, if any
[self checkPendingRoomKeyRequests];
}];
[self->roomKeyRequestViewController show];
};
// If the device was new before, it's not any more.
if (wasNewDevice)
{
[crypto setDeviceVerification:MXDeviceUnverified forDevice:deviceId ofUser:userId success:openDialog failure:nil];
}
else
{
openDialog();
}
}
else if (deviceInfo.trustLevel.isVerified)
{
[crypto acceptAllPendingKeyRequestsFromUser:userId andDevice:deviceId onComplete:^{
[self checkPendingRoomKeyRequests];
}];
}
else
{
[crypto ignoreAllPendingKeyRequestsFromUser:userId andDevice:deviceId onComplete:^{
[self checkPendingRoomKeyRequests];
}];
}
}
else
{
MXLogDebug(@"[AppDelegate] checkPendingRoomKeyRequestsInSession: No details found for device %@:%@", userId, deviceId);
[crypto ignoreAllPendingKeyRequestsFromUser:userId andDevice:deviceId onComplete:^{
[self checkPendingRoomKeyRequests];
}];
}
} failure:^(NSError *error) {
// Retry later
MXLogDebug(@"[AppDelegate] checkPendingRoomKeyRequestsInSession: Failed to download device keys. Retry");
[self checkPendingRoomKeyRequests];
}];
}
}];
}
// Check all opened MXSessions for key share dialog
- (void)checkPendingRoomKeyRequests
{
for (MXSession *mxSession in mxSessionArray)
{
[self checkPendingRoomKeyRequestsInSession:mxSession];
}
}
#pragma mark - Incoming key verification handling
- (void)enableIncomingKeyVerificationObserver:(MXSession*)mxSession
@@ -3996,12 +3780,6 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
- (void)keyVerificationCoordinatorBridgePresenterDelegateDidComplete:(KeyVerificationCoordinatorBridgePresenter *)coordinatorBridgePresenter otherUserId:(NSString * _Nonnull)otherUserId otherDeviceId:(NSString * _Nonnull)otherDeviceId
{
id<MXCrypto> crypto = coordinatorBridgePresenter.session.crypto;
if ([crypto isKindOfClass:[MXLegacyCrypto class]] && (!crypto.backup.hasPrivateKeyInCryptoStore || !crypto.backup.enabled))
{
MXLogDebug(@"[AppDelegate][MXKeyVerification] requestAllPrivateKeys: Request key backup private keys");
[(MXLegacyCrypto *)crypto setOutgoingKeyRequestsEnabled:YES onComplete:nil];
}
[self dismissKeyVerificationCoordinatorBridgePresenter];
}
@@ -781,12 +781,6 @@ extension AuthenticationCoordinator: AuthenticationServiceDelegate {
// MARK: - KeyVerificationCoordinatorDelegate
extension AuthenticationCoordinator: KeyVerificationCoordinatorDelegate {
func keyVerificationCoordinatorDidComplete(_ coordinator: KeyVerificationCoordinatorType, otherUserId: String, otherDeviceId: String) {
if let crypto = session?.crypto as? MXLegacyCrypto, let backup = crypto.backup,
!backup.hasPrivateKeyInCryptoStore || !backup.enabled {
MXLog.debug("[AuthenticationCoordinator][MXKeyVerification] requestAllPrivateKeys: Request key backup private keys")
crypto.setOutgoingKeyRequestsEnabled(true, onComplete: nil)
}
navigationRouter.dismissModule(animated: true) { [weak self] in
self?.authenticationDidComplete()
}
@@ -235,12 +235,6 @@ extension LegacyAuthenticationCoordinator: AuthenticationViewControllerDelegate
// MARK: - KeyVerificationCoordinatorDelegate
extension LegacyAuthenticationCoordinator: KeyVerificationCoordinatorDelegate {
func keyVerificationCoordinatorDidComplete(_ coordinator: KeyVerificationCoordinatorType, otherUserId: String, otherDeviceId: String) {
if let crypto = session?.crypto as? MXLegacyCrypto, let backup = crypto.backup,
!backup.hasPrivateKeyInCryptoStore || !backup.enabled {
MXLog.debug("[LegacyAuthenticationCoordinator][MXKeyVerification] requestAllPrivateKeys: Request key backup private keys")
crypto.setOutgoingKeyRequestsEnabled(true, onComplete: nil)
}
navigationRouter.dismissModule(animated: true) { [weak self] in
self?.authenticationDidComplete()
}
@@ -68,14 +68,7 @@ class SessionVerificationListener {
return
}
if session.state == .storeDataReady {
if let crypto = session.crypto as? MXLegacyCrypto {
// Do not make key share requests while the "Complete security" is not complete.
// If the device is self-verified, the SDK will restore the existing key backup.
// Then, it will re-enable outgoing key share requests
crypto.setOutgoingKeyRequestsEnabled(false, onComplete: nil)
}
} else if session.state == .running {
if session.state == .running {
unregisterSessionStateChangeNotification()
if let crypto = session.crypto {
@@ -101,7 +94,6 @@ class SessionVerificationListener {
self.completion?(.authenticationIsComplete)
} failure: { error in
MXLog.error("[SessionVerificationListener] sessionStateDidChange: Bootstrap failed", context: error)
(crypto as? MXLegacyCrypto)?.setOutgoingKeyRequestsEnabled(true, onComplete: nil)
self.completion?(.authenticationIsComplete)
}
} else {
@@ -111,12 +103,10 @@ class SessionVerificationListener {
self.completion?(.authenticationIsComplete)
} failure: { error in
MXLog.error("[SessionVerificationListener] sessionStateDidChange: Do not know how to bootstrap cross-signing. Skip it.")
(crypto as? MXLegacyCrypto)?.setOutgoingKeyRequestsEnabled(true, onComplete: nil)
self.completion?(.authenticationIsComplete)
}
}
} else {
(crypto as? MXLegacyCrypto)?.setOutgoingKeyRequestsEnabled(true, onComplete: nil)
self.completion?(.authenticationIsComplete)
}
case .crossSigningExists:
@@ -124,13 +114,10 @@ class SessionVerificationListener {
self.completion?(.needsVerification)
default:
MXLog.debug("[SessionVerificationListener] sessionStateDidChange: Nothing to do")
(crypto as? MXLegacyCrypto)?.setOutgoingKeyRequestsEnabled(true, onComplete: nil)
self.completion?(.authenticationIsComplete)
}
} failure: { [weak self] error in
MXLog.error("[SessionVerificationListener] sessionStateDidChange: Fail to refresh crypto state", context: error)
(crypto as? MXLegacyCrypto)?.setOutgoingKeyRequestsEnabled(true, onComplete: nil)
self?.completion?(.authenticationIsComplete)
}
} else {
+8 -20
View File
@@ -370,28 +370,16 @@ CallAudioRouteMenuViewDelegate>
{
typeof(self) self = weakSelf;
self->currentAlert = nil;
// Acknowledge the existence of all devices
[self startActivityIndicator];
if (![self.mainSession.crypto isKindOfClass:[MXLegacyCrypto class]])
// Retry the call
if (call.isIncoming)
{
MXLogFailure(@"[CallViewController] call: Only legacy crypto supports manual setting of known devices");
return;
[call answer];
}
else
{
[call callWithVideo:call.isVideoCall];
}
[(MXLegacyCrypto *)self.mainSession.crypto setDevicesKnown:unknownDevices complete:^{
[self stopActivityIndicator];
// Retry the call
if (call.isIncoming)
{
[call answer];
}
else
{
[call callWithVideo:call.isVideoCall];
}
}];
}
}]];
@@ -412,10 +412,15 @@ class AllChatsCoordinator: NSObject, SplitViewMasterCoordinatorProtocol {
let avatarView = UserAvatarView(frame: view.bounds.inset(by: avatarInsets))
avatarView.isUserInteractionEnabled = false
avatarView.update(theme: ThemeService.shared().theme)
avatarView.autoresizingMask = [.flexibleHeight, .flexibleWidth]
avatarView.autoresizingMask = [.flexibleTopMargin, .flexibleBottomMargin]
view.addSubview(avatarView)
view.bringSubviewToFront(button)
NSLayoutConstraint.activate([
view.widthAnchor.constraint(equalToConstant: 36),
view.heightAnchor.constraint(equalToConstant: 36)
])
self.avatarMenuView = avatarView
updateAvatarButtonItem()
viewController.navigationItem.leftBarButtonItem = UIBarButtonItem(customView: view)
@@ -1121,8 +1121,7 @@ extension AllChatsViewController: SplitViewMasterViewControllerProtocol {
let title: String
let message: String
if let feature = MXSDKOptions.sharedInstance().cryptoSDKFeature,
feature.isEnabled && feature.needsVerificationUpgrade {
if MXSDKOptions.sharedInstance().cryptoMigrationDelegate?.needsVerificationUpgrade == true {
title = VectorL10n.keyVerificationSelfVerifySecurityUpgradeAlertTitle
message = VectorL10n.keyVerificationSelfVerifySecurityUpgradeAlertMessage
} else {
@@ -35,6 +35,7 @@ static NSString * _Nonnull kRCTTextViewClassName = @"RCTTextView";
Some feature flags defined in https://github.com/jitsi/jitsi-meet/blob/master/react/features/base/flags/constants.js
*/
static NSString * _Nonnull kJitsiFeatureFlagChatEnabled = @"chat.enabled";
static NSString * _Nonnull kJitsiFeatureFlagScreenSharingEnabled = @"ios.screensharing.enabled";
@interface JitsiViewController () <PictureInPicturable, JitsiMeetViewDelegate>
@@ -278,6 +279,7 @@ static NSString * _Nonnull kJitsiFeatureFlagChatEnabled = @"chat.enabled";
andAvatar:avatarUrl];
builder.token = self.jwtToken;
[builder setFeatureFlag:kJitsiFeatureFlagChatEnabled withBoolean:NO];
[builder setFeatureFlag:kJitsiFeatureFlagScreenSharingEnabled withBoolean: YES];
}];
[self.jitsiMeetView join:jitsiMeetConferenceOptions];
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="21507" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="dBQ-CG-VDL">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="21701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="dBQ-CG-VDL">
<device id="retina4_7" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21505"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21679"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
@@ -17,7 +17,7 @@
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="jOh-c7-uod">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<rect key="frame" x="0.0" y="20" width="375" height="647"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="c4q-B8-hPy">
<rect key="frame" x="0.0" y="0.0" width="375" height="358"/>
@@ -51,7 +51,7 @@
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<inset key="contentEdgeInsets" minX="10" minY="0.0" maxX="10" maxY="0.0"/>
<state key="normal" title="Got it">
<state key="normal" title=" ">
<color key="titleColor" red="0.01176470588" green="0.70196078429999997" blue="0.50588235290000005" alpha="1" colorSpace="calibratedRGB"/>
</state>
<connections>
@@ -69,9 +69,6 @@ final class LaunchLoadingView: UIView, NibLoadable, Themable {
extension LaunchLoadingView: MXSessionStartupProgressDelegate {
func sessionDidUpdateStartupProgress(state: MXSessionStartupProgress.State) {
guard MXSDKOptions.sharedInstance().enableStartupProgress else {
return
}
update(with: state)
}
@@ -89,7 +86,11 @@ extension LaunchLoadingView: MXSessionStartupProgressDelegate {
CATransaction.begin()
progressContainer.isHidden = false
progressView.progress = Float(state.progress)
statusLabel.text = state.showDelayWarning ? VectorL10n.launchLoadingDelayWarning : VectorL10n.launchLoadingGeneric
if state.stage == .storeMigration {
statusLabel.text = BWIL10n.bwiLaunchLoadingCryptoStoreMigrationInfo
} else {
statusLabel.text = state.showDelayWarning ? VectorL10n.launchLoadingDelayWarning : VectorL10n.launchLoadingGeneric
}
CATransaction.commit()
}
}
@@ -953,15 +953,7 @@ static NSArray<NSNumber*> *initialSyncSilentErrorsHTTPStatusCodes;
[MXKRoomDataSourceManager removeSharedManagerForMatrixSession:mxSession];
if (clearStore)
{
// Force a reload of device keys at the next session start, unless we are just about to migrate
// all data and device keys into CryptoSDK.
// This will fix potential UISIs other peoples receive for our messages.
if ([mxSession.crypto isKindOfClass:[MXLegacyCrypto class]] && !MXSDKOptions.sharedInstance.enableCryptoSDK)
{
[(MXLegacyCrypto *)mxSession.crypto resetDeviceKeys];
}
{
// Clean other stores
[mxSession.scanManager deleteAllAntivirusScans];
[mxSession.aggregations resetData];
@@ -86,7 +86,7 @@
}
else if (_mxUser)
{
self.displayNameTextField.text = (_mxUser.displayname.length) ? _mxUser.displayname : nil;
self.displayNameTextField.text = (_mxUser.displayname.length) ? _mxUser.displayname : _mxUser.userId;
}
else
{
+1 -1
View File
@@ -65,7 +65,7 @@ class PillTextAttachment: NSTextAttachment {
.avatar(url: roomMember.avatarUrl,
string: roomMember.displayname,
matrixId: roomMember.userId),
.text(roomMember.displayname)
.text(roomMember.displayname ?? roomMember.userId)
],
isHighlighted: isHighlighted,
alpha: 1.0,
@@ -138,4 +138,12 @@ extension ContactsPickerCoordinator: ContactsPickerViewModelCoordinatorDelegate
currentAlert = alert
}
func contactsPickerViewModelDidStartValidatingUser(_ coordinator: ContactsPickerViewModelProtocol) {
contactsPickerViewController?.startActivityIndicator()
}
func contactsPickerViewModelDidEndValidatingUser(_ coordinator: ContactsPickerViewModelProtocol) {
contactsPickerViewController?.stopActivityIndicator()
}
}
@@ -201,12 +201,31 @@ extension ContactsPickerViewModel: ContactsTableViewControllerDelegate {
return
}
// Check for user
if MXTools.isMatrixUserIdentifier(contact.displayName) {
let user = MXUser(userId: contact.displayName)
coordinatorDelegate?.contactsPickerViewModelDidStartValidatingUser(self)
user?.update(fromHomeserverOfMatrixSession: self.room.mxSession, success: { [weak self] in
guard let self = self else { return }
self.coordinatorDelegate?.contactsPickerViewModelDidEndValidatingUser(self)
self.displayInvitePrompt(contact: contact)
}, failure: { [weak self] error in
guard let self = self else { return }
self.coordinatorDelegate?.contactsPickerViewModelDidEndValidatingUser(self)
self.displayInvitePrompt(contact: contact, isUnknownUser: true)
})
} else {
displayInvitePrompt(contact: contact)
}
}
private func displayInvitePrompt(contact: MXKContact, isUnknownUser: Bool = false) {
let roomName = room.displayName ?? VectorL10n.spaceTag
let message = VectorL10n.roomParticipantsInvitePromptToMsg(contact.displayName, roomName)
let message = isUnknownUser ? VectorL10n.roomParticipantsInviteUnknownParticipantPromptToMsg(contact.displayName, roomName) : VectorL10n.roomParticipantsInvitePromptToMsg(contact.displayName, roomName)
let inviteActionTitle = isUnknownUser ? VectorL10n.roomParticipantsInviteAnyway : VectorL10n.invite
coordinatorDelegate?.contactsPickerViewModel(self, display: message, title: VectorL10n.roomParticipantsInvitePromptTitle, actions: [
UIAlertAction(title: VectorL10n.cancel, style: .cancel, handler: nil),
UIAlertAction(title: VectorL10n.invite, style: .default, handler: { [weak self] action in
UIAlertAction(title: VectorL10n.cancel, style: .cancel),
UIAlertAction(title: VectorL10n.invite, style: .default, handler: { [weak self] _ in
self?.invite(contact: contact)
})
])
@@ -23,6 +23,8 @@ protocol ContactsPickerViewModelCoordinatorDelegate: AnyObject {
func contactsPickerViewModelDidEndInvite(_ viewModel: ContactsPickerViewModelProtocol)
func contactsPickerViewModel(_ viewModel: ContactsPickerViewModelProtocol, inviteFailedWithError error: Error?)
func contactsPickerViewModel(_ viewModel: ContactsPickerViewModelProtocol, display message: String, title: String, actions: [UIAlertAction])
func contactsPickerViewModelDidStartValidatingUser(_ coordinator: ContactsPickerViewModelProtocol)
func contactsPickerViewModelDidEndValidatingUser(_ coordinator: ContactsPickerViewModelProtocol)
}
protocol ContactsPickerViewModelProtocol {
+28 -5
View File
@@ -282,7 +282,6 @@ final class RoomCoordinator: NSObject, RoomCoordinatorProtocol {
self.stopLoading()
self.parameters.session.store.store(user)
// Update RoomViewController with found target user
self.roomViewController.displayNewDirectChat(withTargetUser: user, session: self.parameters.session)
} failure: { [weak self] error in
@@ -292,10 +291,18 @@ final class RoomCoordinator: NSObject, RoomCoordinatorProtocol {
MXLog.error("[RoomCoordinator] User does not exist")
// Alert user
self.displayError(message: VectorL10n.roomCreationDmError) { [weak self] in
guard let self = self else { return }
self.delegate?.roomCoordinatorDidCancelNewDirectChat(self)
}
self.displayUserNotFoundPrompt(
invite: { [weak self] in
guard let self = self else { return }
self.parameters.session.store.store(MXUser(userId: userId))
// Update RoomViewController with target user anyway
self.roomViewController.displayNewDirectChat(withTargetUser: user, session: self.parameters.session)
},
cancel: { [weak self] in
guard let self = self else { return }
self.delegate?.roomCoordinatorDidCancelNewDirectChat(self)
}
)
}
}
} else {
@@ -531,6 +538,22 @@ final class RoomCoordinator: NSObject, RoomCoordinatorProtocol {
alert.addAction(action)
toPresentable().present(alert, animated: true)
}
private func displayUserNotFoundPrompt(invite: (() -> Void)? = nil, cancel: (() -> Void)? = nil) {
let title = VectorL10n.roomCreationUserNotFoundPromptTitle
let message = VectorL10n.roomCreationUserNotFoundPromptMessage
let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
let cancelAction = UIAlertAction(title: VectorL10n.cancel, style: .cancel) { _ in
cancel?()
}
let inviteAction = UIAlertAction(title: VectorL10n.roomCreationUserNotFoundPromptInviteAction, style: .default) { _ in
invite?()
}
alert.addAction(cancelAction)
alert.addAction(inviteAction)
toPresentable().present(alert, animated: true)
}
}
// MARK: - RoomIdentifiable
+5 -16
View File
@@ -2099,7 +2099,7 @@ static CGSize kThreadListBarButtonItemImageSize;
{
[userPictureView vc_setRoomAvatarImageWith:self.directChatTargetUser.avatarUrl
roomId:self.directChatTargetUser.userId
displayName:self.directChatTargetUser.displayname
displayName:self.directChatTargetUser.displayname ?: self.directChatTargetUser.userId
mediaManager:self.mainSession.mediaManager];
}
}
@@ -5229,7 +5229,7 @@ static CGSize kThreadListBarButtonItemImageSize;
- (MXMediaManager *)mediaManager
{
return self.roomDataSource.mxSession.mediaManager;
return self.mainSession.mediaManager;
}
- (void)roomInputToolbarViewDidOpenActionMenu:(RoomInputToolbarView*)toolbarView
@@ -6459,21 +6459,10 @@ static CGSize kThreadListBarButtonItemImageSize;
self->currentAlert = nil;
// Acknowledge the existence of all devices
[self startActivityIndicator];
self->unknownDevices = nil;
if (![self.mainSession.crypto isKindOfClass:[MXLegacyCrypto class]])
{
MXLogFailure(@"[RoomVC] eventDidChangeSentState: Only legacy crypto supports manual setting of known devices");
return;
}
[(MXLegacyCrypto *)self.mainSession.crypto setDevicesKnown:self->unknownDevices complete:^{
self->unknownDevices = nil;
[self stopActivityIndicator];
// And resend pending messages
[self resendAllUnsentMessages];
}];
// And resend pending messages
[self resendAllUnsentMessages];
}
}]];
@@ -18,7 +18,7 @@
import UIKit
@objcMembers
class RoomCreationIntroCell: MXKRoomBubbleTableViewCell {
class RoomCreationIntroCell: MXKRoomBubbleTableViewCell, Themable {
// MARK: - Constants
@@ -141,6 +141,11 @@
// Outgoing
[tableView registerClass:VoiceBroadcastPlaybackOutgoingWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:VoiceBroadcastPlaybackOutgoingWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
[tableView registerClass:VoiceBroadcastPlaybackOutgoingWithPaginationTitleBubbleCell.class forCellReuseIdentifier:VoiceBroadcastPlaybackOutgoingWithPaginationTitleBubbleCell.defaultReuseIdentifier];
// bwi: from plain provider, needed because of crashes
[tableView registerClass:VoiceBroadcastPlaybackPlainBubbleCell.class forCellReuseIdentifier:VoiceBroadcastPlaybackPlainBubbleCell.defaultReuseIdentifier];
[tableView registerClass:VoiceBroadcastPlaybackWithoutSenderInfoPlainCell.class forCellReuseIdentifier:VoiceBroadcastPlaybackWithoutSenderInfoPlainCell.defaultReuseIdentifier];
[tableView registerClass:VoiceBroadcastPlaybackWithPaginationTitlePlainCell.class forCellReuseIdentifier:VoiceBroadcastPlaybackWithPaginationTitlePlainCell.defaultReuseIdentifier];
}
- (void)registerVoiceBroadcastRecorderCellsForTableView:(UITableView*)tableView
@@ -27,7 +27,7 @@ import DSWaveformImage
public class VoiceMessageController: NSObject, VoiceMessageToolbarViewDelegate, VoiceMessageAudioRecorderDelegate, VoiceMessageAudioPlayerDelegate {
private enum Constants {
static let maximumAudioRecordingDuration: TimeInterval = 120.0
static let maximumAudioRecordingDuration: TimeInterval = 300.0
static let maximumAudioRecordingLengthReachedThreshold: TimeInterval = 10.0
static let elapsedTimeFormat = "m:ss"
static let fileNameDateFormat = "MM.dd.yyyy HH.mm.ss"
@@ -1,62 +0,0 @@
/*
Copyright 2017 Vector Creations Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import <UIKit/UIKit.h>
#import <MatrixSDK/MatrixSDK.h>
/**
The `RoomKeyRequestViewController` display a modal dialog at the top of the
application asking the user if he wants to share room keys with a user's device.
For the moment, the user is himself.
*/
@interface RoomKeyRequestViewController : NSObject
/**
The UIAlertController instance which handles the dialog.
*/
@property (nonatomic, readonly) UIAlertController *alertController;
@property (nonatomic, readonly) MXSession *mxSession;
@property (nonatomic, readonly) MXDeviceInfo *device;
/**
Initialise an `RoomKeyRequestViewController` instance.
@param deviceInfo the device to share keys to.
@param wasNewDevice flag indicating whether this is the first time we meet the device.
@param session the related matrix session.
@param crypto the related (legacy) crypto module
@param onComplete a block called when the the dialog is closed.
@return the newly created instance.
*/
- (instancetype)initWithDeviceInfo:(MXDeviceInfo*)deviceInfo
wasNewDevice:(BOOL)wasNewDevice
andMatrixSession:(MXSession*)session
crypto:(MXLegacyCrypto *)crypto
onComplete:(void (^)(void))onComplete;
/**
Show the dialog in a modal way.
*/
- (void)show;
/**
Hide the dialog.
*/
- (void)hide;
@end
@@ -1,195 +0,0 @@
/*
Copyright 2017 Vector Creations Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "RoomKeyRequestViewController.h"
#import "GeneratedInterface-Swift.h"
@interface RoomKeyRequestViewController () <KeyVerificationCoordinatorBridgePresenterDelegate>
{
void (^onComplete)(void);
KeyVerificationCoordinatorBridgePresenter *keyVerificationCoordinatorBridgePresenter;
BOOL wasNewDevice;
}
@property (nonatomic, strong) MXLegacyCrypto *crypto;
@end
@implementation RoomKeyRequestViewController
- (instancetype)initWithDeviceInfo:(MXDeviceInfo *)deviceInfo
wasNewDevice:(BOOL)theWasNewDevice
andMatrixSession:(MXSession *)session
crypto:(MXLegacyCrypto *)crypto
onComplete:(void (^)(void))onCompleteBlock
{
self = [super init];
if (self)
{
_mxSession = session;
_crypto = crypto;
_device = deviceInfo;
wasNewDevice = theWasNewDevice;
onComplete = onCompleteBlock;
}
return self;
}
- (void)show
{
// Show it modally on the root view controller
UIViewController *rootViewController = [AppDelegate theDelegate].window.rootViewController;
if (rootViewController)
{
NSString *title = [VectorL10n e2eRoomKeyRequestTitle];
NSString *message;
if (wasNewDevice)
{
message = [VectorL10n e2eRoomKeyRequestMessageNewDevice:_device.displayName];
}
else
{
message = [VectorL10n e2eRoomKeyRequestMessage:_device.displayName];
}
_alertController = [UIAlertController alertControllerWithTitle:title
message:message
preferredStyle:UIAlertControllerStyleAlert];
__weak typeof(self) weakSelf = self;
[_alertController addAction:[UIAlertAction actionWithTitle:[VectorL10n e2eRoomKeyRequestStartVerification]
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
if (weakSelf)
{
typeof(self) self = weakSelf;
self->_alertController = nil;
[self showVerificationView];
}
}]];
[_alertController addAction:[UIAlertAction actionWithTitle:[VectorL10n e2eRoomKeyRequestShareWithoutVerifying]
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
if (weakSelf)
{
typeof(self) self = weakSelf;
self->_alertController = nil;
// Accept the received requests from this device
[self.crypto acceptAllPendingKeyRequestsFromUser:self.device.userId andDevice:self.device.deviceId onComplete:^{
self->onComplete();
}];
}
}]];
[_alertController addAction:[UIAlertAction actionWithTitle:[VectorL10n e2eRoomKeyRequestIgnoreRequest]
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
if (weakSelf)
{
typeof(self) self = weakSelf;
self->_alertController = nil;
// Ignore all pending requests from this device
[self.crypto ignoreAllPendingKeyRequestsFromUser:self.device.userId andDevice:self.device.deviceId onComplete:^{
self->onComplete();
}];
}
}]];
[rootViewController presentViewController:_alertController animated:YES completion:nil];
}
}
- (void)hide
{
if (_alertController)
{
[_alertController dismissViewControllerAnimated:YES completion:nil];
_alertController = nil;
}
}
- (void)showVerificationView
{
// Show it modally on the root view controller
UIViewController *rootViewController = [AppDelegate theDelegate].window.rootViewController;
if (rootViewController)
{
keyVerificationCoordinatorBridgePresenter = [[KeyVerificationCoordinatorBridgePresenter alloc] initWithSession:_mxSession];
keyVerificationCoordinatorBridgePresenter.delegate = self;
[keyVerificationCoordinatorBridgePresenter presentFrom:rootViewController otherUserId:_device.userId otherDeviceId:_device.deviceId animated:YES];
}
}
#pragma mark - DeviceVerificationCoordinatorBridgePresenterDelegate
- (void)keyVerificationCoordinatorBridgePresenterDelegateDidComplete:(KeyVerificationCoordinatorBridgePresenter *)coordinatorBridgePresenter otherUserId:(NSString * _Nonnull)otherUserId otherDeviceId:(NSString * _Nonnull)otherDeviceId
{
[self dismissKeyVerificationCoordinatorBridgePresenter];
}
- (void)keyVerificationCoordinatorBridgePresenterDelegateDidCancel:(KeyVerificationCoordinatorBridgePresenter * _Nonnull)coordinatorBridgePresenter
{
[self dismissKeyVerificationCoordinatorBridgePresenter];
}
- (void)dismissKeyVerificationCoordinatorBridgePresenter
{
[keyVerificationCoordinatorBridgePresenter dismissWithAnimated:YES completion:nil];
keyVerificationCoordinatorBridgePresenter = nil;
// Check device new status
[self.crypto downloadKeys:@[self.device.userId] forceDownload:NO success:^(MXUsersDevicesMap<MXDeviceInfo *> *usersDevicesInfoMap, NSDictionary<NSString *,MXCrossSigningInfo *> *crossSigningKeysMap) {
MXDeviceInfo *deviceInfo = [usersDevicesInfoMap objectForDevice:self.device.deviceId forUser:self.device.userId];
if (deviceInfo && deviceInfo.trustLevel.localVerificationStatus == MXDeviceVerified)
{
// Accept the received requests from this device
// As the device is now verified, all other key requests will be automatically accepted.
[self.crypto acceptAllPendingKeyRequestsFromUser:self.device.userId andDevice:self.device.deviceId onComplete:^{
self->onComplete();
}];
}
else
{
// Come back to self.alertController - ie, reopen it
[self show];
}
} failure:^(NSError *error) {
// Should not happen (the device is in the crypto db)
[self show];
}];
}
@end
+4 -51
View File
@@ -232,8 +232,7 @@ typedef NS_ENUM(NSUInteger, LABS_ENABLE)
LABS_ENABLE_NEW_SESSION_MANAGER,
LABS_ENABLE_NEW_CLIENT_INFO_FEATURE,
LABS_ENABLE_WYSIWYG_COMPOSER,
LABS_ENABLE_VOICE_BROADCAST,
LABS_ENABLE_CRYPTO_SDK
LABS_ENABLE_VOICE_BROADCAST
};
typedef NS_ENUM(NSUInteger, SECURITY)
@@ -765,11 +764,6 @@ ChangePasswordCoordinatorBridgePresenterDelegate>
[sectionLabs addRowWithTag:LABS_ENABLE_NEW_SESSION_MANAGER];
}
/* bwi: disabled for our apps
if ([CryptoSDKFeature.shared canManuallyEnableForUserId:self.mainSession.myUserId])
{
[sectionLabs addRowWithTag:LABS_ENABLE_CRYPTO_SDK];
}
[sectionLabs addRowWithTag:LABS_ENABLE_RINGING_FOR_GROUP_CALLS_INDEX];
[sectionLabs addRowWithTag:LABS_ENABLE_THREADS_INDEX];
[sectionLabs addRowWithTag:LABS_ENABLE_AUTO_REPORT_DECRYPTION_ERRORS];
@@ -2976,18 +2970,6 @@ ChangePasswordCoordinatorBridgePresenterDelegate>
[labelAndSwitchCell.mxkSwitch addTarget:self action:@selector(toggleEnableVoiceBroadcastFeature:) forControlEvents:UIControlEventTouchUpInside];
cell = labelAndSwitchCell;
}
else if (row == LABS_ENABLE_CRYPTO_SDK)
{
MXKTableViewCellWithLabelAndSwitch *labelAndSwitchCell = [self getLabelAndSwitchCell:tableView forIndexPath:indexPath];
BOOL isEnabled = MXSDKOptions.sharedInstance.enableCryptoSDK;
labelAndSwitchCell.mxkLabel.text = isEnabled ? VectorL10n.settingsLabsDisableCryptoSdk : VectorL10n.settingsLabsEnableCryptoSdk;
labelAndSwitchCell.mxkSwitch.on = isEnabled;
[labelAndSwitchCell.mxkSwitch setEnabled:!isEnabled];
labelAndSwitchCell.mxkSwitch.onTintColor = ThemeService.shared.theme.tintColor;
[labelAndSwitchCell.mxkSwitch addTarget:self action:@selector(enableCryptoSDKFeature:) forControlEvents:UIControlEventTouchUpInside];
cell = labelAndSwitchCell;
}
}
@@ -3044,12 +3026,7 @@ ChangePasswordCoordinatorBridgePresenterDelegate>
downtimeCell.textLabel.text = [self bwiDowntimeCellText];
downtimeCell.textLabel.textColor = [self bwiDowntimeTextColor];
downtimeCell.textLabel.lineBreakMode = NSLineBreakByWordWrapping;
// bwi: with descriptions coming soon we need to do this dynamically
if ([[[ServerDowntimeDefaultService alloc] init] isSameDay]) {
downtimeCell.textLabel.numberOfLines = 6;
} else {
downtimeCell.textLabel.numberOfLines = 7;
}
downtimeCell.textLabel.numberOfLines = 0;
cell = downtimeCell;
@@ -3066,7 +3043,7 @@ ChangePasswordCoordinatorBridgePresenterDelegate>
downtimeCell.textLabel.text = [BWIL10n bwiOutdatedSettingsMessage:AppInfo.current.displayName];
downtimeCell.textLabel.textColor = [UIColor blackColor];
downtimeCell.textLabel.lineBreakMode = NSLineBreakByWordWrapping;
downtimeCell.textLabel.numberOfLines = 5;
downtimeCell.textLabel.numberOfLines = 0;
cell = downtimeCell;
}
@@ -3879,30 +3856,6 @@ ChangePasswordCoordinatorBridgePresenterDelegate>
RiotSettings.shared.enableVoiceBroadcast = sender.isOn;
}
- (void)enableCryptoSDKFeature:(UISwitch *)sender
{
[currentAlert dismissViewControllerAnimated:NO completion:nil];
UIAlertController *confirmationAlert = [UIAlertController alertControllerWithTitle:VectorL10n.settingsLabsEnableCryptoSdk
message:VectorL10n.settingsLabsConfirmCryptoSdk
preferredStyle:UIAlertControllerStyleAlert];
MXWeakify(self);
[confirmationAlert addAction:[UIAlertAction actionWithTitle:[VectorL10n cancel] style:UIAlertActionStyleCancel handler:^(UIAlertAction * action) {
MXStrongifyAndReturnIfNil(self);
self->currentAlert = nil;
[sender setOn:NO animated:YES];
}]];
[confirmationAlert addAction:[UIAlertAction actionWithTitle:[VectorL10n continue] style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) {
[CryptoSDKFeature.shared enable];
[[AppDelegate theDelegate] reloadMatrixSessions:YES];
}]];
[self presentViewController:confirmationAlert animated:YES completion:nil];
currentAlert = confirmationAlert;
}
- (void)togglePinRoomsWithMissedNotif:(UISwitch *)sender
{
RiotSettings.shared.pinRoomsWithMissedNotificationsOnHome = sender.isOn;
@@ -5297,7 +5250,7 @@ ChangePasswordCoordinatorBridgePresenterDelegate>
#pragma mark - bwi Messenger Additions
- (NSString*) bwiDowntimeCellText {
NSString *downtimeText = [NSString stringWithFormat:@"\n%@\n\n", [[[ServerDowntimeDefaultService alloc] init] downtimeText]];
NSString *downtimeText = [NSString stringWithFormat:@"\n%@\n", [[[ServerDowntimeDefaultService alloc] init] downtimeText]];
return downtimeText;
}
@@ -273,22 +273,12 @@
- (IBAction)onDone:(id)sender
{
// Acknowledge the existence of all devices before leaving this screen
[self startActivityIndicator];
if (![self.mainSession.crypto isKindOfClass:[MXLegacyCrypto class]])
[self dismissViewControllerAnimated:YES completion:nil];
if (self->onCompleteBlock)
{
MXLogFailure(@"[UsersDevicesViewController] onDone: Only legacy crypto supports manual setting of known devices");
return;
self->onCompleteBlock(YES);
}
[(MXLegacyCrypto *)mxSession.crypto setDevicesKnown:usersDevices complete:^{
[self stopActivityIndicator];
[self dismissViewControllerAnimated:YES completion:nil];
if (self->onCompleteBlock)
{
self->onCompleteBlock(YES);
}
}];
}
- (IBAction)onCancel:(id)sender
+4
View File
@@ -4,6 +4,10 @@
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>RTCAppGroupIdentifier</key>
<string>$(APPLICATION_GROUP_IDENTIFIER)</string>
<key>RTCScreenSharingExtension</key>
<string>$(BROADCAST_UPLOAD_EXTENSION_BUNDLE_IDENTIFIER)</string>
<key>CFBundleDisplayName</key>
<string>$(BUNDLE_DISPLAY_NAME)</string>
<key>CFBundleDocumentTypes</key>
+1
View File
@@ -49,6 +49,7 @@ targets:
- package: Lottie
- package: WysiwygComposer
- package: DeviceKit
- package: DTCoreText
configFiles:
Debug: Debug.xcconfig
+1
View File
@@ -49,6 +49,7 @@ targets:
- package: Lottie
- package: WysiwygComposer
- package: DeviceKit
- package: DTCoreText
configFiles:
Debug: Debug.xcconfig
+1
View File
@@ -49,6 +49,7 @@ targets:
- package: Lottie
- package: WysiwygComposer
- package: DeviceKit
- package: DTCoreText
configFiles:
Debug: Debug.xcconfig
+1
View File
@@ -37,6 +37,7 @@ targets:
- target: RiotShareExtension
# - target: SiriIntents
- target: RiotNSE
- target: BroadcastUploadExtension
- target: DesignKit
- target: CommonKit
- package: AnalyticsEvents
+98 -41
View File
@@ -42,7 +42,6 @@ class NotificationService: UNNotificationServiceExtension {
private var ongoingVoIPPushRequests: [String: Bool] = [:]
private var userAccount: MXKAccount?
private var isCryptoSDKEnabled = false
/// Best attempt contents. Will be updated incrementally, if something fails during the process, this best attempt content will be showed as notification. Keys are eventId's
private var bestAttemptContents: [String: UNMutableNotificationContent] = [:]
@@ -121,14 +120,6 @@ class NotificationService: UNNotificationServiceExtension {
return
}
// check if the event arrived outside the user defined working time for this room
guard !isRoomMuted(roomID: roomId) else {
// it's not a Matrix notification, do not change the content
MXLog.debug("[NotificationService] didReceiveRequest: This is not a Matrix notification.")
contentHandler(UNNotificationContent())
return
}
// save this content as fallback content
guard let content = request.content.mutableCopy() as? UNMutableNotificationContent else {
return
@@ -146,10 +137,12 @@ class NotificationService: UNNotificationServiceExtension {
// setup user account
setup(withRoomId: roomId, eventId: eventId) {
// preprocess the payload, will attempt to fetch room display name
self.preprocessPayload(forEventId: eventId, roomId: roomId)
// fetch the event first
self.fetchAndProcessEvent(withEventId: eventId, roomId: roomId)
do {
try self.preprocessPayload(forEventId: eventId, roomId: roomId) // fetch displayname and check against notification times
self.fetchAndProcessEvent(withEventId: eventId, roomId: roomId) // decrypt and parse
} catch {
contentHandler(UNNotificationContent())
}
}
}
@@ -192,20 +185,60 @@ class NotificationService: UNNotificationServiceExtension {
}
}
private func isGlobalSettingsNotificationTimesToggleOn() -> Bool {
let sharedUserDefaults = MXKAppSettings.standard().sharedUserDefaults
guard let data = sharedUserDefaults?.data(forKey: NotificationTimes.sharedUserDefaultsKey) else {
return false
}
guard let notificationTimes = try? JSONDecoder().decode(NotificationTimes.self, from: data) else {
return false
}
return notificationTimes.isEnabled
}
private func isRoomMuted(roomID: String) -> Bool {
private func isRoomSettingsNotificationTimesToggleOn(roomId: String, isDirect: Bool) -> Bool {
let sharedUserDefaults = MXKAppSettings.standard().sharedUserDefaults
guard let data = sharedUserDefaults?.data(forKey: NotificationTimes.sharedUserDefaultsKey) else {
return false
}
guard let notificationTimes = try? JSONDecoder().decode(NotificationTimes.self, from: data) else {
return false
}
if isDirect {
return notificationTimes.rooms[roomId] == true
} else {
return notificationTimes.rooms[roomId] != false
}
}
private func notificationTimeCheckPassed(roomId: String, isDirect: Bool) -> Bool {
guard isGlobalSettingsNotificationTimesToggleOn() else {
return true
}
guard isRoomSettingsNotificationTimesToggleOn(roomId: roomId, isDirect: isDirect) else {
return true
}
return isNotificationTimeEnabled(for: Date())
}
private func isNotificationTimeEnabled(for date: Date) -> Bool {
let sharedUserDefaults = MXKAppSettings.standard().sharedUserDefaults
if #available(iOSApplicationExtension 14.0, *) {
guard let data = sharedUserDefaults?.data(forKey: NotificationTimes.sharedUserDefaultsKey), let notificationTimes = try? JSONDecoder().decode(NotificationTimes.self, from: data) else {
return false
guard let data = sharedUserDefaults?.data(forKey: NotificationTimes.sharedUserDefaultsKey) else {
return true
}
guard let notificationTimes = try? JSONDecoder().decode(NotificationTimes.self, from: data) else {
return true
}
let now = Date()
let calendar = Calendar.current
let weekday: NotificationTimesWeekday
switch calendar.component(.weekday, from: now) {
switch calendar.component(.weekday, from: date) {
case 1: // sunday
weekday = notificationTimes.weekday(index: 6)
case 2: // monday
@@ -222,12 +255,18 @@ class NotificationService: UNNotificationServiceExtension {
weekday = notificationTimes.weekday(index: 5)
default:
MXLog.error("[NotificationService] isRoomMuted failed because of an invalid day component.")
return false
return true
}
return notificationTimes.isEnabled && weekday.isEnabled && weekday.startTime <= now && weekday.endTime >= now
let nowComponents = calendar.dateComponents([.hour, .minute], from: date)
if let hour = nowComponents.hour, let minute = nowComponents.minute {
let checkTime = Date.from(hour: hour, minute: minute)
return notificationTimes.isEnabled && weekday.isEnabled && weekday.startTime <= checkTime && weekday.endTime >= checkTime
} else {
return true
}
} else {
return false
return true
}
}
@@ -269,13 +308,12 @@ class NotificationService: UNNotificationServiceExtension {
self.userAccount = MXKAccountManager.shared()?.activeAccounts.first
if let userAccount = userAccount {
Self.backgroundServiceInitQueue.sync {
if hasChangedCryptoSDK() || NotificationService.backgroundSyncService?.credentials != userAccount.mxCredentials {
if NotificationService.backgroundSyncService?.credentials != userAccount.mxCredentials {
MXLog.debug("[NotificationService] setup: MXBackgroundSyncService init: BEFORE")
self.logMemory()
NotificationService.backgroundSyncService = MXBackgroundSyncService(
withCredentials: userAccount.mxCredentials,
isCryptoSDKEnabled: isCryptoSDKEnabled,
persistTokenDataHandler: { persistTokenDataHandler in
MXKAccountManager.shared().readAndWriteCredentials(persistTokenDataHandler)
}, unauthenticatedHandler: { error, softLogout, refreshTokenAuth, completion in
@@ -292,32 +330,50 @@ class NotificationService: UNNotificationServiceExtension {
}
}
/// Determine whether we have switched from using crypto v1 to v2 or vice versa which will require
/// rebuilding `MXBackgroundSyncService`
private func hasChangedCryptoSDK() -> Bool {
guard isCryptoSDKEnabled != MXSDKOptions.sharedInstance().enableCryptoSDK else {
return false
enum NSEError: Error, LocalizedError {
case isProtectionSet
case roomSummaryNotAvailable
case mutedBecauseOfNotificationTimes
case displayNameNotAvailable
public var errorDescription: String? {
switch self {
case .isProtectionSet:
return "isProtectionSet"
case .roomSummaryNotAvailable:
return "roomSummaryNotAvailable"
case .mutedBecauseOfNotificationTimes:
return "isProtectionSet"
case .displayNameNotAvailable:
return "isProtectionSet"
}
}
isCryptoSDKEnabled = MXSDKOptions.sharedInstance().enableCryptoSDK
return true
}
/// Attempts to preprocess payload and attach room display name to the best attempt content
/// - Parameters:
/// - eventId: Event identifier to mutate best attempt content
/// - roomId: Room identifier to fetch display name
private func preprocessPayload(forEventId eventId: String, roomId: String) {
if localAuthenticationService.isProtectionSet {
MXLog.debug("[NotificationService] preprocessPayload: Do not preprocess because app protection is set")
return
private func preprocessPayload(forEventId eventId: String, roomId: String) throws {
// If a room summary is available, use the displayname for the best attempt title.
guard let roomSummary = NotificationService.backgroundSyncService.roomSummary(forRoomId: roomId) else {
throw NSEError.roomSummaryNotAvailable
}
// If a room summary is available, use the displayname for the best attempt title.
guard let roomSummary = NotificationService.backgroundSyncService.roomSummary(forRoomId: roomId) else { return }
guard let roomDisplayName = roomSummary.displayName else { return }
bestAttemptContents[eventId]?.title = roomDisplayName
guard notificationTimeCheckPassed(roomId: roomId, isDirect: roomSummary.isDirect) else {
throw NSEError.mutedBecauseOfNotificationTimes
}
// At this stage we don't know the message type, so leave the body as set in didReceive.
if localAuthenticationService.isProtectionSet {
MXLog.debug("[NotificationService] preprocessPayload: Do not preprocess because app protection is set")
guard let roomDisplayName = roomSummary.displayName else {
throw NSEError.displayNameNotAvailable
}
bestAttemptContents[eventId]?.title = roomDisplayName
// At this stage we don't know the message type, so leave the body as set in didReceive.
}
}
private func fetchAndProcessEvent(withEventId eventId: String, roomId: String) {
@@ -1014,6 +1070,7 @@ class NotificationService: UNNotificationServiceExtension {
private extension MXPushRule {
var dontNotify: Bool {
let actions = (actions as? [MXPushRuleAction]) ?? []
return actions.contains { $0.actionType == MXPushRuleActionTypeDontNotify }
// Support for MSC3987: The dont_notify push rule action is deprecated and replaced by an empty actions list.
return actions.isEmpty || actions.contains { $0.actionType == MXPushRuleActionTypeDontNotify }
}
}
+1
View File
@@ -10,5 +10,6 @@
<array>
<string>$(KEYCHAIN_ACCESS_GROUP)</string>
</array>
<key>com.apple.developer.usernotifications.filtering</key><true/>
</dict>
</plist>
-5
View File
@@ -102,11 +102,6 @@ static MXSession *fakeSession;
[session setStore:self.fileStore success:^{
MXStrongifyAndReturnIfNil(session);
if ([session.crypto isKindOfClass:[MXLegacyCrypto class]])
{
((MXLegacyCrypto *)session.crypto).warnOnUnknowDevices = NO; // Do not warn for unknown devices. We have cross-signing now
}
self.selectedRooms = [NSMutableArray array];
for (NSString *roomIdentifier in roomIdentifiers) {
MXRoom *room = [MXRoom loadRoomFromStore:self.fileStore withRoomId:roomIdentifier matrixSession:session];
@@ -267,17 +267,6 @@ class QRLoginService: NSObject, QRLoginServiceProtocol {
let session = sessionCreator.createSession(credentials: credentials, client: client, removeOtherAccounts: false)
// MXLog.debug("[QRLoginService] Session created without E2EE support. Inform the interlocutor of finishing")
// guard let requestData = try? JSONEncoder().encode(QRLoginRendezvousPayload(type: .loginFinish, outcome: .success)),
// case .success = await rendezvousService.send(data: requestData) else {
// await teardownRendezvous(state: .failed(error: .rendezvousFailed))
// return
// }
//
// MXLog.debug("[QRLoginService] Login flow finished, returning session")
// state = .completed(session: session, securityCompleted: false)
// return
let cryptoResult = await withCheckedContinuation { continuation in
session.enableCrypto(true) { response in
continuation.resume(returning: response)
@@ -102,7 +102,7 @@ final class MXRoomNotificationSettingsService: RoomNotificationSettingsServiceTy
}
// if the user defined one, use it
if rule.actionsContains(actionType: MXPushRuleActionTypeDontNotify) {
if rule.dontNotify {
enablePushRule(rule: rule, completion: completion)
} else {
removePushRule(rule: rule) {
@@ -136,7 +136,7 @@ final class MXRoomNotificationSettingsService: RoomNotificationSettingsServiceTy
}
// if the user defined one, use it
if rule.actionsContains(actionType: MXPushRuleActionTypeDontNotify) {
if rule.dontNotify {
enablePushRule(rule: rule, completion: completion)
} else {
removePushRule(rule: rule) {
@@ -261,7 +261,7 @@ public extension MXRoom {
// Check whether an override rule has been defined with the roomm id as rule id.
// This kind of rule is created to mute the room
guard let rule = overridePushRule,
rule.actionsContains(actionType: MXPushRuleActionTypeDontNotify),
rule.dontNotify,
rule.conditionIsEnabled(kind: .eventMatch, for: roomId) else {
return false
}
@@ -271,7 +271,7 @@ public extension MXRoom {
var isMentionsOnly: Bool {
// Check push rules at room level
guard let rule = roomPushRule else { return false }
return rule.enabled && rule.actionsContains(actionType: MXPushRuleActionTypeDontNotify)
return rule.enabled && rule.dontNotify
}
}
@@ -57,7 +57,7 @@ final class PollHistoryCoordinator: NSObject, Coordinator, Presentable {
func showPollDetail(_ poll: TimelinePollDetails) {
guard let event = parameters.room.mxSession.store.event(withEventId: poll.id, inRoom: parameters.room.roomId),
let detailCoordinator: PollHistoryDetailCoordinator = try? .init(parameters: .init(event: event, poll: poll, room: parameters.room)) else {
let detailCoordinator: PollHistoryDetailCoordinator = try? .init(parameters: .init(event: event, poll: poll, room: parameters.room, navigationRouter: navigationRouter)) else {
pollHistoryViewModel.context.alertInfo = .init(id: true, title: VectorL10n.settingsDiscoveryErrorMessage)
return
}
@@ -68,8 +68,20 @@ final class PollHistoryCoordinator: NSObject, Coordinator, Presentable {
}
add(childCoordinator: detailCoordinator)
detailCoordinator.start()
toPresentable().present(detailCoordinator.toPresentable(), animated: true)
// bwi #4484: Participant details need a navigation controller not a presented VC
if BWIBuildSettings.shared.bwiPollParticipantsInHistory {
if navigationRouter.modules.isEmpty == false {
navigationRouter.push(detailCoordinator, animated: true, popCompletion: nil)
} else {
navigationRouter.setRootModule(detailCoordinator, popCompletion: nil)
}
detailCoordinator.start()
} else {
detailCoordinator.start()
toPresentable().present(detailCoordinator.toPresentable(), animated: true)
}
}
func toPresentable() -> UIViewController {
@@ -19,10 +19,12 @@ import CommonKit
import MatrixSDK
import SwiftUI
// bwi #4484: Poi history needs to pass a navigation router to show participants
struct PollHistoryDetailCoordinatorParameters {
let event: MXEvent
let poll: TimelinePollDetails
let room: MXRoom
let navigationRouter: NavigationRouterType
}
final class PollHistoryDetailCoordinator: Coordinator, Presentable {
@@ -36,7 +38,7 @@ final class PollHistoryDetailCoordinator: Coordinator, Presentable {
init(parameters: PollHistoryDetailCoordinatorParameters) throws {
self.parameters = parameters
let timelinePollCoordinator = try TimelinePollCoordinator(parameters: .init(session: parameters.room.mxSession, room: parameters.room, pollEvent: parameters.event))
let timelinePollCoordinator = try TimelinePollCoordinator(parameters: .init(session: parameters.room.mxSession, room: parameters.room, pollEvent: parameters.event, showParticipantButton: BWIBuildSettings.shared.bwiPollParticipantsInHistory), navigationRouter: parameters.navigationRouter)
let viewModel = PollHistoryDetailViewModel(poll: parameters.poll)
let view = PollHistoryDetail(viewModel: viewModel.context, contentPoll: timelinePollCoordinator.toView())
@@ -26,8 +26,19 @@ struct PollHistoryDetail: View {
@ObservedObject var viewModel: PollHistoryDetailViewModel.Context
var contentPoll: any View
// bwi #4484: poi participants in history needs a pushed not presented view: Navigation title looks better this way in that case
var body: some View {
navigation
if BWIBuildSettings.shared.bwiPollParticipantsInHistory {
navigation
.accentColor(theme.colors.accent)
.navigationViewStyle(StackNavigationViewStyle())
.navigationTitle(navigationTitle)
.navigationBarTitleDisplayMode(.inline)
} else {
navigation
.accentColor(theme.colors.accent)
}
}
private var navigation: some View {
@@ -50,11 +61,17 @@ struct PollHistoryDetail: View {
.font(theme.fonts.caption1)
.padding([.top])
.accessibilityIdentifier("PollHistoryDetail.date")
AnyView(contentPoll)
.navigationTitle(navigationTitle)
.navigationBarTitleDisplayMode(.inline)
.navigationBarBackButtonHidden(true)
.navigationBarItems(leading: backButton, trailing: doneButton)
if BWIBuildSettings.shared.bwiPollParticipantsInHistory {
AnyView(contentPoll)
} else {
AnyView(contentPoll)
.navigationTitle(navigationTitle)
.navigationBarTitleDisplayMode(.inline)
.navigationBarBackButtonHidden(true)
.navigationBarItems(leading: backButton, trailing: doneButton)
}
viewInTimeline
}
}
@@ -93,6 +93,7 @@ struct PollHistory: View {
} label: {
Text(VectorL10n.pollHistoryLoadMore)
.font(theme.fonts.body)
.foregroundColor(Color(ThemeService.shared().theme.tintColor))
}
.accessibilityIdentifier("PollHistory.loadMore")
.disabled(viewModel.viewState.isLoading)
@@ -22,6 +22,7 @@ struct TimelinePollCoordinatorParameters {
let session: MXSession
let room: MXRoom
let pollEvent: MXEvent
let showParticipantButton: Bool
}
final class TimelinePollCoordinator: Coordinator, Presentable, PollAggregatorDelegate {
@@ -48,7 +49,7 @@ final class TimelinePollCoordinator: Coordinator, Presentable, PollAggregatorDel
self.parameters = parameters
self.navigationRouter = navigationRouter
viewModel = TimelinePollViewModel(timelinePollDetailsState: .loading)
viewModel = TimelinePollViewModel(timelinePollDetailsState: .loading, showParticipantsButton: parameters.showParticipantButton)
try pollAggregator = PollAggregator(session: parameters.session, room: parameters.room, pollEvent: parameters.pollEvent, delegate: self)
viewModel.completion = { [weak self] result in
@@ -48,7 +48,7 @@ class TimelinePollProvider: NSObject {
return coordinator.toPresentable()
}
let parameters = TimelinePollCoordinatorParameters(session: session, room: room, pollEvent: event)
let parameters = TimelinePollCoordinatorParameters(session: session, room: room, pollEvent: event, showParticipantButton: true)
guard let coordinator = try? TimelinePollCoordinator(parameters: parameters, navigationRouter: navigationRouter ) else {
return messageViewController(for: event)
}
@@ -115,6 +115,7 @@ struct TimelinePollViewState: BindableState {
struct TimelinePollViewStateBindings {
var alertInfo: AlertInfo<TimelinePollAlertType>?
var showParticipantButton: Bool
}
enum TimelinePollAlertType {
@@ -30,8 +30,8 @@ class TimelinePollViewModel: TimelinePollViewModelType, TimelinePollViewModelPro
// MARK: - Setup
init(timelinePollDetailsState: TimelinePollDetailsState) {
super.init(initialViewState: TimelinePollViewState(pollState: timelinePollDetailsState, bindings: TimelinePollViewStateBindings()))
init(timelinePollDetailsState: TimelinePollDetailsState, showParticipantsButton: Bool = true) {
super.init(initialViewState: TimelinePollViewState(pollState: timelinePollDetailsState, bindings: TimelinePollViewStateBindings( showParticipantButton: showParticipantsButton)))
}
// MARK: - Public
@@ -74,7 +74,7 @@ struct TimelinePollView: View {
.font(theme.fonts.footnote)
.foregroundColor(theme.colors.tertiaryContent)
if poll.shouldShowShowParticipantsButton {
if poll.shouldShowShowParticipantsButton && viewModel.viewState.bindings.showParticipantButton {
Button(action: {
viewModel.send(viewAction:.showParticipants)
})
@@ -82,6 +82,10 @@ extension MXPushRule: NotificationPushRuleType {
}
var dontNotify: Bool {
getAction(actionType: MXPushRuleActionTypeDontNotify) != nil
guard let actions = actions as? [MXPushRuleAction] else {
return true
}
// Support for MSC3987: The dont_notify push rule action is deprecated and replaced by an empty actions list.
return actions.isEmpty || getAction(actionType: MXPushRuleActionTypeDontNotify) != nil
}
}

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