Merge branch 'develop' into doug/4479_media_size_selection

# Conflicts:
#	Riot/Managers/Settings/RiotSettings.swift
This commit is contained in:
Doug 2021-09-06 17:04:22 +01:00
commit a300cab626
146 changed files with 1741 additions and 1099 deletions

74
.github/ISSUE_TEMPLATE/bug.yml vendored Normal file
View file

@ -0,0 +1,74 @@
name: Bug report for the Element iOS app
description: Report any issues that you have found with the Element app. Please [check open issues](https://github.com/vector-im/element-ios/issues) first, in case it has already been reported.
labels: [T-Defect]
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this bug report!
Please report security issues by email to security@matrix.org
- type: textarea
id: reproduction-steps
attributes:
label: Steps to reproduce
description: Please attach screenshots, videos or logs if you can.
placeholder: Tell us what you see!
value: |
1. Where are you starting? What can you see?
2. What do you click?
3. More steps…
validations:
required: true
- type: textarea
id: result
attributes:
label: What happened?
placeholder: Tell us what went wrong
value: |
### What did you expect?
### What happened?
validations:
required: true
- type: input
id: device
attributes:
label: Your phone model
placeholder: e.g. iPhoneX
validations:
required: false
- type: input
id: os
attributes:
label: Operating system version
placeholder: e.g. iOS14.7.1, under "software version"
validations:
required: false
- type: input
id: version
attributes:
label: Application version
description: You can find the version information in Settings -> Help & About.
placeholder: e.g. Element version 1.5.2
validations:
required: false
- type: input
id: homeserver
attributes:
label: Homeserver
description: Which server is your account registered on?
placeholder: e.g. matrix.org
validations:
required: false
- type: dropdown
id: rageshake
attributes:
label: Have you submitted a rageshake?
description: |
Did you know that you can shake your phone to submit logs for this issue? Trigger the defect, then shake your phone and you will see a popup asking if you would like to open the bug report screen. Click YES, and describe the issue, mentioning that you have also filed a bug. Submit the report to send anonymous logs to the developers.
options:
- 'Yes'
- 'No'
validations:
required: true

View file

@ -1,31 +0,0 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: 'bug'
assignees: ''
---
#### Describe the bug.
A clear and concise description of what the bug is.
#### Steps to reproduce:
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
#### Expected behavior
A clear and concise description of what you expected to happen.
#### Screenshots
If applicable, add screenshots to help explain your problem.
#### Contextual information:
<!-- You can find your device information under Settings -> General -> About -->
- Device: <!-- e.g. iPhone6, under "model name"-->
- OS: <!-- e.g. iOS8.1, under "software version" -->
<!-- The app version should be displayed in the side-panel of the home screen -->
- App Version: <!-- e.g. 1.4.5 -->

36
.github/ISSUE_TEMPLATE/enhancement.yml vendored Normal file
View file

@ -0,0 +1,36 @@
name: Enhancement request
description: Do you have a suggestion or feature request?
labels: [T-Enhancement]
body:
- type: markdown
attributes:
value: |
Thank you for taking the time to propose a new feature or make a suggestion.
- type: textarea
id: usecase
attributes:
label: Your use case
description: What would you like to be able to do? Please feel welcome to include screenshots or mock ups.
placeholder: Tell us what you would like to do!
value: |
#### What would you like to do?
#### Why would you like to do it?
#### How would you like to achieve it?
validations:
required: true
- type: textarea
id: alternative
attributes:
label: Have you considered any alternatives?
placeholder: A clear and concise description of any alternative solutions or features you've considered.
validations:
required: false
- type: textarea
id: additional-context
attributes:
label: Additional context
placeholder: Is there anything else you'd like to add?
validations:
required: false

View file

@ -1,20 +0,0 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: 'feature'
assignees: ''
---
#### Is your feature request related to a problem? Please describe.
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
#### Describe the solution you'd like.
A clear and concise description of what you want to happen.
#### Describe alternatives you've considered.
A clear and concise description of any alternative solutions or features you've considered.
#### Additional context.
Add any other context or screenshots about the feature request here.

1
.gitignore vendored
View file

@ -19,6 +19,7 @@ DerivedData
out/
.vscode/
vendor/
.DS_Store
# CocoaPods
#

View file

@ -1,3 +1,34 @@
## Changes in 1.5.2 (2021-08-27)
✨ Features
- Account Notification Settings: Enable/disable notification settings (Default, Mentions & Keywords and Other) and edit Keywords. ([#4467](https://github.com/vector-im/element-ios/issues/4467))
- Implemented dialogs to inform users about Element iOS11 deprecation. ([#4693](https://github.com/vector-im/element-ios/issues/4693))
🙌 Improvements
- Upgrade MatrixKit version ([v0.15.8](https://github.com/matrix-org/matrix-ios-kit/releases/tag/v0.15.8)).
- Popping the user back to the home screen after leaving a room. ([#1482](https://github.com/vector-im/element-ios/issues/1482))
- Notifications: Replace "Message" fallback with "Notification" as the event may not be a message. ([#4132](https://github.com/vector-im/element-ios/issues/4132))
- MXSessionState: Use Swifty versions. ([#4471](https://github.com/vector-im/element-ios/issues/4471))
- Notifications: Show the body of all message event types. ([#4653](https://github.com/vector-im/element-ios/issues/4653))
- Notifications: Replies now hide the referenced content. ([#4660](https://github.com/vector-im/element-ios/issues/4660))
- Room Notification Settings: This screen is now implemented in SwiftUI for users on iOS14 or above. ([#4669](https://github.com/vector-im/element-ios/issues/4669))
🐛 Bugfixes
- Fixed flickering voice message cells while being sent. ([#4714](https://github.com/vector-im/element-ios/issues/4714))
- Fastfile: Update build number in AppVersion.xcconfig instead of AppIdentifiers.xcconfig. ([#4726](https://github.com/vector-im/element-ios/issues/4726))
- Disabled the create room button while creating a room, preventing duplicates from being created. ([#4746](https://github.com/vector-im/element-ios/issues/4746))
- Fixed cached callbacks race condition, serialized all async operations, properly cleaning up callbacks on failure. ([#4748](https://github.com/vector-im/element-ios/issues/4748))
- Notification Settings: Keywords Notification Setting should be "On" by default. ([#4759](https://github.com/vector-im/element-ios/issues/4759))
🧱 Build
- Support building Ad-hoc alpha release on pull request (#4635). ([#4635](https://github.com/vector-im/element-ios/issues/4635))
- Move app version from AppIdentifiers.xcconfig into a dedicated config file (#4715). ([#4715](https://github.com/vector-im/element-ios/issues/4715))
## Changes in 1.5.1 (2021-08-12)
🐛 Bugfixes

View file

@ -15,5 +15,5 @@
//
// Version
MARKETING_VERSION = 1.5.2
CURRENT_PROJECT_VERSION = 1.5.2
MARKETING_VERSION = 1.5.3
CURRENT_PROJECT_VERSION = 1.5.3

View file

@ -0,0 +1,50 @@
//
// 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
/**
Struct for holding colour values for a particular theme.
*/
public struct ColorValues: Colors {
public let accent: UIColor
public let alert: UIColor
public let primaryContent: UIColor
public let secondaryContent: UIColor
public let tertiaryContent: UIColor
public let quarterlyContent: UIColor
public let quinaryContent: UIColor
public let separator: UIColor
public let system: UIColor
public let tile: UIColor
public let navigation: UIColor
public let background: UIColor
public let namesAndAvatars: [UIColor]
}

View file

@ -15,54 +15,57 @@
//
import Foundation
import UIKit
/// Colors at https://www.figma.com/file/X4XTH9iS2KGJ2wFKDqkyed/Compound?node-id=1255%3A1104
@objc public protocol Colors {
public protocol Colors {
associatedtype ColorType
/// - Focused/Active states
/// - CTAs
var accent: UIColor { get }
var accent: ColorType { get }
/// - Error messages
/// - Content requiring user attention
/// - Notification, alerts
var alert: UIColor { get }
var alert: ColorType { get }
/// - Text
/// - Icons
var primaryContent: UIColor { get }
var primaryContent: ColorType { get }
/// - Text
/// - Icons
var secondaryContent: UIColor { get }
var secondaryContent: ColorType { get }
/// - Text
/// - Icons
var tertiaryContent: UIColor { get }
var tertiaryContent: ColorType { get }
/// - Text
/// - Icons
var quarterlyContent: UIColor { get }
var quarterlyContent: ColorType { get }
/// - Text
/// - Icons
var quinaryContent: UIColor { get }
/// - separating lines and other UI components
var quinaryContent: ColorType { get }
/// - System-based areas and backgrounds
var system: ColorType { get }
/// Separating line
var separator: UIColor { get }
var separator: ColorType { get }
// Cards, tiles
var tile: UIColor { get }
var tile: ColorType { get }
/// Top navigation background on iOS
var navigation: UIColor { get }
var navigation: ColorType { get }
/// Background UI color
var background: UIColor { get }
var background: ColorType { get }
/// - Names in chat timeline
/// - Avatars default states that include first name letter
var namesAndAvatars: [UIColor] { get }
var namesAndAvatars: [ColorType] { get }
}

View file

@ -0,0 +1,67 @@
//
// 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 SwiftUI
/**
Struct for holding colors for use in SwiftUI.
*/
@available(iOS 14.0, *)
public struct ColorSwiftUI: Colors {
public let accent: Color
public let alert: Color
public let primaryContent: Color
public let secondaryContent: Color
public let tertiaryContent: Color
public let quarterlyContent: Color
public let quinaryContent: Color
public let separator: Color
public var system: Color
public let tile: Color
public let navigation: Color
public let background: Color
public let namesAndAvatars: [Color]
init(values: ColorValues) {
accent = Color(values.accent)
alert = Color(values.alert)
primaryContent = Color(values.primaryContent)
secondaryContent = Color(values.secondaryContent)
tertiaryContent = Color(values.tertiaryContent)
quarterlyContent = Color(values.quarterlyContent)
quinaryContent = Color(values.quinaryContent)
separator = Color(values.separator)
system = Color(values.system)
tile = Color(values.tile)
navigation = Color(values.navigation)
background = Color(values.background)
namesAndAvatars = values.namesAndAvatars.map({ Color($0) })
}
}

View file

@ -0,0 +1,67 @@
//
// 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
/**
ObjC class for holding colors for use in UIKit.
*/
@objcMembers public class ColorsUIKit: NSObject {
public let accent: UIColor
public let alert: UIColor
public let primaryContent: UIColor
public let secondaryContent: UIColor
public let tertiaryContent: UIColor
public let quarterlyContent: UIColor
public let quinaryContent: UIColor
public let separator: UIColor
public let system: UIColor
public let tile: UIColor
public let navigation: UIColor
public let background: UIColor
public let namesAndAvatars: [UIColor]
init(values: ColorValues) {
accent = values.accent
alert = values.alert
primaryContent = values.primaryContent
secondaryContent = values.secondaryContent
tertiaryContent = values.tertiaryContent
quarterlyContent = values.quarterlyContent
quinaryContent = values.quinaryContent
separator = values.separator
system = values.system
tile = values.tile
navigation = values.navigation
background = values.background
namesAndAvatars = values.namesAndAvatars
}
}

View file

@ -19,65 +19,67 @@ import UIKit
/// Describe fonts used in the application.
/// Font names are based on Element typograhy https://www.figma.com/file/X4XTH9iS2KGJ2wFKDqkyed/Compound?node-id=1362%3A0 which is based on Apple font text styles (UIFont.TextStyle): https://developer.apple.com/documentation/uikit/uifonttextstyle
/// Create a custom TextStyle enum (like DesignKit.Fonts.TextStyle) is also a possiblity
@objc public protocol Fonts {
public protocol Fonts {
associatedtype FontType
/// The font for large titles.
var largeTitle: UIFont { get }
var largeTitle: FontType { get }
/// `largeTitle` with a Bold weight.
var largeTitleB: UIFont { get }
var largeTitleB: FontType { get }
/// The font for first-level hierarchical headings.
var title1: UIFont { get }
var title1: FontType { get }
/// `title1` with a Bold weight.
var title1B: UIFont { get }
var title1B: FontType { get }
/// The font for second-level hierarchical headings.
var title2: UIFont { get }
var title2: FontType { get }
/// `title2` with a Bold weight.
var title2B: UIFont { get }
var title2B: FontType { get }
/// The font for third-level hierarchical headings.
var title3: UIFont { get }
var title3: FontType { get }
/// `title3` with a Semi Bold weight.
var title3SB: UIFont { get }
var title3SB: FontType { get }
/// The font for headings.
var headline: UIFont { get }
var headline: FontType { get }
/// The font for subheadings.
var subheadline: UIFont { get }
var subheadline: FontType { get }
/// The font for body text.
var body: UIFont { get }
var body: FontType { get }
/// `body` with a Semi Bold weight.
var bodySB: UIFont { get }
var bodySB: FontType { get }
/// The font for callouts.
var callout: UIFont { get }
var callout: FontType { get }
/// `callout` with a Semi Bold weight.
var calloutSB: UIFont { get }
var calloutSB: FontType { get }
/// The font for footnotes.
var footnote: UIFont { get }
var footnote: FontType { get }
/// `footnote` with a Semi Bold weight.
var footnoteSB: UIFont { get }
var footnoteSB: FontType { get }
/// The font for standard captions.
var caption1: UIFont { get }
var caption1: FontType { get }
/// `caption1` with a Semi Bold weight.
var caption1SB: UIFont { get }
var caption1SB: FontType { get }
/// The font for alternate captions.
var caption2: UIFont { get }
var caption2: FontType { get }
/// `caption2` with a Semi Bold weight.
var caption2SB: UIFont { get }
var caption2SB: FontType { get }
}

View file

@ -0,0 +1,88 @@
//
// 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 SwiftUI
/**
Struct for holding fonts for use in SwiftUI.
*/
@available(iOS 14.0, *)
public struct FontSwiftUI: Fonts {
public var largeTitle: Font
public var largeTitleB: Font
public var title1: Font
public var title1B: Font
public var title2: Font
public var title2B: Font
public var title3: Font
public var title3SB: Font
public var headline: Font
public var subheadline: Font
public var body: Font
public var bodySB: Font
public var callout: Font
public var calloutSB: Font
public var footnote: Font
public var footnoteSB: Font
public var caption1: Font
public var caption1SB: Font
public var caption2: Font
public var caption2SB: Font
public init(values: ElementFonts) {
self.largeTitle = Font(values.largeTitle)
self.largeTitleB = Font(values.largeTitleB)
self.title1 = Font(values.title1)
self.title1B = Font(values.title1B)
self.title2 = Font(values.title2)
self.title2B = Font(values.title2B)
self.title3 = Font(values.title3)
self.title3SB = Font(values.title3SB)
self.headline = Font(values.headline)
self.subheadline = Font(values.subheadline)
self.body = Font(values.body)
self.bodySB = Font(values.bodySB)
self.callout = Font(values.callout)
self.calloutSB = Font(values.calloutSB)
self.footnote = Font(values.footnote)
self.footnoteSB = Font(values.footnoteSB)
self.caption1 = Font(values.caption1)
self.caption1SB = Font(values.caption1SB)
self.caption2 = Font(values.caption2)
self.caption2SB = Font(values.caption2SB)
}
}

View file

@ -0,0 +1,87 @@
//
// 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
/**
ObjC class for holding fonts for use in UIKit.
*/
@objc public class FontsUIKit: NSObject, Fonts {
public var largeTitle: UIFont
public var largeTitleB: UIFont
public var title1: UIFont
public var title1B: UIFont
public var title2: UIFont
public var title2B: UIFont
public var title3: UIFont
public var title3SB: UIFont
public var headline: UIFont
public var subheadline: UIFont
public var body: UIFont
public var bodySB: UIFont
public var callout: UIFont
public var calloutSB: UIFont
public var footnote: UIFont
public var footnoteSB: UIFont
public var caption1: UIFont
public var caption1SB: UIFont
public var caption2: UIFont
public var caption2SB: UIFont
public init(values: ElementFonts) {
self.largeTitle = values.largeTitle
self.largeTitleB = values.largeTitleB
self.title1 = values.title1
self.title1B = values.title1B
self.title2 = values.title2
self.title2B = values.title2B
self.title3 = values.title3
self.title3SB = values.title3SB
self.headline = values.headline
self.subheadline = values.subheadline
self.body = values.body
self.bodySB = values.bodySB
self.callout = values.callout
self.calloutSB = values.calloutSB
self.footnote = values.footnote
self.footnoteSB = values.footnoteSB
self.caption1 = values.caption1
self.caption1SB = values.caption1SB
self.caption2 = values.caption2
self.caption2SB = values.caption2SB
}
}

View file

@ -21,11 +21,23 @@ import UIKit
@objc public protocol ThemeV2 {
/// Colors object
var colors: Colors { get }
var colors: ColorsUIKit { get }
/// Fonts object
var fonts: Fonts { get }
var fonts: FontsUIKit { get }
/// may contain more design components in future, like icons, audio files etc.
}
/// Theme v2 for SwiftUI.
@available(iOS 14.0, *)
public protocol ThemeSwiftUIType {
/// Colors object
var colors: ColorSwiftUI { get }
/// Fonts object
var fonts: FontSwiftUI { get }
/// may contain more design components in future, like icons, audio files etc.
}

View file

@ -16,43 +16,36 @@
import Foundation
import UIKit
import SwiftUI
/// 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 quinaryContent: UIColor = UIColor(rgb: 0x394049)
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() {}
/// Dark theme colors.
public class DarkColors {
private static let values = ColorValues(
accent: UIColor(rgb:0x0DBD8B),
alert: UIColor(rgb:0xFF4B55),
primaryContent: UIColor(rgb:0xFFFFFF),
secondaryContent: UIColor(rgb:0xA9B2BC),
tertiaryContent: UIColor(rgb:0x8E99A4),
quarterlyContent: UIColor(rgb:0x6F7882),
quinaryContent: UIColor(rgb:0x394049),
separator: UIColor(rgb:0x21262C),
system: UIColor(rgb:0x21262C),
tile: UIColor(rgb:0x394049),
navigation: UIColor(rgb:0x21262C),
background: UIColor(rgb:0x15191E),
namesAndAvatars: [
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 static var uiKit = ColorsUIKit(values: values)
@available(iOS 14.0, *)
public static var swiftUI = ColorSwiftUI(values: values)
}

View file

@ -16,43 +16,42 @@
import Foundation
import UIKit
import SwiftUI
/// 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 quinaryContent: UIColor = UIColor(rgb: 0xE3E8F0)
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() {}
/// Light theme colors.
public class LightColors {
private static let values = ColorValues(
accent: UIColor(rgb:0x0DBD8B),
alert: UIColor(rgb:0xFF4B55),
primaryContent: UIColor(rgb:0x17191C),
secondaryContent: UIColor(rgb:0x737D8C),
tertiaryContent: UIColor(rgb:0x8D97A5),
quarterlyContent: UIColor(rgb:0xC1C6CD),
quinaryContent: UIColor(rgb:0xE3E8F0),
separator: UIColor(rgb:0xE3E8F0),
system: UIColor(rgb:0xF4F6FA),
tile: UIColor(rgb:0xF3F8FD),
navigation: UIColor(rgb:0xF4F6FA),
background: UIColor(rgb:0xFFFFFF),
namesAndAvatars: [
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 static var uiKit = ColorsUIKit(values: values)
@available(iOS 14.0, *)
public static var swiftUI = ColorSwiftUI(values: values)
}

10
Podfile
View file

@ -1,3 +1,5 @@
source 'https://cdn.cocoapods.org/'
# Uncomment this line to define a global platform for your project
platform :ios, '11.0'
@ -11,7 +13,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.15.7'
$matrixKitVersion = '= 0.15.8'
# $matrixKitVersion = :local
# $matrixKitVersion = {'develop' => 'develop'}
@ -46,7 +48,7 @@ abstract_target 'RiotPods' do
pod 'GBDeviceInfo', '~> 6.6.0'
pod 'Reusable', '~> 4.1'
pod 'KeychainAccess', '~> 4.2.2'
# Piwik for analytics
pod 'MatomoTracker', '~> 7.4.1'
@ -103,7 +105,7 @@ post_install do |installer|
# Plus the app does not enable it
config.build_settings['ENABLE_BITCODE'] = 'NO'
# Make fastlane(xcodebuild) happy by preventing it from building for arm64 simulator
# Make fastlane(xcodebuild) happy by preventing it from building for arm64 simulator
config.build_settings["EXCLUDED_ARCHS[sdk=iphonesimulator*]"] = "arm64"
# Force ReadMoreTextView to use Swift 5.2 version (as there is no code changes to perform)
@ -111,7 +113,7 @@ post_install do |installer|
config.build_settings['SWIFT_VERSION'] = '5.2'
end
# Stop Xcode 12 complaining about old IPHONEOS_DEPLOYMENT_TARGET from pods
# Stop Xcode 12 complaining about old IPHONEOS_DEPLOYMENT_TARGET from pods
config.build_settings.delete 'IPHONEOS_DEPLOYMENT_TARGET'
end
end

View file

@ -37,7 +37,7 @@ PODS:
- DTFoundation/Core
- DTFoundation/UIKit (1.7.18):
- DTFoundation/Core
- ffmpeg-kit-ios-audio (4.4)
- ffmpeg-kit-ios-audio (4.4.LTS)
- FLEX (4.4.1)
- FlowCommoniOS (1.10.0)
- GBDeviceInfo (6.6.0):
@ -58,29 +58,29 @@ PODS:
- MatomoTracker (7.4.1):
- MatomoTracker/Core (= 7.4.1)
- MatomoTracker/Core (7.4.1)
- MatrixKit (0.15.7):
- MatrixKit (0.15.8):
- Down (~> 0.11.0)
- DTCoreText (~> 1.6.25)
- HPGrowingTextView (~> 1.1)
- libPhoneNumber-iOS (~> 0.9.13)
- MatrixKit/Core (= 0.15.7)
- MatrixSDK (= 0.19.7)
- MatrixKit/Core (0.15.7):
- MatrixKit/Core (= 0.15.8)
- MatrixSDK (= 0.19.8)
- MatrixKit/Core (0.15.8):
- Down (~> 0.11.0)
- DTCoreText (~> 1.6.25)
- HPGrowingTextView (~> 1.1)
- libPhoneNumber-iOS (~> 0.9.13)
- MatrixSDK (= 0.19.7)
- MatrixSDK (0.19.7):
- MatrixSDK/Core (= 0.19.7)
- MatrixSDK/Core (0.19.7):
- MatrixSDK (= 0.19.8)
- MatrixSDK (0.19.8):
- MatrixSDK/Core (= 0.19.8)
- MatrixSDK/Core (0.19.8):
- AFNetworking (~> 4.0.0)
- GZIP (~> 1.3.0)
- libbase58 (~> 0.1.4)
- OLMKit (~> 3.2.4)
- Realm (= 10.7.6)
- SwiftyBeaver (= 1.9.5)
- MatrixSDK/JingleCallStack (0.19.7):
- MatrixSDK/JingleCallStack (0.19.8):
- JitsiMeetSDK (= 3.5.0)
- MatrixSDK/Core
- OLMKit (3.2.4):
@ -124,7 +124,7 @@ DEPENDENCIES:
- KeychainAccess (~> 4.2.2)
- KTCenterFlowLayout (~> 1.3.1)
- MatomoTracker (~> 7.4.1)
- MatrixKit (= 0.15.7)
- MatrixKit (= 0.15.8)
- MatrixSDK
- MatrixSDK/JingleCallStack
- OLMKit
@ -189,7 +189,7 @@ SPEC CHECKSUMS:
DSWaveformImage: 3c718a0cf99291887ee70d1d0c18d80101d3d9ce
DTCoreText: ec749e013f2e1f76de5e7c7634642e600a7467ce
DTFoundation: a53f8cda2489208cbc71c648be177f902ee17536
ffmpeg-kit-ios-audio: ddfc3dac6f574e83d53f8ae33586711162685d3e
ffmpeg-kit-ios-audio: 1c365080b8c76aa77b87c926f9f66ac07859b342
FLEX: 7ca2c8cd3a435ff501ff6d2f2141e9bdc934eaab
FlowCommoniOS: bcdf81a5f30717e711af08a8c812eb045411ba94
GBDeviceInfo: ed0db16230d2fa280e1cbb39a5a7f60f6946aaec
@ -204,8 +204,8 @@ SPEC CHECKSUMS:
LoggerAPI: ad9c4a6f1e32f518fdb43a1347ac14d765ab5e3d
Logging: beeb016c9c80cf77042d62e83495816847ef108b
MatomoTracker: 24a846c9d3aa76933183fe9d47fd62c9efa863fb
MatrixKit: 5939d1b63bad3e7f709534a8f105b69f84728591
MatrixSDK: c0bbec5b67cc8771cffdf3b494d622bce0a51ceb
MatrixKit: 2945ade22970747defcc4d564cb0c7aedbd4019d
MatrixSDK: 4d4679b499b4802a11a90b3652f83be496bfaec1
OLMKit: 2d73cd67d149b5c3e3a8eb8ecae93d0b429d8a02
ReadMoreTextView: 19147adf93abce6d7271e14031a00303fe28720d
Realm: ed860452717c8db8f4bf832b6807f7f2ce708839
@ -219,6 +219,6 @@ SPEC CHECKSUMS:
zxcvbn-ios: fef98b7c80f1512ff0eec47ac1fa399fc00f7e3c
ZXingObjC: fdbb269f25dd2032da343e06f10224d62f537bdb
PODFILE CHECKSUM: 605b63b9968e2916d998f4769f162b4b7c2a2577
PODFILE CHECKSUM: 7a2c462b09e09029983e15c0e4ad8dcf4d68df69
COCOAPODS: 1.10.1
COCOAPODS: 1.10.2

View file

@ -4,8 +4,7 @@
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES"
runPostActionsOnFailure = "NO">
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"

View file

@ -5155,12 +5155,10 @@ extension VectorL10n {
static func tr(_ table: String, _ key: String, _ args: CVarArg...) -> String {
let format = NSLocalizedString(key, tableName: table, bundle: Bundle(for: BundleToken.self), comment: "")
let locale: Locale
if let localeIdentifier = Bundle.mxk_language() {
locale = Locale(identifier: localeIdentifier)
} else if let fallbackLocaleIdentifier = Bundle.mxk_fallbackLanguage() {
locale = Locale(identifier: fallbackLocaleIdentifier)
if let providedLocale = LocaleProvider.locale {
locale = providedLocale
} else {
locale = Locale.current
locale = Locale.current
}
return String(format: format, locale: locale, arguments: args)

View file

@ -0,0 +1,31 @@
//
// 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
/**
Provides the locale logic for Riot app based on mx languages.
*/
class LocaleProvider: LocaleProviderType {
static var locale: Locale? {
if let localeIdentifier = Bundle.mxk_language() {
return Locale(identifier: localeIdentifier)
} else if let fallbackLocaleIdentifier = Bundle.mxk_fallbackLanguage() {
return Locale(identifier: fallbackLocaleIdentifier)
}
return nil
}
}

View file

@ -0,0 +1,24 @@
//
// 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
/**
Used to provide an application/target specific locale.
*/
protocol LocaleProviderType {
static var locale: Locale? { get }
}

View file

@ -23,72 +23,15 @@ final class RiotSettings: NSObject {
// MARK: - Constants
private enum UserDefaultsKeys {
static let homeserverUrlString = "homeserverurl"
static let identityServerUrlString = "identityserverurl"
static let enableCrashReport = "enableCrashReport"
static let enableRageShake = "enableRageShake"
static let userInterfaceTheme = "userInterfaceTheme"
static let notificationsShowDecryptedContent = "showDecryptedContent"
static let pinRoomsWithMissedNotifications = "pinRoomsWithMissedNotif"
static let pinRoomsWithUnreadMessages = "pinRoomsWithUnread"
static let allowStunServerFallback = "allowStunServerFallback"
static let hideVerifyThisSessionAlert = "hideVerifyThisSessionAlert"
static let hideReviewSessionsAlert = "hideReviewSessionsAlert"
static let matrixApps = "matrixApps"
static let showNSFWPublicRooms = "showNSFWPublicRooms"
static let settingsScreenShowChangePassword = "settingsScreenShowChangePassword"
static let settingsScreenShowInviteFriends = "settingsScreenShowInviteFriends"
static let settingsScreenShowEnableStunServerFallback = "settingsScreenShowEnableStunServerFallback"
static let settingsSecurityScreenShowSessions = "settingsSecurityScreenShowSessions"
static let settingsSecurityScreenShowSetupBackup = "settingsSecurityScreenShowSetupBackup"
static let settingsSecurityScreenShowRestoreBackup = "settingsSecurityScreenShowRestoreBackup"
static let settingsSecurityScreenShowDeleteBackup = "settingsSecurityScreenShowDeleteBackup"
static let settingsSecurityScreenShowCryptographyInfo = "settingsSecurityScreenShowCryptographyInfo"
static let settingsSecurityScreenShowCryptographyExport = "settingsSecurityScreenShowCryptographyExport"
static let settingsSecurityScreenShowAdvancedUnverifiedDevices = "settingsSecurityScreenShowAdvancedBlacklistUnverifiedDevices"
static let roomCreationScreenAllowEncryptionConfiguration = "roomCreationScreenAllowEncryptionConfiguration"
static let roomCreationScreenRoomIsEncrypted = "roomCreationScreenRoomIsEncrypted"
static let roomCreationScreenAllowRoomTypeConfiguration = "roomCreationScreenAllowRoomTypeConfiguration"
static let roomCreationScreenRoomIsPublic = "roomCreationScreenRoomIsPublic"
static let allowInviteExernalUsers = "allowInviteExernalUsers"
static let showMediaCompressionPrompt = "showMediaCompressionPrompt"
static let enableRingingForGroupCalls = "enableRingingForGroupCalls"
static let roomSettingsScreenShowLowPriorityOption = "roomSettingsScreenShowLowPriorityOption"
static let roomSettingsScreenShowDirectChatOption = "roomSettingsScreenShowDirectChatOption"
static let roomSettingsScreenAllowChangingAccessSettings = "roomSettingsScreenAllowChangingAccessSettings"
static let roomSettingsScreenAllowChangingHistorySettings = "roomSettingsScreenAllowChangingHistorySettings"
static let roomSettingsScreenShowAddressSettings = "roomSettingsScreenShowAddressSettings"
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"
static let homeScreenShowRoomsTab = "homeScreenShowRoomsTab"
static let homeScreenShowCommunitiesTab = "homeScreenShowCommunitiesTab"
static let roomScreenAllowVoIPForDirectRoom = "roomScreenAllowVoIPForDirectRoom"
static let roomScreenAllowVoIPForNonDirectRoom = "roomScreenAllowVoIPForNonDirectRoom"
static let roomScreenAllowCameraAction = "roomScreenAllowCameraAction"
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"
static let hideSpaceBetaAnnounce = "hideSpaceBetaAnnounce"
static let secretsRecoveryAllowReset = "secretsRecoveryAllowReset"
static let versionCheckNextDisplayDateTimeInterval = "versionCheckNextDisplayDateTimeInterval"
}
static let shared = RiotSettings()
/// UserDefaults to be used on reads and writes.
private lazy var defaults: UserDefaults = {
static var defaults: UserDefaults = {
guard let userDefaults = UserDefaults(suiteName: BuildSettings.applicationGroupIdentifier) else {
fatalError("[RiotSettings] Fail to load shared UserDefaults")
}
@ -102,34 +45,9 @@ final class RiotSettings: NSObject {
])
}
// MARK: Servers
var homeserverUrlString: String {
get {
return defaults.string(forKey: UserDefaultsKeys.homeserverUrlString) ?? BuildSettings.serverConfigDefaultHomeserverUrlString
} set {
defaults.set(newValue, forKey: UserDefaultsKeys.homeserverUrlString)
}
}
var identityServerUrlString: String {
get {
return defaults.string(forKey: UserDefaultsKeys.identityServerUrlString) ?? BuildSettings.serverConfigDefaultIdentityServerUrlString
} set {
defaults.set(newValue, forKey: UserDefaultsKeys.identityServerUrlString)
}
}
// MARK: Notifications
/// Indicate if `showDecryptedContentInNotifications` settings has been set once.
var isShowDecryptedContentInNotificationsHasBeenSetOnce: Bool {
return defaults.object(forKey: UserDefaultsKeys.notificationsShowDecryptedContent) != nil
}
/// Indicate if UserDefaults suite has been migrated once.
var isUserDefaultsMigrated: Bool {
return defaults.object(forKey: UserDefaultsKeys.notificationsShowDecryptedContent) != nil
return RiotSettings.defaults.object(forKey: UserDefaultsKeys.notificationsShowDecryptedContent) != nil
}
func migrate() {
@ -139,321 +57,151 @@ final class RiotSettings: NSObject {
// write values to suite
// remove redundant values from standard
for (key, value) in dictionary {
defaults.set(value, forKey: key)
RiotSettings.defaults.set(value, forKey: key)
UserDefaults.standard.removeObject(forKey: key)
}
}
/// Indicate if encrypted messages content should be displayed in notifications.
var showDecryptedContentInNotifications: Bool {
get {
return defaults.bool(forKey: UserDefaultsKeys.notificationsShowDecryptedContent)
} set {
defaults.set(newValue, forKey: UserDefaultsKeys.notificationsShowDecryptedContent)
}
// MARK: Servers
@UserDefault(key: "homeserverurl", defaultValue: BuildSettings.serverConfigDefaultHomeserverUrlString, storage: defaults)
var homeserverUrlString
@UserDefault(key: "identityserverurl", defaultValue: BuildSettings.serverConfigDefaultIdentityServerUrlString, storage: defaults)
var identityServerUrlString
// MARK: Notifications
/// Indicate if `showDecryptedContentInNotifications` settings has been set once.
var isShowDecryptedContentInNotificationsHasBeenSetOnce: Bool {
return RiotSettings.defaults.object(forKey: UserDefaultsKeys.notificationsShowDecryptedContent) != nil
}
/// Indicate if encrypted messages content should be displayed in notifications.
@UserDefault(key: UserDefaultsKeys.notificationsShowDecryptedContent, defaultValue: false, storage: defaults)
var showDecryptedContentInNotifications
/// Indicate if rooms with missed notifications should be displayed first on home screen.
var pinRoomsWithMissedNotificationsOnHome: Bool {
get {
return defaults.bool(forKey: UserDefaultsKeys.pinRoomsWithMissedNotifications)
} set {
defaults.set(newValue, forKey: UserDefaultsKeys.pinRoomsWithMissedNotifications)
}
}
@UserDefault(key: "pinRoomsWithMissedNotif", defaultValue: false, storage: defaults)
var pinRoomsWithMissedNotificationsOnHome
/// Indicate if rooms with unread messages should be displayed first on home screen.
var pinRoomsWithUnreadMessagesOnHome: Bool {
get {
return defaults.bool(forKey: UserDefaultsKeys.pinRoomsWithUnreadMessages)
} set {
defaults.set(newValue, forKey: UserDefaultsKeys.pinRoomsWithUnreadMessages)
}
}
@UserDefault(key: "pinRoomsWithUnread", defaultValue: false, storage: defaults)
var pinRoomsWithUnreadMessagesOnHome
/// Indicate to show Not Safe For Work public rooms.
var showNSFWPublicRooms: Bool {
get {
return defaults.bool(forKey: UserDefaultsKeys.showNSFWPublicRooms)
} set {
defaults.set(newValue, forKey: UserDefaultsKeys.showNSFWPublicRooms)
}
}
@UserDefault(key: "showNSFWPublicRooms", defaultValue: false, storage: defaults)
var showNSFWPublicRooms
// MARK: User interface
var userInterfaceTheme: String? {
get {
return defaults.string(forKey: UserDefaultsKeys.userInterfaceTheme)
} set {
defaults.set(newValue, forKey: UserDefaultsKeys.userInterfaceTheme)
}
}
@UserDefault<String?>(key: "userInterfaceTheme", defaultValue: nil, storage: defaults)
var userInterfaceTheme
// MARK: Other
/// Indicate if `enableCrashReport` settings has been set once.
var isEnableCrashReportHasBeenSetOnce: Bool {
return defaults.object(forKey: UserDefaultsKeys.enableCrashReport) != nil
return RiotSettings.defaults.object(forKey: UserDefaultsKeys.enableCrashReport) != nil
}
var enableCrashReport: Bool {
get {
return defaults.bool(forKey: UserDefaultsKeys.enableCrashReport)
} set {
defaults.set(newValue, forKey: UserDefaultsKeys.enableCrashReport)
}
}
@UserDefault(key: UserDefaultsKeys.enableCrashReport, defaultValue: false, storage: defaults)
var enableCrashReport
var enableRageShake: Bool {
get {
return defaults.bool(forKey: UserDefaultsKeys.enableRageShake)
} set {
defaults.set(newValue, forKey: UserDefaultsKeys.enableRageShake)
}
}
@UserDefault(key: "enableRageShake", defaultValue: false, storage: defaults)
var enableRageShake
// MARK: Labs
/// 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.enableRingingForGroupCalls)
} set {
defaults.set(newValue, forKey: UserDefaultsKeys.enableRingingForGroupCalls)
}
}
@UserDefault(key: "enableRingingForGroupCalls", defaultValue: false, storage: defaults)
var enableRingingForGroupCalls
// MARK: Calls
/// Indicate if `allowStunServerFallback` settings has been set once.
var isAllowStunServerFallbackHasBeenSetOnce: Bool {
return defaults.object(forKey: UserDefaultsKeys.allowStunServerFallback) != nil
}
var allowStunServerFallback: Bool {
get {
return defaults.bool(forKey: UserDefaultsKeys.allowStunServerFallback)
} set {
defaults.set(newValue, forKey: UserDefaultsKeys.allowStunServerFallback)
}
return RiotSettings.defaults.object(forKey: UserDefaultsKeys.allowStunServerFallback) != nil
}
@UserDefault(key: UserDefaultsKeys.allowStunServerFallback, defaultValue: false, storage: defaults)
var allowStunServerFallback
// MARK: Key verification
var hideVerifyThisSessionAlert: Bool {
get {
return defaults.bool(forKey: UserDefaultsKeys.hideVerifyThisSessionAlert)
} set {
defaults.set(newValue, forKey: UserDefaultsKeys.hideVerifyThisSessionAlert)
}
}
@UserDefault(key: "hideVerifyThisSessionAlert", defaultValue: false, storage: defaults)
var hideVerifyThisSessionAlert
var hideReviewSessionsAlert: Bool {
get {
return defaults.bool(forKey: UserDefaultsKeys.hideReviewSessionsAlert)
} set {
defaults.set(newValue, forKey: UserDefaultsKeys.hideReviewSessionsAlert)
}
}
@UserDefault(key: "hideReviewSessionsAlert", defaultValue: false, storage: defaults)
var hideReviewSessionsAlert
var matrixApps: Bool {
get {
return defaults.bool(forKey: UserDefaultsKeys.matrixApps)
} set {
defaults.set(newValue, forKey: UserDefaultsKeys.matrixApps)
}
}
@UserDefault(key: "matrixApps", defaultValue: false, storage: defaults)
var matrixApps
// MARK: - Rooms Screen
var roomsAllowToJoinPublicRooms: Bool {
get {
guard defaults.object(forKey: UserDefaultsKeys.roomsAllowToJoinPublicRooms) != nil else {
return BuildSettings.roomsAllowToJoinPublicRooms
}
return defaults.bool(forKey: UserDefaultsKeys.roomsAllowToJoinPublicRooms)
} set {
defaults.set(newValue, forKey: UserDefaultsKeys.roomsAllowToJoinPublicRooms)
}
}
@UserDefault(key: "roomsAllowToJoinPublicRooms", defaultValue: BuildSettings.roomsAllowToJoinPublicRooms, storage: defaults)
var roomsAllowToJoinPublicRooms
// MARK: - Room Screen
var roomScreenAllowVoIPForDirectRoom: Bool {
get {
guard defaults.object(forKey: UserDefaultsKeys.roomScreenAllowVoIPForDirectRoom) != nil else {
return BuildSettings.roomScreenAllowVoIPForDirectRoom
}
return defaults.bool(forKey: UserDefaultsKeys.roomScreenAllowVoIPForDirectRoom)
} set {
defaults.set(newValue, forKey: UserDefaultsKeys.roomScreenAllowVoIPForDirectRoom)
}
}
var roomScreenAllowVoIPForNonDirectRoom: Bool {
get {
guard defaults.object(forKey: UserDefaultsKeys.roomScreenAllowVoIPForNonDirectRoom) != nil else {
return BuildSettings.roomScreenAllowVoIPForNonDirectRoom
}
return defaults.bool(forKey: UserDefaultsKeys.roomScreenAllowVoIPForNonDirectRoom)
} set {
defaults.set(newValue, forKey: UserDefaultsKeys.roomScreenAllowVoIPForNonDirectRoom)
}
}
var roomScreenAllowCameraAction: Bool {
get {
guard defaults.object(forKey: UserDefaultsKeys.roomScreenAllowCameraAction) != nil else {
return BuildSettings.roomScreenAllowCameraAction
}
return defaults.bool(forKey: UserDefaultsKeys.roomScreenAllowCameraAction)
} set {
defaults.set(newValue, forKey: UserDefaultsKeys.roomScreenAllowCameraAction)
}
}
var roomScreenAllowMediaLibraryAction: Bool {
get {
guard defaults.object(forKey: UserDefaultsKeys.roomScreenAllowMediaLibraryAction) != nil else {
return BuildSettings.roomScreenAllowMediaLibraryAction
}
return defaults.bool(forKey: UserDefaultsKeys.roomScreenAllowMediaLibraryAction)
} set {
defaults.set(newValue, forKey: UserDefaultsKeys.roomScreenAllowMediaLibraryAction)
}
}
var roomScreenAllowStickerAction: Bool {
get {
guard defaults.object(forKey: UserDefaultsKeys.roomScreenAllowStickerAction) != nil else {
return BuildSettings.roomScreenAllowStickerAction
}
return defaults.bool(forKey: UserDefaultsKeys.roomScreenAllowStickerAction)
} set {
defaults.set(newValue, forKey: UserDefaultsKeys.roomScreenAllowStickerAction)
}
}
var roomScreenAllowFilesAction: Bool {
get {
guard defaults.object(forKey: UserDefaultsKeys.roomScreenAllowFilesAction) != nil else {
return BuildSettings.roomScreenAllowFilesAction
}
return defaults.bool(forKey: UserDefaultsKeys.roomScreenAllowFilesAction)
} set {
defaults.set(newValue, forKey: UserDefaultsKeys.roomScreenAllowFilesAction)
}
}
@UserDefault(key: "roomScreenAllowVoIPForDirectRoom", defaultValue: BuildSettings.roomScreenAllowVoIPForDirectRoom, storage: defaults)
var roomScreenAllowVoIPForDirectRoom
@UserDefault(key: "roomScreenAllowVoIPForNonDirectRoom", defaultValue: BuildSettings.roomScreenAllowVoIPForNonDirectRoom, storage: defaults)
var roomScreenAllowVoIPForNonDirectRoom
@UserDefault(key: "roomScreenAllowCameraAction", defaultValue: BuildSettings.roomScreenAllowCameraAction, storage: defaults)
var roomScreenAllowCameraAction
@UserDefault(key: "roomScreenAllowMediaLibraryAction", defaultValue: BuildSettings.roomScreenAllowMediaLibraryAction, storage: defaults)
var roomScreenAllowMediaLibraryAction
@UserDefault(key: "roomScreenAllowStickerAction", defaultValue: BuildSettings.roomScreenAllowStickerAction, storage: defaults)
var roomScreenAllowStickerAction
@UserDefault(key: "roomScreenAllowFilesAction", defaultValue: BuildSettings.roomScreenAllowFilesAction, storage: defaults)
var 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)
}
}
@UserDefault(key: "roomContextualMenuShowMoreOptionForMessages", defaultValue: BuildSettings.roomContextualMenuShowMoreOptionForMessages, storage: defaults)
var roomContextualMenuShowMoreOptionForMessages
@UserDefault(key: "roomContextualMenuShowMoreOptionForStates", defaultValue: BuildSettings.roomContextualMenuShowMoreOptionForStates, storage: defaults)
var roomContextualMenuShowMoreOptionForStates
@UserDefault(key: "roomContextualMenuShowReportContentOption", defaultValue: BuildSettings.roomContextualMenuShowReportContentOption, storage: defaults)
var roomContextualMenuShowReportContentOption
// MARK: - Room Info Screen
var roomInfoScreenShowIntegrations: Bool {
get {
guard defaults.object(forKey: UserDefaultsKeys.roomInfoScreenShowIntegrations) != nil else {
return BuildSettings.roomInfoScreenShowIntegrations
}
return defaults.bool(forKey: UserDefaultsKeys.roomInfoScreenShowIntegrations)
} set {
defaults.set(newValue, forKey: UserDefaultsKeys.roomInfoScreenShowIntegrations)
}
}
@UserDefault(key: "roomInfoScreenShowIntegrations", defaultValue: BuildSettings.roomInfoScreenShowIntegrations, storage: defaults)
var roomInfoScreenShowIntegrations
// 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)
}
}
@UserDefault(key: "roomMemberScreenShowIgnore", defaultValue: BuildSettings.roomMemberScreenShowIgnore, storage: defaults)
var roomMemberScreenShowIgnore
// MARK: - Room Creation Screen
var roomCreationScreenAllowEncryptionConfiguration: Bool {
get {
guard defaults.object(forKey: UserDefaultsKeys.roomCreationScreenAllowEncryptionConfiguration) != nil else {
return BuildSettings.roomCreationScreenAllowEncryptionConfiguration
}
return defaults.bool(forKey: UserDefaultsKeys.roomCreationScreenAllowEncryptionConfiguration)
} set {
defaults.set(newValue, forKey: UserDefaultsKeys.roomCreationScreenAllowEncryptionConfiguration)
}
}
var roomCreationScreenRoomIsEncrypted: Bool {
get {
guard defaults.object(forKey: UserDefaultsKeys.roomCreationScreenRoomIsEncrypted) != nil else {
return BuildSettings.roomCreationScreenRoomIsEncrypted
}
return defaults.bool(forKey: UserDefaultsKeys.roomCreationScreenRoomIsEncrypted)
} set {
defaults.set(newValue, forKey: UserDefaultsKeys.roomCreationScreenRoomIsEncrypted)
}
}
var roomCreationScreenAllowRoomTypeConfiguration: Bool {
get {
guard defaults.object(forKey: UserDefaultsKeys.roomCreationScreenAllowRoomTypeConfiguration) != nil else {
return BuildSettings.roomCreationScreenAllowRoomTypeConfiguration
}
return defaults.bool(forKey: UserDefaultsKeys.roomCreationScreenAllowRoomTypeConfiguration)
} set {
defaults.set(newValue, forKey: UserDefaultsKeys.roomCreationScreenAllowRoomTypeConfiguration)
}
}
var roomCreationScreenRoomIsPublic: Bool {
get {
guard defaults.object(forKey: UserDefaultsKeys.roomCreationScreenRoomIsPublic) != nil else {
return BuildSettings.roomCreationScreenRoomIsPublic
}
return defaults.bool(forKey: UserDefaultsKeys.roomCreationScreenRoomIsPublic)
} set {
defaults.set(newValue, forKey: UserDefaultsKeys.roomCreationScreenRoomIsPublic)
}
}
@UserDefault(key: "roomCreationScreenAllowEncryptionConfiguration", defaultValue: BuildSettings.roomCreationScreenAllowEncryptionConfiguration, storage: defaults)
var roomCreationScreenAllowEncryptionConfiguration
@UserDefault(key: "roomCreationScreenRoomIsEncrypted", defaultValue: BuildSettings.roomCreationScreenRoomIsEncrypted, storage: defaults)
var roomCreationScreenRoomIsEncrypted
@UserDefault(key: "roomCreationScreenAllowRoomTypeConfiguration", defaultValue: BuildSettings.roomCreationScreenAllowRoomTypeConfiguration, storage: defaults)
var roomCreationScreenAllowRoomTypeConfiguration
@UserDefault(key: "roomCreationScreenRoomIsPublic", defaultValue: BuildSettings.roomCreationScreenRoomIsPublic, storage: defaults)
var roomCreationScreenRoomIsPublic
// MARK: Features
var allowInviteExernalUsers: Bool {
get {
guard defaults.object(forKey: UserDefaultsKeys.allowInviteExernalUsers) != nil else {
return BuildSettings.allowInviteExernalUsers
}
return defaults.bool(forKey: UserDefaultsKeys.allowInviteExernalUsers)
} set {
defaults.set(newValue, forKey: UserDefaultsKeys.allowInviteExernalUsers)
}
}
@UserDefault(key: "allowInviteExernalUsers", defaultValue: BuildSettings.allowInviteExernalUsers, storage: defaults)
var allowInviteExernalUsers
/// When set to false the original image is sent and a 1080p preset is used for videos.
/// If `BuildSettings.roomInputToolbarCompressionMode` has a value other than prompt, the build setting takes priority for images.
@ -467,296 +215,99 @@ final class RiotSettings: NSObject {
// MARK: - Main Tabs
var homeScreenShowFavouritesTab: Bool {
get {
guard defaults.object(forKey: UserDefaultsKeys.homeScreenShowFavouritesTab) != nil else {
return BuildSettings.homeScreenShowFavouritesTab
}
return defaults.bool(forKey: UserDefaultsKeys.homeScreenShowFavouritesTab)
} set {
defaults.set(newValue, forKey: UserDefaultsKeys.homeScreenShowFavouritesTab)
}
}
var homeScreenShowPeopleTab: Bool {
get {
guard defaults.object(forKey: UserDefaultsKeys.homeScreenShowPeopleTab) != nil else {
return BuildSettings.homeScreenShowPeopleTab
}
return defaults.bool(forKey: UserDefaultsKeys.homeScreenShowPeopleTab)
} set {
defaults.set(newValue, forKey: UserDefaultsKeys.homeScreenShowPeopleTab)
}
}
var homeScreenShowRoomsTab: Bool {
get {
guard defaults.object(forKey: UserDefaultsKeys.homeScreenShowRoomsTab) != nil else {
return BuildSettings.homeScreenShowRoomsTab
}
return defaults.bool(forKey: UserDefaultsKeys.homeScreenShowRoomsTab)
} set {
defaults.set(newValue, forKey: UserDefaultsKeys.homeScreenShowRoomsTab)
}
}
var homeScreenShowCommunitiesTab: Bool {
get {
guard defaults.object(forKey: UserDefaultsKeys.homeScreenShowCommunitiesTab) != nil else {
return BuildSettings.homeScreenShowCommunitiesTab
}
return defaults.bool(forKey: UserDefaultsKeys.homeScreenShowCommunitiesTab)
} set {
defaults.set(newValue, forKey: UserDefaultsKeys.homeScreenShowCommunitiesTab)
}
}
@UserDefault(key: "homeScreenShowFavouritesTab", defaultValue: BuildSettings.homeScreenShowFavouritesTab, storage: defaults)
var homeScreenShowFavouritesTab
@UserDefault(key: "homeScreenShowPeopleTab", defaultValue: BuildSettings.homeScreenShowPeopleTab, storage: defaults)
var homeScreenShowPeopleTab
@UserDefault(key: "homeScreenShowRoomsTab", defaultValue: BuildSettings.homeScreenShowRoomsTab, storage: defaults)
var homeScreenShowRoomsTab
@UserDefault(key: "homeScreenShowCommunitiesTab", defaultValue: BuildSettings.homeScreenShowCommunitiesTab, storage: defaults)
var homeScreenShowCommunitiesTab
// MARK: General Settings
var settingsScreenShowChangePassword: Bool {
get {
guard defaults.object(forKey: UserDefaultsKeys.settingsScreenShowChangePassword) != nil else {
return BuildSettings.settingsScreenShowChangePassword
}
return defaults.bool(forKey: UserDefaultsKeys.settingsScreenShowChangePassword)
} set {
defaults.set(newValue, forKey: UserDefaultsKeys.settingsScreenShowChangePassword)
}
}
var settingsScreenShowInviteFriends: Bool {
get {
guard defaults.object(forKey: UserDefaultsKeys.settingsScreenShowInviteFriends) != nil else {
return BuildSettings.settingsScreenShowInviteFriends
}
return defaults.bool(forKey: UserDefaultsKeys.settingsScreenShowInviteFriends)
} set {
defaults.set(newValue, forKey: UserDefaultsKeys.settingsScreenShowInviteFriends)
}
}
var settingsScreenShowEnableStunServerFallback: Bool {
get {
guard defaults.object(forKey: UserDefaultsKeys.settingsScreenShowInviteFriends) != nil else {
return BuildSettings.settingsScreenShowEnableStunServerFallback
}
return defaults.bool(forKey: UserDefaultsKeys.settingsScreenShowEnableStunServerFallback)
} set {
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 {
return BuildSettings.settingsSecurityScreenShowSessions
}
return defaults.bool(forKey: UserDefaultsKeys.settingsSecurityScreenShowSessions)
} set {
defaults.set(newValue, forKey: UserDefaultsKeys.settingsSecurityScreenShowSessions)
}
}
var settingsSecurityScreenShowSetupBackup: Bool {
get {
guard defaults.object(forKey: UserDefaultsKeys.settingsSecurityScreenShowSetupBackup) != nil else {
return BuildSettings.settingsSecurityScreenShowSetupBackup
}
return defaults.bool(forKey: UserDefaultsKeys.settingsSecurityScreenShowSetupBackup)
} set {
defaults.set(newValue, forKey: UserDefaultsKeys.settingsSecurityScreenShowSetupBackup)
}
}
var settingsSecurityScreenShowRestoreBackup: Bool {
get {
guard defaults.object(forKey: UserDefaultsKeys.settingsSecurityScreenShowRestoreBackup) != nil else {
return BuildSettings.settingsSecurityScreenShowRestoreBackup
}
return defaults.bool(forKey: UserDefaultsKeys.settingsSecurityScreenShowRestoreBackup)
} set {
defaults.set(newValue, forKey: UserDefaultsKeys.settingsSecurityScreenShowRestoreBackup)
}
}
var settingsSecurityScreenShowDeleteBackup: Bool {
get {
guard defaults.object(forKey: UserDefaultsKeys.settingsSecurityScreenShowDeleteBackup) != nil else {
return BuildSettings.settingsSecurityScreenShowDeleteBackup
}
return defaults.bool(forKey: UserDefaultsKeys.settingsSecurityScreenShowDeleteBackup)
} set {
defaults.set(newValue, forKey: UserDefaultsKeys.settingsSecurityScreenShowDeleteBackup)
}
}
var settingsSecurityScreenShowCryptographyInfo: Bool {
get {
guard defaults.object(forKey: UserDefaultsKeys.settingsSecurityScreenShowCryptographyInfo) != nil else {
return BuildSettings.settingsSecurityScreenShowCryptographyInfo
}
return defaults.bool(forKey: UserDefaultsKeys.settingsSecurityScreenShowCryptographyInfo)
} set {
defaults.set(newValue, forKey: UserDefaultsKeys.settingsSecurityScreenShowCryptographyInfo)
}
}
var settingsSecurityScreenShowCryptographyExport: Bool {
get {
guard defaults.object(forKey: UserDefaultsKeys.settingsSecurityScreenShowCryptographyExport) != nil else {
return BuildSettings.settingsSecurityScreenShowCryptographyExport
}
return defaults.bool(forKey: UserDefaultsKeys.settingsSecurityScreenShowCryptographyExport)
} set {
defaults.set(newValue, forKey: UserDefaultsKeys.settingsSecurityScreenShowCryptographyExport)
}
}
var settingsSecurityScreenShowAdvancedUnverifiedDevices: Bool {
get {
guard defaults.object(forKey: UserDefaultsKeys.settingsSecurityScreenShowAdvancedUnverifiedDevices) != nil else {
return BuildSettings.settingsSecurityScreenShowAdvancedUnverifiedDevices
}
return defaults.bool(forKey: UserDefaultsKeys.settingsSecurityScreenShowAdvancedUnverifiedDevices)
} set {
defaults.set(newValue, forKey: UserDefaultsKeys.settingsSecurityScreenShowAdvancedUnverifiedDevices)
}
}
@UserDefault(key: "settingsScreenShowChangePassword", defaultValue: BuildSettings.settingsScreenShowChangePassword, storage: defaults)
var settingsScreenShowChangePassword
@UserDefault(key: "settingsScreenShowInviteFriends", defaultValue: BuildSettings.settingsScreenShowInviteFriends, storage: defaults)
var settingsScreenShowInviteFriends
@UserDefault(key: "settingsScreenShowEnableStunServerFallback", defaultValue: BuildSettings.settingsScreenShowEnableStunServerFallback, storage: defaults)
var settingsScreenShowEnableStunServerFallback
@UserDefault(key: "settingsScreenShowNotificationDecodedContentOption", defaultValue: BuildSettings.settingsScreenShowNotificationDecodedContentOption, storage: defaults)
var settingsScreenShowNotificationDecodedContentOption
@UserDefault(key: "settingsScreenShowNsfwRoomsOption", defaultValue: BuildSettings.settingsScreenShowNsfwRoomsOption, storage: defaults)
var settingsScreenShowNsfwRoomsOption
@UserDefault(key: "settingsSecurityScreenShowSessions", defaultValue: BuildSettings.settingsSecurityScreenShowSessions, storage: defaults)
var settingsSecurityScreenShowSessions
@UserDefault(key: "settingsSecurityScreenShowSetupBackup", defaultValue: BuildSettings.settingsSecurityScreenShowSetupBackup, storage: defaults)
var settingsSecurityScreenShowSetupBackup
@UserDefault(key: "settingsSecurityScreenShowRestoreBackup", defaultValue: BuildSettings.settingsSecurityScreenShowRestoreBackup, storage: defaults)
var settingsSecurityScreenShowRestoreBackup
@UserDefault(key: "settingsSecurityScreenShowDeleteBackup", defaultValue: BuildSettings.settingsSecurityScreenShowDeleteBackup, storage: defaults)
var settingsSecurityScreenShowDeleteBackup
@UserDefault(key: "settingsSecurityScreenShowCryptographyInfo", defaultValue: BuildSettings.settingsSecurityScreenShowCryptographyInfo, storage: defaults)
var settingsSecurityScreenShowCryptographyInfo
@UserDefault(key: "settingsSecurityScreenShowCryptographyExport", defaultValue: BuildSettings.settingsSecurityScreenShowCryptographyExport, storage: defaults)
var settingsSecurityScreenShowCryptographyExport
@UserDefault(key: "settingsSecurityScreenShowAdvancedBlacklistUnverifiedDevices", defaultValue: BuildSettings.settingsSecurityScreenShowAdvancedUnverifiedDevices, storage: defaults)
var settingsSecurityScreenShowAdvancedUnverifiedDevices
// MARK: - Room Settings Screen
var roomSettingsScreenShowLowPriorityOption: Bool {
get {
guard defaults.object(forKey: UserDefaultsKeys.roomSettingsScreenShowLowPriorityOption) != nil else {
return BuildSettings.roomSettingsScreenShowLowPriorityOption
}
return defaults.bool(forKey: UserDefaultsKeys.roomSettingsScreenShowLowPriorityOption)
} set {
defaults.set(newValue, forKey: UserDefaultsKeys.roomSettingsScreenShowLowPriorityOption)
}
}
var roomSettingsScreenShowDirectChatOption: Bool {
get {
guard defaults.object(forKey: UserDefaultsKeys.roomSettingsScreenShowDirectChatOption) != nil else {
return BuildSettings.roomSettingsScreenShowDirectChatOption
}
return defaults.bool(forKey: UserDefaultsKeys.roomSettingsScreenShowDirectChatOption)
} set {
defaults.set(newValue, forKey: UserDefaultsKeys.roomSettingsScreenShowDirectChatOption)
}
}
var roomSettingsScreenAllowChangingAccessSettings: Bool {
get {
guard defaults.object(forKey: UserDefaultsKeys.roomSettingsScreenAllowChangingAccessSettings) != nil else {
return BuildSettings.roomSettingsScreenAllowChangingAccessSettings
}
return defaults.bool(forKey: UserDefaultsKeys.roomSettingsScreenAllowChangingAccessSettings)
} set {
defaults.set(newValue, forKey: UserDefaultsKeys.roomSettingsScreenAllowChangingAccessSettings)
}
}
var roomSettingsScreenAllowChangingHistorySettings: Bool {
get {
guard defaults.object(forKey: UserDefaultsKeys.roomSettingsScreenAllowChangingHistorySettings) != nil else {
return BuildSettings.roomSettingsScreenAllowChangingHistorySettings
}
return defaults.bool(forKey: UserDefaultsKeys.roomSettingsScreenAllowChangingHistorySettings)
} set {
defaults.set(newValue, forKey: UserDefaultsKeys.roomSettingsScreenAllowChangingHistorySettings)
}
}
var roomSettingsScreenShowAddressSettings: Bool {
get {
guard defaults.object(forKey: UserDefaultsKeys.roomSettingsScreenShowAddressSettings) != nil else {
return BuildSettings.roomSettingsScreenShowAddressSettings
}
return defaults.bool(forKey: UserDefaultsKeys.roomSettingsScreenShowAddressSettings)
} set {
defaults.set(newValue, forKey: UserDefaultsKeys.roomSettingsScreenShowAddressSettings)
}
}
var roomSettingsScreenShowFlairSettings: Bool {
get {
guard defaults.object(forKey: UserDefaultsKeys.roomSettingsScreenShowFlairSettings) != nil else {
return BuildSettings.roomSettingsScreenShowFlairSettings
}
return defaults.bool(forKey: UserDefaultsKeys.roomSettingsScreenShowFlairSettings)
} set {
defaults.set(newValue, forKey: UserDefaultsKeys.roomSettingsScreenShowFlairSettings)
}
}
var roomSettingsScreenShowAdvancedSettings: Bool {
get {
guard defaults.object(forKey: UserDefaultsKeys.roomSettingsScreenShowAdvancedSettings) != nil else {
return BuildSettings.roomSettingsScreenShowAdvancedSettings
}
return defaults.bool(forKey: UserDefaultsKeys.roomSettingsScreenShowAdvancedSettings)
} set {
defaults.set(newValue, forKey: UserDefaultsKeys.roomSettingsScreenShowAdvancedSettings)
}
}
var roomSettingsScreenAdvancedShowEncryptToVerifiedOption: Bool {
get {
guard defaults.object(forKey: UserDefaultsKeys.roomSettingsScreenAdvancedShowEncryptToVerifiedOption) != nil else {
return BuildSettings.roomSettingsScreenAdvancedShowEncryptToVerifiedOption
}
return defaults.bool(forKey: UserDefaultsKeys.roomSettingsScreenAdvancedShowEncryptToVerifiedOption)
} set {
defaults.set(newValue, forKey: UserDefaultsKeys.roomSettingsScreenAdvancedShowEncryptToVerifiedOption)
}
}
@UserDefault(key: "roomSettingsScreenShowLowPriorityOption", defaultValue: BuildSettings.roomSettingsScreenShowLowPriorityOption, storage: defaults)
var roomSettingsScreenShowLowPriorityOption
@UserDefault(key: "roomSettingsScreenShowDirectChatOption", defaultValue: BuildSettings.roomSettingsScreenShowDirectChatOption, storage: defaults)
var roomSettingsScreenShowDirectChatOption
@UserDefault(key: "roomSettingsScreenAllowChangingAccessSettings", defaultValue: BuildSettings.roomSettingsScreenAllowChangingAccessSettings, storage: defaults)
var roomSettingsScreenAllowChangingAccessSettings
@UserDefault(key: "roomSettingsScreenAllowChangingHistorySettings", defaultValue: BuildSettings.roomSettingsScreenAllowChangingHistorySettings, storage: defaults)
var roomSettingsScreenAllowChangingHistorySettings
@UserDefault(key: "roomSettingsScreenShowAddressSettings", defaultValue: BuildSettings.roomSettingsScreenShowAddressSettings, storage: defaults)
var roomSettingsScreenShowAddressSettings
@UserDefault(key: "roomSettingsScreenShowFlairSettings", defaultValue: BuildSettings.roomSettingsScreenShowFlairSettings, storage: defaults)
var roomSettingsScreenShowFlairSettings
@UserDefault(key: "roomSettingsScreenShowAdvancedSettings", defaultValue: BuildSettings.roomSettingsScreenShowAdvancedSettings, storage: defaults)
var roomSettingsScreenShowAdvancedSettings
@UserDefault(key: "roomSettingsScreenAdvancedShowEncryptToVerifiedOption", defaultValue: BuildSettings.roomSettingsScreenAdvancedShowEncryptToVerifiedOption, storage: defaults)
var roomSettingsScreenAdvancedShowEncryptToVerifiedOption
// MARK: - Unified Search
var unifiedSearchScreenShowPublicDirectory: Bool {
get {
guard defaults.object(forKey: UserDefaultsKeys.unifiedSearchScreenShowPublicDirectory) != nil else {
return BuildSettings.unifiedSearchScreenShowPublicDirectory
}
return defaults.bool(forKey: UserDefaultsKeys.unifiedSearchScreenShowPublicDirectory)
} set {
defaults.set(newValue, forKey: UserDefaultsKeys.unifiedSearchScreenShowPublicDirectory)
}
}
@UserDefault(key: "unifiedSearchScreenShowPublicDirectory", defaultValue: BuildSettings.unifiedSearchScreenShowPublicDirectory, storage: defaults)
var unifiedSearchScreenShowPublicDirectory
// MARK: - Secrets Recovery
var secretsRecoveryAllowReset: Bool {
get {
guard defaults.object(forKey: UserDefaultsKeys.secretsRecoveryAllowReset) != nil else {
return BuildSettings.secretsRecoveryAllowReset
}
return defaults.bool(forKey: UserDefaultsKeys.secretsRecoveryAllowReset)
} set {
defaults.set(newValue, forKey: UserDefaultsKeys.secretsRecoveryAllowReset)
}
}
@UserDefault(key: "secretsRecoveryAllowReset", defaultValue: BuildSettings.secretsRecoveryAllowReset, storage: defaults)
var secretsRecoveryAllowReset
// MARK: - Beta
var hideSpaceBetaAnnounce: Bool {
get {
return defaults.bool(forKey: UserDefaultsKeys.hideSpaceBetaAnnounce)
} set {
defaults.set(newValue, forKey: UserDefaultsKeys.hideSpaceBetaAnnounce)
}
}
@UserDefault(key: "hideSpaceBetaAnnounce", defaultValue: false, storage: defaults)
var hideSpaceBetaAnnounce
// MARK: - Version check
var versionCheckNextDisplayDateTimeInterval: TimeInterval {
get {
return defaults.double(forKey: UserDefaultsKeys.versionCheckNextDisplayDateTimeInterval)
} set {
defaults.set(newValue, forKey: UserDefaultsKeys.versionCheckNextDisplayDateTimeInterval)
}
}
@UserDefault(key: "versionCheckNextDisplayDateTimeInterval", defaultValue: 0.0, storage: defaults)
var versionCheckNextDisplayDateTimeInterval
}

View file

@ -142,12 +142,8 @@ class DarkTheme: NSObject, Theme {
}
/// MARK: - Theme v2
var colors: ColorsUIKit = DarkColors.uiKit
lazy var colors: Colors = {
return DarkColors()
}()
var fonts: FontsUIKit = FontsUIKit(values: ElementFonts())
lazy var fonts: Fonts = {
return ElementFonts()
}()
}

View file

@ -149,12 +149,7 @@ class DefaultTheme: NSObject, Theme {
}
/// MARK: - Theme v2
var colors: ColorsUIKit = LightColors.uiKit
lazy var colors: Colors = {
return LightColors()
}()
lazy var fonts: Fonts = {
return ElementFonts()
}()
var fonts: FontsUIKit = FontsUIKit(values: ElementFonts())
}

View file

@ -103,6 +103,18 @@ final class AppCoordinator: NSObject, AppCoordinatorType {
private func setupTheme() {
ThemeService.shared().themeId = RiotSettings.shared.userInterfaceTheme
if #available(iOS 14.0, *) {
guard let themeId = ThemeService.shared().themeIdentifier else {
MXLog.error("[AppCoordinator] No theme id found to update ThemePublisher")
return
}
ThemePublisher.configure(themeId: themeId)
let themeIdPublisher = NotificationCenter.default.publisher(for: Notification.Name.themeServiceDidChangeTheme)
.compactMap({ _ in ThemeService.shared().themeIdentifier })
.eraseToAnyPublisher()
ThemePublisher.shared.republish(themeIdPublisher: themeIdPublisher)
}
}
private func showAuthentication() {

View file

@ -2040,8 +2040,7 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
if (clearCache)
{
// clear the media cache
[MXMediaManager clearCache];
[self clearCache];
}
}
@ -2143,7 +2142,7 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
[self.pushNotificationService deregisterRemoteNotifications];
// Clear cache
[MXMediaManager clearCache];
[self clearCache];
// Reset key backup banner preferences
[SecureBackupBannerPreferences.shared reset];
@ -4322,4 +4321,13 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
return [authVC continueSSOLoginWithToken:loginToken txnId:txnId];
}
#pragma mark - Private
- (void)clearCache
{
[MXMediaManager clearCache];
[MXKAttachment clearCache];
[VoiceMessageAttachmentCacheManagerBridge clearCache];
}
@end

View file

@ -19,14 +19,6 @@ import MatrixSDK
import Combine
import DesignKit
/**
Provides a simple api to retrieve and cache avatar images
*/
protocol AvatarServiceType {
@available(iOS 14.0, *)
func avatarImage(mxContentUri: String, avatarSize: AvatarSize) -> Future<UIImage, Error>
}
enum AvatarServiceError: Error {
case pathNotfound
case loadingImageFailed(Error?)

View file

@ -17,7 +17,7 @@
import Foundation
/// AvatarViewDataProtocol describe a view data that should be given to an AvatarView sublcass
protocol AvatarViewDataProtocol {
protocol AvatarViewDataProtocol: AvatarType {
/// Matrix item identifier (user id or room id)
var matrixItemId: String { get }

View file

@ -200,7 +200,7 @@
// Preview the public room
if (publicRoom.worldReadable)
{
RoomPreviewData *roomPreviewData = [[RoomPreviewData alloc] initWithRoomId:publicRoom.roomId andSession:dataSource.mxSession];
RoomPreviewData *roomPreviewData = [[RoomPreviewData alloc] initWithPublicRoom:publicRoom andSession:dataSource.mxSession];
[self startActivityIndicator];

View file

@ -27,6 +27,8 @@ class HomeViewControllerWithBannerWrapperViewController: UIViewController, Banne
super.init(nibName: nil, bundle: nil)
extendedLayoutIncludesOpaqueBars = true
self.tabBarItem.tag = viewController.tabBarItem.tag
self.tabBarItem.image = viewController.tabBarItem.image
self.accessibilityLabel = viewController.accessibilityLabel

View file

@ -19,7 +19,7 @@ import Foundation
class VersionCheckCoordinator: Coordinator, VersionCheckBannerViewDelegate, VersionCheckAlertViewControllerDelegate {
private enum Constants {
static let osVersionToBeDropped = 11
static let hasOSVersionBeenDropped = false
static let hasOSVersionBeenDropped = true
static let supportURL = URL(string: "https://support.apple.com/en-gb/guide/iphone/iph3e504502/ios")
}

View file

@ -144,7 +144,7 @@ final class RoomNotificationSettingsViewController: UIViewController {
activityPresenter.removeCurrentActivityIndicator(animated: true)
}
self.viewState = viewState
if case let .uiKit(avatarData) = viewState.avatarData {
if let avatarData = viewState.avatarData as? AvatarViewDataProtocol {
mainTableView.tableHeaderView = avatarView
avatarView.configure(viewData: avatarData)
avatarView.update(theme: theme)

View file

@ -26,6 +26,7 @@ enum VoiceMessageAttachmentCacheManagerError: Error {
case durationError(Error?)
case invalidNumberOfSamples
case samplingError
case cancelled
}
/**
@ -51,6 +52,12 @@ struct VoiceMessageAttachmentCacheManagerLoadResult {
let samples: [Float]
}
@objc class VoiceMessageAttachmentCacheManagerBridge: NSObject {
@objc static func clearCache() {
VoiceMessageAttachmentCacheManager.sharedManager.clearCache()
}
}
class VoiceMessageAttachmentCacheManager {
private struct Constants {
@ -67,6 +74,10 @@ class VoiceMessageAttachmentCacheManager {
private let workQueue: DispatchQueue
private let operationQueue: OperationQueue
private var temporaryFilesFolderURL: URL {
return URL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true).appendingPathComponent("VoiceMessages")
}
private init() {
workQueue = DispatchQueue(label: "io.element.VoiceMessageAttachmentCacheManager.queue", qos: .userInitiated)
operationQueue = OperationQueue()
@ -76,16 +87,27 @@ class VoiceMessageAttachmentCacheManager {
func loadAttachment(_ attachment: MXKAttachment, numberOfSamples: Int, completion: @escaping (Result<VoiceMessageAttachmentCacheManagerLoadResult, Error>) -> Void) {
guard attachment.type == MXKAttachmentTypeVoiceMessage else {
completion(Result.failure(VoiceMessageAttachmentCacheManagerError.invalidAttachmentType))
MXLog.error("[VoiceMessageAttachmentCacheManager] Invalid attachment type, ignoring request.")
return
}
guard let identifier = attachment.eventId else {
completion(Result.failure(VoiceMessageAttachmentCacheManagerError.invalidEventId))
MXLog.error("[VoiceMessageAttachmentCacheManager] Invalid event id, ignoring request.")
return
}
guard numberOfSamples > 0 else {
completion(Result.failure(VoiceMessageAttachmentCacheManagerError.invalidNumberOfSamples))
MXLog.error("[VoiceMessageAttachmentCacheManager] Invalid number of samples, ignoring request.")
return
}
do {
try setupTemporaryFilesFolder()
} catch {
completion(Result.failure(VoiceMessageAttachmentCacheManagerError.preparationError(error)))
MXLog.error("[VoiceMessageAttachmentCacheManager] Failed creating temporary files folder with error: \(error)")
return
}
@ -105,6 +127,23 @@ class VoiceMessageAttachmentCacheManager {
}
}
func clearCache() {
for key in completionCallbacks.keys {
invokeFailureCallbacksForIdentifier(key.eventIdentifier, requiredNumberOfSamples: key.requiredNumberOfSamples, error: VoiceMessageAttachmentCacheManagerError.cancelled)
}
operationQueue.cancelAllOperations()
samples.removeAll()
durations.removeAll()
finalURLs.removeAll()
do {
try FileManager.default.removeItem(at: temporaryFilesFolderURL)
} catch {
MXLog.error("[VoiceMessageAttachmentCacheManager] Failed clearing cached disk files with error: \(error)")
}
}
private func enqueueLoadAttachment(_ attachment: MXKAttachment, identifier: String, numberOfSamples: Int, completion: @escaping (Result<VoiceMessageAttachmentCacheManagerLoadResult, Error>) -> Void) {
let callbackKey = CompletionCallbackKey(eventIdentifier: identifier, requiredNumberOfSamples: numberOfSamples)
@ -169,8 +208,7 @@ class VoiceMessageAttachmentCacheManager {
return
}
let temporaryDirectoryURL = URL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true)
let newURL = temporaryDirectoryURL.appendingPathComponent(ProcessInfo().globallyUniqueString).appendingPathExtension("m4a")
let newURL = temporaryFilesFolderURL.appendingPathComponent(ProcessInfo().globallyUniqueString).appendingPathExtension("m4a")
VoiceMessageAudioConverter.convertToMPEG4AAC(sourceURL: URL(fileURLWithPath: filePath), destinationURL: newURL) { result in
self.workQueue.async {
@ -275,4 +313,9 @@ class VoiceMessageAttachmentCacheManager {
MXLog.debug("[VoiceMessageAttachmentCacheManager] Failed task with error: \(error)")
}
private func setupTemporaryFilesFolder() throws {
let url = temporaryFilesFolderURL
try FileManager.default.createDirectory(at: url, withIntermediateDirectories: true, attributes: nil)
}
}

View file

@ -75,8 +75,8 @@
- (HomeViewController *)homeViewController
{
HomeViewControllerWithBannerWrapperViewController *wrapperVC = [self viewControllerForClass:HomeViewControllerWithBannerWrapperViewController.class];
return wrapperVC.homeViewController;
UIViewController *wrapperVC = [self viewControllerForClass:HomeViewControllerWithBannerWrapperViewController.class];
return [(HomeViewControllerWithBannerWrapperViewController *)wrapperVC homeViewController];
}
- (FavouritesViewController *)favouritesViewController

View file

@ -0,0 +1,61 @@
//
// 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.
//
// Taken from https://www.swiftbysundell.com/articles/property-wrappers-in-swift/
import Foundation
@propertyWrapper
struct UserDefault<Value> {
private let key: String
private let defaultValue: Value
private let storage: UserDefaults
init(key: String, defaultValue: Value, storage: UserDefaults = .standard) {
self.defaultValue = defaultValue
self.key = key
self.storage = storage
}
var wrappedValue: Value {
get {
let value = storage.value(forKey: key) as? Value
return value ?? defaultValue
}
set {
if let optional = newValue as? AnyOptional, optional.isNil {
storage.removeObject(forKey: key)
} else {
storage.setValue(newValue, forKey: key)
}
}
}
}
extension UserDefault where Value: ExpressibleByNilLiteral {
init(key: String, storage: UserDefaults = .standard) {
self.init(key: key, defaultValue: nil, storage: storage)
}
}
private protocol AnyOptional {
var isNil: Bool { get }
}
extension Optional: AnyOptional {
var isNil: Bool { self == nil }
}

View file

@ -51,6 +51,10 @@ targets:
script: "\"${PODS_ROOT}/SwiftGen/bin/swiftgen\" config run --config \"Tools/SwiftGen/swiftgen-config.yml\"\n"
sources:
- path: ../RiotSwiftUI/Modules
# Riot will provide it's own LocaleProviderType so exclude.
excludes:
- "Common/Locale/LocaleProvider.swift"
- path: ../Tools
excludes:
- "Logs"

View file

@ -48,6 +48,8 @@ targets:
- path: ../Riot/Modules/SetPinCode/SetupBiometrics/BiometricsAuthenticationPresenter.swift
- path: ../Riot/Categories/UNUserNotificationCenter.swift
- path: ../Riot/Managers/KeyValueStorage/KeyValueStore.swift
- path: ../Riot/Managers/Locale/LocaleProvider.swift
- path: ../Riot/Managers/Locale/LocaleProviderType.swift
- path: ../Riot/Managers/EncryptionKeyManager/EncryptionKeyManager.swift
- path: ../Riot/Categories/Bundle.swift
- path: ../Riot/Generated/Strings.swift
@ -59,3 +61,4 @@ targets:
- path: ../Riot/Categories/String.swift
- path: ../Riot/Categories/Character.swift
- path: ../Riot/Managers/Widgets/WidgetConstants.m
- path: ../Riot/PropertyWrappers/UserDefaultsBackedPropertyWrapper.swift

View file

@ -56,6 +56,7 @@ targets:
- path: ../Riot/Categories/UISearchBar.swift
- path: ../Riot/Categories/String.swift
- path: ../Riot/Modules/Common/Recents/CellData/RecentCellData.m
- path: ../Riot/PropertyWrappers/UserDefaultsBackedPropertyWrapper.swift
- path: ../Riot/Modules/Common/SegmentedViewController/SegmentedViewController.xib
buildPhase: resources
- path: ../Riot/Assets/en.lproj/Vector.strings

View file

@ -0,0 +1,28 @@
//
// 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"
#include "Config/AppVersion.xcconfig"
PRODUCT_NAME = RiotSwiftUI
PRODUCT_BUNDLE_IDENTIFIER = $(BASE_BUNDLE_IDENTIFIER).riotswiftui
INFOPLIST_FILE = RiotSwiftUI/Info.plist
SKIP_INSTALL = YES

View 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"

22
RiotSwiftUI/Info.plist Normal file
View 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>

View file

@ -17,6 +17,7 @@
import Foundation
import Combine
import DesignKit
import UIKit
@available(iOS 14.0, *)
class MockAvatarService: AvatarServiceType {

View file

@ -16,7 +16,7 @@
import Foundation
protocol AvatarInputType {
protocol AvatarInputType: AvatarType {
var mxContentUri: String? { get }
var matrixItemId: String { get }
var displayName: String? { get }
@ -27,8 +27,3 @@ struct AvatarInput: AvatarInputType {
var matrixItemId: String
let displayName: String?
}
enum AvatarInputOption {
case swiftUI(AvatarInputType)
case uiKit(AvatarViewDataProtocol)
}

View file

@ -0,0 +1,19 @@
//
// 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
protocol AvatarType { }

View file

@ -20,7 +20,7 @@ import DesignKit
@available(iOS 14.0, *)
struct AvatarImage: View {
@Environment(\.theme) var theme: Theme
@Environment(\.theme) var theme: ThemeSwiftUI
@Environment(\.dependencies) var dependencies: DependencyContainer
@StateObject var viewModel = AvatarViewModel()
@ -39,7 +39,7 @@ struct AvatarImage: View {
.padding(4)
.frame(width: CGFloat(size.rawValue), height: CGFloat(size.rawValue))
.foregroundColor(.white)
.background(Color(theme.avatarColors[colorIndex]))
.background(theme.colors.namesAndAvatars[colorIndex])
.clipShape(Circle())
// Make the text resizable (i.e. Make it large and then allow it to scale down)
.font(.system(size: 200))
@ -57,7 +57,7 @@ struct AvatarImage: View {
mxContentUri: mxContentUri,
matrixItemId: matrixItemId,
displayName: displayName,
colorCount: theme.avatarColors.count,
colorCount: theme.colors.namesAndAvatars.count,
avatarSize: size
)
}

View 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 DesignKit
import Combine
import UIKit
/**
Provides a simple api to retrieve and cache avatar images
*/
protocol AvatarServiceType {
@available(iOS 14.0, *)
func avatarImage(mxContentUri: String, avatarSize: AvatarSize) -> Future<UIImage, Error>
}

View file

@ -47,7 +47,7 @@ class AvatarViewModel: InjectableObject, ObservableObject {
avatarService.avatarImage(mxContentUri: mxContentUri, avatarSize: avatarSize)
.sink { completion in
guard case let .failure(error) = completion else { return }
MXLog.error("[AvatarService] Failed to retrieve avatar: \(error)")
// MXLog.error("[AvatarService] Failed to retrieve avatar: \(error)")
// TODO: Report non-fatal error when we have Sentry or similar.
} receiveValue: { image in
self.viewState = .avatar(image)

View file

@ -15,6 +15,7 @@
//
import Foundation
import UIKit
enum AvatarViewState {
case empty

View file

@ -23,17 +23,17 @@ import SwiftUI
@available(iOS 14.0, *)
struct VectorContentModifier: ViewModifier {
@StateObject private var themeObserver = ThemeObserver.shared
@ObservedObject private var themePublisher = ThemePublisher.shared
func body(content: Content) -> some View {
content
.theme(themeObserver.theme)
.theme(themePublisher.theme)
}
}
@available(iOS 14.0, *)
extension View {
func vectorContent() -> some View {
self.modifier(VectorContentModifier())
}
func vectorContent() -> some View {
self.modifier(VectorContentModifier())
}
}

View file

@ -0,0 +1,23 @@
//
// 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
class LocaleProvider: LocaleProviderType {
static var locale: Locale? {
return nil
}
}

View file

@ -15,17 +15,21 @@
//
import Foundation
import Combine
import DesignKit
/**
Extension to `ThemeIdentifier` for getting the SwiftUI theme.
*/
@available(iOS 14.0, *)
class ThemeObserver: ObservableObject {
static let shared = ThemeObserver()
init() {
NotificationCenter.default.publisher(for: NSNotification.Name.themeServiceDidChangeTheme).map { _ in
ThemeService.shared().theme
}.assign(to: &$theme)
extension ThemeIdentifier {
fileprivate static let defaultTheme = DefaultThemeSwiftUI()
fileprivate static let darkTheme = DarkThemeSwiftUI()
public var themeSwiftUI: ThemeSwiftUI {
switch self {
case .light:
return Self.defaultTheme
case .dark, .black:
return Self.darkTheme
}
}
@Published var theme: Theme = ThemeService.shared().theme
}

View file

@ -16,14 +16,16 @@
import Foundation
import SwiftUI
import DesignKit
@available(iOS 14.0, *)
private struct ThemeKey: EnvironmentKey {
static let defaultValue = ThemeService.shared().theme
static let defaultValue = ThemePublisher.shared.theme
}
@available(iOS 14.0, *)
extension EnvironmentValues {
var theme: Theme {
var theme: ThemeSwiftUI {
get { self[ThemeKey.self] }
set { self[ThemeKey.self] = newValue }
}
@ -36,7 +38,7 @@ extension EnvironmentValues {
*/
@available(iOS 14.0, *)
extension View {
func theme(_ theme: Theme) -> some View {
func theme(_ theme: ThemeSwiftUI) -> some View {
environment(\.theme, theme)
}
}
@ -49,7 +51,6 @@ extension View {
@available(iOS 14.0, *)
extension View {
func theme(_ themeId: ThemeIdentifier) -> some View {
let theme = ThemeService.shared().theme(withThemeId: themeId.rawValue)
return environment(\.theme, theme)
return environment(\.theme, themeId.themeSwiftUI)
}
}

View file

@ -0,0 +1,51 @@
//
// 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 Combine
/**
Provides the theme and theme updates to SwiftUI.
Replaces the old ThemeObserver. Riot app can push updates to this class
removing the dependency of this class on the `ThemeService`.
*/
@available(iOS 14.0, *)
class ThemePublisher: ObservableObject {
private static var _shared: ThemePublisher? = nil
static var shared: ThemePublisher {
if _shared == nil {
configure(themeId: .light)
}
return _shared!
}
@Published private(set) var theme: ThemeSwiftUI
static func configure(themeId: ThemeIdentifier) {
_shared = ThemePublisher(themeId: .light)
}
init(themeId: ThemeIdentifier) {
_theme = Published.init(initialValue: themeId.themeSwiftUI)
}
func republish(themeIdPublisher: AnyPublisher<ThemeIdentifier, Never>) {
themeIdPublisher
.map(\.themeSwiftUI)
.assign(to: &$theme)
}
}

View file

@ -0,0 +1,23 @@
//
// 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 DesignKit
@available(iOS 14.0, *)
protocol ThemeSwiftUI: ThemeSwiftUIType {
var identifier: ThemeIdentifier { get }
}

View file

@ -0,0 +1,25 @@
//
// 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 DesignKit
@available(iOS 14.0, *)
struct DarkThemeSwiftUI: ThemeSwiftUI {
var identifier: ThemeIdentifier = .dark
var colors: ColorSwiftUI = DarkColors.swiftUI
var fonts: FontSwiftUI = FontSwiftUI(values: ElementFonts())
}

View file

@ -0,0 +1,25 @@
//
// 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 DesignKit
@available(iOS 14.0, *)
struct DefaultThemeSwiftUI: ThemeSwiftUI {
var identifier: ThemeIdentifier = .light
var colors: ColorSwiftUI = LightColors.swiftUI
var fonts: FontSwiftUI = FontSwiftUI(values: ElementFonts())
}

View file

@ -38,25 +38,24 @@ final class RoomNotificationSettingsCoordinator: RoomNotificationSettingsCoordin
// MARK: - Setup
init(room: MXRoom, presentedModally: Bool = true) {
let roomNotificationService = RoomNotificationSettingsService(room: room)
let avatarData: AvatarInputOption?
let roomNotificationService = MXRoomNotificationSettingsService(room: room)
let avatarData: AvatarType?
let showAvatar = presentedModally
if #available(iOS 14.0.0, *) {
avatarData = showAvatar ? .swiftUI(AvatarInput(
avatarData = showAvatar ? AvatarInput(
mxContentUri: room.summary.avatar,
matrixItemId: room.roomId,
displayName: room.summary.displayname
)) : nil
) : nil
} else {
avatarData = showAvatar ? .uiKit(RoomAvatarViewData(
avatarData = showAvatar ? RoomAvatarViewData(
roomId: room.roomId,
displayName: room.summary.displayname,
avatarUrl: room.summary.avatar,
mediaManager: room.mxSession.mediaManager
)) : nil
) : nil
}
let viewModel: RoomNotificationSettingsViewModel
let viewController: UIViewController
if #available(iOS 14.0.0, *) {

View file

@ -0,0 +1,43 @@
//
// 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
/// RoomNotificationSettingsViewController view state
struct RoomNotificationSettingsViewState: RoomNotificationSettingsViewStateType {
let roomEncrypted: Bool
var saving: Bool
var notificationState: RoomNotificationState
var avatarData: AvatarType?
var displayName: String?
}
extension RoomNotificationSettingsViewState {
var notificationOptions: [RoomNotificationState] {
if roomEncrypted {
return [.all, .mute]
} else {
return RoomNotificationState.allCases
}
}
}
extension RoomNotificationSettingsViewState {
var roomEncryptedString: String {
roomEncrypted ? VectorL10n.roomNotifsSettingsEncryptedRoomNotice : ""
}
}

View file

@ -18,36 +18,12 @@
import Foundation
/// RoomNotificationSettingsViewController view state
struct RoomNotificationSettingsViewState: RoomNotificationSettingsViewStateType {
let roomEncrypted: Bool
var saving: Bool
var notificationState: RoomNotificationState
var avatarData: AvatarInputOption?
var displayName: String?
}
extension RoomNotificationSettingsViewState {
var notificationOptions: [RoomNotificationState] {
if roomEncrypted {
return [.all, .mute]
} else {
return RoomNotificationState.allCases
}
}
}
protocol RoomNotificationSettingsViewStateType {
var saving: Bool { get }
var roomEncrypted: Bool { get }
var notificationOptions: [RoomNotificationState] { get }
var notificationState: RoomNotificationState { get }
var avatarData: AvatarInputOption? { get }
var avatarData: AvatarType? { get }
var displayName: String? { get }
}
extension RoomNotificationSettingsViewState {
var roomEncryptedString: String {
roomEncrypted ? VectorL10n.roomNotifsSettingsEncryptedRoomNotice : ""
}
}

View file

@ -16,7 +16,7 @@
import Foundation
final class RoomNotificationSettingsService: RoomNotificationSettingsServiceType {
final class MXRoomNotificationSettingsService: RoomNotificationSettingsServiceType {
typealias Completion = () -> Void

View file

@ -19,11 +19,11 @@ import SwiftUI
@available(iOS 14.0, *)
struct FormItemButtonStyle: ButtonStyle {
@Environment(\.theme) var theme: Theme
@Environment(\.theme) var theme: ThemeSwiftUI
func makeBody(configuration: Self.Configuration) -> some View {
configuration.label
.background(configuration.isPressed ? Color(theme.selectedBackgroundColor) : Color(theme.backgroundColor))
.foregroundColor(Color(theme.textPrimaryColor))
.font(Font(theme.fonts.body))
.background(configuration.isPressed ? theme.colors.system : theme.colors.background)
.foregroundColor(theme.colors.primaryContent)
.font(theme.fonts.body)
}
}

View file

@ -21,7 +21,7 @@ struct FormPickerItem: View {
typealias TapCallback = () -> Void
@Environment(\.theme) var theme: Theme
@Environment(\.theme) var theme: ThemeSwiftUI
var title: String
var selected: Bool
@ -38,7 +38,7 @@ struct FormPickerItem: View {
Spacer()
if selected {
Image("checkmark")
.foregroundColor(Color(theme.tintColor))
.foregroundColor(theme.colors.accent)
}
}
.padding(.trailing)
@ -55,6 +55,7 @@ struct FormPickerItem: View {
@available(iOS 14.0, *)
struct FormPickerItem_Previews: PreviewProvider {
static let items = ["Item 1", "Item 2", "Item 3"]
static var selected: String = items[0]
static var previews: some View {

View file

@ -19,16 +19,16 @@ import SwiftUI
@available(iOS 14.0, *)
struct FormSectionFooter: View {
@Environment(\.theme) var theme: Theme
@Environment(\.theme) var theme: ThemeSwiftUI
var text: String
var body: some View {
Text(text)
.foregroundColor(Color(theme.textSecondaryColor))
.foregroundColor(theme.colors.secondaryContent)
.padding(.top)
.padding(.leading)
.padding(.trailing)
.font(Font(theme.fonts.callout))
.font(theme.fonts.callout)
}
}

View file

@ -19,16 +19,16 @@ import SwiftUI
@available(iOS 14.0, *)
struct FormSectionHeader: View {
@Environment(\.theme) var theme: Theme
@Environment(\.theme) var theme: ThemeSwiftUI
var text: String
var body: some View {
Text(text)
.foregroundColor(Color(theme.textSecondaryColor))
.foregroundColor(theme.colors.secondaryContent)
.padding(.top, 32)
.padding(.leading)
.padding(.bottom, 8)
.font(Font(theme.fonts.subheadline))
.font(theme.fonts.subheadline)
.textCase(.uppercase)
.frame(maxWidth: .infinity, alignment: .leading)
}

View file

@ -41,7 +41,7 @@ struct RoomNotificationSettings: View {
var body: some View {
VectorForm {
if case let .swiftUI(avatarData) = viewModel.viewState.avatarData {
if let avatarData = viewModel.viewState.avatarData as? AvatarInputType {
RoomNotificationSettingsHeader(
avatarData: avatarData,
displayName: viewModel.viewState.displayName
@ -75,7 +75,7 @@ struct RoomNotificationSettings_Previews: PreviewProvider {
static let mockViewModel = RoomNotificationSettingsSwiftUIViewModel(
roomNotificationService: MockRoomNotificationSettingsService.example,
avatarData: .swiftUI(MockAvatarInput.example),
avatarData: MockAvatarInput.example,
displayName: MockAvatarInput.example.displayName,
roomEncrypted: true
)

View file

@ -19,7 +19,7 @@ import SwiftUI
@available(iOS 14.0, *)
struct RoomNotificationSettingsHeader: View {
@Environment(\.theme) var theme: Theme
@Environment(\.theme) var theme: ThemeSwiftUI
var avatarData: AvatarInputType
var displayName: String?
@ -30,8 +30,8 @@ struct RoomNotificationSettingsHeader: View {
AvatarImage(avatarData: avatarData, size: .xxLarge)
if let displayName = displayName {
Text(displayName)
.font(Font(theme.fonts.title3SB))
.foregroundColor(Color(theme.textPrimaryColor))
.font(theme.fonts.title3SB)
.foregroundColor(theme.colors.primaryContent)
.textCase(nil)
}
}

View file

@ -19,7 +19,7 @@ import SwiftUI
@available(iOS 14.0, *)
struct VectorForm<Content: View>: View {
@Environment(\.theme) var theme: Theme
@Environment(\.theme) var theme: ThemeSwiftUI
var content: () -> Content
init(@ViewBuilder content: @escaping () -> Content) {
@ -37,7 +37,7 @@ struct VectorForm<Content: View>: View {
maxHeight: .infinity,
alignment: .top
)
.background(Color(theme.baseColor))
.background(theme.colors.system)
.edgesIgnoringSafeArea(.bottom)
}

View file

@ -55,7 +55,7 @@ class RoomNotificationSettingsViewModel: RoomNotificationSettingsViewModelType {
convenience init(
roomNotificationService: RoomNotificationSettingsServiceType,
avatarData: AvatarInputOption?,
avatarData: AvatarType?,
displayName: String?,
roomEncrypted: Bool
) {

View file

@ -41,7 +41,7 @@ final class NotificationSettingsCoordinator: NotificationSettingsCoordinatorType
init(session: MXSession, screen: NotificationSettingsScreen) {
self.session = session
let notificationSettingsService = NotificationSettingsService(session: session)
let notificationSettingsService = MXNotificationSettingsService(session: session)
let viewModel = NotificationSettingsViewModel(notificationSettingsService: notificationSettingsService, ruleIds: screen.pushRules)
let viewController: UIViewController
switch screen {

View file

@ -0,0 +1,86 @@
//
// 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 DesignKit
/**
Conformance of MXPushRule to the abstraction `NotificationPushRule` for use in `NotificationSettingsViewModel`.
*/
extension MXPushRule: NotificationPushRuleType {
/*
Given a rule, check it match the actions in the static definition.
*/
func matches(standardActions: NotificationStandardActions?) -> Bool {
guard let standardActions = standardActions else {
return false
}
if !enabled && standardActions == .disabled {
return true
}
if enabled,
let actions = standardActions.actions,
highlight == actions.highlight,
sound == actions.sound,
notify == actions.notify,
dontNotify == !actions.notify {
return true
}
return false
}
private func getAction(actionType: MXPushRuleActionType, tweakType: String? = nil) -> MXPushRuleAction? {
guard let actions = actions as? [MXPushRuleAction] else {
return nil
}
return actions.first { action in
var match = action.actionType == actionType
if let tweakType = tweakType,
let actionTweak = action.parameters?["set_tweak"] as? String {
match = match && (tweakType == actionTweak)
}
return match
}
}
var highlight: Bool {
guard let action = getAction(actionType: MXPushRuleActionTypeSetTweak, tweakType: "highlight") else {
return false
}
if let highlight = action.parameters["value"] as? Bool {
return highlight
}
return true
}
var sound: String? {
guard let action = getAction(actionType: MXPushRuleActionTypeSetTweak, tweakType: "sound") else {
return nil
}
return action.parameters["value"] as? String
}
var notify: Bool {
return getAction(actionType: MXPushRuleActionTypeNotify) != nil
}
var dontNotify: Bool {
return getAction(actionType: MXPushRuleActionTypeDontNotify) != nil
}
}

View file

@ -0,0 +1,25 @@
//
// 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
struct MockNotificationPushRule: NotificationPushRuleType {
var ruleId: String!
var enabled: Bool
func matches(standardActions: NotificationStandardActions?) -> Bool {
return false
}
}

View file

@ -0,0 +1,23 @@
//
// 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
protocol NotificationPushRuleType {
var ruleId: String! { get }
var enabled: Bool { get }
func matches(standardActions: NotificationStandardActions?) -> Bool
}

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