Merge pull request #4314 from vector-im/release/1.3.6/release
Release 1.3.6
8
.github/workflows/ci.yml
vendored
|
@ -9,6 +9,10 @@ on:
|
|||
# Allows you to run this workflow manually from the Actions tab
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
# Make the git branch for a PR available to our Fastfile
|
||||
MX_GIT_BRANCH: ${{ github.event.pull_request.head.ref }}
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build
|
||||
|
@ -39,7 +43,7 @@ jobs:
|
|||
bundle config path vendor/bundle
|
||||
bundle install --jobs 4 --retry 3
|
||||
- name: Use right MatrixKit and MatrixSDK versions
|
||||
run: bundle exec fastlane point_dependencies_to_pending_releases
|
||||
run: bundle exec fastlane point_dependencies_to_related_branches
|
||||
|
||||
# Main step
|
||||
- name: Build iOS simulator
|
||||
|
@ -75,7 +79,7 @@ jobs:
|
|||
bundle config path vendor/bundle
|
||||
bundle install --jobs 4 --retry 3
|
||||
- name: Use right MatrixKit and MatrixSDK versions
|
||||
run: bundle exec fastlane point_dependencies_to_pending_releases
|
||||
run: bundle exec fastlane point_dependencies_to_related_branches
|
||||
|
||||
# Main step
|
||||
- name: Unit tests
|
||||
|
|
39
CHANGES.rst
|
@ -1,3 +1,42 @@
|
|||
Changes in 1.3.6 (2021-05-07)
|
||||
=================================================
|
||||
|
||||
✨ Features
|
||||
*
|
||||
|
||||
🙌 Improvements
|
||||
* Jitsi: Use Jitsi server from homeserver's Well Known, if present, to create conferences (#3158).
|
||||
* RoomMemberDetailsVC: Enable / disable "Hide all messages from this user" from settings (#4281).
|
||||
* RoomVC: Show / Hide More and Report Content contextual menu from settings (#4285).
|
||||
* SettingsVC: Show / hide NSFW and decrypted content options from build settings (#4290).
|
||||
* RoomVC: Tweaked Scroll to Bottom FAB button (#4272).
|
||||
* DesignKit: Introduce a new framework to manage design components.
|
||||
* Add Jitsi widget remove banner for privileged users.
|
||||
* Update "Jump to unread" banner to a pill style button.
|
||||
* CallVC: Add transfer button.
|
||||
|
||||
🐛 Bugfix
|
||||
* RoomVC: Avoid navigation to integration management using integration popup with settings set to integration disabled (#4261).
|
||||
* RiotSettings: Logging out resets RiotSettings (#4259).
|
||||
* RoomVC: Crash in `setScrollToBottomHidden` method (#4270).
|
||||
* Notifications: Make them work in debug mode (#4274).
|
||||
* VoIP: Fix call bar layout issue (#4300).
|
||||
|
||||
⚠️ API Changes
|
||||
*
|
||||
|
||||
🗣 Translations
|
||||
*
|
||||
|
||||
🧱 Build
|
||||
* GH Actions: Make jobs use the right version of MatrixKit and MatrixSDK.
|
||||
|
||||
Others
|
||||
*
|
||||
|
||||
Improvements:
|
||||
* Upgrade MatrixKit version ([v0.14.11](https://github.com/matrix-org/matrix-ios-kit/releases/tag/v0.14.11)).
|
||||
|
||||
Changes in 1.3.5 (2021-04-22)
|
||||
=================================================
|
||||
|
||||
|
|
|
@ -44,6 +44,9 @@ class AppConfiguration: CommonConfiguration {
|
|||
// Each room member will be considered as a potential contact.
|
||||
MXKContactManager.shared().contactManagerMXRoomSource = MXKContactManagerMXRoomSource.all
|
||||
|
||||
// Use UIKit BackgroundTask for handling background tasks in the SDK
|
||||
MXSDKOptions.sharedInstance().backgroundModeHandler = MXUIKitBackgroundModeHandler()
|
||||
|
||||
// Enable key backup on app
|
||||
MXSDKOptions.sharedInstance().enableKeyBackupWhenStartingMXCrypto = true
|
||||
}
|
||||
|
|
|
@ -22,8 +22,8 @@ APPLICATION_GROUP_IDENTIFIER = group.im.vector
|
|||
APPLICATION_SCHEME = element
|
||||
|
||||
// Version
|
||||
MARKETING_VERSION = 1.3.5
|
||||
CURRENT_PROJECT_VERSION = 1.3.5
|
||||
MARKETING_VERSION = 1.3.6
|
||||
CURRENT_PROJECT_VERSION = 1.3.6
|
||||
|
||||
|
||||
// Team
|
||||
|
@ -32,13 +32,13 @@ DEVELOPMENT_TEAM = 7J4U792NQT
|
|||
|
||||
// Provisioning profiles
|
||||
RIOT_PROVISIONING_PROFILE_SPECIFIER = Vector App Store
|
||||
RIOT_PROVISIONING_PROFILE = f65e7447-b8a3-46cc-8fba-fa60e55e2511
|
||||
RIOT_PROVISIONING_PROFILE = 4b43c1ca-3246-4984-828f-165838f5715a
|
||||
|
||||
NSE_PROVISIONING_PROFILE_SPECIFIER = "Vector NSE: App Store"
|
||||
NSE_PROVISIONING_PROFILE = 31dc9316-e029-47fd-81f5-778db07d76a2
|
||||
NSE_PROVISIONING_PROFILE = de44ca91-4318-4c23-8611-b531793505c2
|
||||
|
||||
SHARE_EXTENSION_PROVISIONING_PROFILE_SPECIFIER = "Vector Share Extension: App Store"
|
||||
SHARE_EXTENSION_PROVISIONING_PROFILE = 1a3be143-50c7-4ae2-834e-00596a053141
|
||||
SHARE_EXTENSION_PROVISIONING_PROFILE = 546090a2-77ca-4bc2-b904-da5bd97a2f37
|
||||
|
||||
SIRI_INTENTS_PROVISIONING_PROFILE_SPECIFIER = "Vector Siri Intents: App Store"
|
||||
SIRI_INTENTS_PROVISIONING_PROFILE = 18a66f93-ffe1-4008-b343-58350cc65023
|
||||
SIRI_INTENTS_PROVISIONING_PROFILE = 6951ad31-4850-445a-89c8-b64bca0a1c44
|
||||
|
|
|
@ -180,7 +180,7 @@ final class BuildSettings: NSObject {
|
|||
"https://scalar-staging.riot.im/scalar/api",
|
||||
]
|
||||
// Jitsi server used outside integrations to create conference calls from the call button in the timeline
|
||||
static let jitsiServerUrl = NSURL(string: "https://jitsi.riot.im")
|
||||
static let jitsiServerUrl: URL = URL(string: "https://jitsi.riot.im")!
|
||||
|
||||
|
||||
// MARK: - Features
|
||||
|
@ -242,6 +242,8 @@ final class BuildSettings: NSObject {
|
|||
static let settingsScreenShowChangePassword:Bool = true
|
||||
static let settingsScreenShowInviteFriends:Bool = true
|
||||
static let settingsScreenShowEnableStunServerFallback: Bool = true
|
||||
static let settingsScreenShowNotificationDecodedContentOption: Bool = true
|
||||
static let settingsScreenShowNsfwRoomsOption: Bool = true
|
||||
static let settingsSecurityScreenShowSessions:Bool = true
|
||||
static let settingsSecurityScreenShowSetupBackup:Bool = true
|
||||
static let settingsSecurityScreenShowRestoreBackup:Bool = true
|
||||
|
@ -268,6 +270,12 @@ final class BuildSettings: NSObject {
|
|||
static let roomScreenAllowMediaLibraryAction: Bool = true
|
||||
static let roomScreenAllowStickerAction: Bool = true
|
||||
static let roomScreenAllowFilesAction: Bool = true
|
||||
|
||||
// MARK: - Room Contextual Menu
|
||||
|
||||
static let roomContextualMenuShowMoreOptionForMessages: Bool = true
|
||||
static let roomContextualMenuShowMoreOptionForStates: Bool = true
|
||||
static let roomContextualMenuShowReportContentOption: Bool = true
|
||||
|
||||
// MARK: - Room Info Screen
|
||||
|
||||
|
@ -284,6 +292,10 @@ final class BuildSettings: NSObject {
|
|||
static let roomSettingsScreenShowAdvancedSettings: Bool = true
|
||||
static let roomSettingsScreenAdvancedShowEncryptToVerifiedOption: Bool = true
|
||||
|
||||
// MARK: - Room Member Screen
|
||||
|
||||
static let roomMemberScreenShowIgnore: Bool = true
|
||||
|
||||
// MARK: - Message
|
||||
static let messageDetailsAllowShare: Bool = true
|
||||
static let messageDetailsAllowPermalink: Bool = true
|
||||
|
|
|
@ -63,9 +63,6 @@ class CommonConfiguration: NSObject, Configurable {
|
|||
// Disable identicon use
|
||||
sdkOptions.disableIdenticonUseForUserAvatar = true
|
||||
|
||||
// Use UIKit BackgroundTask for handling background tasks in the SDK
|
||||
sdkOptions.backgroundModeHandler = MXUIKitBackgroundModeHandler()
|
||||
|
||||
// Pass httpAdditionalHeaders to the SDK
|
||||
sdkOptions.httpAdditionalHeaders = BuildSettings.httpAdditionalHeaders
|
||||
|
||||
|
|
27
DesignKit/Common.xcconfig
Normal file
|
@ -0,0 +1,27 @@
|
|||
//
|
||||
// Copyright 2021 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"
|
||||
|
||||
PRODUCT_NAME = DesignKit
|
||||
PRODUCT_BUNDLE_IDENTIFIER = $(BASE_BUNDLE_IDENTIFIER).designkit
|
||||
|
||||
INFOPLIST_FILE = DesignKit/Info.plist
|
||||
|
||||
SKIP_INSTALL = YES
|
20
DesignKit/Debug.xcconfig
Normal file
|
@ -0,0 +1,20 @@
|
|||
//
|
||||
// Copyright 2021 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"
|
27
DesignKit/DesignKit.h
Normal file
|
@ -0,0 +1,27 @@
|
|||
//
|
||||
// Copyright 2021 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/Foundation.h>
|
||||
|
||||
//! Project version number for DesignKit.
|
||||
FOUNDATION_EXPORT double DesignKitVersionNumber;
|
||||
|
||||
//! Project version string for DesignKit.
|
||||
FOUNDATION_EXPORT const unsigned char DesignKitVersionString[];
|
||||
|
||||
// In this header, you should import all the public headers of your framework using statements like #import <DesignKit/PublicHeader.h>
|
||||
|
||||
|
22
DesignKit/Info.plist
Normal file
|
@ -0,0 +1,22 @@
|
|||
<?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>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>$(MARKETING_VERSION)</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||
</dict>
|
||||
</plist>
|
20
DesignKit/Release.xcconfig
Normal file
|
@ -0,0 +1,20 @@
|
|||
//
|
||||
// Copyright 2021 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"
|
64
DesignKit/Source/Colors.swift
Normal file
|
@ -0,0 +1,64 @@
|
|||
//
|
||||
// Copyright 2021 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 UIKit
|
||||
|
||||
/// Colors at https://www.figma.com/file/X4XTH9iS2KGJ2wFKDqkyed/Compound?node-id=1255%3A1104
|
||||
@objc public protocol Colors {
|
||||
|
||||
/// - Focused/Active states
|
||||
/// - CTAs
|
||||
var accent: UIColor { get }
|
||||
|
||||
/// - Error messages
|
||||
/// - Content requiring user attention
|
||||
/// - Notification, alerts
|
||||
var alert: UIColor { get }
|
||||
|
||||
/// - Text
|
||||
/// - Icons
|
||||
var primaryContent: UIColor { get }
|
||||
|
||||
/// - Text
|
||||
/// - Icons
|
||||
var secondaryContent: UIColor { get }
|
||||
|
||||
/// - Text
|
||||
/// - Icons
|
||||
var tertiaryContent: UIColor { get }
|
||||
|
||||
/// - Text
|
||||
/// - Icons
|
||||
var quarterlyContent: UIColor { get }
|
||||
|
||||
/// Separating line
|
||||
var separator: UIColor { get }
|
||||
|
||||
// Cards, tiles
|
||||
var tile: UIColor { get }
|
||||
|
||||
/// Top navigation background on iOS
|
||||
var navigation: UIColor { get }
|
||||
|
||||
/// Background UI color
|
||||
var background: UIColor { get }
|
||||
|
||||
/// - Names in chat timeline
|
||||
/// - Avatars default states that include first name letter
|
||||
var namesAndAvatars: [UIColor] { get }
|
||||
|
||||
}
|
28
DesignKit/Source/ThemeV2.swift
Normal file
|
@ -0,0 +1,28 @@
|
|||
//
|
||||
// Copyright 2021 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 UIKit
|
||||
|
||||
/// Theme v2. May be named again as `Theme` when the migration completed.
|
||||
@objc public protocol ThemeV2 {
|
||||
|
||||
/// Colors object
|
||||
var colors: Colors { get }
|
||||
|
||||
/// may contain more design components in future, like icons, audio files etc.
|
||||
|
||||
}
|
56
DesignKit/Variants/Dark/DarkColors.swift
Normal file
|
@ -0,0 +1,56 @@
|
|||
//
|
||||
// Copyright 2021 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 UIKit
|
||||
|
||||
/// Dark theme colors. Will be a struct when things are more Swifty.
|
||||
public class DarkColors: Colors {
|
||||
|
||||
public let accent: UIColor = UIColor(rgb: 0x0DBD8B)
|
||||
|
||||
public let alert: UIColor = UIColor(rgb: 0xFF4B55)
|
||||
|
||||
public let primaryContent: UIColor = UIColor(rgb: 0xFFFFFF)
|
||||
|
||||
public let secondaryContent: UIColor = UIColor(rgb: 0xA9B2BC)
|
||||
|
||||
public let tertiaryContent: UIColor = UIColor(rgb: 0x8E99A4)
|
||||
|
||||
public let quarterlyContent: UIColor = UIColor(rgb: 0x6F7882)
|
||||
|
||||
public let separator: UIColor = UIColor(rgb: 0x21262C)
|
||||
|
||||
public let tile: UIColor = UIColor(rgb: 0x394049)
|
||||
|
||||
public let navigation: UIColor = UIColor(rgb: 0x21262C)
|
||||
|
||||
public let background: UIColor = UIColor(rgb: 0x15191E)
|
||||
|
||||
public let namesAndAvatars: [UIColor] = [
|
||||
UIColor(rgb: 0x368BD6),
|
||||
UIColor(rgb: 0xAC3BA8),
|
||||
UIColor(rgb: 0x03B381),
|
||||
UIColor(rgb: 0xE64F7A),
|
||||
UIColor(rgb: 0xFF812D),
|
||||
UIColor(rgb: 0x2DC2C5),
|
||||
UIColor(rgb: 0x5C56F5),
|
||||
UIColor(rgb: 0x74D12C)
|
||||
]
|
||||
|
||||
public init() {}
|
||||
|
||||
}
|
56
DesignKit/Variants/Light/LightColors.swift
Normal file
|
@ -0,0 +1,56 @@
|
|||
//
|
||||
// Copyright 2021 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 UIKit
|
||||
|
||||
/// Light theme colors. Will be a struct when things are more Swifty.
|
||||
public class LightColors: Colors {
|
||||
|
||||
public let accent: UIColor = UIColor(rgb: 0x0DBD8B)
|
||||
|
||||
public let alert: UIColor = UIColor(rgb: 0xFF4B55)
|
||||
|
||||
public let primaryContent: UIColor = UIColor(rgb: 0x17191C)
|
||||
|
||||
public let secondaryContent: UIColor = UIColor(rgb: 0x737D8C)
|
||||
|
||||
public let tertiaryContent: UIColor = UIColor(rgb: 0x8D97A5)
|
||||
|
||||
public let quarterlyContent: UIColor = UIColor(rgb: 0xC1C6CD)
|
||||
|
||||
public let separator: UIColor = UIColor(rgb: 0xE3E8F0)
|
||||
|
||||
public let tile: UIColor = UIColor(rgb: 0xF3F8FD)
|
||||
|
||||
public let navigation: UIColor = UIColor(rgb: 0xF4F6FA)
|
||||
|
||||
public let background: UIColor = UIColor(rgb: 0xFFFFFF)
|
||||
|
||||
public let namesAndAvatars: [UIColor] = [
|
||||
UIColor(rgb: 0x368BD6),
|
||||
UIColor(rgb: 0xAC3BA8),
|
||||
UIColor(rgb: 0x03B381),
|
||||
UIColor(rgb: 0xE64F7A),
|
||||
UIColor(rgb: 0xFF812D),
|
||||
UIColor(rgb: 0x2DC2C5),
|
||||
UIColor(rgb: 0x5C56F5),
|
||||
UIColor(rgb: 0x74D12C)
|
||||
]
|
||||
|
||||
public init() {}
|
||||
|
||||
}
|
33
DesignKit/target.yml
Normal file
|
@ -0,0 +1,33 @@
|
|||
name: DesignKit
|
||||
|
||||
schemes:
|
||||
DesignKit:
|
||||
analyze:
|
||||
config: Debug
|
||||
archive:
|
||||
config: Release
|
||||
build:
|
||||
targets:
|
||||
DesignKit:
|
||||
- running
|
||||
- profiling
|
||||
- analyzing
|
||||
- archiving
|
||||
profile:
|
||||
config: Release
|
||||
run:
|
||||
config: Debug
|
||||
disableMainThreadChecker: true
|
||||
|
||||
targets:
|
||||
DesignKit:
|
||||
type: framework
|
||||
platform: iOS
|
||||
|
||||
configFiles:
|
||||
Debug: Debug.xcconfig
|
||||
Release: Release.xcconfig
|
||||
|
||||
sources:
|
||||
- path: .
|
||||
- path: ../Riot/Categories/UIColor.swift
|
|
@ -68,7 +68,7 @@ If you want to modify MatrixKit and/or MatrixSDK locally and see the result in E
|
|||
But before you have to checkout [MatrixKit](https://github.com/matrix-org/matrix-ios-kit) repository in `../matrix-ios-kit` and [MatrixSDK](https://github.com/matrix-org/matrix-ios-sdk) in `../matrix-ios-sdk` locally relatively to your Element iOS project folder.
|
||||
Be sure to use compatible branches for Element iOS, MatrixKit and MatrixSDK. For example, if you want to modify Element iOS from develop branch, use MatrixKit and MatrixSDK develop branches and then make your modifications.
|
||||
|
||||
**Important**: By working with local pods (development pods) you will need to use legacy build system in Xcode, to have your local changes taken into account. To enable it go to Xcode menu and select `File > Workspace Settings… > Build System` and then choose `Legacy Build System`.
|
||||
**Important**: By working with [XcodeGen](https://github.com/yonaskolb/XcodeGen) you will need to use the _New Build System_ in Xcode, to have your some of the xcconfig variables taken into account. It should be enabled by default on the latest Xcode versions, but if you need to enable it go to Xcode menu and select `File > Workspace Settings… > Build System` and then choose `New Build System`.
|
||||
|
||||
### `$matrixKitVersion` Modification
|
||||
|
||||
|
|
2
Podfile
|
@ -11,7 +11,7 @@ use_frameworks!
|
|||
# - `{ {kit spec hash} => {sdk spec hash}` to depend on specific pod options (:git => …, :podspec => …) for each 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
|
||||
$matrixKitVersion = '= 0.14.10'
|
||||
$matrixKitVersion = '= 0.14.11'
|
||||
# $matrixKitVersion = :local
|
||||
# $matrixKitVersion = {'develop' => 'develop'}
|
||||
|
||||
|
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 3.9 KiB |
Before Width: | Height: | Size: 4.9 KiB After Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 8.8 KiB After Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 4.5 KiB |
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 9.2 KiB |
Before Width: | Height: | Size: 9.3 KiB After Width: | Height: | Size: 15 KiB |
|
@ -19,5 +19,8 @@
|
|||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"template-rendering-intent" : "template"
|
||||
}
|
||||
}
|
||||
|
|
23
Riot/Assets/Images.xcassets/Call/call_go_to_chat_icon.imageset/Contents.json
vendored
Normal file
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "back.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "back@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "back@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
BIN
Riot/Assets/Images.xcassets/Call/call_go_to_chat_icon.imageset/back.png
vendored
Normal file
After Width: | Height: | Size: 403 B |
BIN
Riot/Assets/Images.xcassets/Call/call_go_to_chat_icon.imageset/back@2x.png
vendored
Normal file
After Width: | Height: | Size: 794 B |
BIN
Riot/Assets/Images.xcassets/Call/call_go_to_chat_icon.imageset/back@3x.png
vendored
Normal file
After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1 KiB After Width: | Height: | Size: 2.9 KiB |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 7.2 KiB |
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 13 KiB |
|
@ -19,5 +19,8 @@
|
|||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"template-rendering-intent" : "template"
|
||||
}
|
||||
}
|
||||
|
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 2.5 KiB |
Before Width: | Height: | Size: 4.6 KiB After Width: | Height: | Size: 6.7 KiB |
Before Width: | Height: | Size: 8.4 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 3 KiB |
Before Width: | Height: | Size: 5.1 KiB After Width: | Height: | Size: 7.5 KiB |
Before Width: | Height: | Size: 8.8 KiB After Width: | Height: | Size: 13 KiB |
|
@ -19,8 +19,5 @@
|
|||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"template-rendering-intent" : "template"
|
||||
}
|
||||
}
|
||||
|
|
Before Width: | Height: | Size: 336 B After Width: | Height: | Size: 370 B |
Before Width: | Height: | Size: 586 B After Width: | Height: | Size: 647 B |
Before Width: | Height: | Size: 888 B After Width: | Height: | Size: 686 B |
BIN
Riot/Assets/Images.xcassets/Room/Activities/new_close.imageset/Close.png
vendored
Normal file
After Width: | Height: | Size: 370 B |
BIN
Riot/Assets/Images.xcassets/Room/Activities/new_close.imageset/Close@2x.png
vendored
Normal file
After Width: | Height: | Size: 509 B |
BIN
Riot/Assets/Images.xcassets/Room/Activities/new_close.imageset/Close@3x.png
vendored
Normal file
After Width: | Height: | Size: 772 B |
26
Riot/Assets/Images.xcassets/Room/Activities/new_close.imageset/Contents.json
vendored
Normal file
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "Close.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "Close@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "Close@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"template-rendering-intent" : "template"
|
||||
}
|
||||
}
|
26
Riot/Assets/Images.xcassets/Room/Activities/room_scroll_up.imageset/Contents.json
vendored
Normal file
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "Up.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "Up@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "Up@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"template-rendering-intent" : "original"
|
||||
}
|
||||
}
|
BIN
Riot/Assets/Images.xcassets/Room/Activities/room_scroll_up.imageset/Up.png
vendored
Normal file
After Width: | Height: | Size: 609 B |
BIN
Riot/Assets/Images.xcassets/Room/Activities/room_scroll_up.imageset/Up@2x.png
vendored
Normal file
After Width: | Height: | Size: 1,015 B |
BIN
Riot/Assets/Images.xcassets/Room/Activities/room_scroll_up.imageset/Up@3x.png
vendored
Normal file
After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 588 B After Width: | Height: | Size: 735 B |
Before Width: | Height: | Size: 1 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 776 B After Width: | Height: | Size: 958 B |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 2 KiB After Width: | Height: | Size: 2.3 KiB |
|
@ -20,8 +20,6 @@
|
|||
<false/>
|
||||
<key>syncLocalContacts</key>
|
||||
<false/>
|
||||
<key>createConferenceCallsWithJitsi</key>
|
||||
<true/>
|
||||
<key>enableRageShake</key>
|
||||
<true/>
|
||||
<key>maxAllowedMediaCacheSize</key>
|
||||
|
@ -34,5 +32,7 @@
|
|||
<integer>15020851</integer>
|
||||
<key>enableBotCreation</key>
|
||||
<false/>
|
||||
<key>enableRingingForGroupCalls</key>
|
||||
<false/>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
|
@ -1,23 +1,26 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "cancel.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "cancel@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "cancel@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"template-rendering-intent" : "template"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -129,3 +129,11 @@
|
|||
"callbar_only_multiple_paused" = "عَدَد %@ مُكالَمَة مُعلَّقة";
|
||||
"callbar_active_and_single_paused" = "مُكالَمَةٌ واحدةٌ نَشِطة (%@) · مُكالَمَةٌ واحدةٌ مُعلَّقة";
|
||||
"callbar_only_single_paused" = "مُكالَمَة مُعلَّقة";
|
||||
"auth_softlogout_reason" = "لَقَد سَجَّلَ مُدير الخادِم الرَّئيس الخَّاصِّ بِك (%1$@) الخُرُوج مِن الحِساب الخَّاصِّ بِك %2$@ (%3$@).";
|
||||
"auth_softlogout_signed_out" = "لَقَد سَجَّلتَ الخُرُوج";
|
||||
"auth_autodiscover_invalid_response" = "اِستِجابَة اِكتِشاف الخادِم الرَّئيس غَير صَالِحة";
|
||||
"auth_accept_policies" = "يُرجَى مُراجَعَة سِياسَات هَذَا الخادِم الرَّئيس وقُبُولِهَا:";
|
||||
"auth_add_email_and_phone_warning" = "التَّسجِيل بِواسِطَة البَريد الإلِكتُرونيّ وَرَقم الهَاتِف معًا غَير مَدعوم حَتَّى تَتَوَفَر بيئة بَرمجة التَّطبيقات (API). سَوفَ يَتِّم أخذ رَقم الهَاتِف فَقَط فِي الاِعتِبار. يُمكِنُكَ إضافَة البَريد الإلِكتُرونيّ الخَّاصّ بِك إلَى مَلَفّ التَّعريف الخَّاصِّ بِك فِي الإعدَادَات.";
|
||||
"auth_reset_password_success_message" = "لَقَد تمَّ إعادَةُ ضَبطِ كَلِمَةِ المُرُور الخَّاصَّةِ بِك.\n\nلَقَد تمَّ تَسجِيلُ خُرُوجِك مِن جَميعِ الجَلَسات وَلَن تَستَلِمَ بَعد الآن دَفعَ الإِشعَارات. لِإعادَةِ تَفعِيل الإِشعَارات، أعِد تَسجِيلَ الدُّخول عَلَى كُلِّ جِهاز.";
|
||||
"auth_reset_password_error_not_found" = "لَا يَبدو أنَّ عُنوان البَريد الإلِكتُرونيّ الخَّاصِّ بِك مُقتَرِنٌ بِمُعَرِّف Matrix عَلَى الخادِمِ الرَّئيس هَذَا.";
|
||||
"auth_reset_password_error_unauthorized" = "فَشَلَ التَّحَقُق مِن عُنوان البَريد الإلِكتُرونيّ: تَأكَّد مِن نَقرِكَ عَلَى الرَّابِط الَّذي فِي البَريد الإلِكتُرونيّ";
|
||||
|
|
|
@ -1327,8 +1327,8 @@
|
|||
"callbar_only_single_active" = "Laufender Anruf (%@)";
|
||||
"room_event_action_delete_confirmation_message" = "Möchtest Du die nicht gesendete Nachricht wirklich löschen?";
|
||||
"room_event_action_delete_confirmation_title" = "Nicht gesendete Nachricht löschen";
|
||||
"room_details_integrations" = "Einbindungen";
|
||||
"room_details_search" = "Raum suchen";
|
||||
"room_details_integrations" = "Integrationen";
|
||||
"room_details_search" = "Raum durchsuchen";
|
||||
"room_multiple_typing_notification" = "%@ und andere";
|
||||
"room_accessibility_video_call" = "Videoanruf";
|
||||
"room_message_replying_to" = "%@ anworten";
|
||||
|
|
|
@ -123,6 +123,12 @@
|
|||
/* Incoming named video conference invite from a specific person */
|
||||
"VIDEO_CONF_NAMED_FROM_USER" = "Video group call from %@: '%@'";
|
||||
|
||||
/* A user added a Jitsi call to a room */
|
||||
"GROUP_CALL_STARTED" = "Group call started";
|
||||
|
||||
/* Group call from user, CallKit caller name */
|
||||
"GROUP_CALL_FROM_USER" = "%@ (Group call)";
|
||||
|
||||
/** Key verification **/
|
||||
|
||||
"KEY_VERIFICATION_REQUEST_FROM_USER" = "%@ wants to verify";
|
||||
|
|
|
@ -65,12 +65,13 @@
|
|||
"less" = "Less";
|
||||
|
||||
// Call Bar
|
||||
"callbar_only_single_active" = "Active call (%@)";
|
||||
"callbar_only_single_active" = "Tap to return to the call (%@)";
|
||||
"callbar_active_and_single_paused" = "1 active call (%@) · 1 paused call";
|
||||
"callbar_active_and_multiple_paused" = "1 active call (%@) · %@ paused calls";
|
||||
"callbar_only_single_paused" = "Paused call";
|
||||
"callbar_only_multiple_paused" = "%@ paused calls";
|
||||
"callbar_return" = "Return";
|
||||
"callbar_only_single_active_group" = "Tap to Join the group call (%@)";
|
||||
|
||||
// Accessibility
|
||||
"accessibility_checkbox_label" = "checkbox";
|
||||
|
@ -312,7 +313,8 @@ Tap the + to start adding people.";
|
|||
"room_member_power_level_short_custom" = "Custom";
|
||||
|
||||
// Chat
|
||||
"room_jump_to_first_unread" = "Jump to first unread message";
|
||||
"room_slide_to_end_group_call" = "Slide to end the call for everyone";
|
||||
"room_jump_to_first_unread" = "Jump to unread";
|
||||
"room_accessiblity_scroll_to_bottom" = "Scroll to bottom";
|
||||
"room_new_message_notification" = "%d new message";
|
||||
"room_new_messages_notification" = "%d new messages";
|
||||
|
@ -395,6 +397,8 @@ Tap the + to start adding people.";
|
|||
"room_accessibility_hangup" = "Hang up";
|
||||
"room_place_voice_call" = "Voice call";
|
||||
"room_open_dialpad" = "Dial pad";
|
||||
"room_join_group_call" = "Join";
|
||||
"room_no_privileges_to_create_group_call" = "You need to be an admin or a moderator to start a call.";
|
||||
|
||||
"media_type_accessibility_image" = "Image";
|
||||
"media_type_accessibility_audio" = "Audio";
|
||||
|
@ -526,6 +530,7 @@ Tap the + to start adding people.";
|
|||
"settings_labs_e2e_encryption_prompt_message" = "To finish setting up encryption you must log in again.";
|
||||
"settings_labs_create_conference_with_jitsi" = "Create conference calls with jitsi";
|
||||
"settings_labs_message_reaction" = "React to messages with emoji";
|
||||
"settings_labs_enable_ringing_for_group_calls" = "Ring for group calls";
|
||||
|
||||
"settings_version" = "Version %@";
|
||||
"settings_olm_version" = "Olm Version %@";
|
||||
|
@ -823,10 +828,22 @@ Tap the + to start adding people.";
|
|||
"event_formatter_message_edited_mention" = "(edited)";
|
||||
"event_formatter_call_voice" = "Voice call";
|
||||
"event_formatter_call_video" = "Video call";
|
||||
"event_formatter_call_has_ended" = "This call has ended";
|
||||
"event_formatter_call_you_currently_in" = "You're currently in this call";
|
||||
"event_formatter_call_connecting" = "Connecting…";
|
||||
"event_formatter_call_ringing" = "Ringing…";
|
||||
"event_formatter_call_has_ended" = "Ended %@";
|
||||
"event_formatter_call_you_currently_in" = "Active call";
|
||||
"event_formatter_call_you_declined" = "You declined this call";
|
||||
"event_formatter_call_you_missed" = "You missed this call";
|
||||
"event_formatter_call_connection_failed" = "Connection failed";
|
||||
"event_formatter_call_back" = "Call back";
|
||||
"event_formatter_call_decline" = "Decline";
|
||||
"event_formatter_call_answer" = "Answer";
|
||||
"event_formatter_call_retry" = "Retry";
|
||||
"event_formatter_call_end_call" = "End call";
|
||||
"event_formatter_group_call" = "Group call";
|
||||
"event_formatter_group_call_join" = "Join";
|
||||
"event_formatter_group_call_leave" = "Leave";
|
||||
"event_formatter_group_call_incoming" = "%@ in %@";
|
||||
|
||||
// Events formatter with you
|
||||
"event_formatter_widget_added_by_you" = "You added the widget: %@";
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// Permissions usage explanations
|
||||
"NSCameraUsageDescription" = "La cámara se utiliza para tomar fotos y vídeos, realizar llamadas de vídeo.";
|
||||
"NSPhotoLibraryUsageDescription" = "La biblioteca de fotos se utiliza para enviar fotos y vídeos.";
|
||||
"NSMicrophoneUsageDescription" = "El micrófono se utiliza para tomar vídeos, realizar llamadas.";
|
||||
"NSCameraUsageDescription" = "La cámara se usa para sacar fotos, vídeos y hacer videollamadas.";
|
||||
"NSPhotoLibraryUsageDescription" = "La biblioteca de fotos se usa para enviar fotos y vídeos.";
|
||||
"NSMicrophoneUsageDescription" = "El micrófono se usa para grabar vídeos y realizar llamadas.";
|
||||
"NSContactsUsageDescription" = "Para mostrarte cuáles de tus contactos ya utilizan Matrix, Element puede enviar las direcciones de correo electrónico y números telefónicos de tu agenda de contactos a tu Servidor de Identidad de Matrix. En los casos que se puede, tu información personal se cifra antes de ser enviada - por favor consulta la política de privacidad de tu Servidor de Identidad.";
|
||||
"NSFaceIDUsageDescription" = "Face ID se usa para acceder a tu aplicación.";
|
||||
"NSCalendarsUsageDescription" = "Mostrar tus reuniones en la aplicación.";
|
||||
|
|
|
@ -54,3 +54,19 @@
|
|||
"MSG_FROM_USER_IN_ROOM_TITLE" = "%@ en %@";
|
||||
/* Sticker from a specific person, not referencing a room. */
|
||||
"STICKER_FROM_USER" = "%@ envió una pegatina";
|
||||
|
||||
/** Key verification **/
|
||||
|
||||
"KEY_VERIFICATION_REQUEST_FROM_USER" = "%@ quiere verificar";
|
||||
|
||||
/** Notification messages **/
|
||||
|
||||
/* New message indicator on unknown room */
|
||||
"MESSAGE" = "Mensaje";
|
||||
|
||||
/* New message indicator from a DM */
|
||||
"MESSAGE_FROM_X" = "Mensaje de %@";
|
||||
|
||||
/* New message indicator on a room */
|
||||
"MESSAGE_IN_X" = "Mensaje en %@";
|
||||
"MESSAGE_PROTECTED" = "Nuevo mensaje";
|
||||
|
|
|
@ -51,7 +51,7 @@
|
|||
"auth_repeat_password_placeholder" = "Repite la contraseña";
|
||||
"auth_repeat_new_password_placeholder" = "Confirma tu contraseña nueva";
|
||||
"auth_home_server_placeholder" = "URL (ej. https://matrix.org)";
|
||||
"auth_identity_server_placeholder" = "URL (ej. https://matrix.org)";
|
||||
"auth_identity_server_placeholder" = "URL (ej.: https://matrix.org)";
|
||||
"auth_invalid_login_param" = "Nombre de usuario y/o contraseña incorrectos";
|
||||
"auth_invalid_user_name" = "Los nombres de usuario solo pueden contener letras, números, puntos, guiones y guiones bajos";
|
||||
"auth_invalid_password" = "Contraseña demasiado corta (mínimo 6)";
|
||||
|
@ -121,12 +121,12 @@
|
|||
"auth_msisdn_validation_title" = "Verificación Pendiente";
|
||||
"auth_msisdn_validation_message" = "Hemos enviado un SMS con un código de activación. Por favor, ingresa este código a continuación.";
|
||||
"auth_msisdn_validation_error" = "No se pudo verificar el número telefónico.";
|
||||
"auth_recaptcha_message" = "Este Servidor Doméstico quiere asegurarse de que no eres un robot";
|
||||
"auth_recaptcha_message" = "Este servidor base quiere asegurarse de que no eres un robot";
|
||||
"auth_reset_password_message" = "Para restablecer tu contraseña, ingresa la dirección de correo electrónico vinculada a tu cuenta:";
|
||||
"auth_reset_password_missing_email" = "Debes ingresar la dirección de correo electrónico vinculada a tu cuenta.";
|
||||
"auth_reset_password_email_validation_message" = "Se envió un correo electrónico a %@. Una vez que hayas seguido el enlace que contiene, haz clic a continuación.";
|
||||
"auth_reset_password_error_unauthorized" = "No se pudo verificar la dirección de correo electrónico: asegúrate de hacer clic en el enlace del correo electrónico";
|
||||
"auth_reset_password_error_not_found" = "Tu dirección de correo electrónico no parece estar asociada a una ID de Matrix en este Servidor Doméstico.";
|
||||
"auth_reset_password_error_not_found" = "Tu dirección de correo electrónico no parece estar asociada a una ID de Matrix en este servidor base.";
|
||||
"auth_reset_password_success_message" = "Tu contraseña fue restablecida.\n\nSe ha cerrado sesión en todos tus dispositivos y ya no recibirás notificaciones push. Para volver a habilitar las notificaciones, vuelve a iniciar sesión en cada dispositivo.";
|
||||
"auth_add_email_and_phone_warning" = "Todavía no es posible registrarse con correo electrónico y número telefónico a la vez, hasta que exista la API. Solo se tendrá en cuenta el número telefónico. Puedes añadir tu correo electrónico a tu perfil en ajustes.";
|
||||
// Chat creation
|
||||
|
@ -550,3 +550,43 @@
|
|||
"deactivate_account_forget_messages_information_part3" = ": esto provocará que los usuarios futuros vean conversaciones incompletas)";
|
||||
// String for App Store
|
||||
"store_short_description" = "Chat/VoIP descentralizado y seguro";
|
||||
"room_participants_leave_prompt_title_for_dm" = "Salir";
|
||||
"people_empty_view_title" = "Personas";
|
||||
"social_login_button_title_sign_up" = "Registrarse con %@";
|
||||
"social_login_button_title_sign_in" = "Iniciar sesión con %@";
|
||||
"social_login_button_title_continue" = "Seguir con %@";
|
||||
"social_login_list_title_sign_up" = "O";
|
||||
"social_login_list_title_sign_in" = "O";
|
||||
|
||||
// Social login
|
||||
|
||||
"social_login_list_title_continue" = "Seguir con";
|
||||
"auth_softlogout_clear_data_sign_out" = "Cerrar sesión";
|
||||
"auth_softlogout_clear_data_sign_out_title" = "¿Seguro?";
|
||||
"auth_softlogout_clear_data_button" = "Borrar todos los datos";
|
||||
"auth_softlogout_clear_data_message_2" = "Bórralos si vas a dejar de usar este dispositivo, o quieres iniciar sesión con otra cuenta.";
|
||||
"auth_softlogout_clear_data_message_1" = "Cuidado: tus datos personales (incluyendo claves de cifrado) todavía están alojados en este dispositivo.";
|
||||
"auth_softlogout_clear_data" = "Borrar datos personales";
|
||||
"auth_softlogout_reason" = "La administración de tu servidor base (%1$@) ha cerrado tu sesión %2$@ (%3$@).";
|
||||
"auth_softlogout_sign_in" = "Iniciar sesión";
|
||||
"auth_softlogout_signed_out" = "No tienes una sesión iniciada";
|
||||
"auth_accept_policies" = "Por favor, lee y acepta los términos de este servidor base:";
|
||||
"auth_add_phone_message_2" = "Pon un número de teléfono para que te descubran personas que te conozcan.";
|
||||
"auth_add_email_message_2" = "Pon un correo para poder recuperar tu cuenta en el futuro, y, opcionalmente que las personas que te conozcan descubran tu cuenta.";
|
||||
"auth_login_single_sign_on" = "Iniciar sesión";
|
||||
|
||||
// Accessibility
|
||||
"accessibility_checkbox_label" = "casilla de selección";
|
||||
"callbar_return" = "Volver";
|
||||
"callbar_only_multiple_paused" = "%@ llamadas en espera";
|
||||
"callbar_only_single_paused" = "Llamada en espera";
|
||||
"callbar_active_and_multiple_paused" = "1 llamada en curso (%@) · %@ llamadas en espera";
|
||||
"callbar_active_and_single_paused" = "1 llamada en curso (%@) · 1 llamada en espera";
|
||||
|
||||
// Call Bar
|
||||
"callbar_only_single_active" = "Llamada en curso (%@)";
|
||||
"less" = "Menos";
|
||||
"more" = "Más";
|
||||
"switch" = "Cambiar";
|
||||
"skip" = "Saltar";
|
||||
"close" = "Cerrar";
|
||||
|
|
1
Riot/Assets/fa.lproj/InfoPlist.strings
Normal file
|
@ -0,0 +1 @@
|
|||
|
1
Riot/Assets/fa.lproj/Localizable.strings
Normal file
|
@ -0,0 +1 @@
|
|||
|
|
@ -1 +1,17 @@
|
|||
|
||||
|
||||
|
||||
|
||||
// Room Details
|
||||
"room_details_title" = "جزئیات اتاق";
|
||||
"invite" = "دعوت";
|
||||
|
||||
// Actions
|
||||
"view" = "مشاهده";
|
||||
"leave" = "ترک";
|
||||
"save" = "ذخیره";
|
||||
"cancel" = "لغو";
|
||||
"retry" = "تلاش مجدد";
|
||||
"continue" = "ادامه";
|
||||
"close" = "بستن";
|
||||
"back" = "بازگشت";
|
||||
|
|
|
@ -1350,3 +1350,9 @@
|
|||
|
||||
// Call Bar
|
||||
"callbar_only_single_active" = "Aktív hívás (%@)";
|
||||
"room_details_integrations" = "Integrációk";
|
||||
"room_details_search" = "Szoba keresése";
|
||||
"room_multiple_typing_notification" = "%@ és mások";
|
||||
"room_accessibility_video_call" = "Videohívás";
|
||||
"room_message_replying_to" = "Válasz erre: %@";
|
||||
"room_message_editing" = "Szerkesztés";
|
||||
|
|
9
Riot/Assets/nb-NO.lproj/InfoPlist.strings
Normal file
|
@ -0,0 +1,9 @@
|
|||
|
||||
|
||||
"NSContactsUsageDescription" = "For å finne kontakter som allerede bruker Matrix, kan Element sende e-postadresser og telefonnummer i din adressebok til utvalgte Matrix identitetstjenere. Der det støttes blir data anonymisert (hashet) - vennligst sjekk din identitetstjener for detaljer.";
|
||||
"NSFaceIDUsageDescription" = "Face ID brukes for å få tilgang til appen.";
|
||||
"NSCalendarsUsageDescription" = "Se dine avtalte møter i appen.";
|
||||
"NSMicrophoneUsageDescription" = "Mikrofonen brukes til videoopptak, og i samtaler.";
|
||||
"NSPhotoLibraryUsageDescription" = "Bildebiblioteket brukes for å sende bilder og videoer.";
|
||||
// Permissions usage explanations
|
||||
"NSCameraUsageDescription" = "Kameraet brukes til å ta bilder, spille inn video, og i videosamtaler.";
|
113
Riot/Assets/nb-NO.lproj/Localizable.strings
Normal file
|
@ -0,0 +1,113 @@
|
|||
|
||||
|
||||
|
||||
/** Key verification **/
|
||||
|
||||
"KEY_VERIFICATION_REQUEST_FROM_USER" = "%@ ønsker å bekrefte";
|
||||
|
||||
/* Incoming named video conference invite from a specific person */
|
||||
"VIDEO_CONF_NAMED_FROM_USER" = "Video-konferansesamtale fra %@: '%@'";
|
||||
|
||||
/* Incoming named voice conference invite from a specific person */
|
||||
"VOICE_CONF_NAMED_FROM_USER" = "Konferansesamtale fra %@: '%@'";
|
||||
|
||||
/* Incoming unnamed voice conference invite from a specific person */
|
||||
"VOICE_CONF_FROM_USER" = "Konferansesamtale fra %@";
|
||||
|
||||
/* Incoming unnamed video conference invite from a specific person */
|
||||
"VIDEO_CONF_FROM_USER" = "Video-konferansesamtale fra %@";
|
||||
|
||||
/* Incoming one-to-one video call */
|
||||
"VIDEO_CALL_FROM_USER" = "Videosamtale fra %@";
|
||||
|
||||
/** Calls **/
|
||||
|
||||
/* Incoming one-to-one voice call */
|
||||
"VOICE_CALL_FROM_USER" = "%@ ringer";
|
||||
|
||||
/* A user has invited you to a named room */
|
||||
"USER_INVITE_TO_NAMED_ROOM" = "%@ har invitert deg til %@";
|
||||
|
||||
/* A user has invited you to an (unamed) group chat */
|
||||
"USER_INVITE_TO_CHAT_GROUP_CHAT" = "%@ har invitert deg til en gruppesamtale";
|
||||
|
||||
/** Invites **/
|
||||
|
||||
/* A user has invited you to a chat */
|
||||
"USER_INVITE_TO_CHAT" = "%@ har invitert deg til en samtale";
|
||||
|
||||
/* Look, stuff's happened, alright? Just open the app. */
|
||||
"MSGS_IN_TWO_PLUS_ROOMS" = "%@ nye meldinger i %@, %@ og andre";
|
||||
|
||||
/* Multiple messages in two rooms */
|
||||
"MSGS_IN_TWO_ROOMS" = "%@ nye meldinger i %@ og %@";
|
||||
|
||||
/* Multiple unread messages from two plus people (ie. for 4+ people: 'others' replaces the third person) */
|
||||
"MSGS_FROM_TWO_PLUS_USERS" = "%@ nye meldinger fra %@, %@ og andre";
|
||||
|
||||
/* Multiple unread messages from three people */
|
||||
"MSGS_FROM_THREE_USERS" = "%@ nye meldinger fra %@, %@ og %@";
|
||||
|
||||
/* Multiple unread messages from two people */
|
||||
"MSGS_FROM_TWO_USERS" = "%@ nye meldinger fra %@ og %@";
|
||||
|
||||
/* Multiple unread messages from a specific person, not referencing a room */
|
||||
"MSGS_FROM_USER" = "%@ nye meldinger i %@";
|
||||
|
||||
/** Coalesced messages **/
|
||||
|
||||
/* Multiple unread messages in a room */
|
||||
"UNREAD_IN_ROOM" = "%@ meldinger i %@";
|
||||
"MESSAGE_PROTECTED" = "Ny melding";
|
||||
|
||||
/* New message indicator on a room */
|
||||
"MESSAGE_IN_X" = "Melding i %@";
|
||||
|
||||
/* New message indicator from a DM */
|
||||
"MESSAGE_FROM_X" = "Melding fra %@";
|
||||
|
||||
/** Notification messages **/
|
||||
|
||||
/* New message indicator on unknown room */
|
||||
"MESSAGE" = "Melding";
|
||||
|
||||
/* Sticker from a specific person, not referencing a room. */
|
||||
"STICKER_FROM_USER" = "%@ sendte et klistremerke";
|
||||
|
||||
/* A single unread message */
|
||||
"SINGLE_UNREAD" = "Du mottok en melding";
|
||||
|
||||
/* A single unread message in a room */
|
||||
"SINGLE_UNREAD_IN_ROOM" = "Du mottok en melding i %@";
|
||||
|
||||
/* New action message from a specific person in a named room. */
|
||||
"IMAGE_FROM_USER_IN_ROOM" = "%@ lastet opp et bilde %@ i %@";
|
||||
|
||||
/** Image Messages **/
|
||||
|
||||
/* New action message from a specific person, not referencing a room. */
|
||||
"IMAGE_FROM_USER" = "%@ sendte et bilde %@";
|
||||
|
||||
/* New action message from a specific person in a named room. */
|
||||
"ACTION_FROM_USER_IN_ROOM" = "%@: * %@ %@";
|
||||
|
||||
/* New action message from a specific person, not referencing a room. */
|
||||
"ACTION_FROM_USER" = "* %@ %@";
|
||||
|
||||
/* New message from a specific person in a named room. Content included. */
|
||||
"MSG_FROM_USER_IN_ROOM_WITH_CONTENT" = "%@ i %@: %@";
|
||||
|
||||
/** Single, unencrypted messages (where we can include the content */
|
||||
|
||||
/* New message from a specific person, not referencing a room. Content included. */
|
||||
"MSG_FROM_USER_WITH_CONTENT" = "%@: %@";
|
||||
|
||||
/* New message from a specific person in a named room */
|
||||
"MSG_FROM_USER_IN_ROOM" = "%@ skrevet i %@";
|
||||
|
||||
/** Single, end-to-end encrypted messages (ie. we don't know what they say) */
|
||||
|
||||
/* New message from a specific person, not referencing a room */
|
||||
"MSG_FROM_USER" = "%@ sendte en melding";
|
||||
/* Message title for a specific person in a named room */
|
||||
"MSG_FROM_USER_IN_ROOM_TITLE" = "%@ i %@";
|
|
@ -557,7 +557,7 @@
|
|||
"secrets_setup_recovery_key_loading" = "Laster…";
|
||||
"secrets_setup_recovery_key_export_action" = "Lagre";
|
||||
"secrets_setup_recovery_key_done_action" = "Fullført";
|
||||
"secrets_setup_recovery_key_storage_alert_title" = "Hold det trygt";
|
||||
"secrets_setup_recovery_key_storage_alert_title" = "Oppbevar trygt";
|
||||
"secrets_setup_recovery_passphrase_validate_action" = "Fullført";
|
||||
"secrets_setup_recovery_passphrase_confirm_passphrase_title" = "Bekreft";
|
||||
"secrets_setup_recovery_passphrase_confirm_passphrase_placeholder" = "Bekreft passordfrasen";
|
||||
|
@ -630,7 +630,7 @@
|
|||
"room_resource_usage_limit_reached_message_1_default" = "Denne hjemmeserveren har overskredet en av sine ressursgrenser så ";
|
||||
"room_resource_limit_exceeded_message_contact_3" = " for å fortsette å bruke denne tjenesten.";
|
||||
"room_resource_limit_exceeded_message_contact_2_link" = "kontakt tjenesteadministratoren";
|
||||
"room_resource_limit_exceeded_message_contact_1" = " Vær så snill ";
|
||||
"room_resource_limit_exceeded_message_contact_1" = " Vennligst ";
|
||||
"room_predecessor_link" = "Trykk her for å se eldre meldinger.";
|
||||
"room_predecessor_information" = "Dette rommet er en fortsettelse av en annen samtale.";
|
||||
"room_replacement_information" = "Dette rommet er erstattet og er ikke lenger aktivt.";
|
||||
|
@ -785,3 +785,78 @@
|
|||
|
||||
// Call Bar
|
||||
"callbar_only_single_active" = "Aktiv samtale (%@)";
|
||||
"secrets_setup_recovery_key_information" = "Oppbevar din sikkerhetsnøkkel trygt. Den kan brukes til å å tilgang til dine sikrede meldinger og data.";
|
||||
|
||||
// MARK: - Secrets set up
|
||||
|
||||
// Recovery Key
|
||||
|
||||
"secrets_setup_recovery_key_title" = "Lagre din sikkerhetsnøkkel";
|
||||
"secrets_recovery_with_key_invalid_recovery_key_message" = "Vennligst sjekk at du har tastet riktig sikkerhetsnøkkel.";
|
||||
"secrets_recovery_with_key_invalid_recovery_key_title" = "Ugyldig sikkerhetsnøkkel, ingen tilgang til sikret lagringsområde";
|
||||
"secrets_recovery_with_key_recover_action" = "Bruk sikkerhetsnøkkel";
|
||||
"secrets_setup_recovery_key_storage_alert_message" = "✓ Skriv ut og oppbevar på et trygt sted\n✓ Lagre på en USB minnepenn, eller ekstern sikkerhetskopi\n✓ Kopièr til din personlige skylagring";
|
||||
"secrets_recovery_with_passphrase_invalid_passphrase_title" = "Feil sikkerhetsfrase, ingen tilgang til sikret lagringsområde";
|
||||
"secrets_recovery_with_key_information_verify_device" = "Bruk din sikkerhetsnøkkel for å bekrefte denne enheten.";
|
||||
"secrets_recovery_with_key_information_default" = "Få tilgang til dine sikrede meldinger og identitetsnøkkelen som brukes for å bekrefte andre sesjoner, ved å taste inn din sikkerhetsnøkkel.";
|
||||
"secrets_recovery_with_passphrase_invalid_passphrase_message" = "Vennligst sjekk at du har tastet riktig sikkerhetsfrase.";
|
||||
"room_open_dialpad" = "Nummertastatur";
|
||||
"settings_labs" = "LABS";
|
||||
"room_place_voice_call" = "Lydsamtale";
|
||||
"settings_pin_rooms_with_unread" = "Feste rom med uleste meldinger";
|
||||
"settings_global_settings_info" = "Globale varslingsinnstillinger er tilgjengelige på din %@ nettleserklient";
|
||||
"room_multiple_typing_notification" = "%@ og andre";
|
||||
"room_event_action_delete_confirmation_message" = "Er du sikker på at du vil slette denne usendte meldingen?";
|
||||
"external_link_confirmation_message" = "Lenken %@ bringer deg til et annet nettsted: %@\n\nEr du sikker på at du vil fortsette?";
|
||||
"room_accessibility_video_call" = "Videosamtale";
|
||||
"room_event_action_delete_confirmation_title" = "Slett usendt melding";
|
||||
"room_unsent_messages_cancel_message" = "Er du sikker på at du vil slette alle usendte meldinger i dette rommet?";
|
||||
"room_unsent_messages_cancel_title" = "Slett usendte meldinger";
|
||||
"room_message_replying_to" = "Svarer til %@";
|
||||
"room_message_editing" = "Redigerer";
|
||||
"room_member_power_level_custom_in" = "Tilpasset (%@) av %@";
|
||||
"pin_protection_confirm_pin_to_disable" = "Bekreft PIN-kode for å deaktivere PIN-kode";
|
||||
"pin_protection_choose_pin" = "Opprett en PIN-kode for sikkerhet";
|
||||
"device_verification_self_verify_alert_message" = "Verifiser den nye påloggingen som vil ha tilgang til kontoen din:% @";
|
||||
|
||||
// Service terms - Variant for identity server when displayed out of a context
|
||||
"service_terms_modal_title_identity_server" = "Finne kontakter";
|
||||
"widget_integration_missing_room_id" = "Manglende rom_id i forespørsel.";
|
||||
"rage_shake_prompt" = "Det ser ut til at du rister telefonen i frustrasjon. Ønsker du å sende inn rapport om feil?";
|
||||
"room_details_addresses_invalid_address_prompt_title" = "Ugyldig alias format";
|
||||
"security_settings_crypto_sessions_description_2" = "Om du ikke gjenkjenner en pålogging, endre ditt passord og tilbakestill sikkerhetskopi.";
|
||||
"settings_key_backup_info_trust_signature_invalid_device_verified" = "Sikkerhetskopien har en ugyldig signatur fra %@";
|
||||
"settings_key_backup_info_trust_signature_valid_device_unverified" = "Sikkerhetskopi har signatur fra %@";
|
||||
"settings_key_backup_info_trust_signature_valid" = "Sikkerhetskopien har en gyldig signatur fra denne økten";
|
||||
"settings_key_backup_info_trust_signature_unknown" = "Sikkerhetskopi av økten har signatur med ID: %@";
|
||||
"settings_key_backup_info_progress_done" = "Alle nøkler sikkerhetskopiert";
|
||||
"settings_key_backup_info_progress" = "Sikkerhetskopierer %@ nøkler…";
|
||||
"settings_key_backup_info_not_valid" = "Denne økten sikkerhetskopierer ikke dine nøkler, men du har en eksisterende sikkerhetskopi du kan gjenopprette fra og legge til, for å gå videre.";
|
||||
"settings_key_backup_info_valid" = "Denne økten sikkerhetskopierer dine nøkler.";
|
||||
"settings_key_backup_info_version" = "Sikkerhetskopi av nøkler versjon : %@";
|
||||
"settings_key_backup_info_signout_warning" = "Før du logger ut, koble denne sesjonen til sikkerhetskopi av nøkler for å unngå tap av nøkler som kanskje bare er lagret på denne enheten.";
|
||||
"settings_key_backup_info_none" = "Nøklene dine for denne sesjonen blir ikke sikkerhetskopiert";
|
||||
"settings_third_party_notices" = "Tredjepartsmerknader";
|
||||
"settings_labs_e2e_encryption_prompt_message" = "Vennligst logg inn igjen for å ferdigstille oppsett av kryptering.";
|
||||
"settings_key_backup" = "Sikkerhetskopi av meldingsnøkler";
|
||||
"settings_ui_theme_picker_message" = "\"Auto\" bruker din enhets innstillinger for å bytte bakgrunnsfarge";
|
||||
|
||||
// MARK: - Favourites
|
||||
|
||||
"favourites_empty_view_title" = "Favorittrom og personer";
|
||||
"create_room_placeholder_address" = "#testrom: matrix.org";
|
||||
"device_verification_emoji_santa" = "Julenisse";
|
||||
"device_verification_security_advice_emoji" = "Sammenlign de unike emojiene, og sjekk at de vises i samme rekkefølge.";
|
||||
|
||||
// MARK: Sign out warning
|
||||
|
||||
"sign_out_existing_key_backup_alert_title" = "Er du sikker på at du vil logge av?";
|
||||
"service_terms_modal_message_identity_server" = "Godta brukervilkårene til identitetsserveren (%@) for å finne kontakter.";
|
||||
"event_formatter_call_back" = "Ring tilbake";
|
||||
"room_details_advanced_e2e_encryption_disabled" = "Kryptering er ikke aktivert i dette rommet.";
|
||||
"room_details_flair_section" = "Vi brukervalg for samfunn";
|
||||
"room_details_photo_for_dm" = "Bilde";
|
||||
"room_details_photo" = "Rombilde";
|
||||
"settings_flair" = "Vis brukervalg hvor tillat";
|
||||
"settings_on_denied_notification" = "Varsler er ikke tillat for %@, vennligst tillat dem i enhetens innstillinger";
|
||||
"settings_pin_rooms_with_missed_notif" = "Fest rom med tapte varsler";
|
||||
|
|
|
@ -1023,7 +1023,7 @@
|
|||
|
||||
// MARK: - Secrets reset
|
||||
|
||||
"secrets_reset_title" = "Alles terugzetten";
|
||||
"secrets_reset_title" = "Alles opnieuw instellen";
|
||||
"secrets_setup_recovery_passphrase_confirm_passphrase_placeholder" = "Wachtwoord bevestigen";
|
||||
"secrets_setup_recovery_passphrase_confirm_passphrase_title" = "Bevestigen";
|
||||
"secrets_setup_recovery_passphrase_validate_action" = "Klaar";
|
||||
|
@ -1058,7 +1058,7 @@
|
|||
// Recover with passphrase
|
||||
|
||||
"secrets_recovery_with_passphrase_title" = "Herstelwachtwoord";
|
||||
"secrets_recovery_reset_action_part_2" = "Alles terugzetten";
|
||||
"secrets_recovery_reset_action_part_2" = "Alles opnieuw instellen";
|
||||
|
||||
// MARK: - Secrets recovery
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// Permissions usage explanations
|
||||
"NSCameraUsageDescription" = "Aparat służy do robienia zdjęć i nagrywania filmów, prowadzenia rozmów wideo.";
|
||||
"NSPhotoLibraryUsageDescription" = "Biblioteka zdjęć służy do wysyłania zdjęć i filmów.";
|
||||
"NSMicrophoneUsageDescription" = "Mikrofon służy do robienia filmów, wykonywania połączeń.";
|
||||
"NSContactsUsageDescription" = "Możemy pokazać Ci, które z Twoich kontaktów korzystają aktualnie z Element, bądź Matrix. Możemy wysyłać adresy e-mail i numery telefonów z Twojej książki adresowej na Twój serwer Matrix. New Vector nie przechowuje Twoich danych, ani nie wykorzystuje ich w żadnym celu. Aby uzyskać dodatkowe informacje zajrzyj do zakładki \"polityka prywatności\" w ustawieniach aplikacji.";
|
||||
"NSCameraUsageDescription" = "Kamera wykorzystywana jest do robienia zdjęć, nagrywania filmów i prowadzenia rozmów wideo.";
|
||||
"NSPhotoLibraryUsageDescription" = "Biblioteka zdjęć wykorzystywana jest do wysyłania zdjęć i filmów.";
|
||||
"NSMicrophoneUsageDescription" = "Mikrofon wykorzystywany jest podczas nagrywania filmów i wykonywania połączeń.";
|
||||
"NSContactsUsageDescription" = "Aby móc znaleźć osoby z Twoich kontaktów, które korzystają już z sieci Matrix, Element może wysłać adresy e-mail i numery telefonów z Twojej książki adresowej do wybranego serwera tożsamości Matrix. Tam, gdzie jest to obsługiwane, dane osobowe są szyfrowane przed wysłaniem - zapoznaj się z polityką prywatności Twojego serwera tożsamości, aby uzyskać więcej informacji.";
|
||||
"NSCalendarsUsageDescription" = "Zobacz swoje zaplanowane spotkania w aplikacji.";
|
||||
"NSFaceIDUsageDescription" = "Face ID wykorzystywane jest do odblokowywania aplikacji.";
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* New message from a specific person, not referencing a room */
|
||||
"MSG_FROM_USER" = "%@ wysłał(a) wiadomość";
|
||||
"MSG_FROM_USER" = "%@ wysłał(-a) wiadomość";
|
||||
/* New message from a specific person, not referencing a room. Content included. */
|
||||
"MSG_FROM_USER_WITH_CONTENT" = "%@: %@";
|
||||
/* New message from a specific person in a named room. Content included. */
|
||||
|
@ -23,27 +23,27 @@
|
|||
/* Look, stuff's happened, alright? Just open the app. */
|
||||
"MSGS_IN_TWO_PLUS_ROOMS" = "%@ nowych wiadomości w %@, %@ i innych";
|
||||
/* New action message from a specific person, not referencing a room. */
|
||||
"IMAGE_FROM_USER" = "%@ wysłał(a) zdjęcie %@";
|
||||
"IMAGE_FROM_USER" = "%@ wysłał(-a) zdjęcie %@";
|
||||
/* New action message from a specific person in a named room. */
|
||||
"IMAGE_FROM_USER_IN_ROOM" = "%@ wysłał(a) zdjęcie %@ w %@";
|
||||
"IMAGE_FROM_USER_IN_ROOM" = "%@ wysłał(-a) zdjęcie %@ w %@";
|
||||
/* Multiple unread messages from a specific person, not referencing a room */
|
||||
"MSGS_FROM_USER" = "%@ nowych wiadomości w %@";
|
||||
/* Multiple messages in two rooms */
|
||||
"MSGS_IN_TWO_ROOMS" = "%@ nowych wiadomości w %@ i %@";
|
||||
/* A user has invited you to a named room */
|
||||
"USER_INVITE_TO_NAMED_ROOM" = "%@ zaprosił(a) Ciebie do %@";
|
||||
"USER_INVITE_TO_NAMED_ROOM" = "%@ zaprosił(-a) Ciebie do %@";
|
||||
/* A user has invited you to an (unamed) group chat */
|
||||
"USER_INVITE_TO_CHAT_GROUP_CHAT" = "%@ zaprosił(a) Ciebie do rozmowy grupowej";
|
||||
"USER_INVITE_TO_CHAT_GROUP_CHAT" = "%@ zaprosił(-a) Ciebie do rozmowy grupowej";
|
||||
/* A user has invited you to a chat */
|
||||
"USER_INVITE_TO_CHAT" = "%@ zaprosił(a) Ciebie do rozmowy";
|
||||
"USER_INVITE_TO_CHAT" = "%@ zaprosił(-a) Ciebie do rozmowy";
|
||||
/* Message title for a specific person in a named room */
|
||||
"MSG_FROM_USER_IN_ROOM_TITLE" = "%@ w %@";
|
||||
/* New message from a specific person in a named room */
|
||||
"MSG_FROM_USER_IN_ROOM" = "%@ opublikowany w %@";
|
||||
/* Sticker from a specific person, not referencing a room. */
|
||||
"STICKER_FROM_USER" = "%@ wysłał(a) naklejkę";
|
||||
"STICKER_FROM_USER" = "%@ wysłał(-a) naklejkę";
|
||||
/* Incoming one-to-one voice call */
|
||||
"VOICE_CALL_FROM_USER" = "Zadzwonił do Ciebie z %@";
|
||||
"VOICE_CALL_FROM_USER" = "Połączenie głosowe z %@";
|
||||
/* Incoming one-to-one video call */
|
||||
"VIDEO_CALL_FROM_USER" = "Połączenie wideo z %@";
|
||||
/* Incoming unnamed voice conference invite from a specific person */
|
||||
|
@ -54,10 +54,11 @@
|
|||
"VOICE_CONF_NAMED_FROM_USER" = "Połączenie grupowe z %@: '%@'";
|
||||
/* Incoming named video conference invite from a specific person */
|
||||
"VIDEO_CONF_NAMED_FROM_USER" = "Grupowe połączenie wideo z %@: '%@'";
|
||||
"KEY_VERIFICATION_REQUEST_FROM_USER" = "%@ wymaga weryfikacji";
|
||||
"KEY_VERIFICATION_REQUEST_FROM_USER" = "%@ chce się z Tobą zweryfikować";
|
||||
/* New message indicator on unknown room */
|
||||
"MESSAGE" = "Wiadomość";
|
||||
/* New message indicator from a DM */
|
||||
"MESSAGE_FROM_X" = "Wiadomość od %@";
|
||||
/* New message indicator on a room */
|
||||
"MESSAGE_IN_X" = "Wiadomość w %@";
|
||||
"MESSAGE_PROTECTED" = "Nowa Wiadomość";
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
"title_groups" = "Bashkësi";
|
||||
"warning" = "Sinjalizim";
|
||||
// Actions
|
||||
"view" = "Parje";
|
||||
"view" = "Shiheni";
|
||||
"next" = "Pasuesja";
|
||||
"back" = "Mbrapsht";
|
||||
"continue" = "Vazhdo";
|
||||
|
@ -1344,3 +1344,4 @@
|
|||
"room_accessibility_video_call" = "Thirrje Video";
|
||||
"room_message_replying_to" = "Në përgjigje të %@";
|
||||
"room_message_editing" = "Përpunim";
|
||||
"room_details_search" = "Kërkoni për dhomë";
|
||||
|
|
|
@ -1 +1,4 @@
|
|||
|
||||
|
||||
"NSFaceIDUsageDescription" = "ittusmres Face ID i wekcam ɣer tsensi nnek.";
|
||||
"NSPhotoLibraryUsageDescription" = "Tettusmres tasedlist n twelafin i wazan n twelafin d ibidyuten.";
|
||||
|
|
|
@ -58,13 +58,6 @@ extern NSString *const kMXKRoomBubbleCellKeyVerificationIncomingRequestAcceptPre
|
|||
*/
|
||||
extern NSString *const kMXKRoomBubbleCellKeyVerificationIncomingRequestDeclinePressed;
|
||||
|
||||
/**
|
||||
Action identifier used when the user pressed "Call back" button for a declined call.
|
||||
|
||||
The `userInfo` dictionary contains an `MXEvent` object under the `kMXKRoomBubbleCellEventKey` key, representing the invite event of the declined call.
|
||||
*/
|
||||
extern NSString *const kMXKRoomBubbleCellCallBackButtonPressed;
|
||||
|
||||
/**
|
||||
Define a `MXKRoomBubbleTableViewCell` category at Riot level to handle bubble customisation.
|
||||
*/
|
||||
|
|
|
@ -33,7 +33,6 @@ NSString *const kMXKRoomBubbleCellLongPressOnReactionView = @"kMXKRoomBubbleCell
|
|||
NSString *const kMXKRoomBubbleCellEventIdKey = @"kMXKRoomBubbleCellEventIdKey";
|
||||
NSString *const kMXKRoomBubbleCellKeyVerificationIncomingRequestAcceptPressed = @"kMXKRoomBubbleCellKeyVerificationAcceptPressed";
|
||||
NSString *const kMXKRoomBubbleCellKeyVerificationIncomingRequestDeclinePressed = @"kMXKRoomBubbleCellKeyVerificationDeclinePressed";
|
||||
NSString *const kMXKRoomBubbleCellCallBackButtonPressed = @"kMXKRoomBubbleCellCallBackButtonPressed";
|
||||
|
||||
@implementation MXKRoomBubbleTableViewCell (Riot)
|
||||
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
|
||||
#import <MatrixSDK/MXSession.h>
|
||||
|
||||
@class HomeserverConfiguration;
|
||||
|
||||
@interface MXSession (Riot)
|
||||
|
||||
/**
|
||||
|
@ -26,15 +28,9 @@
|
|||
- (NSUInteger)vc_missedDiscussionsCount;
|
||||
|
||||
/**
|
||||
Check if E2E by default is welcomed on the user's HS.
|
||||
The default value is YES.
|
||||
|
||||
HS admins can disable it in /.well-known/matrix/client by returning:
|
||||
"im.vector.riot.e2ee": {
|
||||
"default": false
|
||||
}
|
||||
*/
|
||||
- (BOOL)vc_isE2EByDefaultEnabledByHSAdmin;
|
||||
Return the homeserver configuration based on HS Well-Known or BuildSettings properties according to existing values.
|
||||
*/
|
||||
- (HomeserverConfiguration*)vc_homeserverConfiguration;
|
||||
|
||||
/**
|
||||
Riot version of [MXSession canEnableE2EByDefaultInNewRoomWithUsers:]
|
||||
|
|
|
@ -49,25 +49,17 @@
|
|||
return missedDiscussionsCount;
|
||||
}
|
||||
|
||||
- (BOOL)vc_isE2EByDefaultEnabledByHSAdmin
|
||||
- (HomeserverConfiguration*)vc_homeserverConfiguration
|
||||
{
|
||||
BOOL isE2EByDefaultEnabledByHSAdmin = YES;
|
||||
|
||||
MXWellKnown *wellKnown = self.homeserverWellknown;
|
||||
|
||||
if (wellKnown.JSONDictionary[@"im.vector.riot.e2ee"][@"default"])
|
||||
{
|
||||
MXJSONModelSetBoolean(isE2EByDefaultEnabledByHSAdmin, wellKnown.JSONDictionary[@"im.vector.riot.e2ee"][@"default"]);
|
||||
}
|
||||
|
||||
return isE2EByDefaultEnabledByHSAdmin;
|
||||
HomeserverConfigurationBuilder *configurationBuilder = [HomeserverConfigurationBuilder new];
|
||||
return [configurationBuilder buildFrom:self.homeserverWellknown];
|
||||
}
|
||||
|
||||
- (MXHTTPOperation*)vc_canEnableE2EByDefaultInNewRoomWithUsers:(NSArray<NSString*>*)userIds
|
||||
success:(void (^)(BOOL canEnableE2E))success
|
||||
failure:(void (^)(NSError *error))failure;
|
||||
{
|
||||
if (self.vc_isE2EByDefaultEnabledByHSAdmin)
|
||||
if ([self vc_homeserverConfiguration].isE2EEByDefaultEnabled)
|
||||
{
|
||||
return [self canEnableE2EByDefaultInNewRoomWithUsers:userIds success:success failure:failure];
|
||||
}
|
||||
|
|
|
@ -64,4 +64,16 @@ extension UIView {
|
|||
self.accessibilityTraits.insert(.notEnabled)
|
||||
}
|
||||
}
|
||||
|
||||
@objc func vc_addShadow(withColor color: UIColor, offset: CGSize, radius: CGFloat, opacity: CGFloat) {
|
||||
layer.shadowColor = color.cgColor
|
||||
layer.shadowOpacity = Float(opacity)
|
||||
layer.shadowRadius = radius
|
||||
layer.shadowOffset = offset
|
||||
}
|
||||
|
||||
@objc func vc_removeShadow() {
|
||||
layer.shadowColor = UIColor.clear.cgColor
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ internal enum Asset {
|
|||
internal static let callChatIcon = ImageAsset(name: "call_chat_icon")
|
||||
internal static let callDialpadBackspaceIcon = ImageAsset(name: "call_dialpad_backspace_icon")
|
||||
internal static let callDialpadCallIcon = ImageAsset(name: "call_dialpad_call_icon")
|
||||
internal static let callGoToChatIcon = ImageAsset(name: "call_go_to_chat_icon")
|
||||
internal static let callHangupLarge = ImageAsset(name: "call_hangup_large")
|
||||
internal static let callMoreIcon = ImageAsset(name: "call_more_icon")
|
||||
internal static let callPausedIcon = ImageAsset(name: "call_paused_icon")
|
||||
|
@ -104,7 +105,9 @@ internal enum Asset {
|
|||
internal static let actionSticker = ImageAsset(name: "action_sticker")
|
||||
internal static let error = ImageAsset(name: "error")
|
||||
internal static let errorMessageTick = ImageAsset(name: "error_message_tick")
|
||||
internal static let newClose = ImageAsset(name: "new_close")
|
||||
internal static let roomActivitiesRetry = ImageAsset(name: "room_activities_retry")
|
||||
internal static let roomScrollUp = ImageAsset(name: "room_scroll_up")
|
||||
internal static let scrolldown = ImageAsset(name: "scrolldown")
|
||||
internal static let scrolldownDark = ImageAsset(name: "scrolldown_dark")
|
||||
internal static let sendingMessageTick = ImageAsset(name: "sending_message_tick")
|
||||
|
|
|
@ -502,10 +502,14 @@ internal enum VectorL10n {
|
|||
internal static func callbarOnlyMultiplePaused(_ p1: String) -> String {
|
||||
return VectorL10n.tr("Vector", "callbar_only_multiple_paused", p1)
|
||||
}
|
||||
/// Active call (%@)
|
||||
/// Tap to return to the call (%@)
|
||||
internal static func callbarOnlySingleActive(_ p1: String) -> String {
|
||||
return VectorL10n.tr("Vector", "callbar_only_single_active", p1)
|
||||
}
|
||||
/// Tap to Join the group call (%@)
|
||||
internal static func callbarOnlySingleActiveGroup(_ p1: String) -> String {
|
||||
return VectorL10n.tr("Vector", "callbar_only_single_active_group", p1)
|
||||
}
|
||||
/// Paused call
|
||||
internal static var callbarOnlySinglePaused: String {
|
||||
return VectorL10n.tr("Vector", "callbar_only_single_paused")
|
||||
|
@ -1238,13 +1242,41 @@ internal enum VectorL10n {
|
|||
internal static var errorUserAlreadyLoggedIn: String {
|
||||
return VectorL10n.tr("Vector", "error_user_already_logged_in")
|
||||
}
|
||||
/// Answer
|
||||
internal static var eventFormatterCallAnswer: String {
|
||||
return VectorL10n.tr("Vector", "event_formatter_call_answer")
|
||||
}
|
||||
/// Call back
|
||||
internal static var eventFormatterCallBack: String {
|
||||
return VectorL10n.tr("Vector", "event_formatter_call_back")
|
||||
}
|
||||
/// This call has ended
|
||||
internal static var eventFormatterCallHasEnded: String {
|
||||
return VectorL10n.tr("Vector", "event_formatter_call_has_ended")
|
||||
/// Connecting…
|
||||
internal static var eventFormatterCallConnecting: String {
|
||||
return VectorL10n.tr("Vector", "event_formatter_call_connecting")
|
||||
}
|
||||
/// Connection failed
|
||||
internal static var eventFormatterCallConnectionFailed: String {
|
||||
return VectorL10n.tr("Vector", "event_formatter_call_connection_failed")
|
||||
}
|
||||
/// Decline
|
||||
internal static var eventFormatterCallDecline: String {
|
||||
return VectorL10n.tr("Vector", "event_formatter_call_decline")
|
||||
}
|
||||
/// End call
|
||||
internal static var eventFormatterCallEndCall: String {
|
||||
return VectorL10n.tr("Vector", "event_formatter_call_end_call")
|
||||
}
|
||||
/// Ended %@
|
||||
internal static func eventFormatterCallHasEnded(_ p1: String) -> String {
|
||||
return VectorL10n.tr("Vector", "event_formatter_call_has_ended", p1)
|
||||
}
|
||||
/// Retry
|
||||
internal static var eventFormatterCallRetry: String {
|
||||
return VectorL10n.tr("Vector", "event_formatter_call_retry")
|
||||
}
|
||||
/// Ringing…
|
||||
internal static var eventFormatterCallRinging: String {
|
||||
return VectorL10n.tr("Vector", "event_formatter_call_ringing")
|
||||
}
|
||||
/// Video call
|
||||
internal static var eventFormatterCallVideo: String {
|
||||
|
@ -1254,7 +1286,7 @@ internal enum VectorL10n {
|
|||
internal static var eventFormatterCallVoice: String {
|
||||
return VectorL10n.tr("Vector", "event_formatter_call_voice")
|
||||
}
|
||||
/// You're currently in this call
|
||||
/// Active call
|
||||
internal static var eventFormatterCallYouCurrentlyIn: String {
|
||||
return VectorL10n.tr("Vector", "event_formatter_call_you_currently_in")
|
||||
}
|
||||
|
@ -1262,6 +1294,26 @@ internal enum VectorL10n {
|
|||
internal static var eventFormatterCallYouDeclined: String {
|
||||
return VectorL10n.tr("Vector", "event_formatter_call_you_declined")
|
||||
}
|
||||
/// You missed this call
|
||||
internal static var eventFormatterCallYouMissed: String {
|
||||
return VectorL10n.tr("Vector", "event_formatter_call_you_missed")
|
||||
}
|
||||
/// Group call
|
||||
internal static var eventFormatterGroupCall: String {
|
||||
return VectorL10n.tr("Vector", "event_formatter_group_call")
|
||||
}
|
||||
/// %@ in %@
|
||||
internal static func eventFormatterGroupCallIncoming(_ p1: String, _ p2: String) -> String {
|
||||
return VectorL10n.tr("Vector", "event_formatter_group_call_incoming", p1, p2)
|
||||
}
|
||||
/// Join
|
||||
internal static var eventFormatterGroupCallJoin: String {
|
||||
return VectorL10n.tr("Vector", "event_formatter_group_call_join")
|
||||
}
|
||||
/// Leave
|
||||
internal static var eventFormatterGroupCallLeave: String {
|
||||
return VectorL10n.tr("Vector", "event_formatter_group_call_leave")
|
||||
}
|
||||
/// VoIP conference added by %@
|
||||
internal static func eventFormatterJitsiWidgetAdded(_ p1: String) -> String {
|
||||
return VectorL10n.tr("Vector", "event_formatter_jitsi_widget_added", p1)
|
||||
|
@ -2874,7 +2926,11 @@ internal enum VectorL10n {
|
|||
internal static var roomIntroCellInformationRoomWithoutTopicSentence2Part2: String {
|
||||
return VectorL10n.tr("Vector", "room_intro_cell_information_room_without_topic_sentence2_part2")
|
||||
}
|
||||
/// Jump to first unread message
|
||||
/// Join
|
||||
internal static var roomJoinGroupCall: String {
|
||||
return VectorL10n.tr("Vector", "room_join_group_call")
|
||||
}
|
||||
/// Jump to unread
|
||||
internal static var roomJumpToFirstUnread: String {
|
||||
return VectorL10n.tr("Vector", "room_jump_to_first_unread")
|
||||
}
|
||||
|
@ -2950,6 +3006,10 @@ internal enum VectorL10n {
|
|||
internal static func roomNewMessagesNotification(_ p1: Int) -> String {
|
||||
return VectorL10n.tr("Vector", "room_new_messages_notification", p1)
|
||||
}
|
||||
/// You need to be an admin or a moderator to start a call.
|
||||
internal static var roomNoPrivilegesToCreateGroupCall: String {
|
||||
return VectorL10n.tr("Vector", "room_no_privileges_to_create_group_call")
|
||||
}
|
||||
/// Connectivity to the server has been lost.
|
||||
internal static var roomOfflineNotification: String {
|
||||
return VectorL10n.tr("Vector", "room_offline_notification")
|
||||
|
@ -3330,6 +3390,10 @@ internal enum VectorL10n {
|
|||
internal static var roomResourceUsageLimitReachedMessageContact3: String {
|
||||
return VectorL10n.tr("Vector", "room_resource_usage_limit_reached_message_contact_3")
|
||||
}
|
||||
/// Slide to end the call for everyone
|
||||
internal static var roomSlideToEndGroupCall: String {
|
||||
return VectorL10n.tr("Vector", "room_slide_to_end_group_call")
|
||||
}
|
||||
/// Invite members
|
||||
internal static var roomTitleInviteMembers: String {
|
||||
return VectorL10n.tr("Vector", "room_title_invite_members")
|
||||
|
@ -4230,6 +4294,10 @@ internal enum VectorL10n {
|
|||
internal static var settingsLabsE2eEncryptionPromptMessage: String {
|
||||
return VectorL10n.tr("Vector", "settings_labs_e2e_encryption_prompt_message")
|
||||
}
|
||||
/// Ring for group calls
|
||||
internal static var settingsLabsEnableRingingForGroupCalls: String {
|
||||
return VectorL10n.tr("Vector", "settings_labs_enable_ringing_for_group_calls")
|
||||
}
|
||||
/// React to messages with emoji
|
||||
internal static var settingsLabsMessageReaction: String {
|
||||
return VectorL10n.tr("Vector", "settings_labs_message_reaction")
|
||||
|
|
|
@ -17,39 +17,67 @@
|
|||
import Foundation
|
||||
import MatrixKit
|
||||
|
||||
// swiftlint:disable file_length
|
||||
|
||||
#if canImport(JitsiMeetSDK)
|
||||
import JitsiMeetSDK
|
||||
import CallKit
|
||||
#endif
|
||||
|
||||
/// The number of milliseconds in one second.
|
||||
private let MSEC_PER_SEC: TimeInterval = 1000
|
||||
|
||||
@objcMembers
|
||||
/// Service to manage call screens and call bar UI management.
|
||||
class CallPresenter: NSObject {
|
||||
|
||||
private enum Constants {
|
||||
static let pipAnimationDuration: TimeInterval = 0.25
|
||||
static let groupCallInviteLifetime: TimeInterval = 30
|
||||
}
|
||||
|
||||
/// Utilized sessions
|
||||
private var sessions: [MXSession] = []
|
||||
/// Call view controllers map. Keys are callIds.
|
||||
private var callVCs: [String: CallViewController] = [:]
|
||||
/// Call background tasks map. Keys are callIds.
|
||||
private var callBackgroundTasks: [String: MXBackgroundTask] = [:]
|
||||
private weak var presentedCallVC: CallViewController? {
|
||||
/// Actively presented direct call view controller.
|
||||
private weak var presentedCallVC: UIViewController? {
|
||||
didSet {
|
||||
updateOnHoldCall()
|
||||
}
|
||||
}
|
||||
private weak var inBarCallVC: CallViewController?
|
||||
private weak var pipCallVC: CallViewController?
|
||||
private weak var inBarCallVC: UIViewController?
|
||||
private weak var pipCallVC: UIViewController?
|
||||
/// UI operation queue for various UI operations
|
||||
private var uiOperationQueue: OperationQueue = .main
|
||||
/// Flag to indicate whether the presenter is active.
|
||||
private var isStarted: Bool = false
|
||||
private var callTimer: Timer?
|
||||
#if canImport(JitsiMeetSDK)
|
||||
private var widgetEventsListener: Any?
|
||||
/// Jitsi calls map. Keys are CallKit call UUIDs, values are corresponding widgets.
|
||||
private var jitsiCalls: [UUID: Widget] = [:]
|
||||
/// The current Jitsi view controller being displayed or not.
|
||||
private(set) var jitsiVC: JitsiViewController? {
|
||||
didSet {
|
||||
updateOnHoldCall()
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
private var isCallKitEnabled: Bool {
|
||||
MXCallKitAdapter.callKitAvailable() && MXKAppSettings.standard()?.isCallKitEnabled == true
|
||||
}
|
||||
|
||||
private var activeCallVC: CallViewController? {
|
||||
private var activeCallVC: UIViewController? {
|
||||
return callVCs.values.filter { (callVC) -> Bool in
|
||||
guard let call = callVC.mxCall else {
|
||||
return false
|
||||
}
|
||||
return !call.isOnHold
|
||||
}.first
|
||||
}.first ?? jitsiVC
|
||||
}
|
||||
|
||||
private var onHoldCallVCs: [CallViewController] {
|
||||
|
@ -101,20 +129,201 @@ class CallPresenter: NSObject {
|
|||
}
|
||||
|
||||
/// Method to be called when the call status bar is tapped.
|
||||
/// - Returns: If the user interaction handled or not
|
||||
func callStatusBarButtonTapped() -> Bool {
|
||||
if let callVC = inBarCallVC ?? activeCallVC {
|
||||
func callStatusBarTapped() {
|
||||
if let callVC = (inBarCallVC ?? activeCallVC) as? CallViewController {
|
||||
dismissCallBar(for: callVC)
|
||||
presentCallVC(callVC)
|
||||
return true
|
||||
return
|
||||
}
|
||||
if let jitsiVC = jitsiVC {
|
||||
dismissCallBar(for: jitsiVC)
|
||||
presentCallVC(jitsiVC)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK - Group Calls
|
||||
|
||||
/// Open the Jitsi view controller from a widget.
|
||||
/// - Parameter widget: the jitsi widget
|
||||
func displayJitsiCall(withWidget widget: Widget) {
|
||||
#if canImport(JitsiMeetSDK)
|
||||
let createJitsiBlock = { [weak self] in
|
||||
guard let self = self else { return }
|
||||
self.jitsiVC = JitsiViewController()
|
||||
self.jitsiVC?.openWidget(widget, withVideo: true, success: { [weak self] in
|
||||
guard let self = self else { return }
|
||||
if let jitsiVC = self.jitsiVC {
|
||||
jitsiVC.delegate = self
|
||||
self.presentCallVC(jitsiVC)
|
||||
self.startJitsiCall(withWidget: widget)
|
||||
}
|
||||
}, failure: { [weak self] (error) in
|
||||
guard let self = self else { return }
|
||||
self.jitsiVC = nil
|
||||
AppDelegate.theDelegate().showAlert(withTitle: nil,
|
||||
message: VectorL10n.callJitsiError)
|
||||
})
|
||||
}
|
||||
|
||||
if let jitsiVC = jitsiVC {
|
||||
if jitsiVC.widget.widgetId == widget.widgetId {
|
||||
self.presentCallVC(jitsiVC)
|
||||
} else {
|
||||
// end previous Jitsi call first
|
||||
endActiveJitsiCall()
|
||||
createJitsiBlock()
|
||||
}
|
||||
} else {
|
||||
createJitsiBlock()
|
||||
}
|
||||
#else
|
||||
AppDelegate.theDelegate().showAlert(withTitle: nil,
|
||||
message: Bundle.mxk_localizedString(forKey: "not_supported_yet"))
|
||||
#endif
|
||||
}
|
||||
|
||||
private func startJitsiCall(withWidget widget: Widget) {
|
||||
if self.jitsiCalls.first(where: { $0.value.widgetId == widget.widgetId })?.key != nil {
|
||||
// this Jitsi call is already managed by this class, no need to report the call again
|
||||
return
|
||||
}
|
||||
|
||||
guard let roomId = widget.roomId else {
|
||||
return
|
||||
}
|
||||
|
||||
guard let session = sessions.first else {
|
||||
return
|
||||
}
|
||||
|
||||
guard let room = session.room(withRoomId: roomId) else {
|
||||
return
|
||||
}
|
||||
|
||||
let newUUID = UUID()
|
||||
let handle = CXHandle(type: .generic, value: roomId)
|
||||
let startCallAction = CXStartCallAction(call: newUUID, handle: handle)
|
||||
let transaction = CXTransaction(action: startCallAction)
|
||||
JMCallKitProxy.request(transaction) { (error) in
|
||||
if error == nil {
|
||||
JMCallKitProxy.reportCallUpdate(with: newUUID,
|
||||
handle: roomId,
|
||||
displayName: room.summary.displayname,
|
||||
hasVideo: true)
|
||||
JMCallKitProxy.reportOutgoingCall(with: newUUID, connectedAt: nil)
|
||||
|
||||
self.jitsiCalls[newUUID] = widget
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func endActiveJitsiCall() {
|
||||
guard let jitsiVC = jitsiVC else {
|
||||
// there is no active Jitsi call
|
||||
return
|
||||
}
|
||||
|
||||
if pipCallVC == jitsiVC {
|
||||
// this call currently in the PiP mode,
|
||||
// first present it by exiting PiP mode and then dismiss it
|
||||
exitPipCallVC(jitsiVC)
|
||||
}
|
||||
|
||||
dismissCallVC(jitsiVC)
|
||||
jitsiVC.hangup()
|
||||
|
||||
self.jitsiVC = nil
|
||||
|
||||
guard let widget = jitsiVC.widget else {
|
||||
return
|
||||
}
|
||||
guard let uuid = self.jitsiCalls.first(where: { $0.value.widgetId == widget.widgetId })?.key else {
|
||||
// this Jitsi call is not managed by this class
|
||||
return
|
||||
}
|
||||
|
||||
let endCallAction = CXEndCallAction(call: uuid)
|
||||
let transaction = CXTransaction(action: endCallAction)
|
||||
JMCallKitProxy.request(transaction) { (error) in
|
||||
if error == nil {
|
||||
self.jitsiCalls.removeValue(forKey: uuid)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func processWidgetEvent(_ event: MXEvent, inSession session: MXSession) {
|
||||
guard JMCallKitProxy.isProviderConfigured() else {
|
||||
// CallKit proxy is not configured, no benefit in parsing the event
|
||||
return
|
||||
}
|
||||
|
||||
guard let widget = Widget(widgetEvent: event, inMatrixSession: session) else {
|
||||
return
|
||||
}
|
||||
|
||||
if self.jitsiCalls.first(where: { $0.value.widgetId == widget.widgetId })?.key != nil {
|
||||
// this Jitsi call is already managed by this class, no need to report the call again
|
||||
return
|
||||
}
|
||||
|
||||
if widget.isActive {
|
||||
guard widget.type == kWidgetTypeJitsiV1 || widget.type == kWidgetTypeJitsiV2 else {
|
||||
// not a Jitsi widget, ignore
|
||||
return
|
||||
}
|
||||
|
||||
if let jitsiVC = jitsiVC,
|
||||
jitsiVC.widget.widgetId == widget.widgetId {
|
||||
// this is already the Jitsi call we have atm
|
||||
return
|
||||
}
|
||||
|
||||
if TimeInterval(event.age)/MSEC_PER_SEC > Constants.groupCallInviteLifetime {
|
||||
// too late to process the event
|
||||
return
|
||||
}
|
||||
|
||||
// an active Jitsi widget
|
||||
let newUUID = UUID()
|
||||
|
||||
// assume this Jitsi call will survive
|
||||
self.jitsiCalls[newUUID] = widget
|
||||
|
||||
if event.sender == session.myUserId {
|
||||
// outgoing call
|
||||
JMCallKitProxy.reportOutgoingCall(with: newUUID, connectedAt: nil)
|
||||
} else {
|
||||
// incoming call
|
||||
guard RiotSettings.shared.enableRingingForGroupCalls else {
|
||||
// do not ring for Jitsi calls
|
||||
return
|
||||
}
|
||||
let user = session.user(withUserId: event.sender)
|
||||
let displayName = NSString.localizedUserNotificationString(forKey: "GROUP_CALL_FROM_USER",
|
||||
arguments: [user?.displayname as Any])
|
||||
JMCallKitProxy.reportNewIncomingCall(UUID: newUUID,
|
||||
handle: widget.roomId,
|
||||
displayName: displayName,
|
||||
hasVideo: true) { (error) in
|
||||
if error != nil {
|
||||
self.jitsiCalls.removeValue(forKey: newUUID)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
guard let uuid = self.jitsiCalls.first(where: { $0.value.widgetId == widget.widgetId })?.key else {
|
||||
// this Jitsi call is not managed by this class
|
||||
return
|
||||
}
|
||||
JMCallKitProxy.reportCall(with: uuid, endedAt: nil, reason: .remoteEnded)
|
||||
self.jitsiCalls.removeValue(forKey: uuid)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private func updateOnHoldCall() {
|
||||
guard let presentedCallVC = presentedCallVC else {
|
||||
guard let presentedCallVC = presentedCallVC as? CallViewController else {
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -131,9 +340,6 @@ class CallPresenter: NSObject {
|
|||
}
|
||||
|
||||
private func shouldHandleCall(_ call: MXCall) -> Bool {
|
||||
if let delegate = delegate, !delegate.callPresenter(self, shouldHandleNewCall: call) {
|
||||
return false
|
||||
}
|
||||
return callVCs.count < maximumNumberOfConcurrentCalls
|
||||
}
|
||||
|
||||
|
@ -181,7 +387,19 @@ class CallPresenter: NSObject {
|
|||
}
|
||||
return
|
||||
}
|
||||
dismissCallVC(callVC, completion: completion)
|
||||
if callVC.isDisplayingAlert {
|
||||
completion()
|
||||
} else {
|
||||
dismissCallVC(callVC, completion: completion)
|
||||
}
|
||||
}
|
||||
|
||||
private func logCallVC(_ callVC: UIViewController, log: String) {
|
||||
if let callVC = callVC as? CallViewController {
|
||||
NSLog("[CallPresenter] \(log): call: \(String(describing: callVC.mxCall?.callId))")
|
||||
} else if let callVC = callVC as? JitsiViewController {
|
||||
NSLog("[CallPresenter] \(log): call: \(callVC.widget.widgetId)")
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Timer
|
||||
|
@ -200,17 +418,18 @@ class CallPresenter: NSObject {
|
|||
}
|
||||
|
||||
@objc private func callTimerFired(_ timer: Timer) {
|
||||
guard let inBarCallVC = inBarCallVC else {
|
||||
return
|
||||
if let inBarCallVC = inBarCallVC as? CallViewController {
|
||||
guard let call = inBarCallVC.mxCall else {
|
||||
return
|
||||
}
|
||||
guard call.state != .ended else {
|
||||
return
|
||||
}
|
||||
|
||||
updateCallBar()
|
||||
} else if inBarCallVC as? JitsiViewController != nil {
|
||||
updateCallBar()
|
||||
}
|
||||
guard let call = inBarCallVC.mxCall else {
|
||||
return
|
||||
}
|
||||
guard call.state != .ended else {
|
||||
return
|
||||
}
|
||||
|
||||
presentCallBar(for: inBarCallVC, isUpdateOnly: true)
|
||||
}
|
||||
|
||||
// MARK: - Observers
|
||||
|
@ -232,8 +451,32 @@ class CallPresenter: NSObject {
|
|||
selector: #selector(callTileTapped(_:)),
|
||||
name: .RoomCallTileTapped,
|
||||
object: nil)
|
||||
NotificationCenter.default.addObserver(self,
|
||||
selector: #selector(groupCallTileTapped(_:)),
|
||||
name: .RoomGroupCallTileTapped,
|
||||
object: nil)
|
||||
|
||||
isStarted = true
|
||||
|
||||
#if canImport(JitsiMeetSDK)
|
||||
JMCallKitProxy.addListener(self)
|
||||
|
||||
guard let session = sessions.first else {
|
||||
return
|
||||
}
|
||||
|
||||
widgetEventsListener = session.listenToEvents([
|
||||
MXEventType(identifier: kWidgetMatrixEventTypeString),
|
||||
MXEventType(identifier: kWidgetModularEventTypeString)
|
||||
]) { (event, direction, _) in
|
||||
if direction == .backwards {
|
||||
// ignore backwards events
|
||||
return
|
||||
}
|
||||
|
||||
self.processWidgetEvent(event, inSession: session)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
private func removeCallObservers() {
|
||||
|
@ -250,8 +493,24 @@ class CallPresenter: NSObject {
|
|||
NotificationCenter.default.removeObserver(self,
|
||||
name: .RoomCallTileTapped,
|
||||
object: nil)
|
||||
NotificationCenter.default.removeObserver(self,
|
||||
name: .RoomGroupCallTileTapped,
|
||||
object: nil)
|
||||
|
||||
isStarted = false
|
||||
|
||||
#if canImport(JitsiMeetSDK)
|
||||
JMCallKitProxy.removeListener(self)
|
||||
|
||||
guard let session = sessions.first else {
|
||||
return
|
||||
}
|
||||
|
||||
if let widgetEventsListener = widgetEventsListener {
|
||||
session.removeListener(widgetEventsListener)
|
||||
}
|
||||
widgetEventsListener = nil
|
||||
#endif
|
||||
}
|
||||
|
||||
@objc
|
||||
|
@ -269,6 +528,15 @@ class CallPresenter: NSObject {
|
|||
}
|
||||
newCallVC.playRingtone = !isCallKitEnabled
|
||||
newCallVC.delegate = self
|
||||
|
||||
if !call.isIncoming {
|
||||
// put other native calls on hold
|
||||
callVCs.values.forEach({ $0.mxCall.hold(true) })
|
||||
|
||||
// terminate Jitsi calls
|
||||
endActiveJitsiCall()
|
||||
}
|
||||
|
||||
callVCs[call.callId] = newCallVC
|
||||
|
||||
if UIApplication.shared.applicationState == .background && call.isIncoming {
|
||||
|
@ -276,7 +544,7 @@ class CallPresenter: NSObject {
|
|||
// Without CallKit this will allow us to play vibro until the call was ended
|
||||
// With CallKit we'll inform the system when the call is ended to let the system terminate our app to save resources
|
||||
let handler = MXSDKOptions.sharedInstance().backgroundModeHandler
|
||||
let callBackgroundTask = handler.startBackgroundTask(withName: "[CallService] addMatrixCallObserver", expirationHandler: nil)
|
||||
let callBackgroundTask = handler.startBackgroundTask(withName: "[CallPresenter] addMatrixCallObserver", expirationHandler: nil)
|
||||
|
||||
callBackgroundTasks[call.callId] = callBackgroundTask
|
||||
}
|
||||
|
@ -296,23 +564,23 @@ class CallPresenter: NSObject {
|
|||
|
||||
switch call.state {
|
||||
case .createAnswer:
|
||||
NSLog("[CallService] callStateChanged: call created answer: \(call.callId)")
|
||||
NSLog("[CallPresenter] callStateChanged: call created answer: \(call.callId)")
|
||||
if call.isIncoming, isCallKitEnabled, let callVC = callVCs[call.callId] {
|
||||
presentCallVC(callVC)
|
||||
}
|
||||
case .connected:
|
||||
NSLog("[CallService] callStateChanged: call connected: \(call.callId)")
|
||||
NSLog("[CallPresenter] callStateChanged: call connected: \(call.callId)")
|
||||
callTimer?.fire()
|
||||
case .onHold:
|
||||
NSLog("[CallService] callStateChanged: call holded: \(call.callId)")
|
||||
NSLog("[CallPresenter] callStateChanged: call holded: \(call.callId)")
|
||||
callTimer?.fire()
|
||||
callHolded(withCallId: call.callId)
|
||||
case .remotelyOnHold:
|
||||
NSLog("[CallService] callStateChanged: call remotely holded: \(call.callId)")
|
||||
NSLog("[CallPresenter] callStateChanged: call remotely holded: \(call.callId)")
|
||||
callTimer?.fire()
|
||||
callHolded(withCallId: call.callId)
|
||||
case .ended:
|
||||
NSLog("[CallService] callStateChanged: call ended: \(call.callId)")
|
||||
NSLog("[CallPresenter] callStateChanged: call ended: \(call.callId)")
|
||||
endCall(withCallId: call.callId)
|
||||
default:
|
||||
break
|
||||
|
@ -321,7 +589,8 @@ class CallPresenter: NSObject {
|
|||
|
||||
@objc
|
||||
private func callTileTapped(_ notification: Notification) {
|
||||
NSLog("[CallService] callTileTapped")
|
||||
NSLog("[CallPresenter] callTileTapped")
|
||||
|
||||
guard let bubbleData = notification.object as? RoomBubbleCellData else {
|
||||
return
|
||||
}
|
||||
|
@ -334,7 +603,7 @@ class CallPresenter: NSObject {
|
|||
return
|
||||
}
|
||||
|
||||
NSLog("[CallService] callTileTapped: for call: \(callEventContent.callId)")
|
||||
NSLog("[CallPresenter] callTileTapped: for call: \(callEventContent.callId)")
|
||||
|
||||
guard let session = sessions.first else { return }
|
||||
|
||||
|
@ -350,13 +619,55 @@ class CallPresenter: NSObject {
|
|||
return
|
||||
}
|
||||
|
||||
presentCallVC(callVC)
|
||||
if callVC == pipCallVC {
|
||||
exitPipCallVC(callVC)
|
||||
} else {
|
||||
presentCallVC(callVC)
|
||||
}
|
||||
}
|
||||
|
||||
@objc
|
||||
private func groupCallTileTapped(_ notification: Notification) {
|
||||
NSLog("[CallPresenter] groupCallTileTapped")
|
||||
|
||||
guard let bubbleData = notification.object as? RoomBubbleCellData else {
|
||||
return
|
||||
}
|
||||
|
||||
guard let randomEvent = bubbleData.allLinkedEvents().randomElement() else {
|
||||
return
|
||||
}
|
||||
|
||||
guard randomEvent.eventType == .custom,
|
||||
(randomEvent.type == kWidgetMatrixEventTypeString ||
|
||||
randomEvent.type == kWidgetModularEventTypeString) else {
|
||||
return
|
||||
}
|
||||
|
||||
guard let session = sessions.first else { return }
|
||||
|
||||
guard let widget = Widget(widgetEvent: randomEvent, inMatrixSession: session) else {
|
||||
return
|
||||
}
|
||||
|
||||
NSLog("[CallPresenter] groupCallTileTapped: for call: \(widget.widgetId)")
|
||||
|
||||
guard let jitsiVC = jitsiVC,
|
||||
jitsiVC.widget.widgetId == widget.widgetId else {
|
||||
return
|
||||
}
|
||||
|
||||
if jitsiVC == pipCallVC {
|
||||
exitPipCallVC(jitsiVC)
|
||||
} else {
|
||||
presentCallVC(jitsiVC)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Call Screens
|
||||
|
||||
private func presentCallVC(_ callVC: CallViewController, completion: (() -> Void)? = nil) {
|
||||
NSLog("[CallService] presentCallVC: call: \(String(describing: callVC.mxCall?.callId))")
|
||||
private func presentCallVC(_ callVC: UIViewController, completion: (() -> Void)? = nil) {
|
||||
logCallVC(callVC, log: "presentCallVC")
|
||||
|
||||
// do not use PiP transitions here, as we really want to present the screen
|
||||
callVC.transitioningDelegate = nil
|
||||
|
@ -379,8 +690,8 @@ class CallPresenter: NSObject {
|
|||
uiOperationQueue.addOperation(operation)
|
||||
}
|
||||
|
||||
private func dismissCallVC(_ callVC: CallViewController, completion: (() -> Void)? = nil) {
|
||||
NSLog("[CallService] dismissCallVC: call: \(String(describing: callVC.mxCall?.callId))")
|
||||
private func dismissCallVC(_ callVC: UIViewController, completion: (() -> Void)? = nil) {
|
||||
logCallVC(callVC, log: "dismissCallVC")
|
||||
|
||||
// do not use PiP transitions here, as we really want to dismiss the screen
|
||||
callVC.transitioningDelegate = nil
|
||||
|
@ -394,8 +705,8 @@ class CallPresenter: NSObject {
|
|||
uiOperationQueue.addOperation(operation)
|
||||
}
|
||||
|
||||
private func enterPipCallVC(_ callVC: CallViewController, completion: (() -> Void)? = nil) {
|
||||
NSLog("[CallService] enterPipCallVC: call: \(String(describing: callVC.mxCall?.callId))")
|
||||
private func enterPipCallVC(_ callVC: UIViewController, completion: (() -> Void)? = nil) {
|
||||
logCallVC(callVC, log: "enterPipCallVC")
|
||||
|
||||
// assign self as transitioning delegate
|
||||
callVC.transitioningDelegate = self
|
||||
|
@ -410,8 +721,8 @@ class CallPresenter: NSObject {
|
|||
uiOperationQueue.addOperation(operation)
|
||||
}
|
||||
|
||||
private func exitPipCallVC(_ callVC: CallViewController, completion: (() -> Void)? = nil) {
|
||||
NSLog("[CallService] exitPipCallVC: call: \(String(describing: callVC.mxCall?.callId))")
|
||||
private func exitPipCallVC(_ callVC: UIViewController, completion: (() -> Void)? = nil) {
|
||||
logCallVC(callVC, log: "exitPipCallVC")
|
||||
|
||||
// assign self as transitioning delegate
|
||||
callVC.transitioningDelegate = self
|
||||
|
@ -428,24 +739,29 @@ class CallPresenter: NSObject {
|
|||
|
||||
// MARK: - Call Bar
|
||||
|
||||
private func presentCallBar(for callVC: CallViewController?, isUpdateOnly: Bool = false, completion: (() -> Void)? = nil) {
|
||||
NSLog("[CallService] presentCallBar: call: \(String(describing: callVC?.mxCall?.callId))")
|
||||
private func presentCallBar(for callVC: UIViewController, completion: (() -> Void)? = nil) {
|
||||
logCallVC(callVC, log: "presentCallBar")
|
||||
|
||||
let activeCallVC = self.activeCallVC
|
||||
|
||||
let operation = CallBarPresentOperation(presenter: self, activeCallVC: activeCallVC, numberOfPausedCalls: numberOfPausedCalls) { [weak self] in
|
||||
// active calls are more prior to paused ones.
|
||||
// So, if user taps the bar when we have one active and one paused calls, we navigate to the active one.
|
||||
if !isUpdateOnly {
|
||||
self?.inBarCallVC = activeCallVC ?? callVC
|
||||
}
|
||||
// So, if user taps the bar when we have one active and one paused call, we navigate to the active one.
|
||||
self?.inBarCallVC = activeCallVC ?? callVC
|
||||
completion?()
|
||||
}
|
||||
uiOperationQueue.addOperation(operation)
|
||||
}
|
||||
|
||||
private func dismissCallBar(for callVC: CallViewController, completion: (() -> Void)? = nil) {
|
||||
NSLog("[CallService] dismissCallBar: call: \(String(describing: callVC.mxCall?.callId))")
|
||||
private func updateCallBar() {
|
||||
let activeCallVC = self.activeCallVC
|
||||
|
||||
let operation = CallBarUpdateOperation(presenter: self, activeCallVC: activeCallVC, numberOfPausedCalls: numberOfPausedCalls)
|
||||
uiOperationQueue.addOperation(operation)
|
||||
}
|
||||
|
||||
private func dismissCallBar(for callVC: UIViewController, completion: (() -> Void)? = nil) {
|
||||
logCallVC(callVC, log: "dismissCallBar")
|
||||
|
||||
let operation = CallBarDismissOperation(presenter: self) { [weak self] in
|
||||
if callVC == self?.inBarCallVC {
|
||||
|
@ -474,8 +790,13 @@ extension CallPresenter: MXKCallViewControllerDelegate {
|
|||
// wait for the call state changes, will be handled there
|
||||
return
|
||||
} else {
|
||||
dismissCallVC(callVC)
|
||||
self.presentCallBar(for: callVC, completion: completion)
|
||||
if callVC.mxCall.isVideoCall {
|
||||
// go to pip mode here
|
||||
enterPipCallVC(callVC, completion: completion)
|
||||
} else {
|
||||
dismissCallVC(callVC)
|
||||
self.presentCallBar(for: callVC, completion: completion)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -497,20 +818,6 @@ extension CallPresenter: MXKCallViewControllerDelegate {
|
|||
presentCallVC(onHoldCallVC)
|
||||
}
|
||||
|
||||
func callViewControllerDidTapPiPButton(_ callViewController: MXKCallViewController!) {
|
||||
guard let callVC = callViewController as? CallViewController else {
|
||||
// this call screen is not handled by this service
|
||||
return
|
||||
}
|
||||
|
||||
// sanity check
|
||||
// do not enter PiP mode if not a video call
|
||||
guard callVC.mxCall.isVideoCall else { return }
|
||||
|
||||
// go to pip mode here
|
||||
enterPipCallVC(callVC)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// MARK: - UIViewControllerTransitioningDelegate
|
||||
|
@ -562,3 +869,84 @@ extension OperationQueue {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
#if canImport(JitsiMeetSDK)
|
||||
// MARK: - JMCallKitListener
|
||||
|
||||
extension CallPresenter: JMCallKitListener {
|
||||
|
||||
func providerDidReset() {
|
||||
|
||||
}
|
||||
|
||||
func performAnswerCall(UUID: UUID) {
|
||||
guard let widget = jitsiCalls[UUID] else {
|
||||
return
|
||||
}
|
||||
|
||||
displayJitsiCall(withWidget: widget)
|
||||
}
|
||||
|
||||
func performEndCall(UUID: UUID) {
|
||||
guard let widget = jitsiCalls[UUID] else {
|
||||
return
|
||||
}
|
||||
|
||||
if let jitsiVC = jitsiVC, jitsiVC.widget.widgetId == widget.widgetId {
|
||||
// hangup an active call
|
||||
dismissCallVC(jitsiVC)
|
||||
endActiveJitsiCall()
|
||||
} else {
|
||||
// decline incoming call
|
||||
JitsiService.shared.declineWidget(withId: widget.widgetId)
|
||||
}
|
||||
}
|
||||
|
||||
func performSetMutedCall(UUID: UUID, isMuted: Bool) {
|
||||
guard let widget = jitsiCalls[UUID] else {
|
||||
return
|
||||
}
|
||||
|
||||
if let jitsiVC = jitsiVC, jitsiVC.widget.widgetId == widget.widgetId {
|
||||
// mute the active Jitsi call
|
||||
jitsiVC.setAudioMuted(isMuted)
|
||||
}
|
||||
}
|
||||
|
||||
func performStartCall(UUID: UUID, isVideo: Bool) {
|
||||
|
||||
}
|
||||
|
||||
func providerDidActivateAudioSession(session: AVAudioSession) {
|
||||
|
||||
}
|
||||
|
||||
func providerDidDeactivateAudioSession(session: AVAudioSession) {
|
||||
|
||||
}
|
||||
|
||||
func providerTimedOutPerformingAction(action: CXAction) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// MARK: - JitsiViewControllerDelegate
|
||||
|
||||
extension CallPresenter: JitsiViewControllerDelegate {
|
||||
|
||||
func jitsiViewController(_ jitsiViewController: JitsiViewController!, dismissViewJitsiController completion: (() -> Void)!) {
|
||||
if jitsiViewController == jitsiVC {
|
||||
endActiveJitsiCall()
|
||||
}
|
||||
}
|
||||
|
||||
func jitsiViewController(_ jitsiViewController: JitsiViewController!, goBackToApp completion: (() -> Void)!) {
|
||||
if jitsiViewController == jitsiVC {
|
||||
enterPipCallVC(jitsiViewController, completion: completion)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -18,32 +18,31 @@ import Foundation
|
|||
|
||||
@objc
|
||||
protocol CallPresenterDelegate: class {
|
||||
// New call
|
||||
func callPresenter(_ presenter: CallPresenter,
|
||||
shouldHandleNewCall call: MXCall) -> Bool
|
||||
|
||||
// Call screens
|
||||
func callPresenter(_ presenter: CallPresenter,
|
||||
presentCallViewController viewController: CallViewController,
|
||||
presentCallViewController viewController: UIViewController,
|
||||
completion:(() -> Void)?)
|
||||
func callPresenter(_ presenter: CallPresenter,
|
||||
dismissCallViewController viewController: CallViewController,
|
||||
dismissCallViewController viewController: UIViewController,
|
||||
completion:(() -> Void)?)
|
||||
|
||||
// Call Bar
|
||||
func callPresenter(_ presenter: CallPresenter,
|
||||
presentCallBarFor activeCallViewController: CallViewController?,
|
||||
presentCallBarFor activeCallViewController: UIViewController?,
|
||||
numberOfPausedCalls: UInt,
|
||||
completion:(() -> Void)?)
|
||||
func callPresenter(_ presenter: CallPresenter,
|
||||
updateCallBarFor activeCallViewController: UIViewController?,
|
||||
numberOfPausedCalls: UInt)
|
||||
func callPresenter(_ presenter: CallPresenter,
|
||||
dismissCallBar completion:(() -> Void)?)
|
||||
|
||||
// PiP
|
||||
func callPresenter(_ presenter: CallPresenter,
|
||||
enterPipForCallViewController viewController: CallViewController,
|
||||
enterPipForCallViewController viewController: UIViewController,
|
||||
completion:(() -> Void)?)
|
||||
|
||||
func callPresenter(_ presenter: CallPresenter,
|
||||
exitPipForCallViewController viewController: CallViewController,
|
||||
exitPipForCallViewController viewController: UIViewController,
|
||||
completion:(() -> Void)?)
|
||||
}
|
||||
|
|
|
@ -19,12 +19,12 @@ import Foundation
|
|||
class CallBarPresentOperation: AsyncOperation {
|
||||
|
||||
private var presenter: CallPresenter
|
||||
private var activeCallVC: CallViewController?
|
||||
private var activeCallVC: UIViewController?
|
||||
private var numberOfPausedCalls: UInt
|
||||
private var completion: (() -> Void)?
|
||||
|
||||
init(presenter: CallPresenter,
|
||||
activeCallVC: CallViewController?,
|
||||
activeCallVC: UIViewController?,
|
||||
numberOfPausedCalls: UInt,
|
||||
completion: (() -> Void)? = nil) {
|
||||
self.presenter = presenter
|
||||
|
@ -36,7 +36,10 @@ class CallBarPresentOperation: AsyncOperation {
|
|||
override func main() {
|
||||
presenter.delegate?.callPresenter(presenter, presentCallBarFor: activeCallVC, numberOfPausedCalls: numberOfPausedCalls, completion: {
|
||||
self.finish()
|
||||
self.completion?()
|
||||
// wait for the next life cycle to detect status bar layout updates
|
||||
DispatchQueue.main.async {
|
||||
self.completion?()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
|
38
Riot/Managers/Call/Operations/CallBarUpdateOperation.swift
Normal file
|
@ -0,0 +1,38 @@
|
|||
//
|
||||
// Copyright 2020 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
|
||||
|
||||
class CallBarUpdateOperation: AsyncOperation {
|
||||
|
||||
private var presenter: CallPresenter
|
||||
private var activeCallVC: UIViewController?
|
||||
private var numberOfPausedCalls: UInt
|
||||
|
||||
init(presenter: CallPresenter,
|
||||
activeCallVC: UIViewController?,
|
||||
numberOfPausedCalls: UInt) {
|
||||
self.presenter = presenter
|
||||
self.activeCallVC = activeCallVC
|
||||
self.numberOfPausedCalls = numberOfPausedCalls
|
||||
}
|
||||
|
||||
override func main() {
|
||||
presenter.delegate?.callPresenter(presenter, updateCallBarFor: activeCallVC, numberOfPausedCalls: numberOfPausedCalls)
|
||||
self.finish()
|
||||
}
|
||||
|
||||
}
|
|
@ -19,11 +19,11 @@ import Foundation
|
|||
class CallVCDismissOperation: AsyncOperation {
|
||||
|
||||
private var presenter: CallPresenter
|
||||
private var callVC: CallViewController
|
||||
private var callVC: UIViewController
|
||||
private var completion: (() -> Void)?
|
||||
|
||||
init(presenter: CallPresenter,
|
||||
callVC: CallViewController,
|
||||
callVC: UIViewController,
|
||||
completion: (() -> Void)? = nil) {
|
||||
self.presenter = presenter
|
||||
self.callVC = callVC
|
||||
|
|
|
@ -19,11 +19,11 @@ import Foundation
|
|||
class CallVCEnterPipOperation: AsyncOperation {
|
||||
|
||||
private var presenter: CallPresenter
|
||||
private var callVC: CallViewController
|
||||
private var callVC: UIViewController
|
||||
private var completion: (() -> Void)?
|
||||
|
||||
init(presenter: CallPresenter,
|
||||
callVC: CallViewController,
|
||||
callVC: UIViewController,
|
||||
completion: (() -> Void)? = nil) {
|
||||
self.presenter = presenter
|
||||
self.callVC = callVC
|
||||
|
|
|
@ -19,11 +19,11 @@ import Foundation
|
|||
class CallVCExitPipOperation: AsyncOperation {
|
||||
|
||||
private var presenter: CallPresenter
|
||||
private var callVC: CallViewController
|
||||
private var callVC: UIViewController
|
||||
private var completion: (() -> Void)?
|
||||
|
||||
init(presenter: CallPresenter,
|
||||
callVC: CallViewController,
|
||||
callVC: UIViewController,
|
||||
completion: (() -> Void)? = nil) {
|
||||
self.presenter = presenter
|
||||
self.callVC = callVC
|
||||
|
|
|
@ -19,11 +19,11 @@ import Foundation
|
|||
class CallVCPresentOperation: AsyncOperation {
|
||||
|
||||
private var presenter: CallPresenter
|
||||
private var callVC: CallViewController
|
||||
private var callVC: UIViewController
|
||||
private var completion: (() -> Void)?
|
||||
|
||||
init(presenter: CallPresenter,
|
||||
callVC: CallViewController,
|
||||
callVC: UIViewController,
|
||||
completion: (() -> Void)? = nil) {
|
||||
self.presenter = presenter
|
||||
self.callVC = callVC
|
||||
|
|
|
@ -25,7 +25,7 @@ import Foundation
|
|||
class PiPAnimator: NSObject {
|
||||
|
||||
private enum Constants {
|
||||
static let pipViewScale: CGFloat = 0.3
|
||||
static let pipViewSize: CGSize = CGSize(width: 90, height: 130)
|
||||
}
|
||||
|
||||
let animationDuration: TimeInterval
|
||||
|
@ -62,15 +62,15 @@ class PiPAnimator: NSObject {
|
|||
pipView.delegate = pipViewDelegate
|
||||
keyWindow.addSubview(pipView)
|
||||
|
||||
let transform = CGAffineTransform(scaleX: Constants.pipViewScale, y: Constants.pipViewScale)
|
||||
let targetRect = fromVC.view.bounds.applying(transform)
|
||||
let scale = Constants.pipViewSize.width/pipView.frame.width
|
||||
let transform = CGAffineTransform(scaleX: scale, y: scale)
|
||||
let targetSize = Constants.pipViewSize
|
||||
|
||||
let animator = UIViewPropertyAnimator(duration: animationDuration, dampingRatio: 1) {
|
||||
pipView.transform = transform
|
||||
|
||||
pipView.move(in: keyWindow,
|
||||
to: .bottomLeft,
|
||||
targetSize: targetRect.size)
|
||||
targetSize: targetSize)
|
||||
}
|
||||
|
||||
animator.addCompletion { (position) in
|
||||
|
@ -117,6 +117,7 @@ class PiPAnimator: NSObject {
|
|||
animator.addCompletion { (position) in
|
||||
|
||||
toVC.additionalSafeAreaInsets = .zero
|
||||
toVC.view.frame = context.finalFrame(for: toVC)
|
||||
toVC.view.isHidden = false
|
||||
|
||||
snapshot.removeFromSuperview()
|
||||
|
|
|
@ -17,8 +17,8 @@
|
|||
import UIKit
|
||||
|
||||
@objc enum PiPViewPosition: Int {
|
||||
case bottomLeft // default value
|
||||
case bottomRight
|
||||
case bottomLeft
|
||||
case bottomRight // default value
|
||||
case topRight
|
||||
case topLeft
|
||||
}
|
||||
|
@ -32,12 +32,12 @@ import UIKit
|
|||
class PiPView: UIView {
|
||||
|
||||
private enum Defaults {
|
||||
static let margins: UIOffset = UIOffset(horizontal: 20, vertical: 20)
|
||||
static let margins: UIEdgeInsets = UIEdgeInsets(top: 64, left: 20, bottom: 64, right: 20)
|
||||
static let cornerRadius: CGFloat = 8
|
||||
static let animationDuration: TimeInterval = 0.25
|
||||
}
|
||||
|
||||
var margins: UIOffset = Defaults.margins {
|
||||
var margins: UIEdgeInsets = Defaults.margins {
|
||||
didSet {
|
||||
guard self.superview != nil else { return }
|
||||
self.move(to: self.position, animated: true)
|
||||
|
@ -48,7 +48,7 @@ class PiPView: UIView {
|
|||
layer.cornerRadius = cornerRadius
|
||||
}
|
||||
}
|
||||
var position: PiPViewPosition = .bottomLeft
|
||||
var position: PiPViewPosition = .bottomRight
|
||||
weak var delegate: PiPViewDelegate?
|
||||
|
||||
private var originalCenter: CGPoint = .zero
|
||||
|
@ -97,7 +97,7 @@ NSLayoutConstraint.activate([
|
|||
}
|
||||
|
||||
func move(in view: UIView? = nil,
|
||||
to position: PiPViewPosition = .bottomLeft,
|
||||
to position: PiPViewPosition = .bottomRight,
|
||||
targetSize: CGSize? = nil,
|
||||
animated: Bool = false,
|
||||
completion: ((Bool) -> Void)? = nil) {
|
||||
|
@ -148,25 +148,36 @@ NSLayoutConstraint.activate([
|
|||
}
|
||||
let targetSize = targetSize ?? frame.size
|
||||
|
||||
var superviewWidth: CGFloat = 0
|
||||
var superviewHeight: CGFloat = 0
|
||||
|
||||
if UIDevice.current.orientation.isPortrait {
|
||||
superviewWidth = min(view.bounds.width, view.bounds.height)
|
||||
superviewHeight = max(view.bounds.width, view.bounds.height)
|
||||
} else {
|
||||
superviewWidth = max(view.bounds.width, view.bounds.height)
|
||||
superviewHeight = min(view.bounds.width, view.bounds.height)
|
||||
}
|
||||
|
||||
switch position {
|
||||
case .bottomLeft:
|
||||
let origin = CGPoint(x: margins.horizontal + view.safeAreaInsets.left,
|
||||
y: view.bounds.height - view.safeAreaInsets.bottom - targetSize.height - margins.vertical)
|
||||
let origin = CGPoint(x: margins.left + view.safeAreaInsets.left,
|
||||
y: superviewHeight - view.safeAreaInsets.bottom - targetSize.height - margins.bottom)
|
||||
return CGRect(origin: origin,
|
||||
size: targetSize)
|
||||
case .bottomRight:
|
||||
let origin = CGPoint(x: view.bounds.width - view.safeAreaInsets.right - margins.horizontal - targetSize.width,
|
||||
y: view.bounds.height - view.safeAreaInsets.bottom - targetSize.height - margins.vertical)
|
||||
let origin = CGPoint(x: superviewWidth - view.safeAreaInsets.right - margins.right - targetSize.width,
|
||||
y: superviewHeight - view.safeAreaInsets.bottom - targetSize.height - margins.bottom)
|
||||
return CGRect(origin: origin,
|
||||
size: targetSize)
|
||||
case .topRight:
|
||||
let origin = CGPoint(x: view.bounds.width - view.safeAreaInsets.right - margins.horizontal - targetSize.width,
|
||||
y: margins.vertical + view.safeAreaInsets.top)
|
||||
let origin = CGPoint(x: superviewWidth - view.safeAreaInsets.right - margins.right - targetSize.width,
|
||||
y: margins.top + view.safeAreaInsets.top)
|
||||
return CGRect(origin: origin,
|
||||
size: targetSize)
|
||||
case .topLeft:
|
||||
let origin = CGPoint(x: margins.horizontal + view.safeAreaInsets.left,
|
||||
y: margins.vertical + view.safeAreaInsets.top)
|
||||
let origin = CGPoint(x: margins.left + view.safeAreaInsets.left,
|
||||
y: margins.top + view.safeAreaInsets.top)
|
||||
return CGRect(origin: origin,
|
||||
size: targetSize)
|
||||
}
|
||||
|
|
|
@ -323,6 +323,30 @@ Matrix session observer used to detect new opened sessions.
|
|||
|
||||
#pragma mark - UNUserNotificationCenterDelegate
|
||||
|
||||
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler
|
||||
{
|
||||
NSDictionary *userInfo = notification.request.content.userInfo;
|
||||
if (userInfo[Constants.userInfoKeyPresentNotificationOnForeground])
|
||||
{
|
||||
if (!userInfo[Constants.userInfoKeyPresentNotificationInRoom]
|
||||
&& [[AppDelegate theDelegate].visibleRoomId isEqualToString:userInfo[@"room_id"]])
|
||||
{
|
||||
// do not show the notification when we're in the notified room
|
||||
completionHandler(UNNotificationPresentationOptionNone);
|
||||
}
|
||||
else
|
||||
{
|
||||
completionHandler(UNNotificationPresentationOptionBadge
|
||||
| UNNotificationPresentationOptionSound
|
||||
| UNNotificationPresentationOptionAlert);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
completionHandler(UNNotificationPresentationOptionNone);
|
||||
}
|
||||
}
|
||||
|
||||
// iOS 10+, see application:handleActionWithIdentifier:forLocalNotification:withResponseInfo:completionHandler:
|
||||
- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler
|
||||
{
|
||||
|
@ -568,23 +592,37 @@ Matrix session observer used to detect new opened sessions.
|
|||
return;
|
||||
}
|
||||
|
||||
// process the call invite synchronously
|
||||
[session.callManager handleCallEvent:lastCallInvite];
|
||||
MXCall *call = [session.callManager callWithCallId:lastCallInvite.content[@"call_id"]];
|
||||
if (call)
|
||||
if (lastCallInvite.eventType == MXEventTypeCallInvite)
|
||||
{
|
||||
[session.callManager.callKitAdapter reportIncomingCall:call];
|
||||
NSLog(@"[PushNotificationService] didReceiveIncomingPushWithPayload: Reporting new call in room %@ for the event: %@", roomId, eventId);
|
||||
|
||||
// Wait for the sync response in cache to be processed for data integrity.
|
||||
dispatch_group_notify(dispatchGroup, dispatch_get_main_queue(), ^{
|
||||
// After reporting the call, we can continue async. Launch a background sync to handle call answers/declines on other devices of the user.
|
||||
[self launchBackgroundSync];
|
||||
});
|
||||
// process the call invite synchronously
|
||||
[session.callManager handleCallEvent:lastCallInvite];
|
||||
MXCall *call = [session.callManager callWithCallId:lastCallInvite.content[@"call_id"]];
|
||||
if (call)
|
||||
{
|
||||
[session.callManager.callKitAdapter reportIncomingCall:call];
|
||||
NSLog(@"[PushNotificationService] didReceiveIncomingPushWithPayload: Reporting new call in room %@ for the event: %@", roomId, eventId);
|
||||
|
||||
// Wait for the sync response in cache to be processed for data integrity.
|
||||
dispatch_group_notify(dispatchGroup, dispatch_get_main_queue(), ^{
|
||||
// After reporting the call, we can continue async. Launch a background sync to handle call answers/declines on other devices of the user.
|
||||
[self launchBackgroundSync];
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
NSLog(@"[PushNotificationService] didReceiveIncomingPushWithPayload: Error on call object on room %@ for the event: %@", roomId, eventId);
|
||||
}
|
||||
}
|
||||
else if ([lastCallInvite.type isEqualToString:kWidgetMatrixEventTypeString] ||
|
||||
[lastCallInvite.type isEqualToString:kWidgetModularEventTypeString])
|
||||
{
|
||||
[[AppDelegate theDelegate].callPresenter processWidgetEvent:lastCallInvite
|
||||
inSession:session];
|
||||
}
|
||||
else
|
||||
{
|
||||
NSLog(@"[PushNotificationService] didReceiveIncomingPushWithPayload: Error on call object on room %@ for the event: %@", roomId, eventId);
|
||||
// It's a serious error. There is nothing to avoid iOS to kill us here.
|
||||
NSLog(@"[PushNotificationService] didReceiveIncomingPushWithPayload: We have an unknown type of event for %@. There is something wrong.", eventId);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
|
@ -27,7 +27,6 @@ final class RiotSettings: NSObject {
|
|||
static let identityServerUrlString = "identityserverurl"
|
||||
static let enableCrashReport = "enableCrashReport"
|
||||
static let enableRageShake = "enableRageShake"
|
||||
static let createConferenceCallsWithJitsi = "createConferenceCallsWithJitsi"
|
||||
static let userInterfaceTheme = "userInterfaceTheme"
|
||||
static let notificationsShowDecryptedContent = "showDecryptedContent"
|
||||
static let pinRoomsWithMissedNotifications = "pinRoomsWithMissedNotif"
|
||||
|
@ -52,6 +51,7 @@ final class RiotSettings: NSObject {
|
|||
static let roomCreationScreenAllowRoomTypeConfiguration = "roomCreationScreenAllowRoomTypeConfiguration"
|
||||
static let roomCreationScreenRoomIsPublic = "roomCreationScreenRoomIsPublic"
|
||||
static let allowInviteExernalUsers = "allowInviteExernalUsers"
|
||||
static let enableRingingForGroupCalls = "enableRingingForGroupCalls"
|
||||
static let roomSettingsScreenShowLowPriorityOption = "roomSettingsScreenShowLowPriorityOption"
|
||||
static let roomSettingsScreenShowDirectChatOption = "roomSettingsScreenShowDirectChatOption"
|
||||
static let roomSettingsScreenAllowChangingAccessSettings = "roomSettingsScreenAllowChangingAccessSettings"
|
||||
|
@ -60,6 +60,8 @@ final class RiotSettings: NSObject {
|
|||
static let roomSettingsScreenShowFlairSettings = "roomSettingsScreenShowFlairSettings"
|
||||
static let roomSettingsScreenShowAdvancedSettings = "roomSettingsScreenShowAdvancedSettings"
|
||||
static let roomSettingsScreenAdvancedShowEncryptToVerifiedOption = "roomSettingsScreenAdvancedShowEncryptToVerifiedOption"
|
||||
static let settingsScreenShowNotificationDecodedContentOption = "settingsScreenShowNotificationDecodedContentOption"
|
||||
static let settingsScreenShowNsfwRoomsOption = "settingsScreenShowNsfwRoomsOption"
|
||||
static let roomsAllowToJoinPublicRooms = "roomsAllowToJoinPublicRooms"
|
||||
static let homeScreenShowFavouritesTab = "homeScreenShowFavouritesTab"
|
||||
static let homeScreenShowPeopleTab = "homeScreenShowPeopleTab"
|
||||
|
@ -71,7 +73,11 @@ final class RiotSettings: NSObject {
|
|||
static let roomScreenAllowMediaLibraryAction = "roomScreenAllowMediaLibraryAction"
|
||||
static let roomScreenAllowStickerAction = "roomScreenAllowStickerAction"
|
||||
static let roomScreenAllowFilesAction = "roomScreenAllowFilesAction"
|
||||
static let roomContextualMenuShowMoreOptionForMessages = "roomContextualMenuShowMoreOptionForMessages"
|
||||
static let roomContextualMenuShowMoreOptionForStates = "roomContextualMenuShowMoreOptionForStates"
|
||||
static let roomContextualMenuShowReportContentOption = "roomContextualMenuShowReportContentOption"
|
||||
static let roomInfoScreenShowIntegrations = "roomInfoScreenShowIntegrations"
|
||||
static let roomMemberScreenShowIgnore = "roomMemberScreenShowIgnore"
|
||||
static let unifiedSearchScreenShowPublicDirectory = "unifiedSearchScreenShowPublicDirectory"
|
||||
}
|
||||
|
||||
|
@ -85,36 +91,6 @@ final class RiotSettings: NSObject {
|
|||
return userDefaults
|
||||
}()
|
||||
|
||||
// MARK: - Public
|
||||
|
||||
func reset() {
|
||||
defaults.removeObject(forKey: UserDefaultsKeys.settingsScreenShowChangePassword)
|
||||
defaults.removeObject(forKey: UserDefaultsKeys.settingsScreenShowInviteFriends)
|
||||
defaults.removeObject(forKey: UserDefaultsKeys.settingsScreenShowEnableStunServerFallback)
|
||||
defaults.removeObject(forKey: UserDefaultsKeys.settingsSecurityScreenShowSessions)
|
||||
defaults.removeObject(forKey: UserDefaultsKeys.settingsSecurityScreenShowSetupBackup)
|
||||
defaults.removeObject(forKey: UserDefaultsKeys.settingsSecurityScreenShowRestoreBackup)
|
||||
defaults.removeObject(forKey: UserDefaultsKeys.settingsSecurityScreenShowDeleteBackup)
|
||||
defaults.removeObject(forKey: UserDefaultsKeys.settingsSecurityScreenShowCryptographyInfo)
|
||||
defaults.removeObject(forKey: UserDefaultsKeys.settingsSecurityScreenShowCryptographyExport)
|
||||
defaults.removeObject(forKey: UserDefaultsKeys.settingsSecurityScreenShowAdvancedUnverifiedDevices)
|
||||
defaults.removeObject(forKey: UserDefaultsKeys.roomCreationScreenAllowEncryptionConfiguration)
|
||||
defaults.removeObject(forKey: UserDefaultsKeys.roomCreationScreenRoomIsEncrypted)
|
||||
defaults.removeObject(forKey: UserDefaultsKeys.roomCreationScreenAllowRoomTypeConfiguration)
|
||||
defaults.removeObject(forKey: UserDefaultsKeys.roomCreationScreenRoomIsPublic)
|
||||
defaults.removeObject(forKey: UserDefaultsKeys.allowInviteExernalUsers)
|
||||
defaults.removeObject(forKey: UserDefaultsKeys.roomSettingsScreenShowLowPriorityOption)
|
||||
defaults.removeObject(forKey: UserDefaultsKeys.roomSettingsScreenShowDirectChatOption)
|
||||
defaults.removeObject(forKey: UserDefaultsKeys.roomSettingsScreenAllowChangingAccessSettings)
|
||||
defaults.removeObject(forKey: UserDefaultsKeys.roomSettingsScreenAllowChangingHistorySettings)
|
||||
defaults.removeObject(forKey: UserDefaultsKeys.roomSettingsScreenShowAddressSettings)
|
||||
defaults.removeObject(forKey: UserDefaultsKeys.roomSettingsScreenShowFlairSettings)
|
||||
defaults.removeObject(forKey: UserDefaultsKeys.roomSettingsScreenShowAdvancedSettings)
|
||||
defaults.removeObject(forKey: UserDefaultsKeys.roomSettingsScreenAdvancedShowEncryptToVerifiedOption)
|
||||
defaults.removeObject(forKey: UserDefaultsKeys.allowInviteExernalUsers)
|
||||
defaults.removeObject(forKey: UserDefaultsKeys.roomsAllowToJoinPublicRooms)
|
||||
}
|
||||
|
||||
// MARK: Servers
|
||||
|
||||
var homeserverUrlString: String {
|
||||
|
@ -228,14 +204,15 @@ final class RiotSettings: NSObject {
|
|||
|
||||
// MARK: Labs
|
||||
|
||||
var createConferenceCallsWithJitsi: Bool {
|
||||
/// Indicates if CallKit ringing is enabled for group calls. This setting does not disable the CallKit integration for group calls, only relates to ringing.
|
||||
var enableRingingForGroupCalls: Bool {
|
||||
get {
|
||||
return defaults.bool(forKey: UserDefaultsKeys.createConferenceCallsWithJitsi)
|
||||
return defaults.bool(forKey: UserDefaultsKeys.enableRingingForGroupCalls)
|
||||
} set {
|
||||
defaults.set(newValue, forKey: UserDefaultsKeys.createConferenceCallsWithJitsi)
|
||||
defaults.set(newValue, forKey: UserDefaultsKeys.enableRingingForGroupCalls)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: Calls
|
||||
|
||||
/// Indicate if `allowStunServerFallback` settings has been set once.
|
||||
|
@ -352,6 +329,39 @@ final class RiotSettings: NSObject {
|
|||
defaults.set(newValue, forKey: UserDefaultsKeys.roomScreenAllowFilesAction)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Room Contextual Menu
|
||||
|
||||
var roomContextualMenuShowMoreOptionForMessages: Bool {
|
||||
get {
|
||||
guard defaults.object(forKey: UserDefaultsKeys.roomContextualMenuShowMoreOptionForMessages) != nil else {
|
||||
return BuildSettings.roomContextualMenuShowMoreOptionForMessages
|
||||
}
|
||||
return defaults.bool(forKey: UserDefaultsKeys.roomContextualMenuShowMoreOptionForMessages)
|
||||
} set {
|
||||
defaults.set(newValue, forKey: UserDefaultsKeys.roomContextualMenuShowMoreOptionForMessages)
|
||||
}
|
||||
}
|
||||
var roomContextualMenuShowMoreOptionForStates: Bool {
|
||||
get {
|
||||
guard defaults.object(forKey: UserDefaultsKeys.roomContextualMenuShowMoreOptionForStates) != nil else {
|
||||
return BuildSettings.roomContextualMenuShowMoreOptionForStates
|
||||
}
|
||||
return defaults.bool(forKey: UserDefaultsKeys.roomContextualMenuShowMoreOptionForStates)
|
||||
} set {
|
||||
defaults.set(newValue, forKey: UserDefaultsKeys.roomContextualMenuShowMoreOptionForStates)
|
||||
}
|
||||
}
|
||||
var roomContextualMenuShowReportContentOption: Bool {
|
||||
get {
|
||||
guard defaults.object(forKey: UserDefaultsKeys.roomContextualMenuShowReportContentOption) != nil else {
|
||||
return BuildSettings.roomContextualMenuShowReportContentOption
|
||||
}
|
||||
return defaults.bool(forKey: UserDefaultsKeys.roomContextualMenuShowReportContentOption)
|
||||
} set {
|
||||
defaults.set(newValue, forKey: UserDefaultsKeys.roomContextualMenuShowReportContentOption)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Room Info Screen
|
||||
|
||||
|
@ -366,6 +376,19 @@ final class RiotSettings: NSObject {
|
|||
}
|
||||
}
|
||||
|
||||
// MARK: - Room Member Screen
|
||||
|
||||
var roomMemberScreenShowIgnore: Bool {
|
||||
get {
|
||||
guard defaults.object(forKey: UserDefaultsKeys.roomMemberScreenShowIgnore) != nil else {
|
||||
return BuildSettings.roomMemberScreenShowIgnore
|
||||
}
|
||||
return defaults.bool(forKey: UserDefaultsKeys.roomMemberScreenShowIgnore)
|
||||
} set {
|
||||
defaults.set(newValue, forKey: UserDefaultsKeys.roomMemberScreenShowIgnore)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Room Creation Screen
|
||||
|
||||
var roomCreationScreenAllowEncryptionConfiguration: Bool {
|
||||
|
@ -497,6 +520,26 @@ final class RiotSettings: NSObject {
|
|||
defaults.set(newValue, forKey: UserDefaultsKeys.settingsScreenShowEnableStunServerFallback)
|
||||
}
|
||||
}
|
||||
var settingsScreenShowNotificationDecodedContentOption: Bool {
|
||||
get {
|
||||
guard defaults.object(forKey: UserDefaultsKeys.settingsScreenShowNotificationDecodedContentOption) != nil else {
|
||||
return BuildSettings.settingsScreenShowNotificationDecodedContentOption
|
||||
}
|
||||
return defaults.bool(forKey: UserDefaultsKeys.settingsScreenShowNotificationDecodedContentOption)
|
||||
} set {
|
||||
defaults.set(newValue, forKey: UserDefaultsKeys.settingsScreenShowNotificationDecodedContentOption)
|
||||
}
|
||||
}
|
||||
var settingsScreenShowNsfwRoomsOption: Bool {
|
||||
get {
|
||||
guard defaults.object(forKey: UserDefaultsKeys.settingsScreenShowNsfwRoomsOption) != nil else {
|
||||
return BuildSettings.settingsScreenShowNsfwRoomsOption
|
||||
}
|
||||
return defaults.bool(forKey: UserDefaultsKeys.settingsScreenShowNsfwRoomsOption)
|
||||
} set {
|
||||
defaults.set(newValue, forKey: UserDefaultsKeys.settingsScreenShowNsfwRoomsOption)
|
||||
}
|
||||
}
|
||||
var settingsSecurityScreenShowSessions: Bool {
|
||||
get {
|
||||
guard defaults.object(forKey: UserDefaultsKeys.settingsSecurityScreenShowSessions) != nil else {
|
||||
|
|
|
@ -15,10 +15,11 @@
|
|||
*/
|
||||
|
||||
import UIKit
|
||||
import DesignKit
|
||||
|
||||
/// Provide color constant values defined by the designer
|
||||
/// https://app.zeplin.io/project/5c122fa790c5b4241ffa6be7/screen/5c619592daff2f1241d82e75
|
||||
@objc protocol Theme {
|
||||
@objc protocol Theme: ThemeV2 {
|
||||
|
||||
var identifier: String { get }
|
||||
|
||||
|
@ -93,6 +94,9 @@ import UIKit
|
|||
/// Color to tint the search background image
|
||||
var matrixSearchBackgroundImageTintColor: UIColor { get }
|
||||
|
||||
/// Color to use in shadows. Should be contrast to `backgroundColor`.
|
||||
var shadowColor: UIColor { get }
|
||||
|
||||
// MARK: - Customisation methods
|
||||
|
||||
|
||||
|
|
|
@ -155,6 +155,9 @@ NSString *const kThemeServiceDidChangeThemeNotification = @"kThemeServiceDidChan
|
|||
|
||||
// Define the UISearchBar cancel button color
|
||||
[[UIBarButtonItem appearanceWhenContainedInInstancesOfClasses:@[[UISearchBar class]]] setTitleTextAttributes:@{ NSForegroundColorAttributeName : self.theme.tintColor } forState: UIControlStateNormal];
|
||||
|
||||
[[UIStackView appearanceWhenContainedInInstancesOfClasses:@[[UINavigationBar class]]] setSpacing:-7];
|
||||
[[UIStackView appearanceWhenContainedInInstancesOfClasses:@[[UINavigationBar class]]] setDistribution:UIStackViewDistributionEqualCentering];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|